浏览代码

Optimized Inventory, Cart Inventory, and Storage usage (#1115)

* These storage types now mimic Guild Storage and can be loaded/saved whenever needed.
* Relieves mmo_charstatus from having to send storage types and lets the char-server handle it.
* All storage types now have an increased max amount.
* Implemented Premium Storage System. Thanks to @cydh!
* Fixes #441 - Players will no longer be required to log out to resync cart item data before opening a Vending Store.
* Refactored player weight and cart weight calculations into their own functions.
* Added script commands openstorage2, guildstoragecountitem[2] and guildstoragedelitem[2].
* Refactored several function return types as well as documentation.
Thanks to @lighta and @cydh for their help with it!
Aleos 8 年之前
父节点
当前提交
ade1b171eb

+ 0 - 0
conf/import-tmpl/inter_server.conf


+ 2 - 1
conf/inter_athena.conf

@@ -93,7 +93,6 @@ scdata_db: sc_data
 cart_db: cart_inventory
 inventory_db: inventory
 charlog_db: charlog
-storage_db: storage
 skill_db: skill
 interlog_db: interlog
 memo_db: memo
@@ -150,4 +149,6 @@ db_roulette_table: db_roulette
 // Use SQL item_db, mob_db and mob_skill_db for the map server? (yes/no)
 use_sql_db: no
 
+inter_server_conf: conf/inter_server.conf
+
 import: conf/import/inter_conf.txt

+ 26 - 0
conf/inter_server.conf

@@ -0,0 +1,26 @@
+/**
+ * Config for Storages
+ *
+ * To access the premium storage, use script command 'openstorage2'.
+ * If premium storages are added, copy the structure of the storage table and match the table name in this config.
+ * The 'max' of premium storages are not adjusted by 'vip_storage_increase' config nor MIN_STORAGE.
+ *
+ * Structure:
+{
+	id: <storage_id>          // (int) Storage ID will be used for script command 'openstorage2'.
+	name: "<storage name>"    // (string) Storage name will be sent to the client to display on the title bar.
+	table: "<storage_table>"  // (string) Name of table where storage is saved. The table stucture is the same as the default storage table.
+	max: <max_amount>         // (int) *optional* Maximum number of items in storage. MAX_STORAGE will be used if no value is defined.
+},					          // Use comma to add more storages
+ **/
+
+storages: (
+{
+	// Default Storage
+	// DO NOT CHANGE THIS UNLESS YOU KNOW WHAT YOU ARE DOING
+	id: 0
+	name: "Storage"
+	table: "storage"
+	//max: 600
+}
+)

+ 1 - 1
conf/msg_conf/map_msg.conf

@@ -770,7 +770,7 @@
 
 732: Item cannot be opened when your inventory is full.
 
-733: Item '%s' has not yet saved to your cart. Please re-log in order to correctly save your Vending information.
+//733 free
 
 // @cloneequip/@clonestat
 734: Cannot clone your own %s.

+ 1 - 1
conf/msg_conf/map_msg_idn.conf

@@ -769,7 +769,7 @@
 
 732: Item tidak dapat dibuka ketika inventory penuh.
 
-733: Item '%s' belum tersimpan di gerobak. Harap masuk kembali untuk dapat menyimpan informasi vending dengan benar.
+//733 free
 
 // @cloneequip/@clonestat
 734: Tidak dapat mengkloning %s diri sendiri.

+ 67 - 0
doc/packet_interserv.txt

@@ -1328,6 +1328,33 @@ Currently the max packet size is 0xFFFF (see 'WFIFOSET()' in 'src/common/socket.
 	desc:
 		- Delete pet data
 
+0x308a
+	Type: ZI
+	Structure: <cmd>.W <type>.B <account_id>.L <char_id>.L
+	index: 0,2,3,7
+	len: 11
+	parameter:
+		- cmd : packet identification (0x308a)
+		- type : 0 - TABLE_INVENTORY, 1 - TABLE_CART, 2 - TABLE_STORAGE
+		- account_id
+		- char_id
+	desc:
+		- Request inventory/cart/storage data for a player/guild if type = 3
+
+0x308b
+	Type: ZI
+	Structure: <size>.W <type>.B <account_id>.L <char_id>.L <entries>.?B
+	index: 0,2,4,5,9,13
+	len: 11
+	parameter:
+		- cmd : packet identification (0x308a)
+		- type : 0 - TABLE_INVENTORY, 1 - TABLE_CART, 2 - TABLE_STORAGE
+		- account_id
+		- char_id
+		- entries : Inventory/cart/storage entries that will be saved
+	desc:
+		- Request to save inventory/cart/storage entries
+
 0x3090:
 	Type: ZI
 	Structure: <cmd>.W <s_homunculus>.W <aid>.L <sh>.?B
@@ -2139,6 +2166,46 @@ Currently the max packet size is 0xFFFF (see 'WFIFOSET()' in 'src/common/socket.
 	desc:
 		- Send pet deletion status
 
+0x388a
+	Type: IZ
+	Structure: <cmd>.W <size>.W <type>.B <account_id>.L <result>.B <entries>.?B
+	index: 0,2,4,5,9
+	len: 9+variable
+	parameter:
+		- cmd : packet identification (0x388a)
+		- size
+		- type : Storage type, 0 - TABLE_INVENTORY, 1 - TABLE_CART, 2 - TABLE_STORAGE
+		- account_id
+		- result : True if data loaded, false if failed
+		- entries : Inventory/cart/storage entries
+	desc:
+		- Process inventory/cart/storage entries for player from inter-server
+
+0x388b
+	Type: IZ
+	Structure: <cmd>.W <account_id>.L <result>.B <type>.B
+	index: 0,2,6,7
+	len: 11
+	parameter:
+		- cmd : packet identification (0x388b)
+		- account_id
+		- result : 1 - success, 0 - failed
+		- type : Storage type, 0 - TABLE_INVENTORY, 1 - TABLE_CART, 2 - TABLE_STORAGE
+	desc:
+		- Info about inventory/cart/storage data is saved
+
+0x388c
+	Type: IZ
+	Structure: <cmd>.W <len>.W { <storage_table>.? }*?
+	index: 0,2,6,...
+	len: 6+variable
+	parameter:
+		- cmd : packet identification (0x388c)
+		- len : Pakcet length
+		- storage_table : Storage table information
+	desc:
+		- Receive storage information
+
 0x3890
 	Type: IZ
 	Structure: <cmd>.W <size>.W <account_id>.L <flag>.B <s_homunculus>.?B

+ 59 - 12
doc/script_commands.txt

@@ -4617,9 +4617,14 @@ database. If the name is not found, nothing will be deleted.
 *cartdelitem "<item name>",<amount>{,<account ID>};
 *storagedelitem <item id>,<amount>{,<account ID>};
 *storagedelitem "<item name>",<amount>{,<account ID>};
+*guildstoragedelitem <item id>,<amount>{,<account ID>};
+*guildstoragedelitem "<item name>",<amount>{,<account ID>};
 
 This command behaves identically to 'delitem', but deletes items from the player's
-cart or storage. If no cart is mounted, 'cartdelitem' will fail.
+cart, storage, or guild storage.
+
+If no cart is mounted, 'cartdelitem' will return -1.
+If player is not in a guild or storage is open, 'guildstoragedelitem' will return -1.
 
 ---------------------------------------
 
@@ -4635,9 +4640,14 @@ See 'getitem2' for an explanation of the expanded parameters.
 *cartdelitem2 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
 *storagedelitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
 *storagedelitem2 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
+*guildstoragedelitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
+*guildstoragedelitem2 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>};
 
 This command behaves identically to 'delitem2', but deletes items from the player's
-cart or storage. If no cart is mounted, 'cartdelitem2' will fail.
+cart, storage, or guild storage.
+
+If no cart is mounted, 'cartdelitem2' will return -1.
+If player is not in a guild or storage is open, 'guildstoragedelitem2' will return -1.
 
 ---------------------------------------
 
@@ -4663,13 +4673,18 @@ adding up strings:
     
 ---------------------------------------
 
-*cartcountitem(<item id>)
-*cartcountitem("<item name>")
-*storagecountitem(<item id>)
-*storagecountitem("<item name>")
+*cartcountitem(<item id>{,<accountID>})
+*cartcountitem("<item name>"{,<accountID>})
+*storagecountitem(<item id>{,<accountID>})
+*storagecountitem("<item name>"{,<accountID>})
+*guildstoragecountitem(<nameID>{,<accountID>})
+*guildstoragecountitem("<item name>"{,<accountID>})
 
 This command behaves identically to 'countitem', but counts items from the player's
-cart or storage. If no cart is mounted, 'cartcountitem' will return -1.
+cart, storage, or guild storage.
+
+If no cart is mounted, 'cartcountitem' will return -1.
+If player is not in a guild or storage is open, 'guildstoragecountitem' will return -1.
 
 ---------------------------------------
 
@@ -4684,13 +4699,18 @@ See 'getitem2' for an explanation of the expanded parameters.
 
 ---------------------------------------
 
-*cartcountitem2(<item id>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>)
-*cartcountitem2("<item name>",<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>)
-*storagecountitem2(<item id>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>)
-*storagecountitem2("<item name>",<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>)
+*cartcountitem2(<item id>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<accountID>})
+*cartcountitem2("<item name>",<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<accountID>})
+*storagecountitem2(<item id>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<accountID>})
+*storagecountitem2("<item name>",<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<accountID>})
+*guildstoragecountitem2(<nameID>,<Identified>,<Refine>,<Attribute>,<Card0>,<Card1>,<Card2>,<Card3>{,<accountID>})
+*guildstoragecountitem2("<item name>",<Identified>,<Refine>,<Attribute>,<Card0>,<Card1>,<Card2>,<Card3>{,<accountID>})
 
 This command behaves identically to 'countitem2', but counts items from the player's
-cart or storage. If no cart is mounted, 'cartcountitem2' will return -1.
+cart, storage, or guild storage.
+
+If no cart is mounted, 'cartcountitem2' will return -1.
+If player is not in a guild or storage is open, 'guildstoragecountitem2' will return -1.
 
 ---------------------------------------
 
@@ -5054,6 +5074,33 @@ window, to avoid any disruption when both windows overlap.
 
 ---------------------------------------
 
+*openstorage2 <storage_id>,<mode>{,<account_id>};
+
+Just like the 'openstorage' command, except this command can open additional storages
+by the specified <storage_id>. For <storage_id>, please read the conf/inter_server.conf
+for storage groups.
+
+Values for <mode> are:
+	STOR_MODE_NONE : Player only can read the storage entries.
+	STOR_MODE_GET  : Player can get items from the storage.
+	STOR_MODE_PUT  : Player can put items in the storage.
+
+Example:
+	if (vip_status(1)) {
+		mes "I will open your Premium storage.";
+		mes "Thank you for using our service.";
+		close2;
+		openstorage2 1,STOR_MODE_GET|STOR_MODE_PUT;
+	} else {
+		mes "Sorry, your Premium status is expired.";
+		mes "Storage will be opened but you can't put any item into it.";
+		close2;
+		openstorage2 1,STOR_MODE_GET;
+	}
+	end;
+
+---------------------------------------
+
 *openmail({<char_id>});
 
 This will open a character's Mail window on the client connected to the 

+ 38 - 0
sql-files/upgrades/premium_storage.sql

@@ -0,0 +1,38 @@
+--
+-- Table structure for table `storage_1`
+--
+
+CREATE TABLE IF NOT EXISTS `storage_1` (
+  `id` int(11) unsigned NOT NULL auto_increment,
+  `account_id` int(11) unsigned NOT NULL default '0',
+  `nameid` smallint(5) unsigned NOT NULL default '0',
+  `amount` smallint(11) unsigned NOT NULL default '0',
+  `equip` int(11) unsigned NOT NULL default '0',
+  `identify` smallint(6) unsigned NOT NULL default '0',
+  `refine` tinyint(3) unsigned NOT NULL default '0',
+  `attribute` tinyint(4) unsigned NOT NULL default '0',
+  `card0` smallint(5) unsigned NOT NULL default '0',
+  `card1` smallint(5) unsigned NOT NULL default '0',
+  `card2` smallint(5) unsigned NOT NULL default '0',
+  `card3` smallint(5) unsigned NOT NULL default '0',
+  `option_id0` smallint(5) unsigned NOT NULL default '0',
+  `option_val0` smallint(5) unsigned NOT NULL default '0',
+  `option_parm0` tinyint(3) unsigned NOT NULL default '0',
+  `option_id1` smallint(5) unsigned NOT NULL default '0',
+  `option_val1` smallint(5) unsigned NOT NULL default '0',
+  `option_parm1` tinyint(3) unsigned NOT NULL default '0',
+  `option_id2` smallint(5) unsigned NOT NULL default '0',
+  `option_val2` smallint(5) unsigned NOT NULL default '0',
+  `option_parm2` tinyint(3) unsigned NOT NULL default '0',
+  `option_id3` smallint(5) unsigned NOT NULL default '0',
+  `option_val3` smallint(5) unsigned NOT NULL default '0',
+  `option_parm3` tinyint(3) unsigned NOT NULL default '0',
+  `option_id4` smallint(5) unsigned NOT NULL default '0',
+  `option_val4` smallint(5) unsigned NOT NULL default '0',
+  `option_parm4` tinyint(3) unsigned NOT NULL default '0',
+  `expire_time` int(11) unsigned NOT NULL default '0',
+  `bound` tinyint(3) unsigned NOT NULL default '0',
+  `unique_id` bigint(20) unsigned NOT NULL default '0',
+  PRIMARY KEY  (`id`),
+  KEY `account_id` (`account_id`)
+) ENGINE=MyISAM;

+ 133 - 291
src/char/char.c

@@ -262,8 +262,6 @@ static DBData char_create_charstatus(DBKey key, va_list args) {
 	return db_ptr2data(cp);
 }
 
-int char_inventory_to_sql(const struct item items[], int max, int id);
-
 int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){
 	int i = 0;
 	int count = 0;
@@ -280,30 +278,6 @@ int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){
 	StringBuf_Init(&buf);
 	memset(save_status, 0, sizeof(save_status));
 
-	//map inventory data
-	if( memcmp(p->inventory, cp->inventory, sizeof(p->inventory)) ) {
-		if (!char_inventory_to_sql(p->inventory, MAX_INVENTORY, p->char_id))
-			strcat(save_status, " inventory");
-		else
-			errors++;
-	}
-
-	//map cart data
-	if( memcmp(p->cart, cp->cart, sizeof(p->cart)) ) {
-		if (!char_memitemdata_to_sql(p->cart, MAX_CART, p->char_id, TABLE_CART))
-			strcat(save_status, " cart");
-		else
-			errors++;
-	}
-
-	//map storage data
-	if( memcmp(p->storage.items, cp->storage.items, sizeof(p->storage.items)) ) {
-		if (!char_memitemdata_to_sql(p->storage.items, MAX_STORAGE, p->account_id, TABLE_STORAGE))
-			strcat(save_status, " storage");
-		else
-			errors++;
-	}
-
 	if (
 		(p->base_exp != cp->base_exp) || (p->base_level != cp->base_level) ||
 		(p->job_level != cp->job_level) || (p->job_exp != cp->job_exp) ||
@@ -542,28 +516,41 @@ int char_mmo_char_tosql(uint32 char_id, struct mmo_charstatus* p){
 }
 
 /// Saves an array of 'item' entries into the specified table.
-int char_memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch) {
+int char_memitemdata_to_sql(const struct item items[], int max, int id, enum storage_type tableswitch, uint8 stor_id) {
 	StringBuf buf;
 	SqlStmt* stmt;
-	int i,j;
-	const char* tablename;
-	const char* selectoption;
+	int i, j, offset = 0, errors = 0;
+	const char *tablename, *selectoption, *printname;
 	struct item item; // temp storage variable
 	bool* flag; // bit array for inventory matching
 	bool found;
-	int errors = 0;
 
 	switch (tableswitch) {
-	case TABLE_INVENTORY:     tablename = schema_config.inventory_db;     selectoption = "char_id";    break;
-	case TABLE_CART:          tablename = schema_config.cart_db;          selectoption = "char_id";    break;
-	case TABLE_STORAGE:       tablename = schema_config.storage_db;       selectoption = "account_id"; break;
-	case TABLE_GUILD_STORAGE: tablename = schema_config.guild_storage_db; selectoption = "guild_id";   break;
-	default:
-		ShowError("Invalid table name!\n");
-		return 1;
+		case TABLE_INVENTORY:
+			printname = "Inventory";
+			tablename = schema_config.inventory_db;
+			selectoption = "char_id";
+			break;
+		case TABLE_CART:
+			printname = "Cart";
+			tablename = schema_config.cart_db;
+			selectoption = "char_id";
+			break;
+		case TABLE_STORAGE:
+			printname = "Storage";
+			tablename = inter_premiumStorage_getTableName(stor_id);
+			selectoption = "account_id";
+			break;
+		case TABLE_GUILD_STORAGE:
+			printname = "Guild Storage";
+			tablename = schema_config.guild_storage_db;
+			selectoption = "guild_id";
+			break;
+		default:
+			ShowError("Invalid table name!\n");
+			return 1;
 	}
 
-
 	// The following code compares inventory with current database values
 	// and performs modification/deletion/insertion only on relevant rows.
 	// This approach is more complicated than a trivial delete&insert, but
@@ -571,6 +558,10 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
 
 	StringBuf_Init(&buf);
 	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`");
+	if (tableswitch == TABLE_INVENTORY) {
+		StringBuf_Printf(&buf, ", `favorite`");
+		offset = 1;
+	}
 
 	for( i = 0; i < MAX_SLOTS; ++i )
 		StringBuf_Printf(&buf, ", `card%d`", i);
@@ -601,12 +592,14 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
 	SqlStmt_BindColumn(stmt, 7, SQLDT_UINT,      &item.expire_time, 0, NULL, NULL);
 	SqlStmt_BindColumn(stmt, 8, SQLDT_UINT,      &item.bound,       0, NULL, NULL);
 	SqlStmt_BindColumn(stmt, 9, SQLDT_UINT64,    &item.unique_id,   0, NULL, NULL);
+	if (tableswitch == TABLE_INVENTORY)
+		SqlStmt_BindColumn(stmt, 10, SQLDT_CHAR, &item.favorite,    0, NULL, NULL);
 	for( i = 0; i < MAX_SLOTS; ++i )
-		SqlStmt_BindColumn(stmt, 10+i, SQLDT_USHORT, &item.card[i], 0, NULL, NULL);
+		SqlStmt_BindColumn(stmt, 10+offset+i, SQLDT_USHORT, &item.card[i], 0, NULL, NULL);
 	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
-		SqlStmt_BindColumn(stmt, 10+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].id, 0, NULL, NULL);
-		SqlStmt_BindColumn(stmt, 11+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].value, 0, NULL, NULL);
-		SqlStmt_BindColumn(stmt, 12+MAX_SLOTS+i*3, SQLDT_CHAR, &item.option[i].param, 0, NULL, NULL);
+		SqlStmt_BindColumn(stmt, 10+offset+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].id, 0, NULL, NULL);
+		SqlStmt_BindColumn(stmt, 11+offset+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].value, 0, NULL, NULL);
+		SqlStmt_BindColumn(stmt, 12+offset+MAX_SLOTS+i*3, SQLDT_CHAR, &item.option[i].param, 0, NULL, NULL);
 	}
 	// bit array indicating which inventory items have already been matched
 	flag = (bool*) aCalloc(max, sizeof(bool));
@@ -625,6 +618,7 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
 			&&  items[i].card[0] == item.card[0]
 			&&  items[i].card[2] == item.card[2]
 			&&  items[i].card[3] == item.card[3]
+			&&  items[i].unique_id == item.unique_id
 			) {	//They are the same item.
 				int k;
 				
@@ -640,7 +634,7 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
 				    items[i].attribute == item.attribute &&
 				    items[i].expire_time == item.expire_time &&
 				    items[i].bound == item.bound &&
-					items[i].unique_id == item.unique_id )
+					(tableswitch != TABLE_INVENTORY || items[i].favorite == item.favorite) )
 				;	//Do nothing.
 				else
 				{
@@ -648,6 +642,8 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
 					StringBuf_Clear(&buf);
 					StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `bound`='%d', `unique_id`='%"PRIu64"'",
 						tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound, items[i].unique_id);
+					if (tableswitch == TABLE_INVENTORY)
+						StringBuf_Printf(&buf, ", `favorite`='%d'", items[i].favorite);
 					for( j = 0; j < MAX_SLOTS; ++j )
 						StringBuf_Printf(&buf, ", `card%d`=%hu", j, items[i].card[j]);
 					for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
@@ -681,6 +677,8 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
 
 	StringBuf_Clear(&buf);
 	StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`", tablename, selectoption);
+	if (tableswitch == TABLE_INVENTORY)
+		StringBuf_Printf(&buf, ", `favorite`");
 	for( j = 0; j < MAX_SLOTS; ++j )
 		StringBuf_Printf(&buf, ", `card%d`", j);
 	for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
@@ -705,6 +703,8 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
 
 		StringBuf_Printf(&buf, "('%d', '%hu', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%"PRIu64"'",
 			id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound, items[i].unique_id);
+		if (tableswitch == TABLE_INVENTORY)
+			StringBuf_Printf(&buf, ", '%d'", items[i].favorite);
 		for( j = 0; j < MAX_SLOTS; ++j )
 			StringBuf_Printf(&buf, ", '%hu'", items[i].card[j]);
 		for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
@@ -721,178 +721,118 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
 		errors++;
 	}
 
+	ShowInfo("Saved %s (%d) data to table %s for %s: %d\n", printname, stor_id, tablename, selectoption, id);
 	StringBuf_Destroy(&buf);
 	aFree(flag);
 
 	return errors;
 }
-/* pretty much a copy of memitemdata_to_sql except it handles inventory_db exclusively,
- * - this is required because inventory db is the only one with the 'favorite' column. */
-int char_inventory_to_sql(const struct item items[], int max, int id) {
+
+bool char_memitemdata_from_sql(struct s_storage* p, int max, int id, enum storage_type tableswitch, uint8 stor_id) {
 	StringBuf buf;
 	SqlStmt* stmt;
-	int i, j;
-	struct item item; // temp storage variable
-	bool* flag; // bit array for inventory matching
-	bool found;
-	int errors = 0;
+	int i,j, offset = 0;
+	struct item item, *storage;
+	const char *tablename, *selectoption, *printname;
 
+	switch (tableswitch) {
+		case TABLE_INVENTORY:
+			printname = "Inventory";
+			tablename = schema_config.inventory_db;
+			selectoption = "char_id";
+			storage = p->u.items_inventory;
+			break;
+		case TABLE_CART:
+			printname = "Cart";
+			tablename = schema_config.cart_db;
+			selectoption = "char_id";
+			storage = p->u.items_cart;
+			break;
+		case TABLE_STORAGE:
+			printname = "Storage";
+			tablename = inter_premiumStorage_getTableName(stor_id);
+			selectoption = "account_id";
+			storage = p->u.items_storage;
+			break;
+		case TABLE_GUILD_STORAGE:
+			printname = "Guild Storage";
+			tablename = schema_config.guild_storage_db;
+			selectoption = "guild_id";
+			storage = p->u.items_guild;
+			break;
+		default:
+			ShowError("Invalid table name!\n");
+			return false;
+	}
 
-	// The following code compares inventory with current database values
-	// and performs modification/deletion/insertion only on relevant rows.
-	// This approach is more complicated than a trivial delete&insert, but
-	// it significantly reduces cpu load on the database server.
+	memset(p, 0, sizeof(struct s_storage)); //clean up memory
+	p->id = id;
+	p->type = tableswitch;
+	p->stor_id = stor_id;
+	p->max_amount = inter_premiumStorage_getMax(p->stor_id);
+
+	stmt = SqlStmt_Malloc(sql_handle);
+	if (stmt == NULL) {
+		SqlStmt_ShowDebug(stmt);
+		return false;
+	}
 
 	StringBuf_Init(&buf);
-	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`");
-	for( i = 0; i < MAX_SLOTS; ++i )
-		StringBuf_Printf(&buf, ", `card%d`", i);
-	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
-		StringBuf_Printf(&buf, ", `option_id%d`", i);
-		StringBuf_Printf(&buf, ", `option_val%d`", i);
-		StringBuf_Printf(&buf, ", `option_parm%d`", i);
+	StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`,`bound`,`unique_id`");
+	if (tableswitch == TABLE_INVENTORY) {
+		StringBuf_Printf(&buf, ", `favorite`");
+		offset = 1;
+	}
+	for( j = 0; j < MAX_SLOTS; ++j )
+		StringBuf_Printf(&buf, ",`card%d`", j);
+	for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
+		StringBuf_Printf(&buf, ", `option_id%d`", j);
+		StringBuf_Printf(&buf, ", `option_val%d`", j);
+		StringBuf_Printf(&buf, ", `option_parm%d`", j);
 	}
-	StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'", schema_config.inventory_db, id);
+	StringBuf_Printf(&buf, " FROM `%s` WHERE `%s`=? ORDER BY `nameid`", tablename, selectoption );
 
-	stmt = SqlStmt_Malloc(sql_handle);
 	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
-	   ||  SQL_ERROR == SqlStmt_Execute(stmt) )
+		||	SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &id, 0)
+		||	SQL_ERROR == SqlStmt_Execute(stmt) )
 	{
 		SqlStmt_ShowDebug(stmt);
 		SqlStmt_Free(stmt);
 		StringBuf_Destroy(&buf);
-		return 1;
+		return false;
 	}
 
-	SqlStmt_BindColumn(stmt, 0, SQLDT_INT,       &item.id,          0, NULL, NULL);
-	SqlStmt_BindColumn(stmt, 1, SQLDT_USHORT,    &item.nameid,      0, NULL, NULL);
-	SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT,     &item.amount,      0, NULL, NULL);
-	SqlStmt_BindColumn(stmt, 3, SQLDT_UINT,      &item.equip,       0, NULL, NULL);
-	SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR,      &item.identify,    0, NULL, NULL);
-	SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR,      &item.refine,      0, NULL, NULL);
-	SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR,      &item.attribute,   0, NULL, NULL);
-	SqlStmt_BindColumn(stmt, 7, SQLDT_UINT,      &item.expire_time, 0, NULL, NULL);
-	SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR,      &item.favorite,    0, NULL, NULL);
-	SqlStmt_BindColumn(stmt, 9, SQLDT_CHAR,      &item.bound,       0, NULL, NULL);
-	SqlStmt_BindColumn(stmt, 10,SQLDT_UINT64,    &item.unique_id,   0, NULL, NULL);
+	SqlStmt_BindColumn(stmt, 0, SQLDT_INT,          &item.id,        0, NULL, NULL);
+	SqlStmt_BindColumn(stmt, 1, SQLDT_USHORT,       &item.nameid,    0, NULL, NULL);
+	SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT,        &item.amount,    0, NULL, NULL);
+	SqlStmt_BindColumn(stmt, 3, SQLDT_UINT,         &item.equip,     0, NULL, NULL);
+	SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR,         &item.identify,  0, NULL, NULL);
+	SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR,         &item.refine,    0, NULL, NULL);
+	SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR,         &item.attribute, 0, NULL, NULL);
+	SqlStmt_BindColumn(stmt, 7, SQLDT_UINT,         &item.expire_time, 0, NULL, NULL);
+	SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR,         &item.bound,     0, NULL, NULL);
+	SqlStmt_BindColumn(stmt, 9, SQLDT_ULONGLONG,    &item.unique_id, 0, NULL, NULL);
+	if (tableswitch == TABLE_INVENTORY)
+		SqlStmt_BindColumn(stmt, 10, SQLDT_CHAR, &item.favorite,    0, NULL, NULL);
 	for( i = 0; i < MAX_SLOTS; ++i )
-		SqlStmt_BindColumn(stmt, 11+i, SQLDT_USHORT, &item.card[i], 0, NULL, NULL);
-	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
-		SqlStmt_BindColumn(stmt, 11+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].id, 0, NULL, NULL);
-		SqlStmt_BindColumn(stmt, 12+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].value, 0, NULL, NULL);
-		SqlStmt_BindColumn(stmt, 13+MAX_SLOTS+i*3, SQLDT_CHAR, &item.option[i].param, 0, NULL, NULL);
-	}
-
-	// bit array indicating which inventory items have already been matched
-	flag = (bool*) aCalloc(max, sizeof(bool));
+		SqlStmt_BindColumn(stmt, 10+offset+i, SQLDT_USHORT, &item.card[i],   0, NULL, NULL);
+ 	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
+		SqlStmt_BindColumn(stmt, 10+offset+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].id, 0, NULL, NULL);
+		SqlStmt_BindColumn(stmt, 11+offset+MAX_SLOTS+i*3, SQLDT_SHORT, &item.option[i].value, 0, NULL, NULL);
+		SqlStmt_BindColumn(stmt, 12+offset+MAX_SLOTS+i*3, SQLDT_CHAR, &item.option[i].param, 0, NULL, NULL);
+ 	}
 
-	while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) {
-		found = false;
-		// search for the presence of the item in the char's inventory
-		for( i = 0; i < max; ++i ) {
-			// skip empty and already matched entries
-			if( items[i].nameid == 0 || flag[i] )
-				continue;
+	for( i = 0; i < max && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
+		memcpy(&storage[i], &item, sizeof(item));
 
-			if( items[i].nameid == item.nameid
-			   &&  items[i].card[0] == item.card[0]
-			   &&  items[i].card[2] == item.card[2]
-			   &&  items[i].card[3] == item.card[3]
-			   ) {	//They are the same item.
-				int k;
-				
-				ARR_FIND( 0, MAX_SLOTS, j, items[i].card[j] != item.card[j] );
-				ARR_FIND( 0, MAX_ITEM_RDM_OPT, k, items[i].option[k].id != item.option[k].id || items[i].option[k].value != item.option[k].value || items[i].option[k].param != item.option[k].param );
-				
-				if( j == MAX_SLOTS &&
-					k == MAX_ITEM_RDM_OPT &&
-					items[i].amount == item.amount &&
-					items[i].equip == item.equip &&
-					items[i].identify == item.identify &&
-					items[i].refine == item.refine &&
-					items[i].attribute == item.attribute &&
-					items[i].expire_time == item.expire_time &&
-					items[i].favorite == item.favorite &&
-					items[i].bound == item.bound &&
-					items[i].unique_id == item.unique_id )
-					;	//Do nothing.
-				else {
-					// update all fields.
-					StringBuf_Clear(&buf);
-					StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d', `bound`='%d', `unique_id`='%"PRIu64"'",
-					    schema_config.inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].bound, items[i].unique_id);
-					for( j = 0; j < MAX_SLOTS; ++j )
-						StringBuf_Printf(&buf, ", `card%d`=%hu", j, items[i].card[j]);
-					for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
-						StringBuf_Printf(&buf, ", `option_id%d`=%d", j, items[i].option[j].id);
-						StringBuf_Printf(&buf, ", `option_val%d`=%d", j, items[i].option[j].value);
-						StringBuf_Printf(&buf, ", `option_parm%d`=%d", j, items[i].option[j].param);
-					}
-					StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id);
+	p->amount = i;
+	ShowInfo("Loaded %s (%d) data from table %s for %s: %d (total: %d)\n", printname, p->stor_id, tablename, selectoption, id, p->amount);
 
-					if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) {
-						Sql_ShowDebug(sql_handle);
-						errors++;
-					}
-				}
-
-				found = flag[i] = true; //Item dealt with,
-				break; //skip to next item in the db.
-			}
-		}
-		if( !found ) {// Item not present in inventory, remove it.
-			if( SQL_ERROR == Sql_Query(sql_handle, "DELETE from `%s` where `id`='%d' LIMIT 1", schema_config.inventory_db, item.id) ) {
-				Sql_ShowDebug(sql_handle);
-				errors++;
-			}
-		}
-	}
+	SqlStmt_FreeResult(stmt);
 	SqlStmt_Free(stmt);
-
-	StringBuf_Clear(&buf);
-	StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`", schema_config.inventory_db);
-	for( i = 0; i < MAX_SLOTS; ++i )
-		StringBuf_Printf(&buf, ", `card%d`", i);
-	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
-		StringBuf_Printf(&buf, ", `option_id%d`", i);
-		StringBuf_Printf(&buf, ", `option_val%d`", i);
-		StringBuf_Printf(&buf, ", `option_parm%d`", i);
-	}
-	StringBuf_AppendStr(&buf, ") VALUES ");
-
-	found = false;
-	// insert non-matched items into the db as new items
-	for( i = 0; i < max; ++i ) {
-		// skip empty and already matched entries
-		if( items[i].nameid == 0 || flag[i] )
-			continue;
-
-		if( found )
-			StringBuf_AppendStr(&buf, ",");
-		else
-			found = true;
-
-		StringBuf_Printf(&buf, "('%d', '%hu', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%d', '%"PRIu64"'",
-						 id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].bound, items[i].unique_id);
-		for( j = 0; j < MAX_SLOTS; ++j )
-			StringBuf_Printf(&buf, ", '%hu'", items[i].card[j]);
-		for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
-			StringBuf_Printf(&buf, ", '%d'", items[i].option[j].id);
-			StringBuf_Printf(&buf, ", '%d'", items[i].option[j].value);
-			StringBuf_Printf(&buf, ", '%d'", items[i].option[j].param);
-		}
-		StringBuf_AppendStr(&buf, ")");
-	}
-
-	if( found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) {
-		Sql_ShowDebug(sql_handle);
-		errors++;
-	}
-
 	StringBuf_Destroy(&buf);
-	aFree(flag);
 
-	return errors;
+	return true;
 }
 
 /**
@@ -1047,15 +987,13 @@ int char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf) {
 
 //=====================================================================================================
 int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_everything) {
-	int i, j;
+	int i;
 	struct mmo_charstatus* cp;
-	StringBuf buf;
 	SqlStmt* stmt;
 	char last_map[MAP_NAME_LENGTH_EXT];
 	char save_map[MAP_NAME_LENGTH_EXT];
 	char point_map[MAP_NAME_LENGTH_EXT];
 	struct point tmp_point;
-	struct item tmp_item;
 	struct s_skill tmp_skill;
 	uint16 skill_count = 0;
 	struct s_friend tmp_friend;
@@ -1202,93 +1140,6 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
 	}
 	StringBuf_AppendStr(&msg_buf, " memo");
 
-	//read inventory
-	//`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `option_id0`, `option_val0`, `option_id1`, `option_val1`, `option_id2`, `option_val2`, `option_id3`, `option_val3`, `option_id4`, `option_val4`, `expire_time`, `favorite`, `unique_id`)
-	StringBuf_Init(&buf);
-	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`");
-	for( i = 0; i < MAX_SLOTS; ++i )
-		StringBuf_Printf(&buf, ", `card%d`", i);
-	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
-		StringBuf_Printf(&buf, ", `option_id%d`", i);
-		StringBuf_Printf(&buf, ", `option_val%d`", i);
-		StringBuf_Printf(&buf, ", `option_parm%d`", i);
-	}
-	StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", schema_config.inventory_db, MAX_INVENTORY);
-
-	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
-	||	SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
-	||	SQL_ERROR == SqlStmt_Execute(stmt)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT,       &tmp_item.id, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_USHORT,    &tmp_item.nameid, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT,     &tmp_item.amount, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_UINT,      &tmp_item.equip, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR,      &tmp_item.identify, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR,      &tmp_item.refine, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR,      &tmp_item.attribute, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT,      &tmp_item.expire_time, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR,      &tmp_item.favorite, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_CHAR,      &tmp_item.bound, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt,10, SQLDT_UINT64,    &tmp_item.unique_id, 0, NULL, NULL) )
-		SqlStmt_ShowDebug(stmt);
-	for( i = 0; i < MAX_SLOTS; ++i )
-		if( SQL_ERROR == SqlStmt_BindColumn(stmt, 11+i, SQLDT_USHORT, &tmp_item.card[i], 0, NULL, NULL) ) {
-			SqlStmt_ShowDebug(stmt);
-	}
-	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
-		if( SQL_ERROR == SqlStmt_BindColumn(stmt, 11+MAX_SLOTS+i*3, SQLDT_SHORT, &tmp_item.option[i].id, 0, NULL, NULL)
-		||	SQL_ERROR == SqlStmt_BindColumn(stmt, 12+MAX_SLOTS+i*3, SQLDT_SHORT, &tmp_item.option[i].value, 0, NULL, NULL)
-		||	SQL_ERROR == SqlStmt_BindColumn(stmt, 13+MAX_SLOTS+i*3, SQLDT_CHAR, &tmp_item.option[i].param, 0, NULL, NULL) )
-			SqlStmt_ShowDebug(stmt);
-	}
-	for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
-		memcpy(&p->inventory[i], &tmp_item, sizeof(tmp_item));
-
-	StringBuf_AppendStr(&msg_buf, " inventory");
-
-	//read cart
-	//`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `option_id0`, `option_val0`, `option_id1`, `option_val1`, `option_id2`, `option_val2`, `option_id3`, `option_val3`, `option_id4`, `option_val4`, `expire_time`, `favorite`, `unique_id`)
-	StringBuf_Clear(&buf);
-	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`");
-	for( j = 0; j < MAX_SLOTS; ++j )
-		StringBuf_Printf(&buf, ", `card%d`", j);
-	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
-		StringBuf_Printf(&buf, ", `option_id%d`", i);
-		StringBuf_Printf(&buf, ", `option_val%d`", i);
-		StringBuf_Printf(&buf, ", `option_parm%d`", i);
-	}
-	StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", schema_config.cart_db, MAX_CART);
-
-	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
-	||	SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
-	||	SQL_ERROR == SqlStmt_Execute(stmt)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_INT,         &tmp_item.id, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_USHORT,      &tmp_item.nameid, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT,       &tmp_item.amount, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_UINT,        &tmp_item.equip, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR,        &tmp_item.identify, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR,        &tmp_item.refine, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR,        &tmp_item.attribute, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT,        &tmp_item.expire_time, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR,        &tmp_item.bound, 0, NULL, NULL)
-	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_UINT64,      &tmp_item.unique_id, 0, NULL, NULL) )
-		SqlStmt_ShowDebug(stmt);
-	for( i = 0; i < MAX_SLOTS; ++i )
-		if( SQL_ERROR == SqlStmt_BindColumn(stmt, 10+i, SQLDT_USHORT, &tmp_item.card[i], 0, NULL, NULL) )
-			SqlStmt_ShowDebug(stmt);
-	for( i = 0; i < MAX_ITEM_RDM_OPT; i++ ) {
-		if( SQL_ERROR == SqlStmt_BindColumn(stmt, 10+MAX_SLOTS+i*3, SQLDT_SHORT, &tmp_item.option[i].id, 0, NULL, NULL)
-		||	SQL_ERROR == SqlStmt_BindColumn(stmt, 11+MAX_SLOTS+i*3, SQLDT_SHORT, &tmp_item.option[i].value, 0, NULL, NULL)
-		||	SQL_ERROR == SqlStmt_BindColumn(stmt, 12+MAX_SLOTS+i*3, SQLDT_CHAR, &tmp_item.option[i].param, 0, NULL, NULL) )
-			SqlStmt_ShowDebug(stmt);
-	}
-	for( i = 0; i < MAX_CART && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
-		memcpy(&p->cart[i], &tmp_item, sizeof(tmp_item));
-	StringBuf_AppendStr(&msg_buf, " cart");
-
-	//read storage
-	storage_fromsql(p->account_id, &p->storage);
-	StringBuf_AppendStr(&msg_buf, " storage");
-
 	//read skill
 	//`skill` (`char_id`, `id`, `lv`)
 	if( SQL_ERROR == SqlStmt_Prepare(stmt, "SELECT `id`, `lv`,`flag` FROM `%s` WHERE `char_id`=? LIMIT %d", schema_config.skill_db, MAX_SKILL)
@@ -1353,9 +1204,9 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev
 	StringBuf_AppendStr(&msg_buf, " mercenary");
 
 
-	if (charserv_config.save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, StringBuf_Value(&msg_buf));	//ok. all data load successfuly!
+	if (charserv_config.save_log)
+		ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, StringBuf_Value(&msg_buf)); //ok. all data load successfully!
 	SqlStmt_Free(stmt);
-	StringBuf_Destroy(&buf);
 
 	cp = (struct mmo_charstatus *)idb_ensure(char_db_, char_id, char_create_charstatus);
 	memcpy(cp, p, sizeof(struct mmo_charstatus));
@@ -2332,7 +2183,7 @@ bool char_checkdb(void){
 	int i;
 	const char* sqltable[] = {
 		schema_config.char_db, schema_config.hotkey_db, schema_config.scdata_db, schema_config.cart_db, 
-                schema_config.inventory_db, schema_config.charlog_db, schema_config.storage_db, 
+                schema_config.inventory_db, schema_config.charlog_db,
                 schema_config.char_reg_str_table, schema_config.char_reg_num_table, schema_config.acc_reg_str_table,
                 schema_config.acc_reg_num_table, schema_config.skill_db, schema_config.interlog_db, schema_config.memo_db,
 		schema_config.guild_db, schema_config.guild_alliance_db, schema_config.guild_castle_db, 
@@ -2555,13 +2406,6 @@ bool char_checkdb(void){
 		Sql_ShowDebug(sql_handle);
 		return false;
 	}
-	//checking storage_db
-	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT  `id`,`account_id`,`nameid`,`amount`,`equip`,`identify`,`refine`,"
-		"`attribute`,`card0`,`card1`,`card2`,`card3`,`option_id0`,`option_val0`,`option_parm0`,`option_id1`,`option_val1`,`option_parm1`,`option_id2`,`option_val2`,`option_parm2`,`option_id3`,`option_val3`,`option_parm3`,`option_id4`,`option_val4`,`option_parm4`,`expire_time`,`bound`,`unique_id`"
-		" FROM `%s` LIMIT 1;", schema_config.storage_db) ){
-		Sql_ShowDebug(sql_handle);
-		return false;
-	}
 	//checking guild_storage_db
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT  `id`,`guild_id`,`nameid`,`amount`,`equip`,`identify`,`refine`,"
 		"`attribute`,`card0`,`card1`,`card2`,`card3`,`option_id0`,`option_val0`,`option_parm0`,`option_id1`,`option_val1`,`option_parm1`,`option_id2`,`option_val2`,`option_parm2`,`option_id3`,`option_val3`,`option_parm3`,`option_id4`,`option_val4`,`option_parm4`,`expire_time`,`bound`,`unique_id`"
@@ -2600,8 +2444,6 @@ void char_sql_config_read(const char* cfgName) {
 			safestrncpy(schema_config.inventory_db, w2, sizeof(schema_config.inventory_db));
 		else if(!strcmpi(w1,"charlog_db"))
 			safestrncpy(schema_config.charlog_db, w2, sizeof(schema_config.charlog_db));
-		else if(!strcmpi(w1,"storage_db"))
-			safestrncpy(schema_config.storage_db, w2, sizeof(schema_config.storage_db));
 		else if(!strcmpi(w1,"skill_db"))
 			safestrncpy(schema_config.skill_db, w2, sizeof(schema_config.skill_db));
 		else if(!strcmpi(w1,"interlog_db"))

+ 3 - 12
src/char/char.h

@@ -4,8 +4,6 @@
 #ifndef _CHAR_SQL_H_
 #define _CHAR_SQL_H_
 
-#define DB_NAME_LEN 256 //max len of dbs
-
 #include "../config/core.h"
 #include "../common/core.h" // CORE_ST_LAST
 #include "../common/msg_conf.h"
@@ -25,13 +23,6 @@ enum E_CHARSERVER_ST {
 	CHARSERVER_ST_LAST
 };
 
-enum {
-	TABLE_INVENTORY,
-	TABLE_CART,
-	TABLE_STORAGE,
-	TABLE_GUILD_STORAGE,
-};
-
 enum e_char_delete {
 	CHAR_DEL_EMAIL = 1,
 	CHAR_DEL_BIRTHDATE
@@ -210,8 +201,7 @@ DBMap* char_get_onlinedb(); // uint32 account_id -> struct online_char_data*
 
 struct char_session_data {
 	bool auth; // whether the session is authed or not
-	uint32 account_id, login_id1, login_id2;
-	int sex;
+	uint32 account_id, login_id1, login_id2, sex;
 	int found_char[MAX_CHARS]; // ids of chars on this account
 	char email[40]; // e-mail (default: a@a.com) by [Yor]
 	time_t expiration_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
@@ -272,7 +262,8 @@ int char_mmo_chars_fromsql(struct char_session_data* sd, uint8* buf);
 int char_delete_char_sql(uint32 char_id);
 int char_rename_char_sql(struct char_session_data *sd, uint32 char_id);
 int char_divorce_char_sql(int partner_id1, int partner_id2);
-int char_memitemdata_to_sql(const struct item items[], int max, int id, int tableswitch);
+int char_memitemdata_to_sql(const struct item items[], int max, int id, enum storage_type tableswitch, uint8 stor_id);
+bool char_memitemdata_from_sql(struct s_storage* p, int max, int id, enum storage_type tableswitch, uint8 stor_id);
 
 void disconnect_player(uint32 account_id);
 

+ 2 - 4
src/char/char_clif.c

@@ -561,8 +561,7 @@ int chclif_parse_char_delete2_accept(int fd, struct char_session_data* sd) {
 	FIFOSD_CHECK(12)
 	{
 		char birthdate[8+1];
-		uint32 char_id;
-		int i, k;
+		uint32 char_id, i, k;
 		unsigned int base_level;
 		char* data;
 		time_t delete_date;
@@ -636,8 +635,7 @@ int chclif_parse_char_delete2_accept(int fd, struct char_session_data* sd) {
 
 // CH: <082b>.W <char id>.L
 int chclif_parse_char_delete2_cancel(int fd, struct char_session_data* sd) {
-	uint32 char_id;
-	int i;
+	uint32 char_id, i;
 
 	FIFOSD_CHECK(6)
 

+ 11 - 14
src/char/int_auction.c

@@ -3,7 +3,6 @@
 
 #include "../common/mmo.h"
 #include "../common/malloc.h"
-#include "../common/db.h"
 #include "../common/showmsg.h"
 #include "../common/socket.h"
 #include "../common/strlib.h"
@@ -15,8 +14,6 @@
 #include "int_mail.h"
 #include "int_auction.h"
 
-#include <stdio.h>
-#include <string.h>
 #include <stdlib.h>
 
 static DBMap* auction_db_ = NULL; // int auction_id -> struct auction_data*
@@ -24,7 +21,7 @@ static DBMap* auction_db_ = NULL; // int auction_id -> struct auction_data*
 void auction_delete(struct auction_data *auction);
 static int auction_end_timer(int tid, unsigned int tick, int id, intptr_t data);
 
-static int auction_count(int char_id, bool buy)
+static int auction_count(uint32 char_id, bool buy)
 {
 	int i = 0;
 	struct auction_data *auction;
@@ -140,7 +137,7 @@ unsigned int auction_create(struct auction_data *auction)
 	return auction->auction_id;
 }
 
-static void mapif_Auction_message(int char_id, unsigned char result)
+static void mapif_Auction_message(uint32 char_id, unsigned char result)
 {
 	unsigned char buf[74];
 
@@ -266,7 +263,7 @@ void inter_auctions_fromsql(void)
 	Sql_FreeResult(sql_handle);
 }
 
-static void mapif_Auction_sendlist(int fd, int char_id, short count, short pages, unsigned char *buf)
+static void mapif_Auction_sendlist(int fd, uint32 char_id, short count, short pages, unsigned char *buf)
 {
 	int len = (sizeof(struct auction_data) * count) + 12;
 
@@ -283,7 +280,7 @@ static void mapif_Auction_sendlist(int fd, int char_id, short count, short pages
 static void mapif_parse_Auction_requestlist(int fd)
 {
 	char searchtext[NAME_LENGTH];
-	int char_id = RFIFOL(fd,4), len = sizeof(struct auction_data);
+	uint32 char_id = RFIFOL(fd,4), len = sizeof(struct auction_data);
 	int price = RFIFOL(fd,10);
 	short type = RFIFOW(fd,8), page = max(1,RFIFOW(fd,14));
 	unsigned char buf[5 * sizeof(struct auction_data)];
@@ -347,7 +344,7 @@ static void mapif_parse_Auction_register(int fd)
 	mapif_Auction_register(fd, &auction);
 }
 
-static void mapif_Auction_cancel(int fd, int char_id, unsigned char result)
+static void mapif_Auction_cancel(int fd, uint32 char_id, unsigned char result)
 {
 	WFIFOHEAD(fd,7);
 	WFIFOW(fd,0) = 0x3852;
@@ -358,7 +355,7 @@ static void mapif_Auction_cancel(int fd, int char_id, unsigned char result)
 
 static void mapif_parse_Auction_cancel(int fd)
 {
-	int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6);
+	uint32 char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6);
 	struct auction_data *auction;
 
 	if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL )
@@ -385,7 +382,7 @@ static void mapif_parse_Auction_cancel(int fd)
 	mapif_Auction_cancel(fd, char_id, 0); // The auction has been canceled
 }
 
-static void mapif_Auction_close(int fd, int char_id, unsigned char result)
+static void mapif_Auction_close(int fd, uint32 char_id, unsigned char result)
 {
 	WFIFOHEAD(fd,7);
 	WFIFOW(fd,0) = 0x3853;
@@ -396,7 +393,7 @@ static void mapif_Auction_close(int fd, int char_id, unsigned char result)
 
 static void mapif_parse_Auction_close(int fd)
 {
-	int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6);
+	uint32 char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6);
 	struct auction_data *auction;
 
 	if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL )
@@ -427,7 +424,7 @@ static void mapif_parse_Auction_close(int fd)
 	mapif_Auction_close(fd, char_id, 0); // You have ended the auction
 }
 
-static void mapif_Auction_bid(int fd, int char_id, int bid, unsigned char result)
+static void mapif_Auction_bid(int fd, uint32 char_id, int bid, unsigned char result)
 {
 	WFIFOHEAD(fd,11);
 	WFIFOW(fd,0) = 0x3855;
@@ -439,8 +436,8 @@ static void mapif_Auction_bid(int fd, int char_id, int bid, unsigned char result
 
 static void mapif_parse_Auction_bid(int fd)
 {
-	int char_id = RFIFOL(fd,4), bid = RFIFOL(fd,12);
-	unsigned int auction_id = RFIFOL(fd,8);
+	uint32 char_id = RFIFOL(fd,4), auction_id = RFIFOL(fd,8);
+	int bid = RFIFOL(fd,12);
 	struct auction_data *auction;
 
 	if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL || auction->price >= bid || auction->seller_id == char_id )

+ 311 - 170
src/char/int_storage.c

@@ -1,6 +1,7 @@
 // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
 // For more information, see LICENCE in the main folder
 
+#include "../common/malloc.h"
 #include "../common/mmo.h"
 #include "../common/showmsg.h"
 #include "../common/socket.h"
@@ -14,180 +15,193 @@
 
 #define STORAGE_MEMINC	16
 
-/// Save storage data to sql
-int storage_tosql(int account_id, struct storage_data* p)
-{
-	char_memitemdata_to_sql(p->items, MAX_STORAGE, account_id, TABLE_STORAGE);
-	return 0;
+/**
+ * Check if sotrage ID is valid
+ * @param id Storage ID
+ * @return True:Valid, False:Invalid
+ **/
+bool inter_premiumStorage_exists(uint8 id) {
+	if (interserv_config.storages && interserv_config.storage_count) {
+		int i;
+		for (i = 0; i < interserv_config.storage_count; i++) {
+			if (interserv_config.storages[i].id == id)
+				return true;
+		}
+	}
+	return false;
 }
 
-/// Load storage data to mem
-int storage_fromsql(uint32 account_id, struct storage_data* p)
-{
-	StringBuf buf;
-	int i, j;
-
-	memset(p, 0, sizeof(struct storage_data)); //clean up memory
-	p->storage_amount = 0;
-
-	// storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`/`option_id0`/`option_val0`/`option_parm0`/`option_id1`/`option_val1`/`option_parm1`/`option_id2`/`option_val2`/`option_parm2`/`option_id3`/`option_val3`/`option_parm3`/`option_id4`/`option_val4`/`option_parm4`}
-	StringBuf_Init(&buf);
-	StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`,`bound`,`unique_id`");
-	for( j = 0; j < MAX_SLOTS; ++j )
-		StringBuf_Printf(&buf, ",`card%d`", j);
-	for( i = 0; i < MAX_ITEM_RDM_OPT; ++i ) {
-		StringBuf_Printf(&buf, ", `option_id%d`", i);
-		StringBuf_Printf(&buf, ", `option_val%d`", i);
-		StringBuf_Printf(&buf, ", `option_parm%d`", i);
+/**
+ * Get max storage amount
+ * @param id Storage ID
+ * @return Max amount
+ **/
+int inter_premiumStorage_getMax(uint8 id) {
+	if (interserv_config.storages && interserv_config.storage_count) {
+		int i;
+		for (i = 0; i < interserv_config.storage_count; i++) {
+			if (&interserv_config.storages[i] && interserv_config.storages[i].id == id)
+				return interserv_config.storages[i].max_num;
+		}
 	}
-	StringBuf_Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", schema_config.storage_db, account_id);
-
-	if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) )
-		Sql_ShowDebug(sql_handle);
-
-	StringBuf_Destroy(&buf);
+	return MAX_STORAGE;
+}
 
-	for( i = 0; i < MAX_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i )
-	{
-		struct item* item;
-		char* data;
-		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);
-		Sql_GetData(sql_handle, 3, &data, NULL); item->equip = atoi(data);
-		Sql_GetData(sql_handle, 4, &data, NULL); item->identify = atoi(data);
-		Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data);
-		Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data);
-		Sql_GetData(sql_handle, 7, &data, NULL); item->expire_time = (unsigned int)atoi(data);
-		Sql_GetData(sql_handle, 8, &data, NULL); item->bound = atoi(data);
-		Sql_GetData(sql_handle, 9, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
-		for( j = 0; j < MAX_SLOTS; ++j ){
-			Sql_GetData(sql_handle, 10+j, &data, NULL); item->card[j] = atoi(data);
-		}
-		for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
-			Sql_GetData(sql_handle, 10+MAX_SLOTS+j*3, &data, NULL); item->option[j].id = atoi(data);
-			Sql_GetData(sql_handle, 11+MAX_SLOTS+j*3, &data, NULL); item->option[j].value = atoi(data);
-			Sql_GetData(sql_handle, 12+MAX_SLOTS+j*3, &data, NULL); item->option[j].param = atoi(data);
+/**
+ * Get table name of storage
+ * @param id Storage ID
+ * @return Table name
+ **/
+const char *inter_premiumStorage_getTableName(uint8 id) {
+	if (interserv_config.storages && interserv_config.storage_count) {
+		int i;
+		for (i = 0; i < interserv_config.storage_count; i++) {
+			if (&interserv_config.storages[i] && interserv_config.storages[i].id == id)
+				return interserv_config.storages[i].table;
 		}
 	}
-	p->storage_amount = i;
-	Sql_FreeResult(sql_handle);
+	return schema_config.storage_db;
+}
 
-	ShowInfo("storage load complete from DB - id: %d (total: %d)\n", account_id, p->storage_amount);
-	return 1;
+/**
+ * Save inventory entries to SQL
+ * @param char_id: Character ID to save
+ * @param p: Inventory entries
+ * @return 0 if success, or error count
+ */
+static int inventory_tosql(uint32 char_id, struct s_storage* p)
+{
+	return char_memitemdata_to_sql(p->u.items_inventory, MAX_INVENTORY, char_id, TABLE_INVENTORY, p->stor_id);
 }
 
-/// Save guild_storage data to sql
-int guild_storage_tosql(int guild_id, struct guild_storage* p)
+/**
+ * Save storage entries to SQL
+ * @param char_id: Character ID to save
+ * @param p: Storage entries
+ * @return 0 if success, or error count
+ */
+static int storage_tosql(uint32 account_id, struct s_storage* p)
 {
-	char_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;
+	return char_memitemdata_to_sql(p->u.items_storage, MAX_STORAGE, account_id, TABLE_STORAGE, p->stor_id);
 }
 
-/// Load guild_storage data to mem
-int guild_storage_fromsql(int guild_id, struct guild_storage* p)
+/**
+ * Save cart entries to SQL
+ * @param char_id: Character ID to save
+ * @param p: Cart entries
+ * @return 0 if success, or error count
+ */
+static int cart_tosql(uint32 char_id, struct s_storage* p)
 {
-	StringBuf buf;
-	int i, j;
+	return char_memitemdata_to_sql(p->u.items_cart, MAX_CART, char_id, TABLE_CART, p->stor_id);
+}
 
-	memset(p, 0, sizeof(struct guild_storage)); //clean up memory
-	p->storage_amount = 0;
-	p->guild_id = guild_id;
+/**
+ * Fetch inventory entries from table
+ * @param char_id: Character ID to fetch
+ * @param p: Inventory list to save the entries
+ * @return True if success, False if failed
+ */
+static bool inventory_fromsql(uint32 char_id, struct s_storage* p)
+{
+	return char_memitemdata_from_sql( p, MAX_INVENTORY, char_id, TABLE_INVENTORY, p->stor_id );
+}
 
-	// storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`/`option_id0`/`option_val0`/`option_parm0`/`option_id1`/`option_val1`/`option_parm1`/`option_id2`/`option_val2`/`option_parm2`/`option_id3`/`option_val3`/`option_parm3`/`option_id4`/`option_val4`/`option_parm4`}
-	StringBuf_Init(&buf);
-	StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`bound`,`unique_id`");
-	for( j = 0; j < MAX_SLOTS; ++j )
-		StringBuf_Printf(&buf, ",`card%d`", j);
-	for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
-		StringBuf_Printf(&buf, ", `option_id%d`", j);
-		StringBuf_Printf(&buf, ", `option_val%d`", j);
-		StringBuf_Printf(&buf, ", `option_parm%d`", j);
-	}
-	StringBuf_Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", schema_config.guild_storage_db, guild_id);
+/**
+ * Fetch cart entries from table
+ * @param char_id: Character ID to fetch
+ * @param p: Cart list to save the entries
+ * @return True if success, False if failed
+ */
+static bool cart_fromsql(uint32 char_id, struct s_storage* p)
+{
+	return char_memitemdata_from_sql( p, MAX_CART, char_id, TABLE_CART, p->stor_id );
+}
 
-	if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) )
-		Sql_ShowDebug(sql_handle);
+/**
+ * Fetch storage entries from table
+ * @param char_id: Character ID to fetch
+ * @param p: Storage list to save the entries
+ * @param stor_id: Storage ID
+ * @return True if success, False if failed
+ */
+static bool storage_fromsql(uint32 account_id, struct s_storage* p)
+{
+	return char_memitemdata_from_sql( p, MAX_STORAGE, account_id, TABLE_STORAGE, p->stor_id );
+}
 
-	StringBuf_Destroy(&buf);
+/**
+ * Save guild_storage data to sql
+ * @param guild_id: Character ID to save
+ * @param p: Guild Storage list to save the entries
+ * @return 0 if success, or error count
+ */
+bool guild_storage_tosql(int guild_id, struct s_storage* p)
+{
+	//ShowInfo("Guild Storage has been saved (GID: %d)\n", guild_id);
+	return char_memitemdata_to_sql(p->u.items_guild, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE, p->stor_id);
+}
 
-	for( i = 0; i < MAX_GUILD_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i )
-	{
-		struct item* item;
-		char* data;
-		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);
-		Sql_GetData(sql_handle, 3, &data, NULL); item->equip = atoi(data);
-		Sql_GetData(sql_handle, 4, &data, NULL); item->identify = atoi(data);
-		Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data);
-		Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data);
-		Sql_GetData(sql_handle, 7, &data, NULL); item->bound = atoi(data);
-		Sql_GetData(sql_handle, 8, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
-		item->expire_time = 0;
-		for( j = 0; j < MAX_SLOTS; ++j ){
-			Sql_GetData(sql_handle, 9+j, &data, NULL); item->card[j] = atoi(data);
-		}
-		for( j = 0; j < MAX_ITEM_RDM_OPT; ++j ) {
-			Sql_GetData(sql_handle, 9+MAX_SLOTS+j*3, &data, NULL); item->option[j].id = atoi(data);
-			Sql_GetData(sql_handle, 10+MAX_SLOTS+j*3, &data, NULL); item->option[j].value = atoi(data);
-			Sql_GetData(sql_handle, 11+MAX_SLOTS+j*3, &data, NULL); item->option[j].param = atoi(data);
+/**
+ * Fetch guild_storage entries from table
+ * @param char_id: Character ID to fetch
+ * @param p: Storage list to save the entries
+ * @return True if success, False if failed
+ */
+bool guild_storage_fromsql(int guild_id, struct s_storage* p)
+{
+	return char_memitemdata_from_sql( p, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE, p->stor_id );
+}
+
+static void inter_storage_checkDB(void) {
+	int i = 0;
+	// Checking storage tables
+	for (i = 0; i < interserv_config.storage_count; i++) {
+		if (!&interserv_config.storages[i] || !interserv_config.storages[i].name || !interserv_config.storages[i].table || interserv_config.storages[i].table == '\0')
+			continue;
+		if (SQL_ERROR == Sql_Query(sql_handle, "SELECT  `id`,`account_id`,`nameid`,`amount`,`equip`,`identify`,`refine`,"
+			"`attribute`,`card0`,`card1`,`card2`,`card3`,`option_id0`,`option_val0`,`option_parm0`,`option_id1`,`option_val1`,`option_parm1`,"
+			"`option_id2`,`option_val2`,`option_parm2`,`option_id3`,`option_val3`,`option_parm3`,`option_id4`,`option_val4`,`option_parm4`,"
+			"`expire_time`,`bound`,`unique_id`"
+			" FROM `%s` LIMIT 1;", interserv_config.storages[i].table) ){
+			Sql_ShowDebug(sql_handle);
 		}
 	}
-	p->storage_amount = i;
 	Sql_FreeResult(sql_handle);
-
-	ShowInfo("guild storage load complete from DB - id: %d (total: %d)\n", guild_id, p->storage_amount);
-	return 0;
 }
 
 //---------------------------------------------------------
 // storage data initialize
-int inter_storage_sql_init(void)
+void inter_storage_sql_init(void)
 {
-	return 1;
+	inter_storage_checkDB();
+	return;
 }
+
 // storage data finalize
 void inter_storage_sql_final(void)
 {
 	return;
 }
 
-// Delete char storage
-int inter_storage_delete(uint32 account_id)
-{
-	if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id`='%d'", schema_config.storage_db, account_id) )
-		Sql_ShowDebug(sql_handle);
-	return 0;
-}
-int inter_guild_storage_delete(int guild_id)
-{
-	if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `guild_id`='%d'", schema_config.guild_storage_db, guild_id) )
-		Sql_ShowDebug(sql_handle);
-	return 0;
-}
-
 //---------------------------------------------------------
 // packet from map server
 
-int mapif_load_guild_storage(int fd,uint32 account_id,int guild_id, char flag)
+bool mapif_load_guild_storage(int fd,uint32 account_id,int guild_id, char flag)
 {
 	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", schema_config.guild_db, guild_id) )
 		Sql_ShowDebug(sql_handle);
 	else if( Sql_NumRows(sql_handle) > 0 )
 	{// guild exists
-		WFIFOHEAD(fd, sizeof(struct guild_storage)+13);
+		WFIFOHEAD(fd, sizeof(struct s_storage)+13);
 		WFIFOW(fd,0) = 0x3818;
-		WFIFOW(fd,2) = sizeof(struct guild_storage)+13;
+		WFIFOW(fd,2) = sizeof(struct s_storage)+13;
 		WFIFOL(fd,4) = account_id;
 		WFIFOL(fd,8) = guild_id;
 		WFIFOB(fd,12) = flag; //1 open storage, 0 don't open
-		guild_storage_fromsql(guild_id, (struct guild_storage*)WFIFOP(fd,13));
+		guild_storage_fromsql(guild_id, (struct s_storage*)WFIFOP(fd,13));
 		WFIFOSET(fd, WFIFOW(fd,2));
-		return 0;
+		return false;
 	}
 	// guild does not exist
 	Sql_FreeResult(sql_handle);
@@ -197,9 +211,10 @@ int mapif_load_guild_storage(int fd,uint32 account_id,int guild_id, char flag)
 	WFIFOL(fd,4) = account_id;
 	WFIFOL(fd,8) = 0;
 	WFIFOSET(fd, 12);
-	return 0;
+	return true;
 }
-int mapif_save_guild_storage_ack(int fd,uint32 account_id,int guild_id,int fail)
+
+void mapif_save_guild_storage_ack(int fd,uint32 account_id,int guild_id,int fail)
 {
 	WFIFOHEAD(fd,11);
 	WFIFOW(fd,0)=0x3819;
@@ -207,20 +222,18 @@ int mapif_save_guild_storage_ack(int fd,uint32 account_id,int guild_id,int fail)
 	WFIFOL(fd,6)=guild_id;
 	WFIFOB(fd,10)=fail;
 	WFIFOSET(fd,11);
-	return 0;
 }
 
 //---------------------------------------------------------
 // packet from map server
 
-int mapif_parse_LoadGuildStorage(int fd)
+void mapif_parse_LoadGuildStorage(int fd)
 {
 	RFIFOHEAD(fd);
 	mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6),1);
-	return 0;
 }
 
-int mapif_parse_SaveGuildStorage(int fd)
+bool mapif_parse_SaveGuildStorage(int fd)
 {
 	int guild_id;
 	int len;
@@ -229,9 +242,9 @@ int mapif_parse_SaveGuildStorage(int fd)
 	guild_id = RFIFOL(fd,8);
 	len = RFIFOW(fd,2);
 
-	if( sizeof(struct guild_storage) != len - 12 )
+	if( sizeof(struct s_storage) != len - 12 )
 	{
-		ShowError("inter storage: data size error %d != %d\n", sizeof(struct guild_storage), len - 12);
+		ShowError("inter storage: data size error %d != %d\n", sizeof(struct s_storage), len - 12);
 	}
 	else
 	{
@@ -240,21 +253,21 @@ int mapif_parse_SaveGuildStorage(int fd)
 		else if( Sql_NumRows(sql_handle) > 0 )
 		{// guild exists
 			Sql_FreeResult(sql_handle);
-			guild_storage_tosql(guild_id, (struct guild_storage*)RFIFOP(fd,12));
+			guild_storage_tosql(guild_id, (struct s_storage*)RFIFOP(fd,12));
 			mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 0);
-			return 0;
+			return false;
 		}
 		Sql_FreeResult(sql_handle);
 	}
 	mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 1);
-	return 0;
+	return true;
 }
 
 #ifdef BOUND_ITEMS
 /**
-* IZ 0x3856 <account_id>.L <guild_id>.W
-* Tells map-server if the process if complete, unlock the guild storage
-*/
+ * IZ 0x3856 <account_id>.L <guild_id>.W
+ * Tells map-server if the process if complete, unlock the guild storage
+ */
 static void mapif_itembound_ack(int fd, int account_id, int guild_id)
 {
 	WFIFOHEAD(fd,8);
@@ -266,17 +279,17 @@ static void mapif_itembound_ack(int fd, int account_id, int guild_id)
 }
 
 /**
-* IZ 0x3857 <size>.W <count>.W <guild_id>.W { <item>.?B }.*MAX_INVENTORY
-* Send the retrieved guild bound items to map-server, store them to guild storage.
-* By using this method, stackable items will looks how it should be, and overflowed
-* item's stack won't disturbs the guild storage table and the leftover items (when
-* storage is full) will be discarded.
-* @param fd
-* @param guild_id
-* @param items[]
-* @param count
-* @author [Cydh]
-*/
+ * IZ 0x3857 <size>.W <count>.W <guild_id>.W { <item>.?B }.*MAX_INVENTORY
+ * Send the retrieved guild bound items to map-server, store them to guild storage.
+ * By using this method, stackable items will looks how it should be, and overflowed
+ * item's stack won't disturbs the guild storage table and the leftover items (when
+ * storage is full) will be discarded.
+ * @param fd
+ * @param guild_id
+ * @param items[]
+ * @param count
+ * @author [Cydh]
+ */
 static void mapif_itembound_store2gstorage(int fd, int guild_id, struct item items[], unsigned short count) {
 	int size = 8 + sizeof(struct item) * MAX_INVENTORY, i;
 
@@ -294,11 +307,11 @@ static void mapif_itembound_store2gstorage(int fd, int guild_id, struct item ite
 }
 
 /**
-* ZI 0x3056 <char_id>.L <account_id>.L <guild_id>.W
-* Pulls guild bound items for offline characters
-* @author [Akinari]
-*/
-int mapif_parse_itembound_retrieve(int fd)
+ * ZI 0x3056 <char_id>.L <account_id>.L <guild_id>.W
+ * Pulls guild bound items for offline characters
+ * @author [Akinari]
+ */
+bool mapif_parse_itembound_retrieve(int fd)
 {
 	StringBuf buf;
 	SqlStmt* stmt;
@@ -328,7 +341,7 @@ int mapif_parse_itembound_retrieve(int fd)
 		SqlStmt_Free(stmt);
 		StringBuf_Destroy(&buf);
 		mapif_itembound_ack(fd,account_id,guild_id);
-		return 1;
+		return true;
 	}
 
 	SqlStmt_BindColumn(stmt, 0, SQLDT_INT,       &item.id,          0, NULL, NULL);
@@ -357,7 +370,7 @@ int mapif_parse_itembound_retrieve(int fd)
 		StringBuf_Destroy(&buf);
 		SqlStmt_Free(stmt);
 		mapif_itembound_ack(fd,account_id,guild_id);
-		return 1;
+		return true;
 	}
 
 	char_set_session_flag(account_id, 1);
@@ -372,7 +385,7 @@ int mapif_parse_itembound_retrieve(int fd)
 		SqlStmt_Free(stmt);
 		StringBuf_Destroy(&buf);
 		mapif_itembound_ack(fd,account_id,guild_id);
-		return 1;
+		return true;
 	}
 
 	// Send the deleted items to map-server to store them in guild storage [Cydh]
@@ -418,7 +431,7 @@ int mapif_parse_itembound_retrieve(int fd)
 			StringBuf_Destroy(&buf);
 			StringBuf_Destroy(&buf2);
 			mapif_itembound_ack(fd,account_id,guild_id);
-			return 1;
+			return true;
 		}
 		StringBuf_Destroy(&buf2);
 	}
@@ -427,21 +440,149 @@ int mapif_parse_itembound_retrieve(int fd)
 	SqlStmt_Free(stmt);
 
 	char_unset_session_flag(account_id, 1);
-	return 0;
+	return false;
 }
 #endif
 
-int inter_storage_parse_frommap(int fd)
+/*==========================================
+ * Storages (Inventory/Storage/Cart)
+ *------------------------------------------*/
+
+/**
+ * Sending inventory/cart/storage data to player
+ * IZ 0x388a <size>.W <type>.B <account_id>.L <result>.B <inventory>.?B
+ * @param fd
+ * @param account_id
+ * @param type
+ * @param entries Inventory/cart/storage entries
+ * @param result
+ */
+static void mapif_storage_data_loaded(int fd, uint32 account_id, char type, struct s_storage entries, bool result) {
+	uint16 size = sizeof(struct s_storage) + 10;
+	
+	WFIFOHEAD(fd, size);
+	WFIFOW(fd, 0) = 0x388a;
+	WFIFOW(fd, 2) = size;
+	WFIFOB(fd, 4) = type;
+	WFIFOL(fd, 5) = account_id;
+	WFIFOB(fd, 9) = result;
+	memcpy(WFIFOP(fd, 10), &entries, sizeof(struct s_storage));
+	WFIFOSET(fd, size);
+}
+
+/**
+ * Tells player if inventory/cart/storage is saved
+ * IZ 0x388b <account_id>.L <result>.B <type>.B
+ * @param fd
+ * @param account_id
+ * @param char_id
+ * @param success
+ * @param type
+ * @param stor_id
+ */
+void mapif_storage_saved(int fd, uint32 account_id, uint32 char_id, bool success, char type, uint8 stor_id) {
+	WFIFOHEAD(fd,9);
+	WFIFOW(fd, 0) = 0x388b;
+	WFIFOL(fd, 2) = account_id;
+	WFIFOB(fd, 6) = success;
+	WFIFOB(fd, 7) = type;
+	WFIFOB(fd, 8) = stor_id;
+	WFIFOSET(fd,9);
+}
+
+/**
+ * Requested inventory/cart/storage data for a player
+ * ZI 0x308a <type>.B <account_id>.L <char_id>.L <storage_id>.B <mode>.B
+ * @param fd
+ */
+bool mapif_parse_StorageLoad(int fd) {
+	uint32 aid, cid;
+	int type;
+	uint8 stor_id, mode;
+	struct s_storage stor;
+	bool res = true;
+
+	type = RFIFOB(fd,2);
+	aid = RFIFOL(fd,3);
+	cid = RFIFOL(fd,7);
+	stor_id = RFIFOB(fd,11);
+
+	memset(&stor, 0, sizeof(struct s_storage));
+	stor.stor_id = stor_id;
+
+	//ShowInfo("Loading storage for AID=%d.\n", aid);
+	switch (type) {
+		case TABLE_INVENTORY: res = inventory_fromsql(cid, &stor); break;
+		case TABLE_STORAGE:
+			if (!inter_premiumStorage_exists(stor_id)) {
+				ShowError("Invalid storage with id %d\n", stor_id);
+				return false;
+			}
+			res = storage_fromsql(aid, &stor);
+			break;
+		case TABLE_CART:      res = cart_fromsql(cid, &stor);      break;
+		default: return false;
+	}
+
+	mode = RFIFOB(fd, 12);
+	stor.state.put = (mode&STOR_MODE_PUT) ? 1 : 0;
+	stor.state.get = (mode&STOR_MODE_GET) ? 1 : 0;
+
+	mapif_storage_data_loaded(fd, aid, type, stor, res);
+	return true;
+}
+
+/**
+ * Asking to save player's inventory/cart/storage data
+ * ZI 0x308b <size>.W <type>.B <account_id>.L <char_id>.L <entries>.?B
+ * @param fd
+ */
+bool mapif_parse_StorageSave(int fd) {
+	int aid, cid, type;
+	struct s_storage stor;
+
+	RFIFOHEAD(fd);
+	type = RFIFOB(fd, 4);
+	aid = RFIFOL(fd, 5);
+	cid = RFIFOL(fd, 9);
+	
+	memset(&stor, 0, sizeof(struct s_storage));
+	memcpy(&stor, RFIFOP(fd, 13), sizeof(struct s_storage));
+
+	//ShowInfo("Saving storage data for AID=%d.\n", aid);
+	switch(type){
+		case TABLE_INVENTORY:	inventory_tosql(cid, &stor); break;
+		case TABLE_STORAGE:
+			if (!inter_premiumStorage_exists(stor.stor_id)) {
+				ShowError("Invalid storage with id %d\n", stor.stor_id);
+				return false;
+			}
+			storage_tosql(aid, &stor);
+			break;
+		case TABLE_CART:	cart_tosql(cid, &stor); break;
+		default: return false;
+	}
+	mapif_storage_saved(fd, aid, cid, true, type, stor.stor_id);
+	return false;
+}
+
+
+/*==========================================
+ * Parse packet from map-server
+ *------------------------------------------*/
+bool inter_storage_parse_frommap(int fd)
 {
 	RFIFOHEAD(fd);
 	switch(RFIFOW(fd,0)){
-	case 0x3018: mapif_parse_LoadGuildStorage(fd); break;
-	case 0x3019: mapif_parse_SaveGuildStorage(fd); break;
+		case 0x3018: mapif_parse_LoadGuildStorage(fd); break;
+		case 0x3019: mapif_parse_SaveGuildStorage(fd); break;
 #ifdef BOUND_ITEMS
-	case 0x3056: mapif_parse_itembound_retrieve(fd); break;
+		case 0x3056: mapif_parse_itembound_retrieve(fd); break;
 #endif
-	default:
-		return 0;
+		case 0x308a: mapif_parse_StorageLoad(fd); break;
+		case 0x308b: mapif_parse_StorageSave(fd); break;
+		default:
+			return false;
 	}
-	return 1;
+	return true;
 }

+ 8 - 9
src/char/int_storage.h

@@ -4,18 +4,17 @@
 #ifndef _INT_STORAGE_SQL_H_
 #define _INT_STORAGE_SQL_H_
 
-struct storage_data;
-struct guild_storage;
+struct s_storage;
 
-int inter_storage_sql_init(void);
+void inter_storage_sql_init(void);
 void inter_storage_sql_final(void);
-int inter_storage_delete(uint32 account_id);
-int inter_guild_storage_delete(int guild_id);
 
-int inter_storage_parse_frommap(int fd);
+bool inter_premiumStorage_exists(uint8 id);
+int inter_premiumStorage_getMax(uint8 id);
+const char *inter_premiumStorage_getTableName(uint8 id);
 
-int storage_fromsql(uint32 account_id, struct storage_data* p);
-int storage_tosql(uint32 account_id,struct storage_data *p);
-int guild_storage_tosql(int guild_id, struct guild_storage *p);
+bool inter_storage_parse_frommap(int fd);
+
+bool guild_storage_tosql(int guild_id, struct s_storage *p);
 
 #endif /* _INT_STORAGE_SQL_H_ */

+ 105 - 6
src/char/inter.c

@@ -39,10 +39,10 @@ char char_server_id[32] = "ragnarok";
 char char_server_pw[32] = ""; // Allow user to send empty password (bugreport:7787)
 char char_server_db[32] = "ragnarok";
 char default_codepage[32] = ""; //Feature by irmin.
-
+struct Inter_Config interserv_config;
 unsigned int party_share_level = 10;
 
-// recv. packet list
+/// Received packet Lengths from map-server
 int inter_recv_packet_length[] = {
 	-1,-1, 7,-1, -1,13,36, (2+4+4+4+1+NAME_LENGTH),  0,-1, 0, 0,  0, 0,  0, 0,	// 3000-
 	 6,-1, 0, 0,  0, 0, 0, 0, 10,-1, 0, 0,  0, 0,  0, 0,	// 3010-
@@ -52,7 +52,7 @@ int inter_recv_packet_length[] = {
 	-1,-1,10,10,  0,-1,12, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3050-  Auction System [Zephyrus]
 	 6,-1, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3060-  Quest system [Kevin] [Inkfish]
 	-1,10, 6,-1,  0, 0, 0, 0,  0, 0, 0, 0, -1,10,  6,-1,	// 3070-  Mercenary packets [Zephyrus], Elemental packets [pakpil]
-	48,14,-1, 6,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3080-
+	48,14,-1, 6,  0, 0, 0, 0,  0, 0,13,-1,  0, 0,  0, 0,	// 3080-  Pet System, Storage
 	-1,10,-1, 6,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3090-  Homunculus packets [albator]
 };
 
@@ -402,7 +402,7 @@ void mapif_parse_accinfo(int fd) {
 	int u_fd = RFIFOL(fd,2), u_aid = RFIFOL(fd,6), u_group = RFIFOL(fd,10);
 	char type= RFIFOB(fd,14);
 	char query[NAME_LENGTH], query_esq[NAME_LENGTH*2+1];
-	int account_id = 0;
+	uint32 account_id = 0;
 	char *data;
 
 	safestrncpy(query, RFIFOCP(fd,15), NAME_LENGTH);
@@ -495,7 +495,7 @@ void mapif_accinfo_ack(bool success, int map_fd, int u_fd, int u_aid, int accoun
 		}
 	} else {
 		while ( SQL_SUCCESS == Sql_NextRow(sql_handle) ) {
-			int char_id, class_;
+			uint32 char_id, class_;
 			short char_num, base_level, job_level, online;
 			char name[NAME_LENGTH];
 			char *data;
@@ -773,6 +773,8 @@ static int inter_config_read(const char* cfgName)
 			party_share_level = (unsigned int)atof(w2);
 		else if(!strcmpi(w1,"log_inter"))
 			charserv_config.log_inter = atoi(w2);
+		else if(!strcmpi(w1,"inter_server_conf"))
+			strcpy(interserv_config.cfgFile, w2);
 		else if(!strcmpi(w1,"import"))
 			inter_config_read(w2);
 	}
@@ -801,11 +803,86 @@ int inter_log(char* fmt, ...)
 	return 0;
 }
 
+/**
+ * Read inter config file
+ **/
+static void inter_config_readConf(void) {
+	int count = 0;
+	config_setting_t *config = NULL;
+
+	if (conf_read_file(&interserv_config.cfg, interserv_config.cfgFile))
+		return;
+
+	// Read storages
+	config = config_lookup(&interserv_config.cfg, "storages");
+	if (config && (count = config_setting_length(config))) {
+		int i;
+		for (i = 0; i < count; i++) {
+			int id, max_num;
+			const char *name, *tablename;
+			struct s_storage_table table;
+			config_setting_t *entry = config_setting_get_elem(config, i);
+
+			if (!config_setting_lookup_int(entry, "id", &id)) {
+				ShowConfigWarning(entry, "inter_config_readConf: Cannot find storage \"id\" in member %d", i);
+				continue;
+			}
+
+			if (!config_setting_lookup_string(entry, "name", &name)) {
+				ShowConfigWarning(entry, "inter_config_readConf: Cannot find storage \"name\" in member %d", i);
+				continue;
+			}
+
+			if (!config_setting_lookup_string(entry, "table", &tablename)) {
+				ShowConfigWarning(entry, "inter_config_readConf: Cannot find storage \"table\" in member %d", i);
+				continue;
+			}
+
+			if (!config_setting_lookup_int(entry, "max", &max_num))
+				max_num = MAX_STORAGE;
+			else if (max_num > MAX_STORAGE) {
+				ShowConfigWarning(entry, "Storage \"%s\" has \"max\" %d, max is MAX_STORAGE (%d)!\n", name, max_num, MAX_STORAGE);
+				max_num = MAX_STORAGE;
+			}
+
+			memset(&table, 0, sizeof(struct s_storage_table));
+
+			RECREATE(interserv_config.storages, struct s_storage_table, interserv_config.storage_count+1);
+			interserv_config.storages[interserv_config.storage_count].id = id;
+			safestrncpy(interserv_config.storages[interserv_config.storage_count].name, name, NAME_LENGTH);
+			safestrncpy(interserv_config.storages[interserv_config.storage_count].table, tablename, DB_NAME_LEN);
+			interserv_config.storages[interserv_config.storage_count].max_num = max_num;
+			interserv_config.storage_count++;
+		}
+	}
+
+	ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' storage informations in '"CL_WHITE"%s"CL_RESET"'\n", interserv_config.storage_count, interserv_config.cfgFile);
+}
+
+void inter_config_finalConf(void) {
+
+	if (interserv_config.storages)
+		aFree(interserv_config.storages);
+	interserv_config.storages = NULL;
+	interserv_config.storage_count = 0;
+
+	config_destroy(&interserv_config.cfg);
+}
+
+static void inter_config_defaults(void) {
+	interserv_config.storage_count = 0;
+	interserv_config.storages = NULL;
+
+	safestrncpy(interserv_config.cfgFile, "conf/inter_server.conf", sizeof(interserv_config.cfgFile));
+}
+
 // initialize
 int inter_init_sql(const char *file)
 {
 	//int i;
 
+
+	inter_config_defaults();
 	inter_config_read(file);
 
 	//DB connection initialized
@@ -813,7 +890,7 @@ int inter_init_sql(const char *file)
 	ShowInfo("Connect Character DB server.... (Character Server)\n");
 	if( SQL_ERROR == Sql_Connect(sql_handle, char_server_id, char_server_pw, char_server_ip, (uint16)char_server_port, char_server_db) )
 	{
-		ShowError("Couldn't connect with uname='%s',passwd='%s',host='%s',port='%d',database='%s'\n",
+		ShowError("Couldn't connect with username = '%s', password = '%s', host = '%s', port = '%d', database = '%s'\n",
 			char_server_id, char_server_pw, char_server_ip, char_server_port, char_server_db);
 		Sql_ShowDebug(sql_handle);
 		Sql_Free(sql_handle);
@@ -826,6 +903,7 @@ int inter_init_sql(const char *file)
 	}
 
 	wis_db = idb_alloc(DB_OPT_RELEASE_DATA);
+	inter_config_readConf();
 	inter_guild_sql_init();
 	inter_storage_sql_init();
 	inter_party_sql_init();
@@ -845,6 +923,7 @@ void inter_final(void)
 {
 	wis_db->destroy(wis_db, NULL);
 
+	inter_config_finalConf();
 	inter_guild_sql_final();
 	inter_storage_sql_final();
 	inter_party_sql_final();
@@ -860,8 +939,28 @@ void inter_final(void)
 	return;
 }
 
+/**
+ * IZ 0x388c <len>.W { <storage_table>.? }*?
+ * Sends storage information to map-server
+ * @param fd
+ **/
+void inter_Storage_sendInfo(int fd) {
+	int size = sizeof(struct s_storage_table), len = 4 + interserv_config.storage_count * size, i = 0;
+	// Send storage table information
+	WFIFOHEAD(fd, len);
+	WFIFOW(fd, 0) = 0x388c;
+	WFIFOW(fd, 2) = len;
+	for (i = 0; i < interserv_config.storage_count; i++) {
+		if (!&interserv_config.storages[i] || !interserv_config.storages[i].name)
+			continue;
+		memcpy(WFIFOP(fd, 4 + size*i), &interserv_config.storages[i], size);
+	}
+	WFIFOSET(fd, len);
+}
+
 int inter_mapif_init(int fd)
 {
+	inter_Storage_sendInfo(fd);
 	return 0;
 }
 

+ 11 - 0
src/char/inter.h

@@ -4,8 +4,19 @@
 #ifndef _INTER_SQL_H_
 #define _INTER_SQL_H_
 
+#include "../common/conf.h"
+#include "../common/mmo.h"
 #include "../common/sql.h"
 
+struct Inter_Config {
+	char cfgFile[128];				  ///< Inter-Config file
+	config_t cfg;					  ///< Config
+	struct s_storage_table *storages; ///< Storage name & table information
+	uint8 storage_count;			  ///< Number of available storage
+};
+
+extern struct Inter_Config interserv_config;
+
 int inter_init_sql(const char *file);
 void inter_final(void);
 int inter_parse_frommap(int fd);

+ 40 - 14
src/common/mmo.h

@@ -65,7 +65,7 @@
 #define DEFAULT_WALK_SPEED 150 ///Default walk speed
 #define MIN_WALK_SPEED 20 ///Min walk speed
 #define MAX_WALK_SPEED 1000 ///Max walk speed
-#define MAX_STORAGE 600 ///Max number of storage slots a player can have, (up to ~850 tested)
+#define MAX_STORAGE 600 ///Max number of storage slots a player can have
 #define MAX_GUILD_STORAGE 600 ///Max number of storage slots a guild
 #define MAX_PARTY 12 ///Max party member
 #define MAX_GUILD 16+10*6	///Increased max guild members +6 per 1 extension levels [Lupus]
@@ -79,6 +79,7 @@
 #define MAX_QUEST_DROPS 3 ///Max quest drops for a quest
 #define MAX_PC_BONUS_SCRIPT 50 ///Max bonus script can be fetched from `bonus_script` table on player load [Cydh]
 #define MAX_ITEM_RDM_OPT 5	 /// Max item random option [Napster]
+#define DB_NAME_LEN 256 //max len of dbs
 
 // for produce
 #define MIN_ATTRIBUTE 0
@@ -298,19 +299,46 @@ struct skill_cooldown_data {
 	long tick;
 };
 
-struct storage_data {
-	int storage_amount;
-	struct item items[MAX_STORAGE];
+enum storage_type {
+	TABLE_INVENTORY = 1,
+	TABLE_CART,
+	TABLE_STORAGE,
+	TABLE_GUILD_STORAGE,
 };
 
-/// Guild storgae struct
-struct guild_storage {
-	bool dirty; ///< Dirty status, need to be saved
-	int guild_id; ///< Guild ID
-	short storage_amount; ///< Amount of item on storage
-	struct item items[MAX_GUILD_STORAGE]; ///< Item entries
-	bool locked; ///< If locked, can't use storage when item bound retrieval
-	uint32 opened; ///< Holds the char_id that open the storage
+enum e_storage_mode {
+	STOR_MODE_NONE = 0x0,
+	STOR_MODE_GET = 0x1,
+	STOR_MODE_PUT = 0x2,
+	STOR_MODE_ALL = 0x3,
+};
+
+struct s_storage {
+	bool dirty; ///< Dirty status, data needs to be saved
+	bool status; ///< Current status of storage (opened or closed)
+	uint16 amount; ///< Amount of items in storage
+	bool lock; ///< If locked, can't use storage when item bound retrieval
+	uint32 id; ///< Account ID / Character ID / Guild ID (owner of storage)
+	enum storage_type type; ///< Type of storage (inventory, cart, storage, guild storage)
+	uint16 max_amount;
+	uint8 stor_id; ///< Storage ID
+	struct {
+		unsigned get : 1;
+		unsigned put : 1;
+	} state;
+	union { // Max for inventory, storage, cart, and guild storage are 1637 each without changing this struct and struct item [2014/10/27]
+		struct item items_inventory[MAX_INVENTORY];
+		struct item items_storage[MAX_STORAGE];
+		struct item items_cart[MAX_CART];
+		struct item items_guild[MAX_GUILD_STORAGE];
+	} u;
+};
+
+struct s_storage_table {
+	char name[NAME_LENGTH];
+	char table[DB_NAME_LEN];
+	uint16 max_num;
+	uint8 id;
 };
 
 struct s_pet {
@@ -433,8 +461,6 @@ struct mmo_charstatus {
 	uint16 mapport;
 
 	struct point last_point,save_point,memo_point[MAX_MEMOPOINTS];
-	struct item inventory[MAX_INVENTORY],cart[MAX_CART];
-	struct storage_data storage;
 	struct s_skill skill[MAX_SKILL];
 
 	struct s_friend friends[MAX_FRIENDS]; //New friend system [Skotlex]

+ 11 - 15
src/login/account.c

@@ -17,7 +17,6 @@
 #include <stdlib.h>
 
 /// global defines
-#define ACCOUNT_SQL_DB_VERSION 20140928
 
 /// internal structure
 typedef struct AccountDB_SQL {
@@ -117,15 +116,12 @@ static bool account_db_sql_init(AccountDB* self) {
 	db->accounts = Sql_Malloc();
 	sql_handle = db->accounts;
 
-	if( db->db_hostname[0] != '\0' )
-	{// local settings
-		username = db->db_username;
-		password = db->db_password;
-		hostname = db->db_hostname;
-		port     = db->db_port;
-		database = db->db_database;
-		codepage = db->codepage;
-	}
+	username = db->db_username;
+	password = db->db_password;
+	hostname = db->db_hostname;
+	port     = db->db_port;
+	database = db->db_database;
+	codepage = db->codepage;
 
 	if( SQL_ERROR == Sql_Connect(sql_handle, username, password, hostname, port, database) )
 	{
@@ -462,7 +458,7 @@ static void account_db_sql_iter_destroy(AccountDBIterator* self) {
  */
 static bool account_db_sql_iter_next(AccountDBIterator* self, struct mmo_account* acc) {
 	AccountDBIterator_SQL* iter = (AccountDBIterator_SQL*)self;
-	AccountDB_SQL* db = (AccountDB_SQL*)iter->db;
+	AccountDB_SQL* db = iter->db;
 	Sql* sql_handle = db->accounts;
 	char* data;
 
@@ -526,15 +522,15 @@ static bool mmo_auth_fromsql(AccountDB_SQL* db, struct mmo_account* acc, uint32
 	Sql_GetData(sql_handle,  2, &data, NULL); safestrncpy(acc->pass, data, sizeof(acc->pass));
 	Sql_GetData(sql_handle,  3, &data, NULL); acc->sex = data[0];
 	Sql_GetData(sql_handle,  4, &data, NULL); safestrncpy(acc->email, data, sizeof(acc->email));
-	Sql_GetData(sql_handle,  5, &data, NULL); acc->group_id = atoi(data);
-	Sql_GetData(sql_handle,  6, &data, NULL); acc->state = strtoul(data, NULL, 10);
+	Sql_GetData(sql_handle,  5, &data, NULL); acc->group_id = (unsigned int) atoi(data);
+	Sql_GetData(sql_handle,  6, &data, NULL); acc->state = (unsigned int) strtoul(data, NULL, 10);
 	Sql_GetData(sql_handle,  7, &data, NULL); acc->unban_time = atol(data);
 	Sql_GetData(sql_handle,  8, &data, NULL); acc->expiration_time = atol(data);
-	Sql_GetData(sql_handle,  9, &data, NULL); acc->logincount = strtoul(data, NULL, 10);
+	Sql_GetData(sql_handle,  9, &data, NULL); acc->logincount = (unsigned int) strtoul(data, NULL, 10);
 	Sql_GetData(sql_handle, 10, &data, NULL); safestrncpy(acc->lastlogin, data, sizeof(acc->lastlogin));
 	Sql_GetData(sql_handle, 11, &data, NULL); safestrncpy(acc->last_ip, data, sizeof(acc->last_ip));
 	Sql_GetData(sql_handle, 12, &data, NULL); safestrncpy(acc->birthdate, data, sizeof(acc->birthdate));
-	Sql_GetData(sql_handle, 13, &data, NULL); acc->char_slots = atoi(data);
+	Sql_GetData(sql_handle, 13, &data, NULL); acc->char_slots = (uint8) atoi(data);
 	Sql_GetData(sql_handle, 14, &data, NULL); safestrncpy(acc->pincode, data, sizeof(acc->pincode));
 	Sql_GetData(sql_handle, 15, &data, NULL); acc->pincode_change = atol(data);
 #ifdef VIP_ENABLE

+ 61 - 51
src/map/atcommand.c

@@ -922,7 +922,12 @@ ACMD_FUNC(guildstorage)
 		return -1;
 	}
 
-	gstorage_storageopen(sd);
+	if (sd->state.storage_flag == 3) {
+		clif_displaymessage(fd, msg_txt(sd,250));
+		return -1;
+	}
+
+	storage_guild_storageopen(sd);
 	clif_displaymessage(fd, msg_txt(sd,920)); // Guild storage opened.
 	return 0;
 }
@@ -1377,8 +1382,8 @@ ACMD_FUNC(itemreset)
 	nullpo_retr(-1, sd);
 
 	for (i = 0; i < MAX_INVENTORY; i++) {
-		if (sd->status.inventory[i].amount && sd->status.inventory[i].equip == 0) {
-			pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_COMMAND);
+		if (sd->inventory.u.items_inventory[i].amount && sd->inventory.u.items_inventory[i].equip == 0) {
+			pc_delitem(sd, i, sd->inventory.u.items_inventory[i].amount, 0, 0, LOG_TYPE_COMMAND);
 		}
 	}
 	clif_displaymessage(fd, msg_txt(sd,20)); // All of your items have been removed.
@@ -2253,15 +2258,15 @@ ACMD_FUNC(refine)
 		if (pc_is_same_equip_index((enum equip_index)j, sd->equip_index, i))
 			continue;
 
-		if(position && !(sd->status.inventory[i].equip & position))
+		if(position && !(sd->inventory.u.items_inventory[i].equip & position))
 			continue;
 
-		final_refine = cap_value(sd->status.inventory[i].refine + refine, 0, MAX_REFINE);
-		if (sd->status.inventory[i].refine != final_refine) {
-			sd->status.inventory[i].refine = final_refine;
-			current_position = sd->status.inventory[i].equip;
+		final_refine = cap_value(sd->inventory.u.items_inventory[i].refine + refine, 0, MAX_REFINE);
+		if (sd->inventory.u.items_inventory[i].refine != final_refine) {
+			sd->inventory.u.items_inventory[i].refine = final_refine;
+			current_position = sd->inventory.u.items_inventory[i].equip;
 			pc_unequipitem(sd, i, 3);
-			clif_refine(fd, 0, i, sd->status.inventory[i].refine);
+			clif_refine(fd, 0, i, sd->inventory.u.items_inventory[i].refine);
 			clif_delitem(sd, i, 1, 3);
 			clif_additem(sd, i, 1, 0);
 			pc_equipitem(sd, i, current_position);
@@ -4442,9 +4447,9 @@ ACMD_FUNC(repairall)
 
 	count = 0;
 	for (i = 0; i < MAX_INVENTORY; i++) {
-		if (sd->status.inventory[i].nameid && sd->status.inventory[i].attribute == 1) {
-			sd->status.inventory[i].attribute = 0;
-			clif_produceeffect(sd, 0, sd->status.inventory[i].nameid);
+		if (sd->inventory.u.items_inventory[i].nameid && sd->inventory.u.items_inventory[i].attribute == 1) {
+			sd->inventory.u.items_inventory[i].attribute = 0;
+			clif_produceeffect(sd, 0, sd->inventory.u.items_inventory[i].nameid);
 			count++;
 		}
 	}
@@ -5447,20 +5452,20 @@ ACMD_FUNC(dropall)
 	}
 
 	for( i = 0; i < MAX_INVENTORY; i++ ) {
-		if( sd->status.inventory[i].amount ) {
-			if( (item_data = itemdb_exists(sd->status.inventory[i].nameid)) == NULL ) {
-				ShowDebug("Non-existant item %d on dropall list (account_id: %d, char_id: %d)\n", sd->status.inventory[i].nameid, sd->status.account_id, sd->status.char_id);
+		if( sd->inventory.u.items_inventory[i].amount ) {
+			if( (item_data = itemdb_exists(sd->inventory.u.items_inventory[i].nameid)) == NULL ) {
+				ShowDebug("Non-existant item %d on dropall list (account_id: %d, char_id: %d)\n", sd->inventory.u.items_inventory[i].nameid, sd->status.account_id, sd->status.char_id);
 				continue;
 			}
-			if( !pc_candrop(sd,&sd->status.inventory[i]) )
+			if( !pc_candrop(sd,&sd->inventory.u.items_inventory[i]) )
 				continue;
 
 			if( type == -1 || type == (uint8)item_data->type ) {
-				if( sd->status.inventory[i].equip != 0 )
+				if( sd->inventory.u.items_inventory[i].equip != 0 )
 					pc_unequipitem(sd, i, 3);
-				if(pc_dropitem(sd, i, sd->status.inventory[i].amount))
-					count += sd->status.inventory[i].amount;
-				else count2 += sd->status.inventory[i].amount;
+				if(pc_dropitem(sd, i, sd->inventory.u.items_inventory[i].amount))
+					count += sd->inventory.u.items_inventory[i].amount;
+				else count2 += sd->inventory.u.items_inventory[i].amount;
 			}
 		}
 	}
@@ -5487,10 +5492,10 @@ ACMD_FUNC(storeall)
 	}
 
 	for (i = 0; i < MAX_INVENTORY; i++) {
-		if (sd->status.inventory[i].amount) {
-			if(sd->status.inventory[i].equip != 0)
+		if (sd->inventory.u.items_inventory[i].amount) {
+			if(sd->inventory.u.items_inventory[i].equip != 0)
 				pc_unequipitem(sd, i, 3);
-			storage_storageadd(sd,  i, sd->status.inventory[i].amount);
+			storage_storageadd(sd, &sd->storage, i, sd->inventory.u.items_inventory[i].amount);
 		}
 	}
 	storage_storageclose(sd);
@@ -5508,11 +5513,16 @@ ACMD_FUNC(clearstorage)
 		clif_displaymessage(fd, msg_txt(sd,250));
 		return -1;
 	}
+	if (sd->state.storage_flag == 3) {
+		clif_displaymessage(fd, msg_txt(sd,250));
+		return -1;
+	}
 
-	j = sd->status.storage.storage_amount;
+	j = sd->storage.amount;
 	for (i = 0; i < j; ++i) {
-		storage_delitem(sd, i, sd->status.storage.items[i].amount);
+		storage_delitem(sd, &sd->storage, i, sd->storage.u.items_storage[i].amount);
 	}
+	sd->state.storage_flag = 1;
 	storage_storageclose(sd);
 
 	clif_displaymessage(fd, msg_txt(sd,1394)); // Your storage was cleaned.
@@ -5523,7 +5533,7 @@ ACMD_FUNC(cleargstorage)
 {
 	int i, j;
 	struct guild *g;
-	struct guild_storage *gstorage;
+	struct s_storage *gstorage;
 	nullpo_retr(-1, sd);
 
 	g = sd->guild;
@@ -5543,24 +5553,23 @@ ACMD_FUNC(cleargstorage)
 		return -1;
 	}
 
-	gstorage = gstorage_get_storage(sd->status.guild_id);
-	if (gstorage == NULL) {// Doesn't have opened @gstorage yet, so we skip the deletion since *shouldn't* have any item there.
+	if (sd->state.storage_flag == 3) {
+		clif_displaymessage(fd, msg_txt(sd,250));
 		return -1;
 	}
 
-	if (gstorage->opened) {
-		struct map_session_data *tsd = map_charid2sd(gstorage->opened);
-		if (tsd)
-			gstorage_storageclose(tsd);
+	gstorage = guild2storage2(sd->status.guild_id);
+	if (gstorage == NULL) { // Doesn't have opened @gstorage yet, so we skip the deletion since *shouldn't* have any item there.
+		return -1;
 	}
 
-	j = gstorage->storage_amount;
-	gstorage->locked = true; // Lock @gstorage: do not allow any item to be retrieved or stored from any guild member
+	j = gstorage->amount;
+	gstorage->lock = true; // Lock @gstorage: do not allow any item to be retrieved or stored from any guild member
 	for (i = 0; i < j; ++i) {
-		gstorage_delitem(sd, gstorage, i, gstorage->items[i].amount);
+		storage_guild_delitem(sd, gstorage, i, gstorage->u.items_guild[i].amount);
 	}
-	gstorage_storageclose(sd);
-	gstorage->locked = false; // Cleaning done, release lock
+	storage_guild_storageclose(sd);
+	gstorage->lock = false; // Cleaning done, release lock
 
 	clif_displaymessage(fd, msg_txt(sd,1395)); // Your guild storage was cleaned.
 	return 0;
@@ -5580,9 +5589,10 @@ ACMD_FUNC(clearcart)
 		return -1;
 	}
 
-	for( i = 0; i < MAX_CART; i++ )
-		if(sd->status.cart[i].nameid > 0)
-			pc_cart_delitem(sd, i, sd->status.cart[i].amount, 1, LOG_TYPE_OTHER);
+	for (i = 0; i < MAX_CART; i++) {
+		if (sd->cart.u.items_cart[i].nameid > 0)
+			pc_cart_delitem(sd, i, sd->cart.u.items_cart[i].amount, 1, LOG_TYPE_OTHER);
+	}
 
 	clif_clearcart(fd);
 	clif_updatestatus(sd,SP_CARTINFO);
@@ -6997,7 +7007,7 @@ ACMD_FUNC(identify)
 	nullpo_retr(-1, sd);
 
 	for(i=num=0;i<MAX_INVENTORY;i++){
-		if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].identify!=1){
+		if(sd->inventory.u.items_inventory[i].nameid > 0 && sd->inventory.u.items_inventory[i].identify != 1) {
 			num++;
 		}
 	}
@@ -7018,8 +7028,8 @@ ACMD_FUNC(identifyall)
 	int i;
 	nullpo_retr(-1, sd);
 	for(i=0; i<MAX_INVENTORY; i++) {
-		if (sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].identify!=1) {
-			sd->status.inventory[i].identify=1;
+		if (sd->inventory.u.items_inventory[i].nameid > 0 && sd->inventory.u.items_inventory[i].identify != 1) {
+			sd->inventory.u.items_inventory[i].identify = 1;
 			clif_item_identified(sd,i,0);
 		}
 	}
@@ -8609,15 +8619,15 @@ ACMD_FUNC(itemlist)
 
 	if( strcmp(parent_cmd, "storagelist") == 0 ) {
 		location = "storage";
-		items = sd->status.storage.items;
-		size = sd->storage_size;
+		items = sd->storage.u.items_storage;
+		size = sd->storage.max_amount;
 	} else if( strcmp(parent_cmd, "cartlist") == 0 ) {
 		location = "cart";
-		items = sd->status.cart;
+		items = sd->cart.u.items_cart;
 		size = MAX_CART;
 	} else if( strcmp(parent_cmd, "itemlist") == 0 ) {
 		location = "inventory";
-		items = sd->status.inventory;
+		items = sd->inventory.u.items_inventory;
 		size = MAX_INVENTORY;
 	} else
 		return 1;
@@ -8863,11 +8873,11 @@ ACMD_FUNC(delitem)
 	// 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;
+		int delamount = ( amount < sd->inventory.u.items_inventory[idx].amount ) ? amount : sd->inventory.u.items_inventory[idx].amount;
 
-		if( sd->inventory_data[idx]->type == IT_PETEGG && sd->status.inventory[idx].card[0] == CARD0_PET )
+		if( sd->inventory_data[idx]->type == IT_PETEGG && sd->inventory.u.items_inventory[idx].card[0] == CARD0_PET )
 		{// delete pet
-			intif_delete_petdata(MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2]));
+			intif_delete_petdata(MakeDWord(sd->inventory.u.items_inventory[idx].card[1], sd->inventory.u.items_inventory[idx].card[2]));
 		}
 		pc_delitem(sd, idx, delamount, 0, 0, LOG_TYPE_COMMAND);
 
@@ -9723,7 +9733,7 @@ ACMD_FUNC(cloneequip) {
 			if (pc_is_same_equip_index((enum equip_index) i, pl_sd->equip_index, idx))
 				continue;
 
-			tmp_item = pl_sd->status.inventory[idx];
+			tmp_item = pl_sd->inventory.u.items_inventory[idx];
 			if (itemdb_isspecial(tmp_item.card[0]))
 				memset(tmp_item.card, 0, sizeof(tmp_item.card));
 			tmp_item.bound = 0;

+ 6 - 6
src/map/battle.c

@@ -3282,7 +3282,7 @@ static struct Damage battle_calc_multi_attack(struct Damage wd, struct block_lis
 			sc_start(src,src,SC_QD_SHOT_READY,100,target->id,skill_get_time(RL_QD_SHOT,1));
 		}
 		else if(sc && sc->data[SC_FEARBREEZE] && sd->weapontype1==W_BOW
-			&& (i = sd->equip_index[EQI_AMMO]) >= 0 && sd->inventory_data[i] && sd->status.inventory[i].amount > 1)
+			&& (i = sd->equip_index[EQI_AMMO]) >= 0 && sd->inventory_data[i] && sd->inventory.u.items_inventory[i].amount > 1)
 		{
 			int chance = rnd()%100;
 			switch(sc->data[SC_FEARBREEZE]->val1) {
@@ -3292,7 +3292,7 @@ static struct Damage battle_calc_multi_attack(struct Damage wd, struct block_lis
 				case 2:
 				case 1: if( chance < 13) { wd.div_ = 2; break; } // 12 % chance to attack 2 times.
 			}
-			wd.div_ = min(wd.div_,sd->status.inventory[i].amount);
+			wd.div_ = min(wd.div_,sd->inventory.u.items_inventory[i].amount);
 			sc->data[SC_FEARBREEZE]->val4 = wd.div_-1;
 			if (wd.div_ > 1)
 				wd.type = DMG_MULTI_HIT;
@@ -3354,7 +3354,7 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s
 
 				if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON)
 					skillratio += -100 + sd->inventory_data[index]->weight / 10 + sstatus->rhw.atk +
-						100 * sd->inventory_data[index]->wlv * (sd->status.inventory[index].refine + 6);
+						100 * sd->inventory_data[index]->wlv * (sd->inventory.u.items_inventory[index].refine + 6);
 			}
 			status_change_end(src,SC_CRUSHSTRIKE,INVALID_TIMER);
 			skill_break_equip(src,src,EQP_WEAPON,2000,BCT_SELF);
@@ -4315,7 +4315,7 @@ static int64 battle_calc_skill_constant_addition(struct Damage wd, struct block_
 				short index = sd->equip_index[EQI_HAND_L];
 
 				if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR)
-					damagevalue = sstatus->vit * sd->status.inventory[index].refine;
+					damagevalue = sstatus->vit * sd->inventory.u.items_inventory[index].refine;
 				atk = damagevalue;
 			}
 			break;
@@ -5406,7 +5406,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
 			short index = sd->equip_index[EQI_HAND_L];
 
 			if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_ARMOR )
-				ATK_ADD(wd.damage, wd.damage2, 10*sd->status.inventory[index].refine);
+				ATK_ADD(wd.damage, wd.damage2, 10*sd->inventory.u.items_inventory[index].refine);
 		}
 #ifndef RENEWAL
 		//Card Fix for attacker (sd), 2 is added to the "left" flag meaning "attacker cards only"
@@ -7198,7 +7198,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
 
 		if( sd && battle_config.arrow_decrement && sc->data[SC_FEARBREEZE] && sc->data[SC_FEARBREEZE]->val4 > 0) {
 			short idx = sd->equip_index[EQI_AMMO];
-			if (idx >= 0 && sd->status.inventory[idx].amount >= sc->data[SC_FEARBREEZE]->val4) {
+			if (idx >= 0 && sd->inventory.u.items_inventory[idx].amount >= sc->data[SC_FEARBREEZE]->val4) {
 				pc_delitem(sd,idx,sc->data[SC_FEARBREEZE]->val4,0,1,LOG_TYPE_CONSUME);
 				sc->data[SC_FEARBREEZE]->val4 = 0;
 			}

+ 4 - 4
src/map/buyingstore.c

@@ -182,7 +182,7 @@ int8 buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha
 			break;
 		}
 
-		if( sd->status.inventory[idx].amount+amount > BUYINGSTORE_MAX_AMOUNT )
+		if( sd->inventory.u.items_inventory[idx].amount + amount > BUYINGSTORE_MAX_AMOUNT )
 		{// too many items of same kind
 			break;
 		}
@@ -386,13 +386,13 @@ void buyingstore_trade(struct map_session_data* sd, uint32 account_id, unsigned
 			}
 		}
 
-		if( index < 0 || index >= ARRAYLENGTH(sd->status.inventory) || sd->inventory_data[index] == NULL || sd->status.inventory[index].nameid != nameid || sd->status.inventory[index].amount < amount )
+		if( index < 0 || index >= ARRAYLENGTH(sd->inventory.u.items_inventory) || sd->inventory_data[index] == NULL || sd->inventory.u.items_inventory[index].nameid != nameid || sd->inventory.u.items_inventory[index].amount < amount )
 		{// invalid input
 			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
 			return;
 		}
 
-		if( sd->status.inventory[index].expire_time || (sd->status.inventory[index].bound && !pc_can_give_bounded_items(sd)) || !itemdb_cantrade(&sd->status.inventory[index], pc_get_group_level(sd), pc_get_group_level(pl_sd)) || memcmp(sd->status.inventory[index].card, buyingstore_blankslots, sizeof(buyingstore_blankslots)) )
+		if( sd->inventory.u.items_inventory[index].expire_time || (sd->inventory.u.items_inventory[index].bound && !pc_can_give_bounded_items(sd)) || !itemdb_cantrade(&sd->inventory.u.items_inventory[index], pc_get_group_level(sd), pc_get_group_level(pl_sd)) || memcmp(sd->inventory.u.items_inventory[index].card, buyingstore_blankslots, sizeof(buyingstore_blankslots)) )
 		{// non-tradable item
 			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
 			return;
@@ -447,7 +447,7 @@ void buyingstore_trade(struct map_session_data* sd, uint32 account_id, unsigned
 		zeny = amount*pl_sd->buyingstore.items[listidx].price;
 
 		// move item
-		pc_additem(pl_sd, &sd->status.inventory[index], amount, LOG_TYPE_BUYING_STORE);
+		pc_additem(pl_sd, &sd->inventory.u.items_inventory[index], amount, LOG_TYPE_BUYING_STORE);
 		pc_delitem(sd, index, amount, 1, 0, LOG_TYPE_BUYING_STORE);
 		pl_sd->buyingstore.items[listidx].amount-= amount;
 

+ 20 - 8
src/map/chrif.c

@@ -299,9 +299,16 @@ int chrif_save(struct map_session_data *sd, int flag) {
 
 	chrif_bsdata_save(sd, (flag && (flag != 3)));
 
+	if (sd->state.storage_flag == 1)
+		intif_storage_save(sd,&sd->storage);
+	intif_storage_save(sd,&sd->inventory);
+	intif_storage_save(sd,&sd->cart);
+
 	//For data sync
 	if (sd->state.storage_flag == 2)
-		gstorage_storagesave(sd->status.account_id, sd->status.guild_id, flag);
+		storage_guild_storagesave(sd->status.account_id, sd->status.guild_id, flag);
+	if (&sd->premiumStorage && sd->premiumStorage.dirty)
+		intif_storage_save(sd, &sd->premiumStorage);
 
 	if (flag)
 		sd->state.storage_flag = 0; //Force close it.
@@ -1040,14 +1047,14 @@ int chrif_divorceack(uint32 char_id, int partner_id) {
 	if( ( sd = map_charid2sd(char_id) ) != NULL && sd->status.partner_id == partner_id ) {
 		sd->status.partner_id = 0;
 		for(i = 0; i < MAX_INVENTORY; i++)
-			if (sd->status.inventory[i].nameid == WEDDING_RING_M || sd->status.inventory[i].nameid == WEDDING_RING_F)
+			if (sd->inventory.u.items_inventory[i].nameid == WEDDING_RING_M || sd->inventory.u.items_inventory[i].nameid == WEDDING_RING_F)
 				pc_delitem(sd, i, 1, 0, 0, LOG_TYPE_OTHER);
 	}
 
 	if( ( sd = map_charid2sd(partner_id) ) != NULL && sd->status.partner_id == char_id ) {
 		sd->status.partner_id = 0;
 		for(i = 0; i < MAX_INVENTORY; i++)
-			if (sd->status.inventory[i].nameid == WEDDING_RING_M || sd->status.inventory[i].nameid == WEDDING_RING_F)
+			if (sd->inventory.u.items_inventory[i].nameid == WEDDING_RING_M || sd->inventory.u.items_inventory[i].nameid == WEDDING_RING_F)
 				pc_delitem(sd, i, 1, 0, 0, LOG_TYPE_OTHER);
 	}
 
@@ -1597,10 +1604,10 @@ void chrif_parse_ack_vipActive(int fd) {
 			sd->vip.enabled = 1;
 			sd->vip.time = vip_time;
 			// Increase storage size for VIP.
-			sd->storage_size = battle_config.vip_storage_increase + MIN_STORAGE;
-			if (sd->storage_size > MAX_STORAGE) {
+			sd->storage.max_amount = battle_config.vip_storage_increase + MIN_STORAGE;
+			if (sd->storage.max_amount > MAX_STORAGE) {
 				ShowError("intif_parse_ack_vipActive: Storage size for player %s (%d:%d) is larger than MAX_STORAGE. Storage size has been set to MAX_STORAGE.\n", sd->status.name, sd->status.account_id, sd->status.char_id);
-				sd->storage_size = MAX_STORAGE;
+				sd->storage.max_amount = MAX_STORAGE;
 			}
 			// Magic Stone requirement avoidance for VIP.
 			if (battle_config.vip_gemstone)
@@ -1608,7 +1615,7 @@ void chrif_parse_ack_vipActive(int fd) {
 		} else if (sd->vip.enabled) {
 			sd->vip.enabled = 0;
 			sd->vip.time = 0;
-			sd->storage_size = MIN_STORAGE;
+			sd->storage.max_amount = MIN_STORAGE;
 			sd->special_state.no_gemstone = 0;
 			clif_displaymessage(sd->fd,msg_txt(sd,438));
 		}
@@ -1988,11 +1995,16 @@ void do_final_chrif(void) {
  *------------------------------------------*/
 void do_init_chrif(void) {
 	if(sizeof(struct mmo_charstatus) > 0xFFFF){
-		ShowError("mmo_charstatus size = %d is too big to be transmitted. (must be below 0xFFFF) \n",
+		ShowError("mmo_charstatus size = %d is too big to be transmitted. (must be below 0xFFFF)\n",
 			sizeof(struct mmo_charstatus));
 		exit(EXIT_FAILURE);
 	}
 
+	if (sizeof(struct s_storage) > 0xFFFF) {
+		ShowError("s_storage size = %d is too big to be transmitted. (must be below 0xFFFF)\n", sizeof(struct s_storage));
+		exit(EXIT_FAILURE);
+	}
+
 	if((sizeof(struct bonus_script_data) * MAX_PC_BONUS_SCRIPT) > 0xFFFF){
 		ShowError("bonus_script_data size = %d is too big, please reduce MAX_PC_BONUS_SCRIPT (%d) size. (must be below 0xFFFF).\n",
 			(sizeof(struct bonus_script_data) * MAX_PC_BONUS_SCRIPT), MAX_PC_BONUS_SCRIPT);

+ 156 - 136
src/map/clif.c

@@ -1943,15 +1943,15 @@ void clif_selllist(struct map_session_data *sd)
 	WFIFOW(fd,0)=0xc7;
 	for( i = 0; i < MAX_INVENTORY; i++ )
 	{
-		if( sd->status.inventory[i].nameid > 0 && sd->inventory_data[i] )
+		if( sd->inventory.u.items_inventory[i].nameid > 0 && sd->inventory_data[i] )
 		{
-			if( !itemdb_cansell(&sd->status.inventory[i], pc_get_group_level(sd)) )
+			if( !itemdb_cansell(&sd->inventory.u.items_inventory[i], pc_get_group_level(sd)) )
 				continue;
 
-			if( sd->status.inventory[i].expire_time || (sd->status.inventory[i].bound && !pc_can_give_bounded_items(sd)) )
+			if( sd->inventory.u.items_inventory[i].expire_time || (sd->inventory.u.items_inventory[i].bound && !pc_can_give_bounded_items(sd)) )
 				continue; // Cannot Sell Rental Items or Account Bounded Items
 
-			if( sd->status.inventory[i].bound && !pc_can_give_bounded_items(sd))
+			if( sd->inventory.u.items_inventory[i].bound && !pc_can_give_bounded_items(sd))
 				continue; // Don't allow sale of bound items
 
 			val=sd->inventory_data[i]->value_sell;
@@ -2511,13 +2511,13 @@ void clif_additem(struct map_session_data *sd, int n, int amount, unsigned char
 #if PACKETVER >= 20071002
 		WFIFOW(fd,offs+27) = 0;  //  HireExpireDate
 #if PACKETVER >= 20150226
-		clif_add_random_options(WFIFOP(fd,offs+31), &sd->status.inventory[n]);
+		clif_add_random_options(WFIFOP(fd,offs+31), &sd->inventory.u.items_inventory[n]);
 #endif
 #endif
 	}
 	else
 	{
-		if( n < 0 || n >= MAX_INVENTORY || sd->status.inventory[n].nameid <=0 || sd->inventory_data[n] == NULL )
+		if( n < 0 || n >= MAX_INVENTORY || sd->inventory.u.items_inventory[n].nameid <=0 || sd->inventory_data[n] == NULL )
 			return;
 
 		WFIFOW(fd,offs+0) = header;
@@ -2526,11 +2526,11 @@ void clif_additem(struct map_session_data *sd, int n, int amount, unsigned char
 		if (sd->inventory_data[n]->view_id > 0)
 			WFIFOW(fd,offs+6) = sd->inventory_data[n]->view_id;
 		else
-			WFIFOW(fd,offs+6) = sd->status.inventory[n].nameid;
-		WFIFOB(fd,offs+8) = sd->status.inventory[n].identify;
-		WFIFOB(fd,offs+9) = sd->status.inventory[n].attribute;
-		WFIFOB(fd,offs+10) = sd->status.inventory[n].refine;
-		clif_addcards(WFIFOP(fd,offs+11), &sd->status.inventory[n]);
+			WFIFOW(fd,offs+6)=sd->inventory.u.items_inventory[n].nameid;
+		WFIFOB(fd,offs+8)=sd->inventory.u.items_inventory[n].identify;
+		WFIFOB(fd,offs+9)=sd->inventory.u.items_inventory[n].attribute;
+		WFIFOB(fd,offs+10)=sd->inventory.u.items_inventory[n].refine;
+		clif_addcards(WFIFOP(fd,offs+11), &sd->inventory.u.items_inventory[n]);
 #if PACKETVER < 20120925
 		WFIFOW(fd,offs+19) = pc_equippoint(sd,n);
 #else
@@ -2540,14 +2540,14 @@ void clif_additem(struct map_session_data *sd, int n, int amount, unsigned char
 		WFIFOB(fd,offs+21) = itemtype(sd->inventory_data[n]->nameid);
 		WFIFOB(fd,offs+22) = fail;
 #if PACKETVER >= 20061218
-		WFIFOL(fd,offs+23) = sd->status.inventory[n].expire_time;
+		WFIFOL(fd,offs+23)=sd->inventory.u.items_inventory[n].expire_time;
 #endif
 #if PACKETVER >= 20071002
 		/* Yellow color only for non-stackable item */
-		WFIFOW(fd,offs+27) = (sd->status.inventory[n].bound && !itemdb_isstackable(sd->status.inventory[n].nameid)) ? BOUND_DISPYELLOW : sd->inventory_data[n]->flag.bindOnEquip ? BOUND_ONEQUIP : 0;
+		WFIFOW(fd,offs+27)=(sd->inventory.u.items_inventory[n].bound && !itemdb_isstackable(sd->inventory.u.items_inventory[n].nameid)) ? BOUND_DISPYELLOW : sd->inventory_data[n]->flag.bindOnEquip ? BOUND_ONEQUIP : 0;
 #endif
 #if PACKETVER >= 20150226
-		clif_add_random_options(WFIFOP(fd,31), &sd->status.inventory[n]);
+		clif_add_random_options(WFIFOP(fd,31), &sd->inventory.u.items_inventory[n]);
 #endif
 	}
 
@@ -2711,17 +2711,17 @@ void clif_inventorylist(struct map_session_data *sd) {
 
 	for( i = 0, n = 0, ne = 0; i < MAX_INVENTORY; i++ )
 	{
-		if( sd->status.inventory[i].nameid <=0 || sd->inventory_data[i] == NULL )
+		if( sd->inventory.u.items_inventory[i].nameid <=0 || sd->inventory_data[i] == NULL )
 			continue;
 
 		if( !itemdb_isstackable2(sd->inventory_data[i]) )
 		{	//Non-stackable (Equippable)
-			clif_item_sub(bufe, ne*se+4, i+2, &sd->status.inventory[i], sd->inventory_data[i], pc_equippoint(sd,i));
+			clif_item_sub(bufe, ne*se+4, i+2, &sd->inventory.u.items_inventory[i], sd->inventory_data[i], pc_equippoint(sd,i));
 			ne++;
 		}
 		else { //Stackable.
-			clif_item_sub(buf, n*s+4,i+2, &sd->status.inventory[i], sd->inventory_data[i], -2);
-			if( sd->inventory_data[i]->equip == EQP_AMMO && sd->status.inventory[i].equip )
+			clif_item_sub(buf, n*s+4,i+2, &sd->inventory.u.items_inventory[i], sd->inventory_data[i], -2);
+			if( sd->inventory_data[i]->equip == EQP_AMMO && sd->inventory.u.items_inventory[i].equip )
 				arrow=i;
 			n++;
 		}
@@ -2758,9 +2758,9 @@ void clif_inventorylist(struct map_session_data *sd) {
 	}
 #if PACKETVER >= 20111122 && PACKETVER < 20120925
 	for( i = 0; i < MAX_INVENTORY; i++ ) {
-		if( sd->status.inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL )
+		if( sd->inventory.u.items_inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL )
 			continue;
-		if ( sd->status.inventory[i].favorite )
+		if ( sd->inventory.u.items_inventory[i].favorite )
 			clif_favorite_item(sd, i);
 	}
 #endif
@@ -2790,13 +2790,13 @@ void clif_equiplist(struct map_session_data *sd)
 	buf = WFIFOP(fd,0);
 
 	for(i=0,n=0;i<MAX_INVENTORY;i++){
-		if (sd->status.inventory[i].nameid <=0 || sd->inventory_data[i] == NULL)
+		if (sd->inventory.u.items_inventory[i].nameid <=0 || sd->inventory_data[i] == NULL)
 			continue;
 
 		if(itemdb_isstackable2(sd->inventory_data[i]))
 			continue;
 		//Equippable
-		clif_item_sub(buf, n*cmd+4,i+2, &sd->status.inventory[i], sd->inventory_data[i], pc_equippoint(sd,i));
+		clif_item_sub(buf, n*cmd+4,i+2, &sd->inventory.u.items_inventory[i], sd->inventory_data[i], pc_equippoint(sd,i));
 		n++;
 	}
 	if (n) {
@@ -2814,7 +2814,7 @@ void clif_equiplist(struct map_session_data *sd)
 	}
 }
 
-void clif_storagelist(struct map_session_data* sd, struct item* items, int items_length)
+void clif_storagelist(struct map_session_data* sd, struct item* items, int items_length, const char *storename)
 {
 	static const int client_buf = 0x5000; // Max buffer to send
 	struct item_data *id;
@@ -2884,7 +2884,7 @@ void clif_storagelist(struct map_session_data* sd, struct item* items, int items
 		WFIFOW(sd->fd,0)=cmd;
 		WFIFOW(sd->fd,2)=sidx+nn*s;
 #if PACKETVER >= 20120925
-		memset(WFIFOCP(sd->fd,4),0,24); //storename
+		safestrncpy(WFIFOCP(sd->fd,4), storename, NAME_LENGTH); //storename
 #endif
 		memcpy(WFIFOP(sd->fd,sidx),buf + sidx + i*s,nn*s);
 		WFIFOSET(sd->fd,WFIFOW(sd->fd,2));
@@ -2896,12 +2896,23 @@ void clif_storagelist(struct map_session_data* sd, struct item* items, int items
 		WFIFOW(sd->fd,0)=cmde;
 		WFIFOW(sd->fd,2)=sidxe+nn*se;
 #if PACKETVER >= 20120925
-		memset(WFIFOCP(sd->fd,4),0,24); //storename
+		safestrncpy(WFIFOCP(sd->fd,4), storename, NAME_LENGTH); //storename
 #endif
 		memcpy(WFIFOP(sd->fd,sidxe),bufe + sidxe + i*se,nn*se);
 		WFIFOSET(sd->fd,WFIFOW(sd->fd,2));
 	}
 
+	// Empty storage
+	if (n == 0 && ne == 0) {
+		WFIFOHEAD(sd->fd, 4+NAME_LENGTH);
+		WFIFOW(sd->fd,0) = cmd;
+		WFIFOW(sd->fd,2) = 4+NAME_LENGTH;
+#if PACKETVER >= 20120925
+		safestrncpy(WFIFOCP(sd->fd,4), storename, NAME_LENGTH); //storename
+#endif
+		WFIFOSET(sd->fd,WFIFOW(sd->fd,2));
+	}
+
 	if( buf ) aFree(buf);
 	if( bufe ) aFree(bufe);
 }
@@ -2938,15 +2949,15 @@ void clif_cartlist(struct map_session_data *sd)
 
 	for( i = 0, n = 0, ne = 0; i < MAX_CART; i++ )
 	{
-		if( sd->status.cart[i].nameid <= 0 )
+		if( sd->cart.u.items_cart[i].nameid <= 0 )
 			continue;
-		id = itemdb_search(sd->status.cart[i].nameid);
+		id = itemdb_search(sd->cart.u.items_cart[i].nameid);
 		if( !itemdb_isstackable2(id) ) { //Equippable
-			clif_item_sub(bufe, ne*cmd+4,i+2, &sd->status.cart[i], id, id->equip);
+			clif_item_sub(bufe, ne*cmd+4,i+2, &sd->cart.u.items_cart[i], id, id->equip);
 			ne++;
 		}
 		else { //Stackable
-			clif_item_sub(buf, n*s+4,i+2, &sd->status.cart[i], id,-1);
+			clif_item_sub(buf, n*s+4,i+2, &sd->cart.u.items_cart[i], id,-1);
 			n++;
 		}
 	}
@@ -3474,7 +3485,7 @@ void clif_changelook(struct block_list *bl, int type, int val) {
 						if(sd->inventory_data[n]->view_id > 0)
 							val = sd->inventory_data[n]->view_id;
 						else
-							val = sd->status.inventory[n].nameid;
+							val = sd->inventory.u.items_inventory[n].nameid;
 					} else
 						val = 0;
 				}
@@ -3659,7 +3670,7 @@ void clif_arrow_create_list(struct map_session_data *sd)
 		short j, nameid = skill_arrow_db[i].nameid;
 		if (nameid > 0 && itemdb_exists(nameid) &&
 			(j = pc_search_inventory(sd, nameid)) >= 0 &&
-			!sd->status.inventory[j].equip && sd->status.inventory[j].identify)
+			!sd->inventory.u.items_inventory[j].equip && sd->inventory.u.items_inventory[j].identify)
 		{
 			if ((j = itemdb_viewid(nameid)) > 0)
 				WFIFOW(fd,c*2+4) = j;
@@ -3926,7 +3937,7 @@ void clif_useitemack(struct map_session_data *sd,int index,int amount,bool ok)
 		if(sd->inventory_data[index] && sd->inventory_data[index]->view_id > 0)
 			WBUFW(buf,4)=sd->inventory_data[index]->view_id;
 		else
-			WBUFW(buf,4)=sd->status.inventory[index].nameid;
+			WBUFW(buf,4)=sd->inventory.u.items_inventory[index].nameid;
 		WBUFL(buf,6)=sd->bl.id;
 		WBUFW(buf,10)=amount;
 		WBUFB(buf,12)=ok;
@@ -4270,7 +4281,7 @@ void clif_tradeadditem(struct map_session_data* sd, struct map_session_data* tsd
 		WBUFW(buf,15)= 0; //card (4w)
 		WBUFW(buf,17)= 0; //card (4w)
 #if PACKETVER >= 20150226
-		clif_add_random_options(WBUFP(buf, 19), &sd->status.inventory[index]);
+		clif_add_random_options(WBUFP(buf, 19), &sd->inventory.u.items_inventory[index]);
 #endif
 	}
 	else
@@ -4281,22 +4292,22 @@ void clif_tradeadditem(struct map_session_data* sd, struct map_session_data* tsd
 		if(sd->inventory_data[index] && sd->inventory_data[index]->view_id > 0)
 			WBUFW(buf,6) = sd->inventory_data[index]->view_id;
 		else
-			WBUFW(buf,6) = sd->status.inventory[index].nameid; // type id
+			WBUFW(buf,6) = sd->inventory.u.items_inventory[index].nameid; // type id
 #else
 		if(sd->inventory_data[index] && sd->inventory_data[index]->view_id > 0)
 			WBUFW(buf,2) = sd->inventory_data[index]->view_id;
 		else
-			WBUFW(buf,2) = sd->status.inventory[index].nameid;       // type id
+			WBUFW(buf,2) = sd->inventory.u.items_inventory[index].nameid;       // type id
 		WBUFB(buf,4) = sd->inventory_data[index]->type;          // item type
 		WBUFL(buf,5) = amount; // amount
 		buf = WBUFP(buf,1); //Advance 1B
 #endif
-		WBUFB(buf,8) = sd->status.inventory[index].identify; //identify flag
-		WBUFB(buf,9) = sd->status.inventory[index].attribute; // attribute
-		WBUFB(buf,10)= sd->status.inventory[index].refine; //refine
-		clif_addcards(WBUFP(buf, 11), &sd->status.inventory[index]);
+		WBUFB(buf,8) = sd->inventory.u.items_inventory[index].identify; //identify flag
+		WBUFB(buf,9) = sd->inventory.u.items_inventory[index].attribute; // attribute
+		WBUFB(buf,10)= sd->inventory.u.items_inventory[index].refine; //refine
+		clif_addcards(WBUFP(buf, 11), &sd->inventory.u.items_inventory[index]);
 #if PACKETVER >= 20150226
-		clif_add_random_options(WBUFP(buf, 19), &sd->status.inventory[index]);
+		clif_add_random_options(WBUFP(buf, 19), &sd->inventory.u.items_inventory[index]);
 #endif
 	}
 	WFIFOSET(fd,packet_len(cmd));
@@ -6405,10 +6416,10 @@ void clif_use_card(struct map_session_data *sd,int idx)
 			continue;
 		if(sd->inventory_data[i]->type!=IT_WEAPON && sd->inventory_data[i]->type!=IT_ARMOR)
 			continue;
-		if(itemdb_isspecial(sd->status.inventory[i].card[0])) //Can't slot it
+		if(itemdb_isspecial(sd->inventory.u.items_inventory[i].card[0])) //Can't slot it
 			continue;
 
-		if(sd->status.inventory[i].identify==0 )	//Not identified
+		if(sd->inventory.u.items_inventory[i].identify==0 )	//Not identified
 			continue;
 
 		if((sd->inventory_data[i]->equip&ep)==0)	//Not equippable on this part.
@@ -6417,11 +6428,11 @@ void clif_use_card(struct map_session_data *sd,int idx)
 		if(sd->inventory_data[i]->type==IT_WEAPON && ep==EQP_SHIELD) //Shield card won't go on left weapon.
 			continue;
 
-		ARR_FIND( 0, sd->inventory_data[i]->slot, j, sd->status.inventory[i].card[j] == 0 );
+		ARR_FIND( 0, sd->inventory_data[i]->slot, j, sd->inventory.u.items_inventory[i].card[j] == 0 );
 		if( j == sd->inventory_data[i]->slot )	// No room
 			continue;
 
-		if( sd->status.inventory[i].equip > 0 )	// Do not check items that are already equipped
+		if( sd->inventory.u.items_inventory[i].equip > 0 )	// Do not check items that are already equipped
 			continue;
 
 		WFIFOW(fd,4+c*2)=i+2;
@@ -6470,7 +6481,7 @@ void clif_item_identify_list(struct map_session_data *sd)
 	WFIFOHEAD(fd,MAX_INVENTORY * 2 + 4);
 	WFIFOW(fd,0)=0x177;
 	for(i=c=0;i<MAX_INVENTORY;i++){
-		if(sd->status.inventory[i].nameid > 0 && !sd->status.inventory[i].identify){
+		if(sd->inventory.u.items_inventory[i].nameid > 0 && !sd->inventory.u.items_inventory[i].identify){
 			WFIFOW(fd,c*2+4)=i+2;
 			c++;
 		}
@@ -6518,11 +6529,11 @@ void clif_item_repair_list(struct map_session_data *sd,struct map_session_data *
 	WFIFOW(fd,0)=0x1fc;
 	for(i=c=0;i<MAX_INVENTORY;i++){
 		unsigned short nameid;
-		if((nameid=dstsd->status.inventory[i].nameid) > 0 && dstsd->status.inventory[i].attribute!=0){// && skill_can_repair(sd,nameid)){
+		if((nameid=dstsd->inventory.u.items_inventory[i].nameid) > 0 && dstsd->inventory.u.items_inventory[i].attribute!=0){// && skill_can_repair(sd,nameid)){
 			WFIFOW(fd,c*13+4) = i;
 			WFIFOW(fd,c*13+6) = nameid;
-			WFIFOB(fd,c*13+8) = dstsd->status.inventory[i].refine;
-			clif_addcards(WFIFOP(fd,c*13+9), &dstsd->status.inventory[i]);
+			WFIFOB(fd,c*13+8) = dstsd->inventory.u.items_inventory[i].refine;
+			clif_addcards(WFIFOP(fd,c*13+9), &dstsd->inventory.u.items_inventory[i]);
 			c++;
 		}
 	}
@@ -6596,16 +6607,16 @@ void clif_item_refine_list(struct map_session_data *sd)
 	refine_item[3] = refine_item[4] = pc_search_inventory(sd,ITEMID_ORIDECON);
 
 	WFIFOHEAD(fd, MAX_INVENTORY * 13 + 4);
-	WFIFOW(fd,0)=0x221;
-	for(i=c=0;i<MAX_INVENTORY;i++){
+	WFIFOW(fd,0) = 0x221;
+	for(i = c = 0; i < MAX_INVENTORY; i++) {
 		unsigned char wlv;
-		if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].refine < skill_lv &&
-			sd->status.inventory[i].identify && (wlv=itemdb_wlv(sd->status.inventory[i].nameid)) >=1 &&
-			refine_item[wlv]!=-1 && !(sd->status.inventory[i].equip&EQP_ARMS)){
+		if(sd->inventory.u.items_inventory[i].nameid > 0 && sd->inventory.u.items_inventory[i].refine < skill_lv &&
+			sd->inventory.u.items_inventory[i].identify && (wlv = itemdb_wlv(sd->inventory.u.items_inventory[i].nameid)) >=1 &&
+			refine_item[wlv] != -1 && !(sd->inventory.u.items_inventory[i].equip&EQP_ARMS)){
 			WFIFOW(fd,c*13+ 4)=i+2;
-			WFIFOW(fd,c*13+ 6)=sd->status.inventory[i].nameid;
-			WFIFOB(fd,c*13+ 8)=sd->status.inventory[i].refine;
-			clif_addcards(WFIFOP(fd,c*13+9), &sd->status.inventory[i]);
+			WFIFOW(fd,c*13+ 6) = sd->inventory.u.items_inventory[i].nameid;
+			WFIFOB(fd,c*13+ 8) = sd->inventory.u.items_inventory[i].refine;
+			clif_addcards(WFIFOP(fd,c*13+9), &sd->inventory.u.items_inventory[i]);
 			c++;
 		}
 	}
@@ -6661,7 +6672,7 @@ void clif_cart_additem(struct map_session_data *sd,int n,int amount,int fail)
 	nullpo_retv(sd);
 
 	fd=sd->fd;
-	if(n<0 || n>=MAX_CART || sd->status.cart[n].nameid<=0)
+	if(n < 0 || n >= MAX_CART || sd->cart.u.items_cart[n].nameid <= 0)
 		return;
 
 	WFIFOHEAD(fd,packet_len(cmd));
@@ -6669,20 +6680,20 @@ void clif_cart_additem(struct map_session_data *sd,int n,int amount,int fail)
 	WBUFW(buf,0)=cmd;
 	WBUFW(buf,2)=n+2;
 	WBUFL(buf,4)=amount;
-	if((view = itemdb_viewid(sd->status.cart[n].nameid)) > 0)
+	if((view = itemdb_viewid(sd->cart.u.items_cart[n].nameid)) > 0)
 		WBUFW(buf,8)=view;
 	else
-		WBUFW(buf,8)=sd->status.cart[n].nameid;
+		WBUFW(buf,8)=sd->cart.u.items_cart[n].nameid;
 #if PACKETVER >= 5
-	WBUFB(buf,10)=itemdb_type(sd->status.cart[n].nameid);
+	WBUFB(buf,10)=itemdb_type(sd->cart.u.items_cart[n].nameid);
 	offset += 1;
 #endif
-	WBUFB(buf,10+offset)=sd->status.cart[n].identify;
-	WBUFB(buf,11+offset)=sd->status.cart[n].attribute;
-	WBUFB(buf,12+offset)=sd->status.cart[n].refine;
-	clif_addcards(WBUFP(buf,13+offset), &sd->status.cart[n]);
+	WBUFB(buf,10+offset)=sd->cart.u.items_cart[n].identify;
+	WBUFB(buf,11+offset)=sd->cart.u.items_cart[n].attribute;
+	WBUFB(buf,12+offset)=sd->cart.u.items_cart[n].refine;
+	clif_addcards(WBUFP(buf,13+offset), &sd->cart.u.items_cart[n]);
 #if PACKETVER >= 20150226
-	clif_add_random_options(WBUFP(buf,21+offset), &sd->status.cart[n]);
+	clif_add_random_options(WBUFP(buf,21+offset), &sd->cart.u.items_cart[n]);
 #endif
 	WFIFOSET(fd,packet_len(cmd));
 }
@@ -7035,18 +7046,18 @@ void clif_vendinglist(struct map_session_data* sd, int id, struct s_vending* ven
 	for( i = 0; i < count; i++ )
 	{
 		int index = vending[i].index;
-		struct item_data* data = itemdb_search(vsd->status.cart[index].nameid);
+		struct item_data* data = itemdb_search(vsd->cart.u.items_cart[index].nameid);
 		WFIFOL(fd,offset+ 0+i*item_length) = vending[i].value;
 		WFIFOW(fd,offset+ 4+i*item_length) = vending[i].amount;
 		WFIFOW(fd,offset+ 6+i*item_length) = vending[i].index + 2;
 		WFIFOB(fd,offset+ 8+i*item_length) = itemtype(data->nameid);
-		WFIFOW(fd,offset+ 9+i*item_length) = ( data->view_id > 0 ) ? data->view_id : vsd->status.cart[index].nameid;
-		WFIFOB(fd,offset+11+i*item_length) = vsd->status.cart[index].identify;
-		WFIFOB(fd,offset+12+i*item_length) = vsd->status.cart[index].attribute;
-		WFIFOB(fd,offset+13+i*item_length) = vsd->status.cart[index].refine;
-		clif_addcards(WFIFOP(fd,offset+14+i*item_length), &vsd->status.cart[index]);
+		WFIFOW(fd,offset+ 9+i*item_length) = ( data->view_id > 0 ) ? data->view_id : vsd->cart.u.items_cart[index].nameid;
+		WFIFOB(fd,offset+11+i*item_length) = vsd->cart.u.items_cart[index].identify;
+		WFIFOB(fd,offset+12+i*item_length) = vsd->cart.u.items_cart[index].attribute;
+		WFIFOB(fd,offset+13+i*item_length) = vsd->cart.u.items_cart[index].refine;
+		clif_addcards(WFIFOP(fd,offset+14+i*item_length), &vsd->cart.u.items_cart[index]);
 #if PACKETVER >= 20150226
-		clif_add_random_options(WFIFOP(fd,offset+22+i*item_length), &vsd->status.cart[index]);
+		clif_add_random_options(WFIFOP(fd,offset+22+i*item_length), &vsd->cart.u.items_cart[index]);
 #endif
 	}
 	WFIFOSET(fd,WFIFOW(fd,2));
@@ -7120,18 +7131,18 @@ void clif_openvending(struct map_session_data* sd, int id, struct s_vending* ven
 	WFIFOL(fd,4) = id;
 	for( i = 0; i < count; i++ ) {
 		int index = vending[i].index;
-		struct item_data* data = itemdb_search(sd->status.cart[index].nameid);
+		struct item_data* data = itemdb_search(sd->cart.u.items_cart[index].nameid);
 		WFIFOL(fd, 8+i*item_length) = vending[i].value;
 		WFIFOW(fd,12+i*item_length) = vending[i].index + 2;
 		WFIFOW(fd,14+i*item_length) = vending[i].amount;
 		WFIFOB(fd,16+i*item_length) = itemtype(data->nameid);
-		WFIFOW(fd,17+i*item_length) = ( data->view_id > 0 ) ? data->view_id : sd->status.cart[index].nameid;
-		WFIFOB(fd,19+i*item_length) = sd->status.cart[index].identify;
-		WFIFOB(fd,20+i*item_length) = sd->status.cart[index].attribute;
-		WFIFOB(fd,21+i*item_length) = sd->status.cart[index].refine;
-		clif_addcards(WFIFOP(fd,22+i*item_length), &sd->status.cart[index]);
+		WFIFOW(fd,17+i*item_length) = ( data->view_id > 0 ) ? data->view_id : sd->cart.u.items_cart[index].nameid;
+		WFIFOB(fd,19+i*item_length) = sd->cart.u.items_cart[index].identify;
+		WFIFOB(fd,20+i*item_length) = sd->cart.u.items_cart[index].attribute;
+		WFIFOB(fd,21+i*item_length) = sd->cart.u.items_cart[index].refine;
+		clif_addcards(WFIFOP(fd,22+i*item_length), &sd->cart.u.items_cart[index]);
 #if PACKETVER >= 20150226
-		clif_add_random_options(WFIFOP(fd,30+i*item_length), &sd->status.cart[index]);
+		clif_add_random_options(WFIFOP(fd,30+i*item_length), &sd->cart.u.items_cart[index]);
 #endif
 	}
 	WFIFOSET(fd,WFIFOW(fd,2));
@@ -7631,9 +7642,9 @@ void clif_sendegg(struct map_session_data *sd)
 	WFIFOHEAD(fd, MAX_INVENTORY * 2 + 4);
 	WFIFOW(fd,0)=0x1a6;
 	for(i=0,n=0;i<MAX_INVENTORY;i++){
-		if(sd->status.inventory[i].nameid<=0 || sd->inventory_data[i] == NULL ||
-		   sd->inventory_data[i]->type!=IT_PETEGG ||
-		   sd->status.inventory[i].amount<=0)
+		if(sd->inventory.u.items_inventory[i].nameid <= 0 || sd->inventory_data[i] == NULL ||
+		   sd->inventory_data[i]->type != IT_PETEGG ||
+		   sd->inventory.u.items_inventory[i].amount <= 0)
 			continue;
 		WFIFOW(fd,n*2+4)=i+2;
 		n++;
@@ -9159,21 +9170,21 @@ void clif_messagecolor2(struct map_session_data *sd, unsigned long color, const
 void clif_refresh_storagewindow(struct map_session_data *sd) {
 	// Notify the client that the storage is open
 	if( sd->state.storage_flag == 1 ) {
-		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, MAX_STORAGE);
+		storage_sortitem(sd->storage.u.items_storage, ARRAYLENGTH(sd->storage.u.items_storage));
+		clif_storagelist(sd, sd->storage.u.items_storage, ARRAYLENGTH(sd->storage.u.items_storage), storage_getName(0));
+		clif_updatestorageamount(sd, sd->storage.amount, MAX_STORAGE);
 	}
 	// Notify the client that the gstorage is open otherwise it will
 	// remain locked forever and nobody will be able to access it
 	if( sd->state.storage_flag == 2 ) {
-		struct guild_storage *gstor = gstorage_get_storage(sd->status.guild_id);
+		struct s_storage *gstor = guild2storage2(sd->status.guild_id);
 
 		if( !gstor ) // Shouldn't happen. The information should already be at the map-server
 			intif_request_guild_storage(sd->status.account_id, sd->status.guild_id);
 		else {
-			storage_sortitem(gstor->items, ARRAYLENGTH(gstor->items));
-			clif_storagelist(sd, gstor->items, ARRAYLENGTH(gstor->items));
-			clif_updatestorageamount(sd, gstor->storage_amount, MAX_GUILD_STORAGE);
+			storage_sortitem(gstor->u.items_guild, ARRAYLENGTH(gstor->u.items_guild));
+			clif_storagelist(sd, gstor->u.items_guild, ARRAYLENGTH(gstor->u.items_guild), "Guild Storage");
+			clif_updatestorageamount(sd, gstor->amount, MAX_GUILD_STORAGE);
 		}
 	}
 }
@@ -9649,12 +9660,12 @@ void clif_viewequip_ack(struct map_session_data* sd, struct map_session_data* ts
 
 	for(i=0,n=0; i < MAX_INVENTORY; i++)
 	{
-		if (tsd->status.inventory[i].nameid <= 0 || tsd->inventory_data[i] == NULL)	// Item doesn't exist
+		if (tsd->inventory.u.items_inventory[i].nameid <= 0 || tsd->inventory_data[i] == NULL)	// Item doesn't exist
 			continue;
 		if (!itemdb_isequip2(tsd->inventory_data[i])) // Is not equippable
 			continue;
 		// Add item info : refine, identify flag, element, etc.
-		clif_item_sub(WBUFP(buf,0), n*s+43,i + 2, &tsd->status.inventory[i], tsd->inventory_data[i], pc_equippoint(tsd, i));
+		clif_item_sub(WBUFP(buf,0), n*s+43,i + 2, &tsd->inventory.u.items_inventory[i], tsd->inventory_data[i], pc_equippoint(tsd, i));
 		n++;
 	}
 
@@ -11191,7 +11202,7 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd)
 	else if (pc_cant_act2(sd))
 		return;
 
-	if(!sd->status.inventory[index].identify) {
+	if(!sd->inventory.u.items_inventory[index].identify) {
 		clif_equipitemack(sd,index,0,ITEM_EQUIP_ACK_FAIL);	// fail
 		return;
 	}
@@ -12307,8 +12318,8 @@ void clif_parse_ItemIdentify(int fd,struct map_session_data *sd) {
 	// - Invalid item ID or item doesn't exist
 	// - Item is already identified
 	if (idx < 0 || idx >= MAX_INVENTORY ||
-		sd->status.inventory[idx].nameid <= 0 || sd->inventory_data[idx] == NULL ||
-		sd->status.inventory[idx].identify) {// cancel pressed
+		sd->inventory.u.items_inventory[idx].nameid <= 0 || sd->inventory_data[idx] == NULL ||
+		sd->inventory.u.items_inventory[idx].identify) {// cancel pressed
 			sd->state.workinprogress = WIP_DISABLE_NONE;
 			clif_menuskill_clear(sd);
 			return;
@@ -12451,10 +12462,12 @@ void clif_parse_MoveToKafra(int fd, struct map_session_data *sd)
 		return;
 
 	if (sd->state.storage_flag == 1)
-		storage_storageadd(sd, item_index, item_amount);
+		storage_storageadd(sd, &sd->storage, item_index, item_amount);
 	else
 	if (sd->state.storage_flag == 2)
-		gstorage_storageadd(sd, item_index, item_amount);
+		storage_guild_storageadd(sd, item_index, item_amount);
+	else if (sd->state.storage_flag == 3)
+		storage_storageadd(sd, &sd->premiumStorage, item_index, item_amount);
 }
 
 
@@ -12471,9 +12484,11 @@ void clif_parse_MoveFromKafra(int fd,struct map_session_data *sd)
 	item_amount = RFIFOL(fd,info->pos[1]);
 
 	if (sd->state.storage_flag == 1)
-		storage_storageget(sd, item_index, item_amount);
+		storage_storageget(sd, &sd->storage, item_index, item_amount);
 	else if(sd->state.storage_flag == 2)
-		gstorage_storageget(sd, item_index, item_amount);
+		storage_guild_storageget(sd, item_index, item_amount);
+	else if(sd->state.storage_flag == 3)
+		storage_storageget(sd, &sd->premiumStorage, item_index, item_amount);
 }
 
 
@@ -12491,9 +12506,11 @@ void clif_parse_MoveToKafraFromCart(int fd, struct map_session_data *sd){
 		return;
 
 	if (sd->state.storage_flag == 1)
-		storage_storageaddfromcart(sd, idx, amount);
+		storage_storageaddfromcart(sd, &sd->storage, idx, amount);
 	else if (sd->state.storage_flag == 2)
-		gstorage_storageaddfromcart(sd, idx, amount);
+		storage_guild_storageaddfromcart(sd, idx, amount);
+	else if (sd->state.storage_flag == 3)
+		storage_storageaddfromcart(sd, &sd->premiumStorage, idx, amount);
 }
 
 
@@ -12510,10 +12527,12 @@ void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd){
 		return;
 
 	if (sd->state.storage_flag == 1)
-		storage_storagegettocart(sd, idx, amount);
+		storage_storagegettocart(sd, &sd->storage, idx, amount);
 	else
 	if (sd->state.storage_flag == 2)
-		gstorage_storagegettocart(sd, idx, amount);
+		storage_guild_storagegettocart(sd, idx, amount);
+	else if (sd->state.storage_flag == 3)
+		storage_storagegettocart(sd, &sd->premiumStorage, idx, amount);
 }
 
 
@@ -12525,7 +12544,9 @@ void clif_parse_CloseKafra(int fd, struct map_session_data *sd)
 		storage_storageclose(sd);
 	else
 	if( sd->state.storage_flag == 2 )
-		gstorage_storageclose(sd);
+		storage_guild_storageclose(sd);
+	else if( sd->state.storage_flag == 3 )
+		storage_premiumStorage_close(sd);
 }
 
 
@@ -13815,7 +13836,7 @@ void clif_account_name(int fd, uint32 account_id, const char* accname)
 //! TODO: Figure out how does this actually work
 void clif_parse_GMReqAccountName(int fd, struct map_session_data *sd)
 {
-	int account_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
+	uint32 account_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
 	/*
 	char query[30];
 	safesnprintf(query,sizeof(query),"%d", account_id);
@@ -15078,23 +15099,22 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd){
 		return;
 	}
 
-	if( amount != 1 || amount > sd->status.inventory[idx].amount ) { // By client, amount is always set to 1. Maybe this is a future implementation.
+	if( amount != 1 || amount > sd->inventory.u.items_inventory[idx].amount ) { // By client, amount is always set to 1. Maybe this is a future implementation.
 		ShowWarning("Character %s trying to set invalid amount in auctions.\n", sd->status.name);
 		return;
 	}
 
-	if( (item = itemdb_exists(sd->status.inventory[idx].nameid)) != NULL && !(item->type == IT_ARMOR || item->type == IT_PETARMOR || item->type == IT_WEAPON || item->type == IT_CARD || item->type == IT_ETC || item->type == IT_SHADOWGEAR) )
+	if( (item = itemdb_exists(sd->inventory.u.items_inventory[idx].nameid)) != NULL && !(item->type == IT_ARMOR || item->type == IT_PETARMOR || item->type == IT_WEAPON || item->type == IT_CARD || item->type == IT_ETC || item->type == IT_SHADOWGEAR) )
 	{ // Consumable or pets are not allowed
 		clif_Auction_setitem(sd->fd, idx, true);
 		return;
 	}
 
-	if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time ||
-			!sd->status.inventory[idx].identify ||
-			(sd->status.inventory[idx].bound && !pc_can_give_bounded_items(sd)) ||
-			!itemdb_available(sd->status.inventory[idx].nameid) ||
-			!itemdb_canauction(&sd->status.inventory[idx],pc_get_group_level(sd)) // Quest Item or something else
-			) {
+	if( !pc_can_give_items(sd) || sd->inventory.u.items_inventory[idx].expire_time ||
+			!sd->inventory.u.items_inventory[idx].identify ||
+			(sd->inventory.u.items_inventory[idx].bound && !pc_can_give_bounded_items(sd)) ||
+			!itemdb_available(sd->inventory.u.items_inventory[idx].nameid) ||
+			!itemdb_canauction(&sd->inventory.u.items_inventory[idx],pc_get_group_level(sd)) ) { // Quest Item or something else
 		clif_Auction_setitem(sd->fd, idx, true);
 		return;
 	}
@@ -15173,7 +15193,7 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd)
 	}
 
 	// Auction checks...
-	if( sd->status.inventory[sd->auction.index].bound && !pc_can_give_bounded_items(sd) ) {
+	if( sd->inventory.u.items_inventory[sd->auction.index].bound && !pc_can_give_bounded_items(sd) ) {
 		clif_displaymessage(sd->fd, msg_txt(sd,293));
 		clif_Auction_message(fd, 2); // The auction has been canceled
 		return;
@@ -15195,13 +15215,13 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd)
 	auction.buyer_id = 0;
 	memset(auction.buyer_name, '\0', sizeof(auction.buyer_name));
 
-	if( sd->status.inventory[sd->auction.index].nameid == 0 || sd->status.inventory[sd->auction.index].amount < sd->auction.amount )
+	if( sd->inventory.u.items_inventory[sd->auction.index].nameid == 0 || sd->inventory.u.items_inventory[sd->auction.index].amount < sd->auction.amount )
 	{
 		clif_Auction_message(fd, 2); // The auction has been canceled
 		return;
 	}
 
-	if( (item = itemdb_exists(sd->status.inventory[sd->auction.index].nameid)) == NULL )
+	if( (item = itemdb_exists(sd->inventory.u.items_inventory[sd->auction.index].nameid)) == NULL )
 	{ // Just in case
 		clif_Auction_message(fd, 2); // The auction has been canceled
 		return;
@@ -15209,7 +15229,7 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd)
 
 	safestrncpy(auction.item_name, item->jname, sizeof(auction.item_name));
 	auction.type = item->type;
-	memcpy(&auction.item, &sd->status.inventory[sd->auction.index], sizeof(struct item));
+	memcpy(&auction.item, &sd->inventory.u.items_inventory[sd->auction.index], sizeof(struct item));
 	auction.item.amount = 1;
 	auction.timestamp = 0;
 
@@ -17217,9 +17237,9 @@ int clif_spellbook_list(struct map_session_data *sd)
 
 	for( i = 0, c = 0; i < MAX_INVENTORY; i ++ )
 	{
-		if( itemdb_is_spellbook2(sd->status.inventory[i].nameid) )
+		if( itemdb_is_spellbook2(sd->inventory.u.items_inventory[i].nameid) )
 		{
-			WFIFOW(fd, c * 2 + 4) = sd->status.inventory[i].nameid;
+			WFIFOW(fd, c * 2 + 4) = sd->inventory.u.items_inventory[i].nameid;
 			c++;
 		}
 	}
@@ -17255,8 +17275,8 @@ int clif_magicdecoy_list(struct map_session_data *sd, uint16 skill_lv, short x,
 	WFIFOW(fd,0) = 0x1ad; // This is the official packet. [pakpil]
 
 	for( i = 0, c = 0; i < MAX_INVENTORY; i ++ ) {
-		if( itemdb_is_element(sd->status.inventory[i].nameid) ) {
-			WFIFOW(fd, c * 2 + 4) = sd->status.inventory[i].nameid;
+		if( itemdb_is_element(sd->inventory.u.items_inventory[i].nameid) ) {
+			WFIFOW(fd, c * 2 + 4) = sd->inventory.u.items_inventory[i].nameid;
 			c ++;
 		}
 	}
@@ -17288,8 +17308,8 @@ int clif_poison_list(struct map_session_data *sd, uint16 skill_lv) {
 	WFIFOW(fd,0) = 0x1ad; // This is the official packet. [pakpil]
 
 	for( i = 0, c = 0; i < MAX_INVENTORY; i ++ ) {
-		if( itemdb_is_poison(sd->status.inventory[i].nameid) ) {
-			WFIFOW(fd, c * 2 + 4) = sd->status.inventory[i].nameid;
+		if( itemdb_is_poison(sd->inventory.u.items_inventory[i].nameid) ) {
+			WFIFOW(fd, c * 2 + 4) = sd->inventory.u.items_inventory[i].nameid;
 			c ++;
 		}
 	}
@@ -17429,10 +17449,10 @@ void clif_parse_MoveItem(int fd, struct map_session_data *sd) {
 	if (index < 0 || index >= MAX_INVENTORY)
 		return;
 
-	if ( sd->status.inventory[index].favorite && type == 1 )
-		sd->status.inventory[index].favorite = 0;
+	if ( sd->inventory.u.items_inventory[index].favorite && type == 1 )
+		sd->inventory.u.items_inventory[index].favorite = 0;
 	else if( type == 0 )
-		sd->status.inventory[index].favorite = 1;
+		sd->inventory.u.items_inventory[index].favorite = 1;
 	else
 		return;/* nothing to do. */
 
@@ -17449,7 +17469,7 @@ void clif_favorite_item(struct map_session_data* sd, unsigned short index) {
 	WFIFOHEAD(fd,packet_len(0x908));
 	WFIFOW(fd,0) = 0x908;
 	WFIFOW(fd,2) = index+2;
-	WFIFOL(fd,4) = (sd->status.inventory[index].favorite == 1) ? 0 : 1;
+	WFIFOL(fd,4) = (sd->inventory.u.items_inventory[index].favorite == 1) ? 0 : 1;
 	WFIFOSET(fd,packet_len(0x908));
 }
 
@@ -18347,7 +18367,7 @@ static bool clif_merge_item_has_pair(struct map_session_data *sd, struct item *i
 
 	nullpo_retr(false, sd);
 
-	ARR_FIND(0, MAX_INVENTORY, i, (it_ = &sd->status.inventory[i]) && it->nameid == it_->nameid && it->bound == it_->bound && memcmp(it_, it, sizeof(struct item)) != 0);
+	ARR_FIND(0, MAX_INVENTORY, i, (it_ = &sd->inventory.u.items_inventory[i]) && it->nameid == it_->nameid && it->bound == it_->bound && memcmp(it_, it, sizeof(struct item)) != 0);
 	if (i < MAX_INVENTORY)
 		return true;
 
@@ -18397,7 +18417,7 @@ void clif_merge_item_open(struct map_session_data *sd) {
 
 	// Get entries
 	for (i = 0; i < MAX_INVENTORY; i++) {
-		if (!clif_merge_item_check(sd->inventory_data[i], (it = &sd->status.inventory[i])))
+		if (!clif_merge_item_check(sd->inventory_data[i], (it = &sd->inventory.u.items_inventory[i])))
 			continue;
 		if (clif_merge_item_has_pair(sd, it))
 			indexes[n++] = i;
@@ -18444,14 +18464,14 @@ void clif_parse_merge_item_req(int fd, struct map_session_data* sd) {
 
 	for (i = 0, j = 0; i < n; i++) {
 		unsigned short idx = RFIFOW(fd, info->pos[1] + i*2) - 2;
-		if (!clif_merge_item_check((id = sd->inventory_data[idx]), &sd->status.inventory[idx]))
+		if (!clif_merge_item_check((id = sd->inventory_data[idx]), &sd->inventory.u.items_inventory[idx]))
 			continue;
 		indexes[j] = idx;
 		if (j && id->nameid != sd->inventory_data[indexes[0]]->nameid) { // Only can merge 1 kind at once
 			clif_merge_item_ack(sd, 0, 0, MERGE_ITEM_FAILED_NOT_MERGE);
 			return;
 		}
-		count += sd->status.inventory[idx].amount;
+		count += sd->inventory.u.items_inventory[idx].amount;
 		j++;
 	}
 
@@ -18467,13 +18487,13 @@ void clif_parse_merge_item_req(int fd, struct map_session_data* sd) {
 
 	// Merrrrge!!!!
 	for (i = 1; i < n; i++) {
-		unsigned short idx = indexes[i], amt = sd->status.inventory[idx].amount;
-		log_pick_pc(sd, LOG_TYPE_MERGE_ITEM, -amt, &sd->status.inventory[idx]);
-		memset(&sd->status.inventory[idx], 0, sizeof(sd->status.inventory[0]));
+		unsigned short idx = indexes[i], amt = sd->inventory.u.items_inventory[idx].amount;
+		log_pick_pc(sd, LOG_TYPE_MERGE_ITEM, -amt, &sd->inventory.u.items_inventory[idx]);
+		memset(&sd->inventory.u.items_inventory[idx], 0, sizeof(sd->inventory.u.items_inventory[0]));
 		sd->inventory_data[idx] = NULL;
 		clif_delitem(sd, idx, amt, 0);
 	}
-	sd->status.inventory[indexes[0]].amount = count;
+	sd->inventory.u.items_inventory[indexes[0]].amount = count;
 
 	clif_merge_item_ack(sd, indexes[0]+2, count, MERGE_ITEM_SUCCESS);
 }
@@ -18564,8 +18584,8 @@ void clif_parse_Oneclick_Itemidentify(int fd, struct map_session_data *sd) {
 	// - Invalid item ID or item doesn't exist
 	// - Item is already identified
 	if (idx < 0 || idx >= MAX_INVENTORY ||
-		sd->status.inventory[idx].nameid <= 0 || sd->inventory_data[idx] == NULL ||
-		sd->status.inventory[idx].identify)
+		sd->inventory.u.items_inventory[idx].nameid <= 0 || sd->inventory_data[idx] == NULL ||
+		sd->inventory.u.items_inventory[idx].identify)
 			return;
 
 	// Ignore the request - No magnifiers in inventory

+ 2 - 3
src/map/clif.h

@@ -10,8 +10,7 @@
 
 struct Channel;
 struct item;
-struct storage_data;
-struct guild_storage;
+struct s_storage;
 //#include "map.h"
 struct block_list;
 struct unit_data;
@@ -617,7 +616,7 @@ void clif_tradecompleted(struct map_session_data* sd, int fail);
 void clif_tradeundo(struct map_session_data* sd);
 
 // storage
-void clif_storagelist(struct map_session_data* sd, struct item* items, int items_length);
+void clif_storagelist(struct map_session_data* sd, struct item* items, int items_length, const char *storename);
 void clif_updatestorageamount(struct map_session_data* sd, int amount, int max_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);

+ 24 - 18
src/map/guild.c

@@ -865,7 +865,7 @@ int guild_member_withdraw(int guild_id, uint32 account_id, uint32 char_id, int f
 	if(sd != NULL && sd->status.guild_id == guild_id) {
 		// do stuff that needs the guild_id first, BEFORE we wipe it
 		if (sd->state.storage_flag == 2) //Close the guild storage.
-			gstorage_storageclose(sd);
+			storage_guild_storageclose(sd);
 		guild_send_dot_remove(sd);
 		channel_pcquit(sd,3); //leave guild and ally chan
 		sd->status.guild_id = 0;
@@ -907,29 +907,35 @@ void guild_retrieveitembound(uint32 char_id, uint32 account_id, int guild_id) {
 		int j;
 		j = pc_bound_chk(sd,BOUND_GUILD,idxlist);
 		if (j) {
-			struct guild_storage* stor = gstorage_guild2storage(sd->status.guild_id);
+			struct s_storage* stor = guild2storage(sd->status.guild_id);
+			struct guild *g = guild_search(guild_id);
 			int i;
-			// Close the storage first if someone open it
-			if (stor && stor->opened) {
-				struct map_session_data *tsd = map_charid2sd(stor->opened);
-				if (tsd)
-					gstorage_storageclose(tsd);
+			if (stor && stor->status) { //Someone is in guild storage, close them
+				int i;
+				for (i = 0; i < g->max_member; i++) {
+					TBL_PC *pl_sd = g->member[i].sd;
+					if (pl_sd && pl_sd->state.storage_flag == 2)
+						storage_guild_storageclose(pl_sd);
+				}
 			}
 			for (i = 0; i < j; i++) { //Loop the matching items, gstorage_additem takes care of opening storage
 				if (stor)
-					gstorage_additem(sd,stor,&sd->status.inventory[idxlist[i]],sd->status.inventory[idxlist[i]].amount);
-				pc_delitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,4,LOG_TYPE_GSTORAGE);
+					storage_guild_additem(sd,stor,&sd->inventory.u.items_inventory[idxlist[i]],sd->inventory.u.items_inventory[idxlist[i]].amount);
+				pc_delitem(sd,idxlist[i],sd->inventory.u.items_inventory[idxlist[i]].amount,0,4,LOG_TYPE_GSTORAGE);
 			}
-			gstorage_storageclose(sd); //Close and save the storage
+			storage_guild_storageclose(sd); //Close and save the storage
 		}
 	} else { //Character is offline, ask char server to do the job
-		struct guild_storage* stor = gstorage_get_storage(guild_id);
+		struct s_storage* stor = guild2storage2(guild_id);
 		struct guild *g = guild_search(guild_id);
 		nullpo_retv(g);
-		if(stor && stor->opened) { //Someone is in guild storage, close them
-			struct map_session_data *tsd = map_charid2sd(stor->opened);
-			if (tsd)
-				gstorage_storageclose(tsd);
+		if (stor && stor->status) { //Someone is in guild storage, close them
+			int i;
+			for (i = 0; i < g->max_member; i++) {
+				TBL_PC *pl_sd = g->member[i].sd;
+				if (pl_sd && pl_sd->state.storage_flag == 2)
+					storage_guild_storageclose(pl_sd);
+			}
 		}
 		intif_itembound_guild_retrieve(char_id,account_id,guild_id);
 	}
@@ -1724,7 +1730,7 @@ int guild_broken(int guild_id,int flag) {
 		struct map_session_data *sd = g->member[i].sd;
 		if(sd != NULL){
 			if(sd->state.storage_flag == 2)
-				gstorage_storage_quit(sd,1);
+				storage_guild_storage_quit(sd,1);
 			sd->status.guild_id=0;
 			sd->guild = NULL;
 			sd->state.gmaster_flag = 0;
@@ -1739,7 +1745,7 @@ int guild_broken(int guild_id,int flag) {
 
 	guild_db->foreach(guild_db,guild_broken_sub,guild_id);
 	castle_db->foreach(castle_db,castle_guild_broken_sub,guild_id);
-	gstorage_delete(guild_id);
+	storage_guild_delete(guild_id);
 	if( channel_config.ally_enable ) {
 		channel_delete(g->channel);
 	}
@@ -1885,7 +1891,7 @@ int guild_break(struct map_session_data *sd,char *name) {
 	//Guild bound item check - Removes the bound flag
 	j = pc_bound_chk(sd,BOUND_GUILD,idxlist);
 	for(i = 0; i < j; i++)
-		pc_delitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_BOUND_REMOVAL);
+		pc_delitem(sd,idxlist[i],sd->inventory.u.items_inventory[idxlist[i]].amount,0,1,LOG_TYPE_BOUND_REMOVAL);
 #endif
 
 	intif_guild_break(g->guild_id);

+ 291 - 42
src/map/intif.c

@@ -21,10 +21,12 @@
 #include "elemental.h"
 #include "mail.h"
 #include "quest.h"
+#include "status.h"
 
 #include <stdlib.h>
 
-static const int packet_len_table[]={
+/// Received packet Lengths from inter-server
+static const int packet_len_table[] = {
 	-1,-1,27,-1, -1, 0,37,-1, 10+NAME_LENGTH,-1, 0, 0,  0, 0,  0, 0, //0x3800-0x380f
 	 0, 0, 0, 0,  0, 0, 0, 0, -1,11, 0, 0,  0, 0,  0, 0, //0x3810
 	39,-1,15,15, 15+NAME_LENGTH,19, 7,-1,  0, 0, 0, 0,  0, 0,  0, 0, //0x3820
@@ -33,7 +35,7 @@ static const int packet_len_table[]={
 	-1,-1, 7, 7,  7,11, 8,-1,  0, 0, 0, 0,  0, 0,  0, 0, //0x3850  Auctions [Zephyrus] itembound[Akinari]
 	-1, 7, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, //0x3860  Quests [Kevin] [Inkfish]
 	-1, 3, 3, 0,  0, 0, 0, 0,  0, 0, 0, 0, -1, 3,  3, 0, //0x3870  Mercenaries [Zephyrus] / Elemental [pakpil]
-	12,-1, 7, 3,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, //0x3880
+	12,-1, 7, 3,  0, 0, 0, 0,  0, 0,-1, 9, -1, 0,  0, 0, //0x3880  Pet System,  Storages
 	-1,-1, 7, 3,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, //0x3890  Homunculus [albator]
 };
 
@@ -52,6 +54,23 @@ int CheckForCharServer(void)
 	return ((char_fd <= 0) || session[char_fd] == NULL || session[char_fd]->wdata == NULL);
 }
 
+/**
+ * Get sd from pc_db (map_id2db) or auth_db (in case if parsing packet from inter-server when sd not added to pc_db yet)
+ * @param account_id
+ * @param char_id
+ * @return sd Found sd or NULL if not found
+ */
+struct map_session_data *inter_search_sd(uint32 account_id, uint32 char_id)
+{
+	struct map_session_data *sd = NULL;
+	struct auth_node *node = chrif_auth_check(account_id, char_id, ST_LOGIN);
+	if (node)
+		sd = node->sd;
+	else
+		sd = map_id2sd(account_id);
+	return sd;
+}
+
 /**
  * Request the char-serv to create a pet (to register it actually)
  * @param account_id
@@ -493,40 +512,40 @@ int intif_request_registry(struct map_session_data *sd, int flag)
 
 /**
  * Request to load guild storage from char-serv
- * @param account_id : Player account identification
- * @param guild_id : Guild of player
- * @return 0:error, 1=msg sent
+ * @param account_id: Player account identification
+ * @param guild_id: Guild of player
+ * @return false - error, true - message sent
  */
-int intif_request_guild_storage(uint32 account_id,int guild_id)
+bool intif_request_guild_storage(uint32 account_id, int guild_id)
 {
 	if (CheckForCharServer())
-		return 0;
+		return false;
 	WFIFOHEAD(inter_fd,10);
 	WFIFOW(inter_fd,0) = 0x3018;
 	WFIFOL(inter_fd,2) = account_id;
 	WFIFOL(inter_fd,6) = guild_id;
 	WFIFOSET(inter_fd,10);
-	return 1;
+	return true;
 }
 
 /**
  * Request to save guild storage
- * @param account_id : account requesting the save
- * @param gstor : Guild storage struct to save
- * @return 
+ * @param account_id: account requesting the save
+ * @param gstor: Guild storage struct to save
+ * @return false - error, true - message sent
  */
-int intif_send_guild_storage(uint32 account_id,struct guild_storage *gstor)
+bool intif_send_guild_storage(uint32 account_id, struct s_storage *gstor)
 {
 	if (CheckForCharServer())
-		return 0;
-	WFIFOHEAD(inter_fd,sizeof(struct guild_storage)+12);
+		return false;
+	WFIFOHEAD(inter_fd,sizeof(struct s_storage)+12);
 	WFIFOW(inter_fd,0) = 0x3019;
-	WFIFOW(inter_fd,2) = (unsigned short)sizeof(struct guild_storage)+12;
+	WFIFOW(inter_fd,2) = (unsigned short)sizeof(struct s_storage)+12;
 	WFIFOL(inter_fd,4) = account_id;
-	WFIFOL(inter_fd,8) = gstor->guild_id;
-	memcpy( WFIFOP(inter_fd,12),gstor, sizeof(struct guild_storage) );
+	WFIFOL(inter_fd,8) = gstor->id;
+	memcpy( WFIFOP(inter_fd,12),gstor, sizeof(struct s_storage) );
 	WFIFOSET(inter_fd,WFIFOW(inter_fd,2));
-	return 1;
+	return true;
 }
 
 /**
@@ -1412,7 +1431,7 @@ void intif_parse_Registers(int fd)
  */
 int intif_parse_LoadGuildStorage(int fd)
 {
-	struct guild_storage *gstor;
+	struct s_storage *gstor;
 	struct map_session_data *sd;
 	int guild_id, flag;
 
@@ -1428,12 +1447,12 @@ int intif_parse_LoadGuildStorage(int fd)
 			return 0;
 		}
 	}
-	gstor = gstorage_guild2storage(guild_id);
+	gstor = guild2storage(guild_id);
 	if (!gstor) {
 		ShowWarning("intif_parse_LoadGuildStorage: error guild_id %d not exist\n",guild_id);
 		return 0;
 	}
-	if (gstor->opened) { // Already open.. lets ignore this update
+	if (gstor->status) { // Already open.. lets ignore this update
 		ShowWarning("intif_parse_LoadGuildStorage: storage received for a client already open (User %d:%d)\n", flag?sd->status.account_id:1, flag?sd->status.char_id:1);
 		return 0;
 	}
@@ -1441,15 +1460,15 @@ int intif_parse_LoadGuildStorage(int fd)
 		ShowWarning("intif_parse_LoadGuildStorage: received storage for an already modified non-saved storage! (User %d:%d)\n", flag?sd->status.account_id:1, flag?sd->status.char_id:1);
 		return 0;
 	}
-	if( RFIFOW(fd,2)-13 != sizeof(struct guild_storage) ){
-		ShowError("intif_parse_LoadGuildStorage: data size error %d %d\n",RFIFOW(fd,2)-13 , sizeof(struct guild_storage));
-		gstor->opened = 0;
+	if (RFIFOW(fd,2)-13 != sizeof(struct s_storage)) {
+		ShowError("intif_parse_LoadGuildStorage: data size error %d %d\n",RFIFOW(fd,2)-13 , sizeof(struct s_storage));
+		gstor->status = false;
 		return 0;
 	}
 
-	memcpy(gstor,RFIFOP(fd,13),sizeof(struct guild_storage));
+	memcpy(gstor,RFIFOP(fd,13),sizeof(struct s_storage));
 	if( flag )
-		gstorage_storageopen(sd);
+		storage_guild_storageopen(sd);
 
 	return 1;
 }
@@ -1461,7 +1480,7 @@ int intif_parse_LoadGuildStorage(int fd)
  */
 int intif_parse_SaveGuildStorage(int fd)
 {
-	gstorage_storagesaved(/*RFIFOL(fd,2), */RFIFOL(fd,6));
+	storage_guild_storagesaved(/*RFIFOL(fd,2), */RFIFOL(fd,6));
 	return 1;
 }
 
@@ -3058,7 +3077,7 @@ void intif_parse_broadcast_obtain_special_item(int fd) {
  * @param guild_id : Guild of char
  */
 void intif_itembound_guild_retrieve(uint32 char_id,uint32 account_id,int guild_id) {
-	struct guild_storage *gstor = gstorage_get_storage(guild_id);
+	struct s_storage *gstor = guild2storage2(guild_id);
 	
 	if( CheckForCharServer() )
 		return;
@@ -3070,7 +3089,7 @@ void intif_itembound_guild_retrieve(uint32 char_id,uint32 account_id,int guild_i
 	WFIFOW(inter_fd,10) = guild_id;
 	WFIFOSET(inter_fd,12);
 	if (gstor)
-		gstor->locked = true; //Lock for retrieval process
+		gstor->lock = true; //Lock for retrieval process
 	ShowInfo("Request guild bound item(s) retrieval for CID = "CL_WHITE"%d"CL_RESET", AID = %d, Guild ID = "CL_WHITE"%d"CL_RESET".\n", char_id, account_id, guild_id);
 }
 
@@ -3082,21 +3101,21 @@ void intif_itembound_guild_retrieve(uint32 char_id,uint32 account_id,int guild_i
  */
 void intif_parse_itembound_ack(int fd) {
 	int guild_id = RFIFOW(fd,6);
-	struct guild_storage *gstor = gstorage_get_storage(guild_id);
+	struct s_storage *gstor = guild2storage2(guild_id);
 	if (gstor)
-		gstor->locked = false; //Unlock now that operation is completed
+		gstor->lock = false; //Unlock now that operation is completed
 }
 
 /**
-* IZ 0x3857 <size>.W <count>.W <guild_id>.W { <item>.?B }.*MAX_INVENTORY
-* Received the retrieved guild bound items from inter-server, store them to guild storage.
-* @param fd
-* @author [Cydh]
-*/
+ * IZ 0x3857 <size>.W <count>.W <guild_id>.W { <item>.?B }.*MAX_INVENTORY
+ * Received the retrieved guild bound items from inter-server, store them to guild storage.
+ * @param fd
+ * @author [Cydh]
+ */
 void intif_parse_itembound_store2gstorage(int fd) {
 	unsigned short i, failed = 0;
 	short count = RFIFOW(fd, 4), guild_id = RFIFOW(fd, 6);
-	struct guild_storage *gstor = gstorage_guild2storage(guild_id);
+	struct s_storage *gstor = guild2storage(guild_id);
 
 	if (!gstor) {
 		ShowError("intif_parse_itembound_store2gstorage: Guild '%d' not found.\n", guild_id);
@@ -3108,16 +3127,239 @@ void intif_parse_itembound_store2gstorage(int fd) {
 		struct item *item = (struct item*)RFIFOP(fd, 8 + i*sizeof(struct item));
 		if (!item)
 			continue;
-		if (!gstorage_additem2(gstor, item, item->amount))
+		if (!storage_guild_additem2(gstor, item, item->amount))
 			failed++;
 	}
 	ShowInfo("Retrieved '"CL_WHITE"%d"CL_RESET"' (failed: %d) guild bound item(s) for Guild ID = "CL_WHITE"%d"CL_RESET".\n", count, failed, guild_id);
-	gstor->locked = false;
-	gstor->opened = 0;
+	gstor->lock = false;
+	gstor->status = false;
 }
 #endif
 
-//-----------------------------------------------------------------
+/**
+ * Receive inventory/cart/storage data for player
+ * IZ 0x388a <size>.W <type>.B <account_id>.L <result>.B <storage>.?B
+ * @param fd
+ */
+static bool intif_parse_StorageReceived(int fd)
+{
+	char type =  RFIFOB(fd,4);
+	uint32 account_id = RFIFOL(fd, 5);
+	struct map_session_data *sd = map_id2sd(account_id);
+	struct s_storage *stor, *p; //storage
+	size_t sz_stor = sizeof(struct s_storage);
+
+	if (!sd) {
+		ShowError("intif_parse_StorageReceived: No player online for receiving inventory/cart/storage data (AID: %d)\n", account_id);
+		return false;
+	}
+
+	if (!RFIFOB(fd, 9)) {
+		ShowError("intif_parse_StorageReceived: Failed to load! (AID: %d, type: %d)\n", account_id, type);
+		return false;
+	}
+
+	p = (struct s_storage *)RFIFOP(fd,10);
+
+	switch (type) { 
+		case TABLE_INVENTORY: stor = &sd->inventory; break;
+		case TABLE_STORAGE:
+			if (p->stor_id == 0)
+				stor = &sd->storage;
+			else
+				stor = &sd->premiumStorage;
+			break;
+		case TABLE_CART:
+			stor = &sd->cart;
+			break;
+		default: return false;
+	}
+
+	if (stor->stor_id == p->stor_id) {
+		if (stor->status) { // Already open.. lets ignore this update
+			ShowWarning("intif_parse_StorageReceived: storage received for a client already open (User %d:%d)\n", sd->status.account_id, sd->status.char_id);
+			return false;
+		}
+		if (stor->dirty) { // Already have storage, and it has been modified and not saved yet! Exploit!
+			ShowWarning("intif_parse_StorageReceived: received storage for an already modified non-saved storage! (User %d:%d)\n", sd->status.account_id, sd->status.char_id);
+			return false;
+		}
+	}
+	if (RFIFOW(fd,2)-10 != sz_stor) {
+		ShowError("intif_parse_StorageReceived: data size error %d %d\n",RFIFOW(fd,2)-10 , sz_stor);
+		stor->status = false;
+		return false;
+	}
+
+	memcpy(stor, p, sz_stor); //copy the items data to correct destination
+
+	switch (type) {
+		case TABLE_INVENTORY: {
+#ifdef BOUND_ITEMS
+			int j, idxlist[MAX_INVENTORY];
+#endif
+			pc_setinventorydata(sd);
+			pc_setequipindex(sd);
+			pc_check_expiration(sd);
+			pc_check_available_item(sd, ITMCHK_INVENTORY);
+			pc_itemcd_do(sd, true);
+#ifdef BOUND_ITEMS
+			// Party bound item check
+			if (sd->status.party_id == 0 && (j = pc_bound_chk(sd, BOUND_PARTY, idxlist))) { // Party was deleted while character offline
+				int i;
+				for (i = 0; i < j; i++)
+					pc_delitem(sd, idxlist[i], sd->inventory.u.items_inventory[idxlist[i]].amount, 0, 1, LOG_TYPE_OTHER);
+			}
+#endif
+			//Set here because we need the inventory data for weapon sprite parsing.
+			status_set_viewdata(&sd->bl, sd->status.class_);
+			pc_load_combo(sd);
+			status_calc_pc(sd, (enum e_status_calc_opt)(SCO_FIRST|SCO_FORCE));
+			status_calc_weight(sd, 1|2); // Refresh item weight data
+			chrif_scdata_request(sd->status.account_id, sd->status.char_id);
+			break;
+		}
+
+		case TABLE_CART:
+			pc_check_available_item(sd, ITMCHK_CART);
+			if (sd->state.autotrade) {
+				clif_parse_LoadEndAck(sd->fd, sd);
+				sd->autotrade_tid = add_timer(gettick() + battle_config.feature_autotrade_open_delay, pc_autotrade_timer, sd->bl.id, 0);
+			}else if( sd->state.prevend ){
+				clif_clearcart(sd->fd);
+				clif_cartlist(sd);
+				clif_openvendingreq(sd, sd->vend_skill_lv+2);
+			}
+			break;
+
+		case TABLE_STORAGE:
+			if (stor->stor_id)
+				storage_premiumStorage_open(sd);
+			else {
+#ifdef VIP_ENABLE
+				if (!pc_isvip(sd))
+					stor->max_amount = MIN_STORAGE;
+#endif
+				pc_check_available_item(sd, ITMCHK_STORAGE);
+			}
+			break;
+	}
+	return true;
+}
+
+/**
+ * Save inventory/cart/storage data for a player
+ * IZ 0x388b <account_id>.L <result>.B <type>.B <storage_id>.B
+ * @param fd
+ */
+static void intif_parse_StorageSaved(int fd)
+{
+	if (RFIFOB(fd, 6)) {
+		switch (RFIFOB(fd, 7)) {
+			case TABLE_INVENTORY: //inventory
+				//ShowInfo("Inventory has been saved (AID: %d).\n", RFIFOL(fd, 2));
+				break;
+			case TABLE_STORAGE: //storage
+				//ShowInfo("Storage has been saved (AID: %d).\n", RFIFOL(fd, 2));
+				if (RFIFOB(fd, 8))
+					storage_premiumStorage_saved(map_id2sd(RFIFOL(fd, 2)));
+				break;
+			case TABLE_CART: // cart
+				//ShowInfo("Cart has been saved (AID: %d).\n", RFIFOL(fd, 2));
+				{
+					struct map_session_data *sd = map_id2sd(RFIFOL(fd, 2));
+
+					if( sd && sd->state.prevend ){
+						intif_storage_request(sd,TABLE_CART,0,STOR_MODE_ALL);
+					}
+				}
+				break;
+			default:
+				break;
+		}
+	} else
+		ShowError("Failed to save inventory/cart/storage data (AID: %d, type: %d).\n", RFIFOL(fd, 2), RFIFOB(fd, 7));
+}
+
+/**
+ * IZ 0x388c <len>.W { <storage_table>.? }*?
+ * Receive storage information
+ **/
+void intif_parse_StorageInfo_recv(int fd) {
+	int i, size = sizeof(struct s_storage_table), count = (RFIFOW(fd, 2) - 4) / size;
+
+	storage_count = 0;
+	if (storage_db)
+		aFree(storage_db);
+	storage_db = NULL;
+
+	for (i = 0; i < count; i++) {
+		char name[NAME_LENGTH + 1];
+
+		safestrncpy(name, RFIFOCP(fd, 5 + size * i), NAME_LENGTH);
+		if (name[0] == '\0')
+			continue;
+		RECREATE(storage_db, struct s_storage_table, storage_count+1);
+		memcpy(&storage_db[storage_count], RFIFOP(fd, 4 + size * i), size);
+		storage_count++;
+	}
+
+	if (battle_config.etc_log)
+		ShowInfo("Received '"CL_WHITE"%d"CL_RESET"' storage info from inter-server.\n", storage_count);
+}
+
+/**
+ * Request inventory/cart/storage data for a player
+ * ZI 0x308a <type>.B <account_id>.L <char_id>.L <storage_id>.B
+ * @param sd: Player data
+ * @param type: Storage type
+ * @param stor_id: Storage ID
+ * @param mode: Storage mode
+ * @return false - error, true - message sent
+ */
+bool intif_storage_request(struct map_session_data *sd, enum storage_type type, uint8 stor_id, uint8 mode)
+{
+	if (CheckForCharServer())
+		return false;
+
+	WFIFOHEAD(inter_fd, 13);
+	WFIFOW(inter_fd, 0) = 0x308a;
+	WFIFOB(inter_fd, 2) = type;
+	WFIFOL(inter_fd, 3) = sd->status.account_id;
+	WFIFOL(inter_fd, 7) = sd->status.char_id;
+	WFIFOB(inter_fd, 11) = stor_id;
+	WFIFOB(inter_fd, 12) = mode;
+	WFIFOSET(inter_fd, 13);
+	return true;
+}
+
+/**
+ * Request to save inventory/cart/storage data from player
+ * ZI 0x308b <size>.W <type>.B <account_id>.L <char_id>.L <entries>.?B
+ * @param sd: Player data
+ * @param stor: Storage data
+ * @ return false - error, true - message sent
+ */
+bool intif_storage_save(struct map_session_data *sd, struct s_storage *stor)
+{
+	int stor_size = sizeof(struct s_storage);
+
+	nullpo_retr(false, sd);
+	nullpo_retr(false, stor);
+
+	if (CheckForCharServer())
+		return false;
+
+	WFIFOHEAD(inter_fd, stor_size+13);
+	WFIFOW(inter_fd, 0) = 0x308b;
+	WFIFOW(inter_fd, 2) = stor_size+13;
+	WFIFOB(inter_fd, 4) = stor->type;
+	WFIFOL(inter_fd, 5) = sd->status.account_id;
+	WFIFOL(inter_fd, 9) = sd->status.char_id;
+	memcpy(WFIFOP(inter_fd, 13), stor, stor_size);
+	WFIFOSET(inter_fd, stor_size+13);
+	return true;
+}
 
 /**
  * Communication from the inter server, Main entry point interface (inter<=>map) 
@@ -3231,7 +3473,12 @@ int intif_parse(int fd)
 	case 0x3882:	intif_parse_SavePetOk(fd); break;
 	case 0x3883:	intif_parse_DeletePetOk(fd); break;
 
-	// Homunculus
+	// Storage
+	case 0x388a:	intif_parse_StorageReceived(fd); break;
+	case 0x388b:	intif_parse_StorageSaved(fd); break;
+	case 0x388c:	intif_parse_StorageInfo_recv(fd); break;
+
+	// Homunculus System
 	case 0x3890:	intif_parse_CreateHomunculus(fd); break;
 	case 0x3891:	intif_parse_RecvHomunculusData(fd); break;
 	case 0x3892:	intif_parse_SaveHomunculusOk(fd); break;
@@ -3241,7 +3488,9 @@ int intif_parse(int fd)
 		ShowError("intif_parse : unknown packet %d %x\n",fd,RFIFOW(fd,0));
 		return 0;
 	}
+
 	// Skip packet
 	RFIFOSKIP(fd,packet_len);
+
 	return 1;
 }

+ 6 - 2
src/map/intif.h

@@ -29,8 +29,8 @@ int intif_wis_message_to_gm(char *Wisp_name, int permission, char *mes);
 int intif_saveregistry(struct map_session_data *sd);
 int intif_request_registry(struct map_session_data *sd, int flag);
 
-int intif_request_guild_storage(uint32 account_id, int guild_id);
-int intif_send_guild_storage(uint32 account_id, struct guild_storage *gstor);
+bool intif_request_guild_storage(uint32 account_id, int guild_id);
+bool intif_send_guild_storage(uint32 account_id, struct s_storage *gstor);
 
 int intif_create_party(struct party_member *member,char *name,int item,int item2);
 int intif_request_partyinfo(int party_id, uint32 char_id);
@@ -110,6 +110,10 @@ int intif_elemental_save(struct s_elemental *ele);
 
 int intif_request_accinfo(int u_fd, int aid, int group_lv, char* query, char type);
 
+// STORAGE
+bool intif_storage_request(struct map_session_data *sd, enum storage_type type, uint8 stor_id, uint8 mode);
+bool intif_storage_save(struct map_session_data *sd, struct s_storage *stor);
+
 int CheckForCharServer(void);
 
 #endif /* _INTIF_H_ */

+ 1 - 1
src/map/itemdb.c

@@ -1836,7 +1836,7 @@ void itemdb_reload(void) {
 	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);
-		pc_check_available_item(sd); // Check for invalid(ated) items.
+		pc_check_available_item(sd, ITMCHK_ALL); // Check for invalid(ated) items.
 		/* clear combo bonuses */
 		if( sd->combos.count ) {
 			aFree(sd->combos.bonus);

+ 9 - 9
src/map/mail.c

@@ -83,16 +83,16 @@ bool mail_setitem(struct map_session_data *sd, short idx, uint32 amount) {
 
 		if( idx < 0 || idx >= MAX_INVENTORY )
 			return false;
-		if( amount > sd->status.inventory[idx].amount )
+		if( amount > sd->inventory.u.items_inventory[idx].amount )
 			return false;
-		if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time
-			|| !itemdb_available(sd->status.inventory[idx].nameid)
-			|| !itemdb_canmail(&sd->status.inventory[idx],pc_get_group_level(sd))
-			|| (sd->status.inventory[idx].bound && !pc_can_give_bounded_items(sd)) )
+		if( !pc_can_give_items(sd) || sd->inventory.u.items_inventory[idx].expire_time
+			|| !itemdb_available(sd->inventory.u.items_inventory[idx].nameid)
+			|| !itemdb_canmail(&sd->inventory.u.items_inventory[idx],pc_get_group_level(sd))
+			|| (sd->inventory.u.items_inventory[idx].bound && !pc_can_give_bounded_items(sd)) )
 			return false;
 
 		sd->mail.index = idx;
-		sd->mail.nameid = sd->status.inventory[idx].nameid;
+		sd->mail.nameid = sd->inventory.u.items_inventory[idx].nameid;
 		sd->mail.amount = amount;
 		return true;
 	}
@@ -111,16 +111,16 @@ bool mail_setattachment(struct map_session_data *sd, struct mail_message *msg)
 	n = sd->mail.index;
 	if( sd->mail.amount )
 	{
-		if( sd->status.inventory[n].nameid != sd->mail.nameid )
+		if( sd->inventory.u.items_inventory[n].nameid != sd->mail.nameid )
 			return false;
 
-		if( sd->status.inventory[n].amount < sd->mail.amount )
+		if( sd->inventory.u.items_inventory[n].amount < sd->mail.amount )
 			return false;
 
 		if( sd->weight > sd->max_weight )
 			return false;
 
-		memcpy(&msg->item, &sd->status.inventory[n], sizeof(struct item));
+		memcpy(&msg->item, &sd->inventory.u.items_inventory[n], sizeof(struct item));
 		msg->item.amount = sd->mail.amount;
 	}
 	else

+ 3 - 2
src/map/map.c

@@ -2067,8 +2067,6 @@ int map_quit(struct map_session_data *sd) {
 	if (sd->ed) // Remove effects here rather than unit_remove_map_pc so we don't clear on Teleport/map change.
 		elemental_clean_effect(sd->ed);
 
-	if( sd->state.storage_flag == 1 ) sd->state.storage_flag = 0; // No need to Double Save Storage on Quit.
-
 	if (sd->state.permanent_speed == 1) sd->state.permanent_speed = 0; // Remove lock so speed is set back to normal at login.
 
 	if( map[sd->bl.m].instance_id )
@@ -4656,6 +4654,9 @@ int do_init(int argc, char *argv[])
 	rnd_init();
 	map_config_read(MAP_CONF_NAME);
 
+	if (save_settings == CHARSAVE_NONE)
+		ShowWarning("Value of 'save_settings' is not set, player's data only will be saved every 'autosave_time' (%d seconds).\n", autosave_interval/1000);
+
 	// loads npcs
 	map_reloadnpc(false);
 

+ 13 - 13
src/map/npc.c

@@ -1552,8 +1552,8 @@ void npc_shop_currency_type(struct map_session_data *sd, struct npc_data *nd, in
 				}
 
 				for (i = 0; i < MAX_INVENTORY; i++) {
-					if (sd->status.inventory[i].nameid == id->nameid)
-						total += sd->status.inventory[i].amount;
+					if (sd->inventory.u.items_inventory[i].nameid == id->nameid)
+						total += sd->inventory.u.items_inventory[i].amount;
 				}
 			}
 
@@ -1882,19 +1882,19 @@ static int npc_selllist_sub(struct map_session_data* sd, int n, unsigned short*
 
 		idx = item_list[i*2]-2;
 
-		script_setarray_pc(sd, "@sold_nameid", i, (void*)(intptr_t)sd->status.inventory[idx].nameid, &key_nameid);
+		script_setarray_pc(sd, "@sold_nameid", i, (void*)(intptr_t)sd->inventory.u.items_inventory[idx].nameid, &key_nameid);
 		script_setarray_pc(sd, "@sold_quantity", i, (void*)(intptr_t)item_list[i*2+1], &key_amount);
 
-		if( itemdb_isequip(sd->status.inventory[idx].nameid) )
+		if( itemdb_isequip(sd->inventory.u.items_inventory[idx].nameid) )
 		{// process equipment based information into the arrays
-			script_setarray_pc(sd, "@sold_refine", i, (void*)(intptr_t)sd->status.inventory[idx].refine, &key_refine);
-			script_setarray_pc(sd, "@sold_attribute", i, (void*)(intptr_t)sd->status.inventory[idx].attribute, &key_attribute);
-			script_setarray_pc(sd, "@sold_identify", i, (void*)(intptr_t)sd->status.inventory[idx].identify, &key_identify);
+			script_setarray_pc(sd, "@sold_refine", i, (void*)(intptr_t)sd->inventory.u.items_inventory[idx].refine, &key_refine);
+			script_setarray_pc(sd, "@sold_attribute", i, (void*)(intptr_t)sd->inventory.u.items_inventory[idx].attribute, &key_attribute);
+			script_setarray_pc(sd, "@sold_identify", i, (void*)(intptr_t)sd->inventory.u.items_inventory[idx].identify, &key_identify);
 
 			for( j = 0; j < MAX_SLOTS; j++ )
 			{// store each of the cards from the equipment in the array
 				snprintf(card_slot, sizeof(card_slot), "@sold_card%d", j + 1);
-				script_setarray_pc(sd, card_slot, i, (void*)(intptr_t)sd->status.inventory[idx].card[j], &key_card[j]);
+				script_setarray_pc(sd, card_slot, i, (void*)(intptr_t)sd->inventory.u.items_inventory[idx].card[j], &key_card[j]);
 			}
 		}
 	}
@@ -1940,9 +1940,9 @@ uint8 npc_selllist(struct map_session_data* sd, int n, unsigned short *item_list
 			return 1;
 		}
 
-		nameid = sd->status.inventory[idx].nameid;
+		nameid = sd->inventory.u.items_inventory[idx].nameid;
 
-		if( !nameid || !sd->inventory_data[idx] || sd->status.inventory[idx].amount < amount )
+		if( !nameid || !sd->inventory_data[idx] || sd->inventory.u.items_inventory[idx].amount < amount )
 		{
 			return 1;
 		}
@@ -1970,11 +1970,11 @@ uint8 npc_selllist(struct map_session_data* sd, int n, unsigned short *item_list
 		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( sd->inventory_data[idx]->type == IT_PETEGG && sd->inventory.u.items_inventory[idx].card[0] == CARD0_PET )
 		{
-			if( search_petDB_index(sd->status.inventory[idx].nameid, PET_EGG) >= 0 )
+			if( search_petDB_index(sd->inventory.u.items_inventory[idx].nameid, PET_EGG) >= 0 )
 			{
-				intif_delete_petdata(MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2]));
+				intif_delete_petdata(MakeDWord(sd->inventory.u.items_inventory[idx].card[1], sd->inventory.u.items_inventory[idx].card[2]));
 			}
 		}
 

+ 1 - 1
src/map/party.c

@@ -643,7 +643,7 @@ int party_member_withdraw(int party_id, uint32 account_id, uint32 char_id, char
 		j = pc_bound_chk(sd,BOUND_PARTY,idxlist);
 
 		for(i = 0; i < j; i++)
-			pc_delitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_BOUND_REMOVAL);
+			pc_delitem(sd,idxlist[i],sd->inventory.u.items_inventory[idxlist[i]].amount,0,1,LOG_TYPE_BOUND_REMOVAL);
 #endif
 
 		sd->status.party_id = 0;

+ 182 - 191
src/map/pc.c

@@ -518,19 +518,19 @@ void pc_inventory_rentals(struct map_session_data *sd)
 	unsigned int next_tick = UINT_MAX;
 
 	for( i = 0; i < MAX_INVENTORY; i++ ) { // Check for Rentals on Inventory
-		if( sd->status.inventory[i].nameid == 0 )
+		if( sd->inventory.u.items_inventory[i].nameid == 0 )
 			continue; // Nothing here
-		if( sd->status.inventory[i].expire_time == 0 )
+		if( sd->inventory.u.items_inventory[i].expire_time == 0 )
 			continue;
-		if( sd->status.inventory[i].expire_time <= time(NULL) ) {
+		if( sd->inventory.u.items_inventory[i].expire_time <= time(NULL) ) {
 			if (sd->inventory_data[i]->unequip_script)
 				run_script(sd->inventory_data[i]->unequip_script, 0, sd->bl.id, fake_nd->bl.id);
-			clif_rental_expired(sd->fd, i, sd->status.inventory[i].nameid);
-			pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_OTHER);
+			clif_rental_expired(sd->fd, i, sd->inventory.u.items_inventory[i].nameid);
+			pc_delitem(sd, i, sd->inventory.u.items_inventory[i].amount, 0, 0, LOG_TYPE_OTHER);
 		} else {
-			unsigned int expire_tick = (unsigned int)(sd->status.inventory[i].expire_time - time(NULL));
+			unsigned int expire_tick = (unsigned int)(sd->inventory.u.items_inventory[i].expire_time - time(NULL));
 
-			clif_rental_time(sd->fd, sd->status.inventory[i].nameid, (int)expire_tick);
+			clif_rental_time(sd->fd, sd->inventory.u.items_inventory[i].nameid, (int)expire_tick);
 			next_tick = umin(expire_tick, next_tick);
 			c++;
 		}
@@ -695,14 +695,14 @@ void pc_setinventorydata(struct map_session_data *sd)
 	nullpo_retv(sd);
 
 	for(i = 0; i < MAX_INVENTORY; i++) {
-		unsigned short id = sd->status.inventory[i].nameid;
+		unsigned short id = sd->inventory.u.items_inventory[i].nameid;
 		sd->inventory_data[i] = id?itemdb_search(id):NULL;
 	}
 }
 
 /**
 * 'Calculates' weapon type
-* @param sd : player
+* @param sd : Player
 */
 void pc_calcweapontype(struct map_session_data *sd)
 {
@@ -760,22 +760,22 @@ void pc_setequipindex(struct map_session_data *sd)
 		sd->equip_index[i] = -1;
 
 	for (i = 0; i < MAX_INVENTORY; i++) {
-		if (sd->status.inventory[i].nameid <= 0)
+		if (sd->inventory.u.items_inventory[i].nameid <= 0)
 			continue;
-		if (sd->status.inventory[i].equip) {
+		if (sd->inventory.u.items_inventory[i].equip) {
 			uint8 j;
 			for (j = 0; j < EQI_MAX; j++)
-				if (sd->status.inventory[i].equip & equip_bitmask[j])
+				if (sd->inventory.u.items_inventory[i].equip & equip_bitmask[j])
 					sd->equip_index[j] = i;
 
-			if (sd->status.inventory[i].equip & EQP_HAND_R) {
+			if (sd->inventory.u.items_inventory[i].equip & EQP_HAND_R) {
 				if (sd->inventory_data[i])
 					sd->weapontype1 = sd->inventory_data[i]->look;
 				else
 					sd->weapontype1 = 0;
 			}
 
-			if( sd->status.inventory[i].equip & EQP_HAND_L ) {
+			if( sd->inventory.u.items_inventory[i].equip & EQP_HAND_L ) {
 				if( sd->inventory_data[i] && sd->inventory_data[i]->type == IT_WEAPON )
 					sd->weapontype2 = sd->inventory_data[i]->look;
 				else
@@ -789,7 +789,7 @@ void pc_setequipindex(struct map_session_data *sd)
 //static int pc_isAllowedCardOn(struct map_session_data *sd,int s,int eqindex,int flag)
 //{
 //	int i;
-//	struct item *item = &sd->status.inventory[eqindex];
+//	struct item *item = &sd->inventory.u.items_inventory[eqindex];
 //	struct item_data *data;
 //
 //	//Crafted/made/hatched items.
@@ -828,7 +828,7 @@ bool pc_isequipped(struct map_session_data *sd, unsigned short nameid)
 		if( sd->inventory_data[index]->nameid == nameid )
 			return true;
 		for( j = 0; j < sd->inventory_data[index]->slot; j++ ){
-			if( sd->status.inventory[index].card[j] == nameid )
+			if( sd->inventory.u.items_inventory[index].card[j] == nameid )
 				return true;
 		}
 	}
@@ -1067,10 +1067,6 @@ uint8 pc_isequip(struct map_session_data *sd,int n)
 bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_time, int group_id, struct mmo_charstatus *st, bool changing_mapservers)
 {
 	int i;
-#ifdef BOUND_ITEMS
-	int j;
-	int idxlist[MAX_INVENTORY];
-#endif
 	unsigned long tick = gettick();
 	uint32 ip = session[sd->fd]->client_addr;
 
@@ -1105,7 +1101,8 @@ bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_
 	sd->status.body = cap_value(sd->status.body,MIN_BODY_STYLE,MAX_BODY_STYLE);
 
 	//Initializations to null/0 unneeded since map_session_data was filled with 0 upon allocation.
-	if(!sd->status.hp) pc_setdead(sd);
+	if (!sd->status.hp)
+		pc_setdead(sd);
 	sd->state.connect_new = 1;
 
 	sd->followtimer = INVALID_TIMER; // [MouseJstr]
@@ -1155,8 +1152,11 @@ bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_
 	if (!(battle_config.display_skill_fail&2))
 		sd->state.showdelay = 1;
 
-	pc_setinventorydata(sd);
-	pc_setequipindex(sd);
+	memset(&sd->inventory, 0, sizeof(struct s_storage));
+	memset(&sd->cart, 0, sizeof(struct s_storage));
+	memset(&sd->storage, 0, sizeof(struct s_storage));
+	memset(&sd->premiumStorage, 0, sizeof(struct s_storage));
+	memset(&sd->equip_index, -1, sizeof(sd->equip_index));
 
 	if( sd->status.option&OPTION_INVISIBLE && !pc_can_use_command( sd, "hide", COMMAND_ATCOMMAND ) ){
 		sd->status.option &= ~OPTION_INVISIBLE;
@@ -1165,8 +1165,7 @@ bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_
 	status_change_init(&sd->bl);
 
 	sd->sc.option = sd->status.option; //This is the actual option used in battle.
-	//Set here because we need the inventory data for weapon sprite parsing.
-	status_set_viewdata(&sd->bl, sd->status.class_);
+
 	unit_dataset(&sd->bl);
 
 	sd->guild_x = -1;
@@ -1247,20 +1246,8 @@ bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_
 		clif_changemap(sd,sd->bl.m,sd->bl.x,sd->bl.y);
 	}
 
-	/**
-	 * Check if player have any item cooldowns on
-	 **/
-	pc_itemcd_do(sd,true);
 	pc_validate_skill(sd);
 
-#ifdef BOUND_ITEMS
-	// Party bound item check
-	if(sd->status.party_id == 0 && (j = pc_bound_chk(sd,BOUND_PARTY,idxlist))) { // Party was deleted while character offline
-		for(i=0;i<j;i++)
-			pc_delitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_OTHER);
-	}
-#endif
-
 	/* [Ind] */
 	sd->sc_display = NULL;
 	sd->sc_display_count = 0;
@@ -1336,6 +1323,8 @@ bool pc_set_hate_mob(struct map_session_data *sd, int pos, struct block_list *bl
 
 /*==========================================
  * Invoked once after the char/account/account2 registry variables are received. [Skotlex]
+ * We didn't receive item information at this point so DO NOT attempt to do item operations here.
+ * See intif_parse_StorageReceived() for item operations [lighta]
  *------------------------------------------*/
 void pc_reg_received(struct map_session_data *sd)
 {
@@ -1415,6 +1404,10 @@ void pc_reg_received(struct map_session_data *sd)
 		return;
 	sd->state.active = 1;
 
+	intif_storage_request(sd,TABLE_STORAGE, 0, STOR_MODE_ALL); // Request storage data
+	intif_storage_request(sd,TABLE_CART, 0, STOR_MODE_ALL); // Request cart data
+	intif_storage_request(sd,TABLE_INVENTORY, 0, STOR_MODE_ALL); // Request inventory data
+
 	if (sd->status.party_id)
 		party_member_joined(sd);
 	if (sd->status.guild_id)
@@ -1437,13 +1430,8 @@ void pc_reg_received(struct map_session_data *sd)
 	if (!chrif_auth_finished(sd))
 		ShowError("pc_reg_received: Failed to properly remove player %d:%d from logging db!\n", sd->status.account_id, sd->status.char_id);
 
-	pc_load_combo(sd);
-
-	status_calc_pc(sd, (enum e_status_calc_opt)(SCO_FIRST|SCO_FORCE));
-	chrif_scdata_request(sd->status.account_id, sd->status.char_id);
 	chrif_skillcooldown_request(sd->status.account_id, sd->status.char_id);
 	chrif_bsdata_request(sd->status.char_id);
-	sd->storage_size = MIN_STORAGE; //default to min
 #ifdef VIP_ENABLE
 	sd->vip.time = 0;
 	sd->vip.enabled = 0;
@@ -1471,13 +1459,6 @@ void pc_reg_received(struct map_session_data *sd)
 
 		clif_changeoption( &sd->bl );
 	}
-
-	pc_check_expiration(sd);
-
-	if( sd->state.autotrade ) {
-		clif_parse_LoadEndAck(sd->fd, sd);
-		sd->autotrade_tid = add_timer(gettick() + battle_config.feature_autotrade_open_delay, pc_autotrade_timer, sd->bl.id, 0);
-	}
 }
 
 static int pc_calc_skillpoint(struct map_session_data* sd)
@@ -2269,7 +2250,7 @@ void pc_delautobonus(struct map_session_data* sd, struct s_autobonus *autobonus,
 					//Create a list of all equipped positions to see if all items needed for the autobonus are still present [Playtester]
 					for(j = 0; j < EQI_MAX; j++) {
 						if(sd->equip_index[j] >= 0)
-							equip_pos_idx |= sd->status.inventory[sd->equip_index[j]].equip;
+							equip_pos_idx |= sd->inventory.u.items_inventory[sd->equip_index[j]].equip;
 					}
 					if((equip_pos_idx&autobonus[i].pos) == autobonus[i].pos)
 						script_run_autobonus(autobonus[i].bonus_script,sd,autobonus[i].pos);
@@ -2303,7 +2284,7 @@ void pc_exeautobonus(struct map_session_data *sd,struct s_autobonus *autobonus)
 		//Create a list of all equipped positions to see if all items needed for the autobonus are still present [Playtester]
 		for(j = 0; j < EQI_MAX; j++) {
 			if(sd->equip_index[j] >= 0)
-				equip_pos_idx |= sd->status.inventory[sd->equip_index[j]].equip;
+				equip_pos_idx |= sd->inventory.u.items_inventory[sd->equip_index[j]].equip;
 		}
 		if((equip_pos_idx&autobonus->pos) == autobonus->pos)
 			script_run_autobonus(autobonus->other_script,sd,autobonus->pos);
@@ -4108,31 +4089,31 @@ int pc_insert_card(struct map_session_data* sd, int idx_card, int idx_equip)
 		return 0; //Invalid item index.
 	if( idx_card < 0 || idx_card >= MAX_INVENTORY || sd->inventory_data[idx_card] == NULL )
 		return 0; //Invalid card index.
-	if( sd->status.inventory[idx_equip].nameid <= 0 || sd->status.inventory[idx_equip].amount < 1 )
+	if( sd->inventory.u.items_inventory[idx_equip].nameid <= 0 || sd->inventory.u.items_inventory[idx_equip].amount < 1 )
 		return 0; // target item missing
-	if( sd->status.inventory[idx_card].nameid <= 0 || sd->status.inventory[idx_card].amount < 1 )
+	if( sd->inventory.u.items_inventory[idx_card].nameid <= 0 || sd->inventory.u.items_inventory[idx_card].amount < 1 )
 		return 0; // target card missing
 	if( sd->inventory_data[idx_equip]->type != IT_WEAPON && sd->inventory_data[idx_equip]->type != IT_ARMOR )
 		return 0; // only weapons and armor are allowed
 	if( sd->inventory_data[idx_card]->type != IT_CARD )
 		return 0; // must be a card
-	if( sd->status.inventory[idx_equip].identify == 0 )
+	if( sd->inventory.u.items_inventory[idx_equip].identify == 0 )
 		return 0; // target must be identified
-	if( itemdb_isspecial(sd->status.inventory[idx_equip].card[0]) )
+	if( itemdb_isspecial(sd->inventory.u.items_inventory[idx_equip].card[0]) )
 		return 0; // card slots reserved for other purposes
 	if( (sd->inventory_data[idx_equip]->equip & sd->inventory_data[idx_card]->equip) == 0 )
 		return 0; // card cannot be compounded on this item type
 	if( sd->inventory_data[idx_equip]->type == IT_WEAPON && sd->inventory_data[idx_card]->equip == EQP_SHIELD )
 		return 0; // attempted to place shield card on left-hand weapon.
-	if( sd->status.inventory[idx_equip].equip != 0 )
+	if( sd->inventory.u.items_inventory[idx_equip].equip != 0 )
 		return 0; // item must be unequipped
 
-	ARR_FIND( 0, sd->inventory_data[idx_equip]->slot, i, sd->status.inventory[idx_equip].card[i] == 0 );
+	ARR_FIND( 0, sd->inventory_data[idx_equip]->slot, i, sd->inventory.u.items_inventory[idx_equip].card[i] == 0 );
 	if( i == sd->inventory_data[idx_equip]->slot )
 		return 0; // no free slots
 
 	// remember the card id to insert
-	nameid = sd->status.inventory[idx_card].nameid;
+	nameid = sd->inventory.u.items_inventory[idx_card].nameid;
 
 	if( pc_delitem(sd,idx_card,1,1,0,LOG_TYPE_OTHER) == 1 )
 	{// failed
@@ -4140,9 +4121,9 @@ int pc_insert_card(struct map_session_data* sd, int idx_card, int idx_equip)
 	}
 	else
 	{// success
-		log_pick_pc(sd, LOG_TYPE_OTHER, -1, &sd->status.inventory[idx_equip]);
-		sd->status.inventory[idx_equip].card[i] = nameid;
-		log_pick_pc(sd, LOG_TYPE_OTHER,  1, &sd->status.inventory[idx_equip]);
+		log_pick_pc(sd, LOG_TYPE_OTHER, -1, &sd->inventory.u.items_inventory[idx_equip]);
+		sd->inventory.u.items_inventory[idx_equip].card[i] = nameid;
+		log_pick_pc(sd, LOG_TYPE_OTHER,  1, &sd->inventory.u.items_inventory[idx_equip]);
 		clif_insert_card(sd,idx_equip,idx_card,0);
 	}
 
@@ -4216,8 +4197,8 @@ char pc_checkadditem(struct map_session_data *sd, unsigned short nameid, int amo
 
 	for(i=0;i<MAX_INVENTORY;i++){
 		// FIXME: This does not consider the checked item's cards, thus could check a wrong slot for stackability.
-		if(sd->status.inventory[i].nameid==nameid){
-			if( amount > MAX_AMOUNT - sd->status.inventory[i].amount || ( data->stack.inventory && amount > data->stack.amount - sd->status.inventory[i].amount ) )
+		if(sd->inventory.u.items_inventory[i].nameid == nameid){
+			if( amount > MAX_AMOUNT - sd->inventory.u.items_inventory[i].amount || ( data->stack.inventory && amount > data->stack.amount - sd->inventory.u.items_inventory[i].amount ) )
 				return CHKADDITEM_OVERAMOUNT;
 			return CHKADDITEM_EXIST;
 		}
@@ -4239,7 +4220,7 @@ uint8 pc_inventoryblank(struct map_session_data *sd)
 	nullpo_ret(sd);
 
 	for(i = 0, b = 0; i < MAX_INVENTORY; i++){
-		if(sd->status.inventory[i].nameid==0)
+		if(sd->inventory.u.items_inventory[i].nameid == 0)
 			b++;
 	}
 
@@ -4450,7 +4431,7 @@ short pc_search_inventory(struct map_session_data *sd, unsigned short nameid) {
 	short i;
 	nullpo_retr(-1, sd);
 
-	ARR_FIND( 0, MAX_INVENTORY, i, sd->status.inventory[i].nameid == nameid && (sd->status.inventory[i].amount > 0 || nameid == 0) );
+	ARR_FIND( 0, MAX_INVENTORY, i, sd->inventory.u.items_inventory[i].nameid == nameid && (sd->inventory.u.items_inventory[i].amount > 0 || nameid == 0) );
 	return ( i < MAX_INVENTORY ) ? i : -1;
 }
 
@@ -4501,16 +4482,14 @@ char pc_additem(struct map_session_data *sd,struct item *item,int amount,e_log_p
 	// Stackable | Non Rental
 	if( itemdb_isstackable2(id) && item->expire_time == 0 ) {
 		for( i = 0; i < MAX_INVENTORY; i++ ) {
-			if( sd->status.inventory[i].nameid == item->nameid &&
-				sd->status.inventory[i].bound == item->bound &&
-				sd->status.inventory[i].expire_time == 0 &&
-				sd->status.inventory[i].unique_id == item->unique_id &&
-				memcmp(&sd->status.inventory[i].card, &item->card, sizeof(item->card)) == 0
-				)
-			{
-				if( amount > MAX_AMOUNT - sd->status.inventory[i].amount || ( id->stack.inventory && amount > id->stack.amount - sd->status.inventory[i].amount ) )
+			if( sd->inventory.u.items_inventory[i].nameid == item->nameid &&
+				sd->inventory.u.items_inventory[i].bound == item->bound &&
+				sd->inventory.u.items_inventory[i].expire_time == 0 &&
+				sd->inventory.u.items_inventory[i].unique_id == item->unique_id &&
+				memcmp(&sd->inventory.u.items_inventory[i].card, &item->card, sizeof(item->card)) == 0 ) {
+				if( amount > MAX_AMOUNT - sd->inventory.u.items_inventory[i].amount || ( id->stack.inventory && amount > id->stack.amount - sd->inventory.u.items_inventory[i].amount ) )
 					return ADDITEM_OVERAMOUNT;
-				sd->status.inventory[i].amount += amount;
+				sd->inventory.u.items_inventory[i].amount += amount;
 				clif_additem(sd,i,amount,0);
 				break;
 			}
@@ -4522,24 +4501,24 @@ char pc_additem(struct map_session_data *sd,struct item *item,int amount,e_log_p
 		if( i < 0 )
 			return ADDITEM_OVERITEM;
 
-		memcpy(&sd->status.inventory[i], item, sizeof(sd->status.inventory[0]));
+		memcpy(&sd->inventory.u.items_inventory[i], item, sizeof(sd->inventory.u.items_inventory[0]));
 		// clear equip and favorite fields first, just in case
 		if( item->equip )
-			sd->status.inventory[i].equip = 0;
+			sd->inventory.u.items_inventory[i].equip = 0;
 		if( item->favorite )
-			sd->status.inventory[i].favorite = 0;
+			sd->inventory.u.items_inventory[i].favorite = 0;
 
-		sd->status.inventory[i].amount = amount;
+		sd->inventory.u.items_inventory[i].amount = amount;
 		sd->inventory_data[i] = id;
 		sd->last_addeditem_index = i;
 
 		if (!itemdb_isstackable2(id) || id->flag.guid)
-			sd->status.inventory[i].unique_id = item->unique_id ? item->unique_id : pc_generate_unique_id(sd);
+			sd->inventory.u.items_inventory[i].unique_id = item->unique_id ? item->unique_id : pc_generate_unique_id(sd);
 
 		clif_additem(sd,i,amount,0);
 	}
 
-	log_pick_pc(sd, log_type, amount, &sd->status.inventory[i]);
+	log_pick_pc(sd, log_type, amount, &sd->inventory.u.items_inventory[i]);
 
 	sd->weight += w;
 	clif_updatestatus(sd,SP_WEIGHT);
@@ -4550,11 +4529,11 @@ char pc_additem(struct map_session_data *sd,struct item *item,int amount,e_log_p
 	/* rental item check */
 	if( item->expire_time ) {
 		if( time(NULL) > item->expire_time ) {
-			clif_rental_expired(sd->fd, i, sd->status.inventory[i].nameid);
-			pc_delitem(sd, i, sd->status.inventory[i].amount, 1, 0, LOG_TYPE_OTHER);
+			clif_rental_expired(sd->fd, i, sd->inventory.u.items_inventory[i].nameid);
+			pc_delitem(sd, i, sd->inventory.u.items_inventory[i].amount, 1, 0, LOG_TYPE_OTHER);
 		} else {
 			unsigned int seconds = (unsigned int)( item->expire_time - time(NULL) );
-			clif_rental_time(sd->fd, sd->status.inventory[i].nameid, seconds);
+			clif_rental_time(sd->fd, sd->inventory.u.items_inventory[i].nameid, seconds);
 			pc_inventory_rental_add(sd, seconds);
 		}
 	}
@@ -4576,17 +4555,17 @@ char pc_delitem(struct map_session_data *sd,int n,int amount,int type, short rea
 {
 	nullpo_retr(1, sd);
 
-	if(n < 0 || sd->status.inventory[n].nameid==0 || amount <= 0 || sd->status.inventory[n].amount<amount || sd->inventory_data[n] == NULL)
+	if(n < 0 || sd->inventory.u.items_inventory[n].nameid == 0 || amount <= 0 || sd->inventory.u.items_inventory[n].amount<amount || sd->inventory_data[n] == NULL)
 		return 1;
 
-	log_pick_pc(sd, log_type, -amount, &sd->status.inventory[n]);
+	log_pick_pc(sd, log_type, -amount, &sd->inventory.u.items_inventory[n]);
 
-	sd->status.inventory[n].amount -= amount;
+	sd->inventory.u.items_inventory[n].amount -= amount;
 	sd->weight -= sd->inventory_data[n]->weight*amount ;
-	if( sd->status.inventory[n].amount <= 0 ){
-		if(sd->status.inventory[n].equip)
+	if( sd->inventory.u.items_inventory[n].amount <= 0 ){
+		if(sd->inventory.u.items_inventory[n].equip)
 			pc_unequipitem(sd,n,3);
-		memset(&sd->status.inventory[n],0,sizeof(sd->status.inventory[0]));
+		memset(&sd->inventory.u.items_inventory[n],0,sizeof(sd->inventory.u.items_inventory[0]));
 		sd->inventory_data[n] = NULL;
 	}
 	if(!(type&1))
@@ -4614,9 +4593,9 @@ bool pc_dropitem(struct map_session_data *sd,int n,int amount)
 	if(amount <= 0)
 		return false;
 
-	if(sd->status.inventory[n].nameid <= 0 ||
-		sd->status.inventory[n].amount <= 0 ||
-		sd->status.inventory[n].amount < amount ||
+	if(sd->inventory.u.items_inventory[n].nameid <= 0 ||
+		sd->inventory.u.items_inventory[n].amount <= 0 ||
+		sd->inventory.u.items_inventory[n].amount < amount ||
 		sd->state.trading || sd->state.vending ||
 		!sd->inventory_data[n] //pc_delitem would fail on this case.
 		)
@@ -4628,13 +4607,13 @@ bool pc_dropitem(struct map_session_data *sd,int n,int amount)
 		return false; //Can't drop items in nodrop mapflag maps.
 	}
 
-	if( !pc_candrop(sd,&sd->status.inventory[n]) )
+	if( !pc_candrop(sd,&sd->inventory.u.items_inventory[n]) )
 	{
 		clif_displaymessage (sd->fd, msg_txt(sd,263));
 		return false;
 	}
 
-	if (!map_addflooritem(&sd->status.inventory[n], amount, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 2, 0))
+	if (!map_addflooritem(&sd->inventory.u.items_inventory[n], amount, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 2, 0))
 		return false;
 
 	pc_delitem(sd, n, amount, 1, 0, LOG_TYPE_PICKDROP_PLAYER);
@@ -4731,7 +4710,7 @@ bool pc_isUseitem(struct map_session_data *sd,int n)
 	nullpo_ret(sd);
 
 	item = sd->inventory_data[n];
-	nameid = sd->status.inventory[n].nameid;
+	nameid = sd->inventory.u.items_inventory[n].nameid;
 
 	if( item == NULL )
 		return false;
@@ -4928,7 +4907,7 @@ int pc_useitem(struct map_session_data *sd,int n)
 			return 0;
 #endif
 	}
-	item = sd->status.inventory[n];
+	item = sd->inventory.u.items_inventory[n];
 	id = sd->inventory_data[n];
 
 	if (item.nameid == 0 || item.amount <= 0)
@@ -5042,17 +5021,14 @@ unsigned char pc_cart_additem(struct map_session_data *sd,struct item *item,int
 	if( (w = data->weight*amount) + sd->cart_weight > sd->cart_weight_max )
 		return 1;
 
-	// ID no longer points to inventory/kafra ID. While we get a new one we don't want to mess up vending creation.
-	item->id = 0;
-
 	i = MAX_CART;
 	if( itemdb_isstackable2(data) && !item->expire_time )
 	{
 		for (i = 0; i < MAX_CART; i++) {
-			if (sd->status.cart[i].nameid == item->nameid
-				&& sd->status.cart[i].bound == item->bound
-				&& sd->status.cart[i].unique_id == item->unique_id
-				&& memcmp(sd->status.cart[i].card, item->card, sizeof(item->card)) == 0
+			if (sd->cart.u.items_cart[i].nameid == item->nameid
+				&& sd->cart.u.items_cart[i].bound == item->bound
+				&& sd->cart.u.items_cart[i].unique_id == item->unique_id
+				&& memcmp(sd->cart.u.items_cart[i].card, item->card, sizeof(item->card)) == 0
 				)
 				break;
 		}
@@ -5060,25 +5036,26 @@ unsigned char pc_cart_additem(struct map_session_data *sd,struct item *item,int
 
 	if( i < MAX_CART )
 	{// item already in cart, stack it
-		if( amount > MAX_AMOUNT - sd->status.cart[i].amount || ( data->stack.cart && amount > data->stack.amount - sd->status.cart[i].amount ) )
+		if( amount > MAX_AMOUNT - sd->cart.u.items_cart[i].amount || ( data->stack.cart && amount > data->stack.amount - sd->cart.u.items_cart[i].amount ) )
 			return 2; // no slot
 
-		sd->status.cart[i].amount+=amount;
+		sd->cart.u.items_cart[i].amount += amount;
 		clif_cart_additem(sd,i,amount,0);
 	}
 	else
 	{// item not stackable or not present, add it
-		ARR_FIND( 0, MAX_CART, i, sd->status.cart[i].nameid == 0 );
+		ARR_FIND( 0, MAX_CART, i, sd->cart.u.items_cart[i].nameid == 0 );
 		if( i == MAX_CART )
 			return 2; // no slot
 
-		memcpy(&sd->status.cart[i],item,sizeof(sd->status.cart[0]));
-		sd->status.cart[i].amount=amount;
+		memcpy(&sd->cart.u.items_cart[i],item,sizeof(sd->cart.u.items_cart[0]));
+		sd->cart.u.items_cart[i].id = 0;
+		sd->cart.u.items_cart[i].amount = amount;
 		sd->cart_num++;
 		clif_cart_additem(sd,i,amount,0);
 	}
-	sd->status.cart[i].favorite = 0;/* clear */
-	log_pick_pc(sd, log_type, amount, &sd->status.cart[i]);
+	sd->cart.u.items_cart[i].favorite = 0; // clear
+	log_pick_pc(sd, log_type, amount, &sd->cart.u.items_cart[i]);
 
 	sd->cart_weight += w;
 	clif_updatestatus(sd,SP_CARTINFO);
@@ -5093,16 +5070,16 @@ void pc_cart_delitem(struct map_session_data *sd,int n,int amount,int type,e_log
 {
 	nullpo_retv(sd);
 
-	if(sd->status.cart[n].nameid == 0 ||
-	   sd->status.cart[n].amount<amount)
+	if(sd->cart.u.items_cart[n].nameid == 0 ||
+		sd->cart.u.items_cart[n].amount < amount)
 		return;
 
-	log_pick_pc(sd, log_type, -amount, &sd->status.cart[n]);
+	log_pick_pc(sd, log_type, -amount, &sd->cart.u.items_cart[n]);
 
-	sd->status.cart[n].amount -= amount;
-	sd->cart_weight -= itemdb_weight(sd->status.cart[n].nameid)*amount ;
-	if(sd->status.cart[n].amount <= 0){
-		memset(&sd->status.cart[n],0,sizeof(sd->status.cart[0]));
+	sd->cart.u.items_cart[n].amount -= amount;
+	sd->cart_weight -= itemdb_weight(sd->cart.u.items_cart[n].nameid) * amount;
+	if(sd->cart.u.items_cart[n].amount <= 0) {
+		memset(&sd->cart.u.items_cart[n],0,sizeof(sd->cart.u.items_cart[0]));
 		sd->cart_num--;
 	}
 	if(!type) {
@@ -5124,7 +5101,7 @@ void pc_putitemtocart(struct map_session_data *sd,int idx,int amount)
 	if (idx < 0 || idx >= MAX_INVENTORY) //Invalid index check [Skotlex]
 		return;
 
-	item_data = &sd->status.inventory[idx];
+	item_data = &sd->inventory.u.items_inventory[idx];
 
 	if( item_data->nameid == 0 || amount < 1 || item_data->amount < amount || sd->state.vending )
 		return;
@@ -5149,7 +5126,7 @@ int pc_cartitem_amount(struct map_session_data* sd, int idx, int amount)
 
 	nullpo_retr(-1, sd);
 
-	item_data = &sd->status.cart[idx];
+	item_data = &sd->cart.u.items_cart[idx];
 	if( item_data->nameid == 0 || item_data->amount == 0 )
 		return -1;
 
@@ -5169,7 +5146,7 @@ void pc_getitemfromcart(struct map_session_data *sd,int idx,int amount)
 	if (idx < 0 || idx >= MAX_CART) //Invalid index check [Skotlex]
 		return;
 
-	item_data=&sd->status.cart[idx];
+	item_data=&sd->cart.u.items_cart[idx];
 
 	if(item_data->nameid == 0 || amount < 1 || item_data->amount < amount || sd->state.vending )
 		return;
@@ -5191,9 +5168,9 @@ void pc_getitemfromcart(struct map_session_data *sd,int idx,int amount)
  *------------------------------------------*/
 int pc_bound_chk(TBL_PC *sd,enum bound_type type,int *idxlist)
 {
-	int i=0, j=0;
-	for(i=0;i<MAX_INVENTORY;i++){
-		if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0 && sd->status.inventory[i].bound == type) {
+	int i = 0, j = 0;
+	for(i = 0; i < MAX_INVENTORY; i++) {
+		if(sd->inventory.u.items_inventory[i].nameid > 0 && sd->inventory.u.items_inventory[i].amount > 0 && sd->inventory.u.items_inventory[i].bound == type) {
 			idxlist[j] = i;
 			j++;
 		}
@@ -5769,7 +5746,7 @@ bool pc_checkequip2(struct map_session_data *sd, unsigned short nameid, int min,
 		if(equip_bitmask[i]) {
 			int idx = sd->equip_index[i];
 
-			if (sd->status.inventory[idx].nameid == nameid)
+			if (sd->inventory.u.items_inventory[idx].nameid == nameid)
 				return true;
 		}
 	}
@@ -7782,8 +7759,8 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 				int eq_num=0,eq_n[MAX_INVENTORY];
 				memset(eq_n,0,sizeof(eq_n));
 				for(i=0;i<MAX_INVENTORY;i++) {
-					if( (type == 1 && !sd->status.inventory[i].equip)
-						|| (type == 2 && sd->status.inventory[i].equip)
+					if( (type == 1 && !sd->inventory.u.items_inventory[i].equip)
+						|| (type == 2 && sd->inventory.u.items_inventory[i].equip)
 						||  type == 3)
 					{
 						int l;
@@ -7797,7 +7774,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 				if(eq_num > 0){
 					int n = eq_n[rnd()%eq_num];
 					if(rnd()%10000 < per) {
-						if(sd->status.inventory[n].equip)
+						if(sd->inventory.u.items_inventory[n].equip)
 							pc_unequipitem(sd,n,3);
 						pc_dropitem(sd,n,1);
 					}
@@ -7805,12 +7782,12 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
 			}
 			else if(id > 0) {
 				for(i=0;i<MAX_INVENTORY;i++){
-					if(sd->status.inventory[i].nameid == id
+					if(sd->inventory.u.items_inventory[i].nameid == id
 						&& rnd()%10000 < per
-						&& ((type == 1 && !sd->status.inventory[i].equip)
-							|| (type == 2 && sd->status.inventory[i].equip)
+						&& ((type == 1 && !sd->inventory.u.items_inventory[i].equip)
+							|| (type == 2 && sd->inventory.u.items_inventory[i].equip)
 							|| type == 3) ){
-						if(sd->status.inventory[i].equip)
+						if(sd->inventory.u.items_inventory[i].equip)
 							pc_unequipitem(sd,i,3);
 						pc_dropitem(sd,i,1);
 						break;
@@ -9402,16 +9379,16 @@ static int pc_checkcombo(struct map_session_data *sd, struct item_data *data) {
 							continue;
 					}
 					combo_idx[j].idx = index;
-					pos |= sd->status.inventory[index].equip;
+					pos |= sd->inventory.u.items_inventory[index].equip;
 					found = true;
 					break;
 				} else { //Cards
 					uint16 z;
-					if ( sd->inventory_data[index]->slot == 0 || itemdb_isspecial(sd->status.inventory[index].card[0]) )
+					if ( sd->inventory_data[index]->slot == 0 || itemdb_isspecial(sd->inventory.u.items_inventory[index].card[0]) )
 						continue;
 					for (z = 0; z < sd->inventory_data[index]->slot; z++) {
 						bool do_continue=false;			
-						if (sd->status.inventory[index].card[z] != id)
+						if (sd->inventory.u.items_inventory[index].card[z] != id)
 							continue;
 						if(j>0){
 							int c1, c2;
@@ -9430,7 +9407,7 @@ static int pc_checkcombo(struct map_session_data *sd, struct item_data *data) {
 							continue;
 						combo_idx[j].idx = index;
 						combo_idx[j].card[z] = id;
-						pos |= sd->status.inventory[index].equip;
+						pos |= sd->inventory.u.items_inventory[index].equip;
 						found = true;
  						break;
  					}
@@ -9536,13 +9513,13 @@ int pc_load_combo(struct map_session_data *sd) {
 			continue;
 		if( id->combos_count )
 			ret += pc_checkcombo(sd,id);
-		if(!itemdb_isspecial(sd->status.inventory[idx].card[0])) {
+		if(!itemdb_isspecial(sd->inventory.u.items_inventory[idx].card[0])) {
 			struct item_data *data;
 			int j;
 			for( j = 0; j < id->slot; j++ ) {
-				if (!sd->status.inventory[idx].card[j])
+				if (!sd->inventory.u.items_inventory[idx].card[j])
 					continue;
-				if ( ( data = itemdb_exists(sd->status.inventory[idx].card[j]) ) != NULL ) {
+				if ( ( data = itemdb_exists(sd->inventory.u.items_inventory[idx].card[j]) ) != NULL ) {
 					if( data->combos_count )
 						ret += pc_checkcombo(sd,data);
 				}
@@ -9577,14 +9554,14 @@ bool pc_equipitem(struct map_session_data *sd,short n,int req_pos)
 	pos = pc_equippoint(sd,n); //With a few exceptions, item should go in all specified slots.
 
 	if(battle_config.battle_log)
-		ShowInfo("equip %hu(%d) %x:%x\n",sd->status.inventory[n].nameid,n,id?id->equip:0,req_pos);
+		ShowInfo("equip %hu (%d) %x:%x\n",sd->inventory.u.items_inventory[n].nameid,n,id?id->equip:0,req_pos);
 
 	if((res = pc_isequip(sd,n))) {
 		clif_equipitemack(sd,n,0,res);	// fail
 		return false;
 	}
 
-	if (!(pos&req_pos) || sd->status.inventory[n].equip != 0 || sd->status.inventory[n].attribute==1 ) { // [Valaris]
+	if (!(pos&req_pos) || sd->inventory.u.items_inventory[n].equip != 0 || sd->inventory.u.items_inventory[n].attribute==1 ) { // [Valaris]
 		clif_equipitemack(sd,n,0,ITEM_EQUIP_ACK_FAIL);	// fail
 		return false;
 	}
@@ -9626,8 +9603,8 @@ bool pc_equipitem(struct map_session_data *sd,short n,int req_pos)
 		}
 	}
 
-	if (id->flag.bindOnEquip && !sd->status.inventory[n].bound) {
-		sd->status.inventory[n].bound = (char)battle_config.default_bind_on_equip;
+	if (id->flag.bindOnEquip && !sd->inventory.u.items_inventory[n].bound) {
+		sd->inventory.u.items_inventory[n].bound = (char)battle_config.default_bind_on_equip;
 		clif_notify_bindOnEquip(sd,n);
 	}
 
@@ -9674,7 +9651,7 @@ bool pc_equipitem(struct map_session_data *sd,short n,int req_pos)
 	else
 		clif_equipitemack(sd,n,pos,ITEM_EQUIP_ACK_OK);
 
-	sd->status.inventory[n].equip=pos;
+	sd->inventory.u.items_inventory[n].equip = pos;
 
 	if(pos & EQP_HAND_R) {
 		if(id)
@@ -9712,14 +9689,14 @@ bool pc_equipitem(struct map_session_data *sd,short n,int req_pos)
 	/* check for combos (MUST be before status_calc_pc) */
 	if( id->combos_count )
 		pc_checkcombo(sd,id);
-	if(itemdb_isspecial(sd->status.inventory[n].card[0]))
+	if(itemdb_isspecial(sd->inventory.u.items_inventory[n].card[0]))
 		; //No cards
 	else {
 		for( i = 0; i < id->slot; i++ ) {
 			struct item_data *data;
-			if (!sd->status.inventory[n].card[i])
+			if (!sd->inventory.u.items_inventory[n].card[i])
 				continue;
-			if ( ( data = itemdb_exists(sd->status.inventory[n].card[i]) ) != NULL ) {
+			if ( ( data = itemdb_exists(sd->inventory.u.items_inventory[n].card[i]) ) != NULL ) {
 				if( data->combos_count )
 					pc_checkcombo(sd,data);
 			}
@@ -9735,14 +9712,14 @@ bool pc_equipitem(struct map_session_data *sd,short n,int req_pos)
 		//only run the script if item isn't restricted
 		if (id->equip_script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) || !itemdb_isNoEquip(id,sd->bl.m)))
 			run_script(id->equip_script,0,sd->bl.id,fake_nd->bl.id);
-		if(itemdb_isspecial(sd->status.inventory[n].card[0]))
+		if(itemdb_isspecial(sd->inventory.u.items_inventory[n].card[0]))
 			; //No cards
 		else {
 			for( i = 0; i < id->slot; i++ ) {
 				struct item_data *data;
-				if (!sd->status.inventory[n].card[i])
+				if (!sd->inventory.u.items_inventory[n].card[i])
 					continue;
-				if ( ( data = itemdb_exists(sd->status.inventory[n].card[i]) ) != NULL ) {
+				if ( ( data = itemdb_exists(sd->inventory.u.items_inventory[n].card[i]) ) != NULL ) {
 					if (data->equip_script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) || !itemdb_isNoEquip(data,sd->bl.m)))
 						run_script(data->equip_script,0,sd->bl.id,fake_nd->bl.id);
 				}
@@ -9772,7 +9749,7 @@ bool pc_unequipitem(struct map_session_data *sd, int n, int flag) {
 		clif_unequipitemack(sd,0,0,0);
 		return false;
 	}
-	if (!sd->status.inventory[n].equip) {
+	if (!sd->inventory.u.items_inventory[n].equip) {
 		clif_unequipitemack(sd,n,0,0);
 		return false; //Nothing to unequip
 	}
@@ -9790,14 +9767,18 @@ bool pc_unequipitem(struct map_session_data *sd, int n, int flag) {
 	}
 
 	if (battle_config.battle_log)
-		ShowInfo("unequip %d %x:%x\n",n,pc_equippoint(sd,n),sd->status.inventory[n].equip);
+		ShowInfo("unequip %d %x:%x\n",n,pc_equippoint(sd,n),sd->inventory.u.items_inventory[n].equip);
 
+	if (!sd->inventory.u.items_inventory[n].equip) { //Nothing to unequip
+		clif_unequipitemack(sd, n, 0, 0);
+		return false;
+	}
 	for(i = 0; i < EQI_MAX; i++) {
-		if (sd->status.inventory[n].equip & equip_bitmask[i])
+		if (sd->inventory.u.items_inventory[n].equip & equip_bitmask[i])
 			sd->equip_index[i] = -1;
 	}
 
-	if(sd->status.inventory[n].equip & EQP_HAND_R) {
+	if(sd->inventory.u.items_inventory[n].equip & EQP_HAND_R) {
 		sd->weapontype1 = 0;
 		sd->status.weapon = sd->weapontype2;
 		pc_calcweapontype(sd);
@@ -9805,21 +9786,21 @@ bool pc_unequipitem(struct map_session_data *sd, int n, int flag) {
 		if( !battle_config.dancing_weaponswitch_fix )
 			status_change_end(&sd->bl, SC_DANCING, INVALID_TIMER); // Unequipping => stop dancing.
 	}
-	if(sd->status.inventory[n].equip & EQP_HAND_L) {
+	if(sd->inventory.u.items_inventory[n].equip & EQP_HAND_L) {
 		sd->status.shield = sd->weapontype2 = 0;
 		pc_calcweapontype(sd);
 		clif_changelook(&sd->bl,LOOK_SHIELD,sd->status.shield);
 	}
 
-	if(sd->status.inventory[n].equip & EQP_SHOES)
+	if(sd->inventory.u.items_inventory[n].equip & EQP_SHOES)
 		clif_changelook(&sd->bl,LOOK_SHOES,0);
 
-	clif_unequipitemack(sd,n,sd->status.inventory[n].equip,1);
+	clif_unequipitemack(sd,n,sd->inventory.u.items_inventory[n].equip,1);
 	pc_set_costume_view(sd);
 
 	status_change_end(&sd->bl,SC_HEAT_BARREL,INVALID_TIMER);
 	// On weapon change (right and left hand)
-	if ((sd->status.inventory[n].equip & EQP_ARMS) && sd->inventory_data[n]->type == IT_WEAPON) {
+	if ((sd->inventory.u.items_inventory[n].equip & EQP_ARMS) && sd->inventory_data[n]->type == IT_WEAPON) {
 		if (!sd->sc.data[SC_SEVENWIND] || sd->sc.data[SC_ASPERSIO]) //Check for seven wind (but not level seven!)
 			skill_enchant_elemental_end(&sd->bl, SC_NONE);
 		status_change_end(&sd->bl, SC_FEARBREEZE, INVALID_TIMER);
@@ -9828,7 +9809,7 @@ bool pc_unequipitem(struct map_session_data *sd, int n, int flag) {
 	}
 
 	// On armor change
-	if (sd->status.inventory[n].equip & EQP_ARMOR) {
+	if (sd->inventory.u.items_inventory[n].equip & EQP_ARMOR) {
 		if (sd->sc.data[SC_HOVERING] && sd->inventory_data[n]->nameid == ITEMID_HOVERING_BOOSTER)
 			status_change_end(&sd->bl, SC_HOVERING, INVALID_TIMER);
 		//status_change_end(&sd->bl, SC_BENEDICTIO, INVALID_TIMER); // No longer is removed? Need confirmation
@@ -9839,10 +9820,10 @@ bool pc_unequipitem(struct map_session_data *sd, int n, int flag) {
 	if (sd->inventory_data[n]->type == IT_AMMO)
 		status_change_end(&sd->bl, SC_P_ALTER, INVALID_TIMER);
 
-	if( sd->state.autobonus&sd->status.inventory[n].equip )
-		sd->state.autobonus &= ~sd->status.inventory[n].equip; //Check for activated autobonus [Inkfish]
+	if (sd->state.autobonus&sd->inventory.u.items_inventory[n].equip)
+		sd->state.autobonus &= ~sd->inventory.u.items_inventory[n].equip; //Check for activated autobonus [Inkfish]
 
-	sd->status.inventory[n].equip = 0;
+	sd->inventory.u.items_inventory[n].equip = 0;
 	iflag = sd->npc_item_flag;
 
 	/* check for combos (MUST be before status_calc_pc) */
@@ -9850,15 +9831,15 @@ bool pc_unequipitem(struct map_session_data *sd, int n, int flag) {
 		if( sd->inventory_data[n]->combos_count ) {
 			if( pc_removecombo(sd,sd->inventory_data[n]) )
 				status_cacl = true;
-		} if(itemdb_isspecial(sd->status.inventory[n].card[0]))
+		} if(itemdb_isspecial(sd->inventory.u.items_inventory[n].card[0]))
 			; //No cards
 		else {
 			for( i = 0; i < sd->inventory_data[n]->slot; i++ ) {
 				struct item_data *data;
 
-				if (!sd->status.inventory[n].card[i])
+				if (!sd->inventory.u.items_inventory[n].card[i])
 					continue;
-				if ( ( data = itemdb_exists(sd->status.inventory[n].card[i]) ) != NULL ) {
+				if ( ( data = itemdb_exists(sd->inventory.u.items_inventory[n].card[i]) ) != NULL ) {
 					if( data->combos_count ) {
 						if( pc_removecombo(sd,data) )
 							status_cacl = true;
@@ -9880,15 +9861,15 @@ bool pc_unequipitem(struct map_session_data *sd, int n, int flag) {
 	if (sd->inventory_data[n]) {
 		if (sd->inventory_data[n]->unequip_script)
 			run_script(sd->inventory_data[n]->unequip_script,0,sd->bl.id,fake_nd->bl.id);
-		if(itemdb_isspecial(sd->status.inventory[n].card[0]))
+		if(itemdb_isspecial(sd->inventory.u.items_inventory[n].card[0]))
 			; //No cards
 		else {
 			for( i = 0; i < sd->inventory_data[n]->slot; i++ ) {
 				struct item_data *data;
-				if (!sd->status.inventory[n].card[i])
+				if (!sd->inventory.u.items_inventory[n].card[i])
 					continue;
 
-				if ( ( data = itemdb_exists(sd->status.inventory[n].card[i]) ) != NULL ) {
+				if ( ( data = itemdb_exists(sd->inventory.u.items_inventory[n].card[i]) ) != NULL ) {
 					if( data->unequip_script )
 						run_script(data->unequip_script,0,sd->bl.id,fake_nd->bl.id);
 				}
@@ -9914,10 +9895,10 @@ void pc_checkitem(struct map_session_data *sd) {
 	if( sd->state.vending ) //Avoid reorganizing items when we are vending, as that leads to exploits (pointed out by End of Exam)
 		return;
 
-	pc_check_available_item(sd); // Check for invalid(ated) items.
+	pc_check_available_item(sd, ITMCHK_NONE); // Check for invalid(ated) items.
 
 	for( i = 0; i < MAX_INVENTORY; i++ ) {
-		it = sd->status.inventory[i];
+		it = sd->inventory.u.items_inventory[i];
 
 		if( it.nameid == 0 )
 			continue;
@@ -9944,8 +9925,13 @@ void pc_checkitem(struct map_session_data *sd) {
 
 /*==========================================
  * Checks for unavailable items and removes them.
+ * @param sd: Player data
+ * @param type Forced check:
+ *   1 - Inventory
+ *   2 - Cart
+ *   4 - Storage
  *------------------------------------------*/
-void pc_check_available_item(struct map_session_data *sd)
+void pc_check_available_item(struct map_session_data *sd, uint8 type)
 {
 	int i;
 	unsigned short nameid;
@@ -9953,57 +9939,57 @@ void pc_check_available_item(struct map_session_data *sd)
 
 	nullpo_retv(sd);
 
-	if (battle_config.item_check&0x1) { // Check for invalid(ated) items in inventory.
+	if (battle_config.item_check&ITMCHK_INVENTORY || type&ITMCHK_INVENTORY) { // Check for invalid(ated) items in inventory.
 		for(i = 0; i < MAX_INVENTORY; i++) {
-			nameid = sd->status.inventory[i].nameid;
+			nameid = sd->inventory.u.items_inventory[i].nameid;
 
 			if (!nameid)
 				continue;
 			if (!itemdb_available(nameid)) {
 				sprintf(output, msg_txt(sd, 709), nameid); // Item %hu has been removed from your inventory.
 				clif_displaymessage(sd->fd, output);
-				ShowWarning("Removed invalid/disabled item id %hu from inventory (amount=%d, char_id=%d).\n", nameid, sd->status.inventory[i].amount, sd->status.char_id);
-				pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_OTHER);
+				ShowWarning("Removed invalid/disabled item (ID: %hu, amount: %d) from inventory (char_id: %d).\n", nameid, sd->inventory.u.items_inventory[i].amount, sd->status.char_id);
+				pc_delitem(sd, i, sd->inventory.u.items_inventory[i].amount, 0, 0, LOG_TYPE_OTHER);
 				continue;
 			}
-			if (!sd->status.inventory[i].unique_id && !itemdb_isstackable(nameid))
-				sd->status.inventory[i].unique_id = pc_generate_unique_id(sd);
+			if (!sd->inventory.u.items_inventory[i].unique_id && !itemdb_isstackable(nameid))
+				sd->inventory.u.items_inventory[i].unique_id = pc_generate_unique_id(sd);
 		}
 	}
 
-	if (battle_config.item_check&0x2) { // Check for invalid(ated) items in cart.
+	if (battle_config.item_check&ITMCHK_CART || type&ITMCHK_CART) { // Check for invalid(ated) items in cart.
 		for(i = 0; i < MAX_CART; i++) {
-			nameid = sd->status.cart[i].nameid;
+			nameid = sd->cart.u.items_cart[i].nameid;
 
 			if (!nameid)
 				continue;
 			if (!itemdb_available(nameid)) {
 				sprintf(output, msg_txt(sd, 710), nameid); // Item %hu has been removed from your cart.
 				clif_displaymessage(sd->fd, output);
-				ShowWarning("Removed invalid/disabled item id %hu from cart (amount=%d, char_id=%d).\n", nameid, sd->status.cart[i].amount, sd->status.char_id);
-				pc_cart_delitem(sd, i, sd->status.cart[i].amount, 0, LOG_TYPE_OTHER);
+				ShowWarning("Removed invalid/disabled item (ID: %hu, amount: %d) from cart (char_id: %d).\n", nameid, sd->cart.u.items_cart[i].amount, sd->status.char_id);
+				pc_cart_delitem(sd, i, sd->cart.u.items_cart[i].amount, 0, LOG_TYPE_OTHER);
 				continue;
 			}
-			if (!sd->status.cart[i].unique_id && !itemdb_isstackable(nameid))
-				sd->status.cart[i].unique_id = pc_generate_unique_id(sd);
+			if (!sd->cart.u.items_cart[i].unique_id && !itemdb_isstackable(nameid))
+				sd->cart.u.items_cart[i].unique_id = pc_generate_unique_id(sd);
 		}
 	}
 
-	if (battle_config.item_check&0x4) { // Check for invalid(ated) items in storage.
-		for(i = 0; i < sd->storage_size; i++) {
-			nameid = sd->status.storage.items[i].nameid;
+	if (battle_config.item_check&ITMCHK_STORAGE || type&ITMCHK_STORAGE) { // Check for invalid(ated) items in storage.
+		for(i = 0; i < sd->storage.max_amount; i++) {
+			nameid = sd->storage.u.items_storage[i].nameid;
 
 			if (!nameid)
 				continue;
 			if (!itemdb_available(nameid)) {
 				sprintf(output, msg_txt(sd, 711), nameid); // Item %hu has been removed from your storage.
 				clif_displaymessage(sd->fd, output);
-				ShowWarning("Removed invalid/disabled item id %hu from storage (amount=%d, char_id=%d).\n", nameid, sd->status.storage.items[i].amount, sd->status.char_id);
-				storage_delitem(sd, i, sd->status.storage.items[i].amount);
+				ShowWarning("Removed invalid/disabled item (ID: %hu, amount: %d) from storage (char_id: %d).\n", nameid, sd->storage.u.items_storage[i].amount, sd->status.char_id);
+				storage_delitem(sd, &sd->storage, i, sd->storage.u.items_storage[i].amount);
 				continue;
 			}
-			if (!sd->status.storage.items[i].unique_id && !itemdb_isstackable(nameid))
-				sd->status.storage.items[i].unique_id = pc_generate_unique_id(sd);
+			if (!sd->storage.u.items_storage[i].unique_id && !itemdb_isstackable(nameid))
+				sd->storage.u.items_storage[i].unique_id = pc_generate_unique_id(sd);
  		}
 	}
 }
@@ -10126,9 +10112,9 @@ bool pc_divorce(struct map_session_data *sd)
 	p_sd->status.partner_id = 0;
 	for( i = 0; i < MAX_INVENTORY; i++ )
 	{
-		if( sd->status.inventory[i].nameid == WEDDING_RING_M || sd->status.inventory[i].nameid == WEDDING_RING_F )
+		if( sd->inventory.u.items_inventory[i].nameid == WEDDING_RING_M || sd->inventory.u.items_inventory[i].nameid == WEDDING_RING_F )
 			pc_delitem(sd, i, 1, 0, 0, LOG_TYPE_OTHER);
-		if( p_sd->status.inventory[i].nameid == WEDDING_RING_M || p_sd->status.inventory[i].nameid == WEDDING_RING_F )
+		if( p_sd->inventory.u.items_inventory[i].nameid == WEDDING_RING_M || p_sd->inventory.u.items_inventory[i].nameid == WEDDING_RING_F )
 			pc_delitem(p_sd, i, 1, 0, 0, LOG_TYPE_OTHER);
 	}
 
@@ -11473,6 +11459,11 @@ void pc_damage_log_clear(struct map_session_data *sd, int id)
  */
 void pc_scdata_received(struct map_session_data *sd) {
 	pc_inventory_rentals(sd); // Needed here to remove rentals that have Status Changes after chrif_load_scdata has finished
+
+	if (pc_iscarton(sd)) {
+		sd->cart_weight_max = 0; // Force a client refesh
+		status_calc_cart_weight(sd, 1|2|4);
+	}
 }
 
 /**

+ 17 - 3
src/map/pc.h

@@ -206,7 +206,7 @@ struct map_session_data {
 		unsigned int arrow_atk : 1;
 		unsigned int gangsterparadise : 1;
 		unsigned int rest : 1;
-		unsigned int storage_flag : 2; //0: closed, 1: Normal Storage open, 2: guild storage open [Skotlex]
+		unsigned int storage_flag : 3; //0: closed, 1: Normal Storage open, 2: guild storage open [Skotlex], 3: Premium Storage
 		unsigned int snovice_dead_flag : 1; //Explosion spirits on death: 0 off, 1 used.
 		unsigned int abra_flag : 2; // Abracadabra bugfix by Aru
 		unsigned int autocast : 1; // Autospell flag [Inkfish]
@@ -274,6 +274,11 @@ struct map_session_data {
 	uint32 packet_ver;  // 5: old, 6: 7july04, 7: 13july04, 8: 26july04, 9: 9aug04/16aug04/17aug04, 10: 6sept04, 11: 21sept04, 12: 18oct04, 13: 25oct04 ... 18
 	struct mmo_charstatus status;
 
+	// Item Storages
+	struct s_storage storage, premiumStorage;
+	struct s_storage inventory;
+	struct s_storage cart;
+
 	struct item_data* inventory_data[MAX_INVENTORY]; // direct pointers to itemdb entries (faster than doing item_id lookups)
 	short equip_index[EQI_MAX];
 	unsigned int weight,max_weight;
@@ -514,6 +519,7 @@ struct map_session_data {
 	int vended_id;
 	int vender_id;
 	int vend_num;
+	uint16 vend_skill_lv;
 	char message[MESSAGE_SIZE];
 	struct s_vending vending[MAX_VENDING];
 
@@ -648,7 +654,6 @@ struct map_session_data {
 	int c_marker[MAX_SKILL_CRIMSON_MARKER]; /// Store target that marked by Crimson Marker [Cydh]
 	bool flicker; /// Check RL_FLICKER usage status [Cydh]
 
-	int storage_size; /// Holds player storage size (VIP system).
 #ifdef VIP_ENABLE
 	struct vip_info vip;
 #endif
@@ -783,6 +788,14 @@ enum adopt_responses {
 	ADOPT_MARRIED,
 };
 
+enum item_check {
+	ITMCHK_NONE      = 0x0,
+	ITMCHK_INVENTORY = 0x1,
+	ITMCHK_CART      = 0x2,
+	ITMCHK_STORAGE   = 0x4,
+	ITMCHK_ALL       = ITMCHK_INVENTORY|ITMCHK_CART|ITMCHK_STORAGE,
+};
+
 struct {
 	unsigned int base_hp[MAX_LEVEL], base_sp[MAX_LEVEL]; //Storage for the first calculation with hp/sp factor and multiplicator
 	int hp_factor, hp_multiplicator, sp_factor;
@@ -954,6 +967,7 @@ void pc_reg_received(struct map_session_data *sd);
 void pc_close_npc(struct map_session_data *sd,int flag);
 int pc_close_npc_timer(int tid, unsigned int tick, int id, intptr_t data);
 
+void pc_setequipindex(struct map_session_data *sd);
 uint8 pc_isequip(struct map_session_data *sd,int n);
 int pc_equippoint(struct map_session_data *sd,int n);
 void pc_setinventorydata(struct map_session_data *sd);
@@ -1077,7 +1091,7 @@ int pc_resethate(struct map_session_data*);
 bool pc_equipitem(struct map_session_data *sd, short n, int req_pos);
 bool pc_unequipitem(struct map_session_data*,int,int);
 void pc_checkitem(struct map_session_data*);
-void pc_check_available_item(struct map_session_data *sd);
+void pc_check_available_item(struct map_session_data *sd, uint8 type);
 int pc_useitem(struct map_session_data*,int);
 
 int pc_skillatk_bonus(struct map_session_data *sd, uint16 skill_id);

+ 5 - 8
src/map/pet.c

@@ -556,8 +556,8 @@ int pet_recv_petdata(uint32 account_id,struct s_pet *p,int flag)
 
 		//Delete egg from inventory. [Skotlex]
 		for (i = 0; i < MAX_INVENTORY; i++) {
-			if(sd->status.inventory[i].card[0] == CARD0_PET &&
-				p->pet_id == MakeDWord(sd->status.inventory[i].card[1], sd->status.inventory[i].card[2]))
+			if(sd->inventory.u.items_inventory[i].card[0] == CARD0_PET &&
+				p->pet_id == MakeDWord(sd->inventory.u.items_inventory[i].card[1], sd->inventory.u.items_inventory[i].card[2]))
 				break;
 		}
 
@@ -601,8 +601,8 @@ int pet_select_egg(struct map_session_data *sd,short egg_index)
 	if(egg_index < 0 || egg_index >= MAX_INVENTORY)
 		return 0; //Forged packet!
 
-	if(sd->status.inventory[egg_index].card[0] == CARD0_PET)
-		intif_request_petdata(sd->status.account_id, sd->status.char_id, MakeDWord(sd->status.inventory[egg_index].card[1], sd->status.inventory[egg_index].card[2]) );
+	if(sd->inventory.u.items_inventory[egg_index].card[0] == CARD0_PET)
+		intif_request_petdata(sd->status.account_id, sd->status.char_id, MakeDWord(sd->inventory.u.items_inventory[egg_index].card[1], sd->inventory.u.items_inventory[egg_index].card[2]) );
 	else
 		ShowError("wrong egg item inventory %d\n",egg_index);
 
@@ -861,10 +861,7 @@ int pet_equipitem(struct map_session_data *sd,int index)
 
 	pd = sd->pd;
 
-	if (!pd)
-		return 1;
-
-	nameid = sd->status.inventory[index].nameid;
+	nameid = sd->inventory.u.items_inventory[index].nameid;
 
 	if(pd->petDB->AcceID == 0 || nameid != pd->petDB->AcceID || pd->pet.equip != 0) {
 		clif_equipitemack(sd,0,0,ITEM_EQUIP_ACK_FAIL);

+ 246 - 155
src/map/script.c

@@ -45,13 +45,9 @@
 #include "battleground.h"
 #include "party.h"
 #include "mail.h"
-#include "script.h"
 #include "quest.h"
 #include "elemental.h"
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
 #include <math.h>
 #ifndef WIN32
 #endif
@@ -4254,7 +4250,7 @@ void script_run_autobonus(const char *autobonus, struct map_session_data *sd, un
 	if( script )
 	{
 		int j;
-		ARR_FIND( 0, EQI_MAX, j, sd->equip_index[j] >= 0 && sd->status.inventory[sd->equip_index[j]].equip == pos );
+		ARR_FIND( 0, EQI_MAX, j, sd->equip_index[j] >= 0 && sd->inventory.u.items_inventory[sd->equip_index[j]].equip == pos );
 		if( j < EQI_MAX ) {
 			//Single item autobonus
 			current_equip_item_index = sd->equip_index[j];
@@ -6467,6 +6463,8 @@ BUILDIN_FUNC(viewpoint)
 /// cartcountitem2 <nameID>,<Identified>,<Refine>,<Attribute>,<Card0>,<Card1>,<Card2>,<Card3>{,<accountID>})
 /// storagecountitem <nameID>{,<accountID>});
 /// storagecountitem2 <nameID>,<Identified>,<Refine>,<Attribute>,<Card0>,<Card1>,<Card2>,<Card3>{,<accountID>})
+/// guildstoragecountitem <nameID>{,<accountID>});
+/// guildstoragecountitem2 <nameID>,<Identified>,<Refine>,<Attribute>,<Card0>,<Card1>,<Card2>,<Card3>{,<accountID>})
 BUILDIN_FUNC(countitem)
 {
 	int i = 0, aid = 3;
@@ -6477,6 +6475,7 @@ BUILDIN_FUNC(countitem)
 	uint16 size, count = 0;
 	struct item *items;
 	TBL_PC *sd = NULL;
+	struct s_storage *gstor;
 
 	if( command[strlen(command)-1] == '2' ) {
 		i = 1;
@@ -6496,22 +6495,33 @@ BUILDIN_FUNC(countitem)
 	}
 	
 	if( !strncmp(command, "cart", 4) ) {
-		loc = 1;
+		loc = TABLE_CART;
 		size = MAX_CART;
-		items = sd->status.cart;
+		items = sd->cart.u.items_cart;
 	}
 	else if( !strncmp(command, "storage", 7) ) {
-		loc = 2;
+		loc = TABLE_STORAGE;
 		size = MAX_STORAGE;
-		items = sd->status.storage.items;
+		items = sd->storage.u.items_storage;
+	}
+	else if( !strncmp(command, "guildstorage", 12) ) {
+		gstor = guild2storage2(sd->status.guild_id);
+
+		if (gstor && !sd->state.storage_flag) {
+			loc = TABLE_GUILD_STORAGE;
+			size = MAX_GUILD_STORAGE;
+			items = gstor->u.items_guild;
+		} else {
+			script_pushint(st, -1);
+			return SCRIPT_CMD_SUCCESS;
+		}
 	}
-	//TODO: 3 - Guild Storage
 	else {
 		size = MAX_INVENTORY;
-		items = sd->status.inventory;
+		items = sd->inventory.u.items_inventory;
 	}
 
-	if( loc == 1 && !pc_iscarton(sd) ) {
+	if( loc == TABLE_CART && !pc_iscarton(sd) ) {
 		ShowError("buildin_%s: Player doesn't have cart (CID:%d).\n", command, sd->status.char_id);
 		script_pushint(st,-1);
 		return SCRIPT_CMD_SUCCESS;
@@ -6531,6 +6541,9 @@ BUILDIN_FUNC(countitem)
 		return SCRIPT_CMD_FAILURE;
 	}
 
+	if (loc == TABLE_GUILD_STORAGE)
+		gstor->lock = true;
+
 	if( !i ) { // For count/cart/storagecountitem function
 		unsigned short nameid = id->nameid;
 		for( i = 0; i < size; i++ )
@@ -6561,6 +6574,11 @@ BUILDIN_FUNC(countitem)
 			}
 	}
 
+	if (loc == TABLE_GUILD_STORAGE) {
+		storage_guild_storageclose(sd);
+		gstor->lock = false;
+	}
+
 	script_pushint(st, count);
 	return SCRIPT_CMD_SUCCESS;
 }
@@ -7332,16 +7350,24 @@ static void buildin_delitem_delete(struct map_session_data* sd, int idx, int* am
 {
 	int delamount;
 	struct item *itm = NULL;
+	struct s_storage *gstor = NULL;
 
 	switch(loc) {
-		case 1:	// cart
-			itm = &sd->status.cart[idx];
+		case TABLE_CART:
+			itm = &sd->cart.u.items_cart[idx];
+			break;
+		case TABLE_STORAGE:
+			itm = &sd->storage.u.items_storage[idx];
 			break;
-		case 2:	// storage
-			itm = &sd->status.storage.items[idx];
+		case TABLE_GUILD_STORAGE:
+		{
+			gstor = guild2storage2(sd->status.guild_id);
+
+			itm = &gstor->u.items_guild[idx];
+		}
 			break;
-		default:	//inventory
-			itm = &sd->status.inventory[idx];
+		default: // TABLE_INVENTORY
+			itm = &sd->inventory.u.items_inventory[idx];
 			break;
 	}
 
@@ -7354,14 +7380,21 @@ static void buildin_delitem_delete(struct map_session_data* sd, int idx, int* am
 			intif_delete_petdata(MakeDWord(itm->card[1], itm->card[2]));
 		}
 		switch(loc) {
-			case 1:
+			case TABLE_CART:
 				pc_cart_delitem(sd,idx,delamount,0,LOG_TYPE_SCRIPT);
 				break;
-			case 2:
-				storage_delitem(sd,idx,delamount);
+			case TABLE_STORAGE:
+				storage_delitem(sd,&sd->storage,idx,delamount);
 				log_pick_pc(sd,LOG_TYPE_SCRIPT,-delamount,itm);
 				break;
-			default:
+			case TABLE_GUILD_STORAGE:
+				gstor->lock = true;
+				storage_guild_delitem(sd, gstor, idx, delamount);
+				log_pick_pc(sd, LOG_TYPE_SCRIPT, -delamount, itm);
+				storage_guild_storageclose(sd);
+				gstor->lock = false;
+				break;
+			default: // TABLE_INVENTORY
 				pc_delitem(sd, idx, delamount, 0, 0, LOG_TYPE_SCRIPT);
 				break;
 		}
@@ -7395,17 +7428,25 @@ static bool buildin_delitem_search(struct map_session_data* sd, struct item* it,
 	}
 
 	switch(loc) {
-		case 1:	// cart
+		case TABLE_CART:
 			size = MAX_CART;
-			items = sd->status.cart;
+			items = sd->cart.u.items_cart;
 			break;
-		case 2:	// storage
+		case TABLE_STORAGE:
 			size = MAX_STORAGE;
-			items = sd->status.storage.items;
+			items = sd->storage.u.items_storage;
+			break;
+		case TABLE_GUILD_STORAGE:
+		{
+			struct s_storage *gstor = guild2storage2(sd->status.guild_id);
+
+			size = MAX_GUILD_STORAGE;
+			items = gstor->u.items_guild;
+		}
 			break;
-		default:	//inventory
+		default: // TABLE_INVENTORY
 			size = MAX_INVENTORY;
-			items = sd->status.inventory;
+			items = sd->inventory.u.items_inventory;
 			break;
 	}
 
@@ -7513,6 +7554,8 @@ static bool buildin_delitem_search(struct map_session_data* sd, struct item* it,
 /// cartdelitem "<item name>",<amount>{,<account id>}
 /// storagedelitem <item id>,<amount>{,<account id>}
 /// storagedelitem "<item name>",<amount>{,<account id>}
+/// guildstoragedelitem <item id>,<amount>{,<account id>}
+/// guildstoragedelitem "<item name>",<amount>{,<account id>}
 BUILDIN_FUNC(delitem)
 {
 	TBL_PC *sd;
@@ -7522,10 +7565,11 @@ BUILDIN_FUNC(delitem)
 	char* command = (char*)script_getfuncname(st);
 
 	if(!strncmp(command, "cart", 4))
-		loc = 1;
+		loc = TABLE_CART;
 	else if(!strncmp(command, "storage", 7))
-		loc = 2;
-	//TODO: 3 - Guild Storage
+		loc = TABLE_STORAGE;
+	else if(!strncmp(command, "guildstorage", 12))
+		loc = TABLE_GUILD_STORAGE;
 
 	if( script_hasdata(st,4) )
 	{
@@ -7545,10 +7589,19 @@ BUILDIN_FUNC(delitem)
 			return SCRIPT_CMD_SUCCESS;
 	}
 
-	if (loc == 1 && !pc_iscarton(sd)) {
+	if (loc == TABLE_CART && !pc_iscarton(sd)) {
 		ShowError("buildin_cartdelitem: player doesn't have cart (CID=%d).\n", sd->status.char_id);
+		script_pushint(st, -1);
 		return SCRIPT_CMD_FAILURE;
 	}
+	if (loc == TABLE_GUILD_STORAGE) {
+		struct s_storage *gstor = guild2storage2(sd->status.guild_id);
+
+		if (gstor == NULL || sd->state.storage_flag) {
+			script_pushint(st, -1);
+			return SCRIPT_CMD_FAILURE;
+		}
+	}
 
 	data = script_getdata(st,2);
 	get_val(st,data);
@@ -7600,6 +7653,8 @@ BUILDIN_FUNC(delitem)
 /// cartdelitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
 /// storagedelitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
 /// storagedelitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
+/// guildstoragedelitem2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
+/// guildstoragedelitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
 BUILDIN_FUNC(delitem2)
 {
 	TBL_PC *sd;
@@ -7609,10 +7664,11 @@ BUILDIN_FUNC(delitem2)
 	char* command = (char*)script_getfuncname(st);
 
 	if(!strncmp(command, "cart", 4))
-		loc = 1;
+		loc = TABLE_CART;
 	else if(!strncmp(command, "storage", 7))
-		loc = 2;
-	//TODO: 3 - Guild Storage
+		loc = TABLE_STORAGE;
+	else if(!strncmp(command, "guildstorage", 12))
+		loc = TABLE_GUILD_STORAGE;
 
 	if( script_hasdata(st,11) )
 	{
@@ -7632,11 +7688,19 @@ BUILDIN_FUNC(delitem2)
 			return SCRIPT_CMD_SUCCESS;
 	}
 
-	if (loc == 1 && !pc_iscarton(sd)) {
+	if (loc == TABLE_CART && !pc_iscarton(sd)) {
 		ShowError("buildin_cartdelitem: player doesn't have cart (CID=%d).\n", sd->status.char_id);
 		script_pushint(st,-1);
 		return SCRIPT_CMD_FAILURE;
 	}
+	if (loc == TABLE_GUILD_STORAGE) {
+		struct s_storage *gstor = guild2storage2(sd->status.guild_id);
+
+		if (gstor == NULL || sd->state.storage_flag) {
+			script_pushint(st, -1);
+			return SCRIPT_CMD_FAILURE;
+		}
+	}
 
 	data = script_getdata(st,2);
 	get_val(st,data);
@@ -8152,7 +8216,7 @@ BUILDIN_FUNC(getequipuniqueid)
 		return SCRIPT_CMD_FAILURE;
 	}
 
-	item = &sd->status.inventory[i];
+	item = &sd->inventory.u.items_inventory[i];
 	if (item != 0) {
 		int maxlen = 256;
 		char *buf = (char *)aMalloc(maxlen*sizeof(char));
@@ -8213,7 +8277,7 @@ BUILDIN_FUNC(getequipname)
  *------------------------------------------*/
 BUILDIN_FUNC(getbrokenid)
 {
-	int i,num,id=0,brokencounter=0;
+	int i,num,id = 0,brokencounter = 0;
 	TBL_PC *sd;
 
 	if (!script_charid2sd(3, sd)) {
@@ -8221,12 +8285,12 @@ BUILDIN_FUNC(getbrokenid)
 		return SCRIPT_CMD_FAILURE;
 	}
 
-	num=script_getnum(st,2);
-	for(i=0; i<MAX_INVENTORY; i++) {
-		if(sd->status.inventory[i].attribute){
+	num = script_getnum(st,2);
+	for(i = 0; i < MAX_INVENTORY; i++) {
+		if(sd->inventory.u.items_inventory[i].attribute) {
 				brokencounter++;
-				if(num==brokencounter){
-					id=sd->status.inventory[i].nameid;
+				if(num == brokencounter){
+					id = sd->inventory.u.items_inventory[i].nameid;
 					break;
 				}
 		}
@@ -8244,20 +8308,20 @@ BUILDIN_FUNC(getbrokenid)
 BUILDIN_FUNC(repair)
 {
 	int i,num;
-	int repaircounter=0;
+	int repaircounter = 0;
 	TBL_PC *sd;
 
 	if (!script_charid2sd(3,sd))
 		return SCRIPT_CMD_FAILURE;
 
-	num=script_getnum(st,2);
-	for(i=0; i<MAX_INVENTORY; i++) {
-		if(sd->status.inventory[i].attribute){
+	num = script_getnum(st,2);
+	for(i = 0; i < MAX_INVENTORY; i++) {
+		if(sd->inventory.u.items_inventory[i].attribute) {
 				repaircounter++;
-				if(num==repaircounter){
-					sd->status.inventory[i].attribute=0;
+				if(num == repaircounter) {
+					sd->inventory.u.items_inventory[i].attribute = 0;
 					clif_equiplist(sd);
-					clif_produceeffect(sd, 0, sd->status.inventory[i].nameid);
+					clif_produceeffect(sd, 0, sd->inventory.u.items_inventory[i].nameid);
 					clif_misceffect(&sd->bl, 3);
 					break;
 				}
@@ -8280,10 +8344,10 @@ BUILDIN_FUNC(repairall)
 
 	for(i = 0; i < MAX_INVENTORY; i++)
 	{
-		if(sd->status.inventory[i].nameid && sd->status.inventory[i].attribute)
+		if(sd->inventory.u.items_inventory[i].nameid && sd->inventory.u.items_inventory[i].attribute)
 		{
-			sd->status.inventory[i].attribute = 0;
-			clif_produceeffect(sd,0,sd->status.inventory[i].nameid);
+			sd->inventory.u.items_inventory[i].attribute = 0;
+			clif_produceeffect(sd,0,sd->inventory.u.items_inventory[i].nameid);
 			repaircounter++;
 		}
 	}
@@ -8343,7 +8407,7 @@ BUILDIN_FUNC(getequipisenableref)
 
 	if( equip_index_check(num) )
 		i = pc_checkequip(sd,equip_bitmask[num]);
-	if( i >= 0 && sd->inventory_data[i] && !sd->inventory_data[i]->flag.no_refine && !sd->status.inventory[i].expire_time )
+	if( i >= 0 && sd->inventory_data[i] && !sd->inventory_data[i]->flag.no_refine && !sd->inventory.u.items_inventory[i].expire_time )
 		script_pushint(st,1);
 	else
 		script_pushint(st,0);
@@ -8373,7 +8437,7 @@ BUILDIN_FUNC(getequiprefinerycnt)
 	if (equip_index_check(num))
 		i=pc_checkequip(sd,equip_bitmask[num]);
 	if(i >= 0)
-		script_pushint(st,sd->status.inventory[i].refine);
+		script_pushint(st,sd->inventory.u.items_inventory[i].refine);
 	else
 		script_pushint(st,0);
 
@@ -8433,8 +8497,8 @@ BUILDIN_FUNC(getequippercentrefinery)
 
 	if (equip_index_check(num))
 		i = pc_checkequip(sd,equip_bitmask[num]);
-	if(i >= 0 && sd->status.inventory[i].nameid && sd->status.inventory[i].refine < MAX_REFINE)
-		script_pushint(st,status_get_refine_chance((enum refine_type)itemdb_wlv(sd->status.inventory[i].nameid), (int)sd->status.inventory[i].refine));
+	if(i >= 0 && sd->inventory.u.items_inventory[i].nameid && sd->inventory.u.items_inventory[i].refine < MAX_REFINE)
+		script_pushint(st,status_get_refine_chance((enum refine_type)itemdb_wlv(sd->inventory.u.items_inventory[i].nameid), (int)sd->inventory.u.items_inventory[i].refine));
 	else
 		script_pushint(st,0);
 
@@ -8463,32 +8527,32 @@ BUILDIN_FUNC(successrefitem) {
 	if (equip_index_check(pos))
 		i = pc_checkequip(sd,equip_bitmask[pos]);
 	if (i >= 0) {
-		unsigned int ep = sd->status.inventory[i].equip;
+		unsigned int ep = sd->inventory.u.items_inventory[i].equip;
 
 		//Logs items, got from (N)PC scripts [Lupus]
-		log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->status.inventory[i]);
+		log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->inventory.u.items_inventory[i]);
 
-		if (sd->status.inventory[i].refine >= MAX_REFINE) {
+		if (sd->inventory.u.items_inventory[i].refine >= MAX_REFINE) {
 			script_pushint(st, MAX_REFINE);
 			return SCRIPT_CMD_SUCCESS;
 		}
 
-		sd->status.inventory[i].refine += up;
-		sd->status.inventory[i].refine = cap_value( sd->status.inventory[i].refine, 0, MAX_REFINE);
+		sd->inventory.u.items_inventory[i].refine += up;
+		sd->inventory.u.items_inventory[i].refine = cap_value( sd->inventory.u.items_inventory[i].refine, 0, MAX_REFINE);
 		pc_unequipitem(sd,i,2); // status calc will happen in pc_equipitem() below
 
-		clif_refine(sd->fd,0,i,sd->status.inventory[i].refine);
+		clif_refine(sd->fd,0,i,sd->inventory.u.items_inventory[i].refine);
 		clif_delitem(sd,i,1,3);
 
 		//Logs items, got from (N)PC scripts [Lupus]
-		log_pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->status.inventory[i]);
+		log_pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->inventory.u.items_inventory[i]);
 
 		clif_additem(sd,i,1,0);
 		pc_equipitem(sd,i,ep);
 		clif_misceffect(&sd->bl,3);
-		if (sd->status.inventory[i].refine == MAX_REFINE &&
-			sd->status.inventory[i].card[0] == CARD0_FORGE &&
-			sd->status.char_id == (int)MakeDWord(sd->status.inventory[i].card[2],sd->status.inventory[i].card[3]))
+		if (sd->inventory.u.items_inventory[i].refine == MAX_REFINE &&
+			sd->inventory.u.items_inventory[i].card[0] == CARD0_FORGE &&
+			sd->status.char_id == (int)MakeDWord(sd->inventory.u.items_inventory[i].card[2],sd->inventory.u.items_inventory[i].card[3]))
 		{ // Fame point system [DracoRPG]
 			switch (sd->inventory_data[i]->wlv){
 				case 1:
@@ -8502,7 +8566,7 @@ BUILDIN_FUNC(successrefitem) {
 					break;
 			 }
 		}
-		script_pushint(st, sd->status.inventory[i].refine);
+		script_pushint(st, sd->inventory.u.items_inventory[i].refine);
 		return SCRIPT_CMD_SUCCESS;
 	}
 
@@ -8530,9 +8594,9 @@ BUILDIN_FUNC(failedrefitem) {
 	if (equip_index_check(pos))
 		i = pc_checkequip(sd,equip_bitmask[pos]);
 	if (i >= 0) {
-		sd->status.inventory[i].refine = 0;
+		sd->inventory.u.items_inventory[i].refine = 0;
 		pc_unequipitem(sd,i,3); //recalculate bonus
-		clif_refine(sd->fd,1,i,sd->status.inventory[i].refine); //notify client of failure
+		clif_refine(sd->fd,1,i,sd->inventory.u.items_inventory[i].refine); //notify client of failure
 		pc_delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT);
 		clif_misceffect(&sd->bl,2); 	// display failure effect
 		script_pushint(st, 1);
@@ -8565,25 +8629,25 @@ BUILDIN_FUNC(downrefitem) {
 	if (equip_index_check(pos))
 		i = pc_checkequip(sd,equip_bitmask[pos]);
 	if (i >= 0) {
-		unsigned int ep = sd->status.inventory[i].equip;
+		unsigned int ep = sd->inventory.u.items_inventory[i].equip;
 
 		//Logs items, got from (N)PC scripts [Lupus]
-		log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->status.inventory[i]);
+		log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->inventory.u.items_inventory[i]);
 
 		pc_unequipitem(sd,i,2); // status calc will happen in pc_equipitem() below
-		sd->status.inventory[i].refine -= down;
-		sd->status.inventory[i].refine = cap_value( sd->status.inventory[i].refine, 0, MAX_REFINE);
+		sd->inventory.u.items_inventory[i].refine -= down;
+		sd->inventory.u.items_inventory[i].refine = cap_value( sd->inventory.u.items_inventory[i].refine, 0, MAX_REFINE);
 
-		clif_refine(sd->fd,2,i,sd->status.inventory[i].refine);
+		clif_refine(sd->fd,2,i,sd->inventory.u.items_inventory[i].refine);
 		clif_delitem(sd,i,1,3);
 
 		//Logs items, got from (N)PC scripts [Lupus]
-		log_pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->status.inventory[i]);
+		log_pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->inventory.u.items_inventory[i]);
 
 		clif_additem(sd,i,1,0);
 		pc_equipitem(sd,i,ep);
 		clif_misceffect(&sd->bl,2);
-		script_pushint(st, sd->status.inventory[i].refine);
+		script_pushint(st, sd->inventory.u.items_inventory[i].refine);
 		return SCRIPT_CMD_SUCCESS;
 	}
 
@@ -8640,7 +8704,7 @@ BUILDIN_FUNC(breakequip) {
 	if (equip_index_check(pos))
 		i = pc_checkequip(sd,equip_bitmask[pos]);
 	if (i >= 0) {
-		sd->status.inventory[i].attribute = 1;
+		sd->inventory.u.items_inventory[i].attribute = 1;
 		pc_unequipitem(sd,i,3);
 		clif_equiplist(sd);
 		script_pushint(st,1);
@@ -8801,7 +8865,7 @@ BUILDIN_FUNC(autobonus)
 	if (current_equip_combo_pos)
 		pos = current_equip_combo_pos;
 	else
-		pos = sd->status.inventory[current_equip_item_index].equip;
+		pos = sd->inventory.u.items_inventory[current_equip_item_index].equip;
 
 	if((sd->state.autobonus&pos) == pos)
 		return SCRIPT_CMD_SUCCESS;
@@ -8843,7 +8907,7 @@ BUILDIN_FUNC(autobonus2)
 	if (current_equip_combo_pos)
 		pos = current_equip_combo_pos;
 	else
-		pos = sd->status.inventory[current_equip_item_index].equip;
+		pos = sd->inventory.u.items_inventory[current_equip_item_index].equip;
 
 	if((sd->state.autobonus&pos) == pos)
 		return SCRIPT_CMD_SUCCESS;
@@ -8885,7 +8949,7 @@ BUILDIN_FUNC(autobonus3)
 	if (current_equip_combo_pos)
 		pos = current_equip_combo_pos;
 	else
-		pos = sd->status.inventory[current_equip_item_index].equip;
+		pos = sd->inventory.u.items_inventory[current_equip_item_index].equip;
 
 	if((sd->state.autobonus&pos) == pos)
 		return SCRIPT_CMD_SUCCESS;
@@ -9522,7 +9586,7 @@ BUILDIN_FUNC(guildopenstorage)
 	if( sd == NULL )
 		return SCRIPT_CMD_SUCCESS;
 
-	ret = gstorage_storageopen(sd);
+	ret = storage_guild_storageopen(sd);
 	script_pushint(st,ret);
 	return SCRIPT_CMD_SUCCESS;
 }
@@ -9961,9 +10025,9 @@ BUILDIN_FUNC(killmonsterall)
 BUILDIN_FUNC(clone)
 {
 	TBL_PC *sd, *msd=NULL;
-	uint32 char_id;
-	int master_id=0,x,y, flag = 0, m;
+	uint32 char_id, master_id = 0, x, y, flag = 0, m;
 	enum e_mode mode = 0;
+
 	unsigned int duration = 0;
 	const char *mapname,*event;
 
@@ -12531,7 +12595,7 @@ BUILDIN_FUNC(getequipcardcnt)
 		return SCRIPT_CMD_SUCCESS;
 	}
 
-	if(itemdb_isspecial(sd->status.inventory[i].card[0]))
+	if(itemdb_isspecial(sd->inventory.u.items_inventory[i].card[0]))
 	{
 		script_pushint(st,0);
 		return SCRIPT_CMD_SUCCESS;
@@ -12539,7 +12603,7 @@ BUILDIN_FUNC(getequipcardcnt)
 
 	count = 0;
 	for( j = 0; j < sd->inventory_data[i]->slot; j++ )
-		if( sd->status.inventory[i].card[j] && itemdb_type(sd->status.inventory[i].card[j]) == IT_CARD )
+		if( sd->inventory.u.items_inventory[i].card[j] && itemdb_type(sd->inventory.u.items_inventory[i].card[j]) == IT_CARD )
 			count++;
 
 	script_pushint(st,count);
@@ -12562,16 +12626,16 @@ BUILDIN_FUNC(successremovecards) {
 		return SCRIPT_CMD_SUCCESS;
 	}
 
-	if(itemdb_isspecial(sd->status.inventory[i].card[0]))
+	if(itemdb_isspecial(sd->inventory.u.items_inventory[i].card[0]))
 		return SCRIPT_CMD_SUCCESS;
 
 	for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c ) {
-		if( sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD ) {// extract this card from the item
+		if( sd->inventory.u.items_inventory[i].card[c] && itemdb_type(sd->inventory.u.items_inventory[i].card[c]) == IT_CARD ) {// extract this card from the item
 			unsigned char flag = 0;
 			struct item item_tmp;
 			memset(&item_tmp,0,sizeof(item_tmp));
 			cardflag = 1;
-			item_tmp.nameid   = sd->status.inventory[i].card[c];
+			item_tmp.nameid   = sd->inventory.u.items_inventory[i].card[c];
 			item_tmp.identify = 1;
 
 			if((flag=pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){	// get back the cart in inventory
@@ -12586,20 +12650,20 @@ BUILDIN_FUNC(successremovecards) {
 		struct item item_tmp;
 		memset(&item_tmp,0,sizeof(item_tmp));
 
-		item_tmp.nameid      = sd->status.inventory[i].nameid;
+		item_tmp.nameid      = sd->inventory.u.items_inventory[i].nameid;
 		item_tmp.identify    = 1;
-		item_tmp.refine      = sd->status.inventory[i].refine;
-		item_tmp.attribute   = sd->status.inventory[i].attribute;
-		item_tmp.expire_time = sd->status.inventory[i].expire_time;
-		item_tmp.bound       = sd->status.inventory[i].bound;
+		item_tmp.refine      = sd->inventory.u.items_inventory[i].refine;
+		item_tmp.attribute   = sd->inventory.u.items_inventory[i].attribute;
+		item_tmp.expire_time = sd->inventory.u.items_inventory[i].expire_time;
+		item_tmp.bound       = sd->inventory.u.items_inventory[i].bound;
 
 		for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++)
-			item_tmp.card[j]=sd->status.inventory[i].card[j];
+			item_tmp.card[j]=sd->inventory.u.items_inventory[i].card[j];
 		
 		for (j = 0; j < MAX_ITEM_RDM_OPT; j++){
-			item_tmp.option[j].id=sd->status.inventory[i].option[j].id;
-			item_tmp.option[j].value=sd->status.inventory[i].option[j].value;
-			item_tmp.option[j].param=sd->status.inventory[i].option[j].param;
+			item_tmp.option[j].id=sd->inventory.u.items_inventory[i].option[j].id;
+			item_tmp.option[j].value=sd->inventory.u.items_inventory[i].option[j].value;
+			item_tmp.option[j].param=sd->inventory.u.items_inventory[i].option[j].param;
 		}
 
 		pc_delitem(sd,i,1,0,3,LOG_TYPE_SCRIPT);
@@ -12632,11 +12696,11 @@ BUILDIN_FUNC(failedremovecards) {
 	if (i < 0 || !sd->inventory_data[i])
 		return SCRIPT_CMD_SUCCESS;
 
-	if(itemdb_isspecial(sd->status.inventory[i].card[0]))
+	if(itemdb_isspecial(sd->inventory.u.items_inventory[i].card[0]))
 		return SCRIPT_CMD_SUCCESS;
 
 	for( c = sd->inventory_data[i]->slot - 1; c >= 0; --c ) {
-		if( sd->status.inventory[i].card[c] && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD ) {
+		if( sd->inventory.u.items_inventory[i].card[c] && itemdb_type(sd->inventory.u.items_inventory[i].card[c]) == IT_CARD ) {
 			cardflag = 1;
 
 			if(typefail == 2) {// add cards to inventory, clear
@@ -12645,7 +12709,7 @@ BUILDIN_FUNC(failedremovecards) {
 
 				memset(&item_tmp,0,sizeof(item_tmp));
 
-				item_tmp.nameid   = sd->status.inventory[i].card[c];
+				item_tmp.nameid   = sd->inventory.u.items_inventory[i].card[c];
 				item_tmp.identify = 1;
 
 				if((flag=pc_additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT))){
@@ -12665,20 +12729,20 @@ BUILDIN_FUNC(failedremovecards) {
 
 			memset(&item_tmp,0,sizeof(item_tmp));
 
-			item_tmp.nameid      = sd->status.inventory[i].nameid;
+			item_tmp.nameid      = sd->inventory.u.items_inventory[i].nameid;
 			item_tmp.identify    = 1;
-			item_tmp.refine      = sd->status.inventory[i].refine;
-			item_tmp.attribute   = sd->status.inventory[i].attribute;
-			item_tmp.expire_time = sd->status.inventory[i].expire_time;
-			item_tmp.bound       = sd->status.inventory[i].bound;
+			item_tmp.refine      = sd->inventory.u.items_inventory[i].refine;
+			item_tmp.attribute   = sd->inventory.u.items_inventory[i].attribute;
+			item_tmp.expire_time = sd->inventory.u.items_inventory[i].expire_time;
+			item_tmp.bound       = sd->inventory.u.items_inventory[i].bound;
 
 			for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++)
-				item_tmp.card[j]=sd->status.inventory[i].card[j];
+				item_tmp.card[j]=sd->inventory.u.items_inventory[i].card[j];
 			
 			for (j = 0; j < MAX_ITEM_RDM_OPT; j++){
-				item_tmp.option[j].id=sd->status.inventory[i].option[j].id;
-				item_tmp.option[j].value=sd->status.inventory[i].option[j].value;
-				item_tmp.option[j].param=sd->status.inventory[i].option[j].param;
+				item_tmp.option[j].id=sd->inventory.u.items_inventory[i].option[j].id;
+				item_tmp.option[j].value=sd->inventory.u.items_inventory[i].option[j].value;
+				item_tmp.option[j].param=sd->inventory.u.items_inventory[i].option[j].param;
 			}
 
 			pc_delitem(sd,i,1,0,2,LOG_TYPE_SCRIPT);
@@ -13254,7 +13318,7 @@ BUILDIN_FUNC(getequipcardid)
 	if (equip_index_check(num))
 		i=pc_checkequip(sd,equip_bitmask[num]);
 	if(i >= 0 && slot>=0 && slot<4)
-		script_pushint(st,sd->status.inventory[i].card[slot]);
+		script_pushint(st,sd->inventory.u.items_inventory[i].card[slot]);
 	else
 		script_pushint(st,0);
 	return SCRIPT_CMD_SUCCESS;
@@ -13346,20 +13410,20 @@ BUILDIN_FUNC(getinventorylist)
 	if (!script_charid2sd(2,sd))
 		return SCRIPT_CMD_FAILURE;
 	for(i=0;i<MAX_INVENTORY;i++){
-		if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0){
-			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);
+		if(sd->inventory.u.items_inventory[i].nameid > 0 && sd->inventory.u.items_inventory[i].amount > 0){
+			pc_setreg(sd,reference_uid(add_str("@inventorylist_id"), j),sd->inventory.u.items_inventory[i].nameid);
+			pc_setreg(sd,reference_uid(add_str("@inventorylist_amount"), j),sd->inventory.u.items_inventory[i].amount);
+			pc_setreg(sd,reference_uid(add_str("@inventorylist_equip"), j),sd->inventory.u.items_inventory[i].equip);
+			pc_setreg(sd,reference_uid(add_str("@inventorylist_refine"), j),sd->inventory.u.items_inventory[i].refine);
+			pc_setreg(sd,reference_uid(add_str("@inventorylist_identify"), j),sd->inventory.u.items_inventory[i].identify);
+			pc_setreg(sd,reference_uid(add_str("@inventorylist_attribute"), j),sd->inventory.u.items_inventory[i].attribute);
 			for (k = 0; k < MAX_SLOTS; k++)
 			{
 				sprintf(card_var, "@inventorylist_card%d",k+1);
-				pc_setreg(sd,reference_uid(add_str(card_var), j),sd->status.inventory[i].card[k]);
+				pc_setreg(sd,reference_uid(add_str(card_var), j),sd->inventory.u.items_inventory[i].card[k]);
 			}
-			pc_setreg(sd,reference_uid(add_str("@inventorylist_expire"), j),sd->status.inventory[i].expire_time);
-			pc_setreg(sd,reference_uid(add_str("@inventorylist_bound"), j),sd->status.inventory[i].bound);
+			pc_setreg(sd,reference_uid(add_str("@inventorylist_expire"), j),sd->inventory.u.items_inventory[i].expire_time);
+			pc_setreg(sd,reference_uid(add_str("@inventorylist_bound"), j),sd->inventory.u.items_inventory[i].bound);
 			j++;
 		}
 	}
@@ -13401,8 +13465,8 @@ BUILDIN_FUNC(clearitem)
 		return SCRIPT_CMD_FAILURE;
 
 	for (i=0; i<MAX_INVENTORY; i++) {
-		if (sd->status.inventory[i].amount) {
-			pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_SCRIPT);
+		if (sd->inventory.u.items_inventory[i].amount) {
+			pc_delitem(sd, i, sd->inventory.u.items_inventory[i].amount, 0, 0, LOG_TYPE_SCRIPT);
 		}
 	}
 	return SCRIPT_CMD_SUCCESS;
@@ -14181,7 +14245,7 @@ BUILDIN_FUNC(getmercinfo)
 
 	if( script_hasdata(st,3) )
 	{
-		int char_id = script_getnum(st,3);
+		uint32 char_id = script_getnum(st,3);
 
 		if( ( sd = map_charid2sd(char_id) ) == NULL )
 		{
@@ -14240,11 +14304,11 @@ BUILDIN_FUNC(checkequipedcard)
 		c=script_getnum(st,2);
 
 		for(i=0;i<MAX_INVENTORY;i++){
-			if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount && sd->inventory_data[i]){
-				if (itemdb_isspecial(sd->status.inventory[i].card[0]))
+			if(sd->inventory.u.items_inventory[i].nameid > 0 && sd->inventory.u.items_inventory[i].amount && sd->inventory_data[i]){
+				if (itemdb_isspecial(sd->inventory.u.items_inventory[i].card[0]))
 					continue;
 				for(n=0;n<sd->inventory_data[i]->slot;n++){
-					if(sd->status.inventory[i].card[n]==c){
+					if(sd->inventory.u.items_inventory[i].card[n] == c) {
 						script_pushint(st,1);
 						return SCRIPT_CMD_SUCCESS;
 					}
@@ -14740,13 +14804,13 @@ BUILDIN_FUNC(isequippedcnt)
 
 			if (itemdb_type(id) != IT_CARD) { //No card. Count amount in inventory.
 				if (sd->inventory_data[index]->nameid == id)
-					ret+= sd->status.inventory[index].amount;
+					ret+= sd->inventory.u.items_inventory[index].amount;
 			} else { //Count cards.
 				short k;
-				if (itemdb_isspecial(sd->status.inventory[index].card[0]))
+				if (itemdb_isspecial(sd->inventory.u.items_inventory[index].card[0]))
 					continue; //No cards
 				for(k=0; k<sd->inventory_data[index]->slot; k++) {
-					if (sd->status.inventory[index].card[k] == id)
+					if (sd->inventory.u.items_inventory[index].card[k] == id)
 						ret++; //[Lupus]
 				}
 			}
@@ -14804,13 +14868,13 @@ BUILDIN_FUNC(isequipped)
 			} else { //Cards
 				short k;
 				if (sd->inventory_data[index]->slot == 0 ||
-					itemdb_isspecial(sd->status.inventory[index].card[0]))
+					itemdb_isspecial(sd->inventory.u.items_inventory[index].card[0]))
 					continue;
 
 				for (k = 0; k < sd->inventory_data[index]->slot; k++)
 				{	//New hash system which should support up to 4 slots on any equipment. [Skotlex]
 					unsigned int hash = 0;
-					if (sd->status.inventory[index].card[k] != id)
+					if (sd->inventory.u.items_inventory[index].card[k] != id)
 						continue;
 
 					hash = 1<<((j<5?j:j-5)*4 + k);
@@ -14870,12 +14934,12 @@ BUILDIN_FUNC(cardscnt)
 
 		if(itemdb_type(id) != IT_CARD) {
 			if (sd->inventory_data[index]->nameid == id)
-				ret+= sd->status.inventory[index].amount;
+				ret+= sd->inventory.u.items_inventory[index].amount;
 		} else {
-			if (itemdb_isspecial(sd->status.inventory[index].card[0]))
+			if (itemdb_isspecial(sd->inventory.u.items_inventory[index].card[0]))
 				continue;
 			for(k=0; k<sd->inventory_data[index]->slot; k++) {
-				if (sd->status.inventory[index].card[k] == id)
+				if (sd->inventory.u.items_inventory[index].card[k] == id)
 					ret++;
 			}
 		}
@@ -14893,7 +14957,7 @@ BUILDIN_FUNC(getrefine)
 {
 	TBL_PC *sd;
 	if ((sd = script_rid2sd(st))!= NULL)
-		script_pushint(st,sd->status.inventory[current_equip_item_index].refine);
+		script_pushint(st,sd->inventory.u.items_inventory[current_equip_item_index].refine);
 	else
 		script_pushint(st,0);
 	return SCRIPT_CMD_SUCCESS;
@@ -14953,7 +15017,7 @@ BUILDIN_FUNC(equip) {
 	if ((item_data = itemdb_exists(nameid))) {
 		int i;
 
-		ARR_FIND( 0, MAX_INVENTORY, i, sd->status.inventory[i].nameid == nameid );
+		ARR_FIND( 0, MAX_INVENTORY, i, sd->inventory.u.items_inventory[i].nameid == nameid );
 		if (i < MAX_INVENTORY) {
 			pc_equipitem(sd,i,item_data->equip);
 			script_pushint(st,1);
@@ -20280,13 +20344,13 @@ BUILDIN_FUNC(countbound)
 	type = script_getnum(st,2);
 
 	for( i = 0; i < MAX_INVENTORY; i ++ ) {
-		if( sd->status.inventory[i].nameid > 0 && (
-			(!type && sd->status.inventory[i].bound) || (type && sd->status.inventory[i].bound == type)
+		if( sd->inventory.u.items_inventory[i].nameid > 0 && (
+			(!type && sd->inventory.u.items_inventory[i].bound) || (type && sd->inventory.u.items_inventory[i].bound == type)
 			))
 		{
-			pc_setreg(sd,reference_uid(add_str("@bound_items"), k),sd->status.inventory[i].nameid);
+			pc_setreg(sd,reference_uid(add_str("@bound_items"), k),sd->inventory.u.items_inventory[i].nameid);
 			k++;
-			j += sd->status.inventory[i].amount;
+			j += sd->inventory.u.items_inventory[i].amount;
 		}
 	}
 
@@ -21021,7 +21085,8 @@ BUILDIN_FUNC(mergeitem2) {
 	}
 
 	for (i = 0; i < MAX_INVENTORY; i++) {
-		struct item *it = &sd->status.inventory[i];
+		struct item *it = &sd->inventory.u.items_inventory[i];
+
 		if (!it || !it->unique_id || it->expire_time || !itemdb_isstackable(it->nameid))
 			continue;
 		if ((!nameid || (nameid == it->nameid))) {
@@ -21681,16 +21746,16 @@ BUILDIN_FUNC(getrandomoptinfo) {
 	struct map_session_data *sd;
 	int val;
 	int param = script_getnum(st, 2);
-	if ((sd = script_rid2sd(st)) != NULL && current_equip_item_index != -1 && current_equip_opt_index != -1 && sd->status.inventory[current_equip_item_index].option[current_equip_opt_index].id) {
+	if ((sd = script_rid2sd(st)) != NULL && current_equip_item_index != -1 && current_equip_opt_index != -1 && sd->inventory.u.items_inventory[current_equip_item_index].option[current_equip_opt_index].id) {
 		switch (param) {
 			case ROA_ID:
-				val = sd->status.inventory[current_equip_item_index].option[current_equip_opt_index].id;
+				val = sd->inventory.u.items_inventory[current_equip_item_index].option[current_equip_opt_index].id;
 				break;
 			case ROA_VALUE:
-				val = sd->status.inventory[current_equip_item_index].option[current_equip_opt_index].value;
+				val = sd->inventory.u.items_inventory[current_equip_item_index].option[current_equip_opt_index].value;
 				break;
 			case ROA_PARAM:
-				val = sd->status.inventory[current_equip_item_index].option[current_equip_opt_index].param;
+				val = sd->inventory.u.items_inventory[current_equip_item_index].option[current_equip_opt_index].param;
 				break;
 			default:
 				ShowWarning("buildin_getrandomoptinfo: Invalid attribute type %d (Max %d).\n", param, MAX_ITEM_RDM_OPT);
@@ -21736,13 +21801,13 @@ BUILDIN_FUNC(getequiprandomoption) {
 
 	switch (type) {
 		case ROA_ID:
-			val = sd->status.inventory[i].option[index].id;
+			val = sd->inventory.u.items_inventory[i].option[index].id;
 			break;
 		case ROA_VALUE:
-			val = sd->status.inventory[i].option[index].value;
+			val = sd->inventory.u.items_inventory[i].option[index].value;
 			break;
 		case ROA_PARAM:
-			val = sd->status.inventory[i].option[index].param;
+			val = sd->inventory.u.items_inventory[i].option[index].param;
 			break;
 		default:
 			ShowWarning("buildin_getequiprandomoption: Invalid attribute type %d (Max %d).\n", type, MAX_ITEM_RDM_OPT);
@@ -21785,14 +21850,14 @@ BUILDIN_FUNC(setrandomoption) {
 	if (equip_index_check(pos))
 		i = pc_checkequip(sd, equip_bitmask[pos]);
 	if (i >= 0) {
-		ep = sd->status.inventory[i].equip;
-		log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->status.inventory[i]);
+		ep = sd->inventory.u.items_inventory[i].equip;
+		log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->inventory.u.items_inventory[i]);
 		pc_unequipitem(sd, i, 2);
-		sd->status.inventory[i].option[index].id = id;
-		sd->status.inventory[i].option[index].value = value;
-		sd->status.inventory[i].option[index].param = param;
+		sd->inventory.u.items_inventory[i].option[index].id = id;
+		sd->inventory.u.items_inventory[i].option[index].value = value;
+		sd->inventory.u.items_inventory[i].option[index].param = param;
 		clif_delitem(sd, i, 1, 3);
-		log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->status.inventory[i]);
+		log_pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->inventory.u.items_inventory[i]);
 		clif_additem(sd, i, 1, 0);
 		pc_equipitem(sd, i, ep);
 		script_pushint(st, 1);
@@ -21910,7 +21975,28 @@ BUILDIN_FUNC(getguildalliance)
 		script_pushint(st, 2);
 	else
 		script_pushint(st, 1);
+	return SCRIPT_CMD_SUCCESS;
+}
+
+/*
+ * openstorage2 <storage_id>,<mode>{,<account_id>}
+ * mode @see enum e_storage_mode
+ **/
+BUILDIN_FUNC(openstorage2) {
+	int stor_id = script_getnum(st, 2);
+	TBL_PC *sd = NULL;
+
+	if (!script_accid2sd(4, sd)) {
+		script_pushint(st, 0);
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	if (!storage_exists(stor_id)) {
+		ShowError("buildin_openstorage2: Invalid storage_id '%d'!\n", stor_id);
+		return SCRIPT_CMD_FAILURE;
+	}
 
+	script_pushint(st, storage_premiumStorage_load(sd, stor_id, script_getnum(st, 3)));
 	return SCRIPT_CMD_SUCCESS;
 }
 
@@ -22007,9 +22093,11 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(makeitem2,"visiiiiiiiii"),
 	BUILDIN_DEF(delitem,"vi?"),
 	BUILDIN_DEF2(delitem,"storagedelitem","vi?"),
+	BUILDIN_DEF2(delitem,"guildstoragedelitem","vi?"),
 	BUILDIN_DEF2(delitem,"cartdelitem","vi?"),
 	BUILDIN_DEF(delitem2,"viiiiiiii?"),
 	BUILDIN_DEF2(delitem2,"storagedelitem2","viiiiiiii?"),
+	BUILDIN_DEF2(delitem2,"guildstoragedelitem2","viiiiiiii?"),
 	BUILDIN_DEF2(delitem2,"cartdelitem2","viiiiiiii?"),
 	BUILDIN_DEF2(enableitemuse,"enable_items",""),
 	BUILDIN_DEF2(disableitemuse,"disable_items",""),
@@ -22021,9 +22109,11 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(rand,"i?"),
 	BUILDIN_DEF(countitem,"v?"),
 	BUILDIN_DEF2(countitem,"storagecountitem","v?"),
+	BUILDIN_DEF2(countitem,"guildstoragecountitem","v?"),
 	BUILDIN_DEF2(countitem,"cartcountitem","v?"),
 	BUILDIN_DEF2(countitem,"countitem2","viiiiiii?"),
 	BUILDIN_DEF2(countitem,"storagecountitem2","viiiiiii?"),
+	BUILDIN_DEF2(countitem,"guildstoragecountitem2","viiiiiii?"),
 	BUILDIN_DEF2(countitem,"cartcountitem2","viiiiiii?"),
 	BUILDIN_DEF(checkweight,"vi*"),
 	BUILDIN_DEF(checkweight2,"rr"),
@@ -22500,6 +22590,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(setrandomoption,"iiiii?"),
 	BUILDIN_DEF(needed_status_point,"ii?"),
 	BUILDIN_DEF(jobcanentermap,"s?"),
+	BUILDIN_DEF(openstorage2,"ii?"),
 
 	// WoE TE
 	BUILDIN_DEF(agitstart3,""),

+ 4 - 0
src/map/script_constants.h

@@ -3170,6 +3170,10 @@
 	export_constant(CARD0_CREATE);
 	export_constant(CARD0_PET);
 
+	export_constant(STOR_MODE_NONE);
+	export_constant(STOR_MODE_GET);
+	export_constant(STOR_MODE_PUT);
+
 	#undef export_constant
 
 #endif /* _SCRIPT_CONSTANTS_H_ */

+ 37 - 32
src/map/skill.c

@@ -2493,7 +2493,7 @@ int skill_break_equip(struct block_list *src, struct block_list *bl, unsigned sh
 	if (sd) {
 		for (i = 0; i < EQI_MAX; i++) {
 			short j = sd->equip_index[i];
-			if (j < 0 || sd->status.inventory[j].attribute == 1 || !sd->inventory_data[j])
+			if (j < 0 || sd->inventory.u.items_inventory[j].attribute == 1 || !sd->inventory_data[j])
 				continue;
 
 			switch(i) {
@@ -2519,7 +2519,7 @@ int skill_break_equip(struct block_list *src, struct block_list *bl, unsigned sh
 					continue;
 			}
 			if (flag) {
-				sd->status.inventory[j].attribute = 1;
+				sd->inventory.u.items_inventory[j].attribute = 1;
 				pc_unequipitem(sd, j, 3);
 			}
 		}
@@ -3833,7 +3833,7 @@ static int skill_check_condition_mercenary(struct block_list *bl, int skill, int
 		index[i] = -1;
 		if( itemid[i] < 1 ) continue; // No item
 		index[i] = pc_search_inventory(sd, itemid[i]);
-		if( index[i] < 0 || sd->status.inventory[index[i]].amount < amount[i] )
+		if( index[i] < 0 || sd->inventory.u.items_inventory[index[i]].amount < amount[i] )
 		{
 			clif_skill_fail(sd, skill, USESKILL_FAIL_LEVEL, 0);
 			return 0;
@@ -7309,7 +7309,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 			else {
 				sd->state.prevend = 1;
 				sd->state.workinprogress = WIP_DISABLE_ALL;
-				clif_openvendingreq(sd,2+skill_lv);
+				sd->vend_skill_lv = skill_lv;
+				ARR_FIND(0, MAX_CART, i, sd->cart.u.items_cart[i].nameid && sd->cart.u.items_cart[i].id == 0);
+				if (i < MAX_CART)
+					intif_storage_save(sd, &sd->cart);
+				else
+					clif_openvendingreq(sd,2+skill_lv);
 			}
 		}
 		break;
@@ -7486,7 +7491,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 					map_freeblock_unlock();
 					return 1;
 				}
-					if (sd->inventory_data[j] == NULL || sd->status.inventory[j].amount < require.amount[x]) {
+					if (sd->inventory_data[j] == NULL || sd->inventory.u.items_inventory[j].amount < require.amount[x]) {
 					clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
 					map_freeblock_unlock();
 					return 1;
@@ -7626,7 +7631,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 			int ebottle = pc_search_inventory(sd,ITEMID_EMPTY_BOTTLE);
 			short alcohol_idx = -1, acid_idx = -1, fire_idx = -1;
 			if( ebottle >= 0 )
-				ebottle = sd->status.inventory[ebottle].amount;
+				ebottle = sd->inventory.u.items_inventory[ebottle].amount;
 			//check if you can produce all three, if not, then fail:
 			if (!(alcohol_idx = skill_can_produce_mix(sd,ITEMID_ALCOHOL,-1, 100)) //100 Alcohol
 				|| !(acid_idx = skill_can_produce_mix(sd,ITEMID_ACID_BOTTLE,-1, 50)) //50 Acid Bottle
@@ -9626,7 +9631,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 			else {
 				shield_def = shield_data->def;
 				shield_mdef = sd->bonus.shieldmdef;
-				shield_refine = sd->status.inventory[sd->equip_index[EQI_HAND_L]].refine;
+				shield_refine = sd->inventory.u.items_inventory[sd->equip_index[EQI_HAND_L]].refine;
 			}
 			if (flag&1) {
 				sc_start(src,bl,SC_SILENCE,100,skill_lv,shield_mdef * 30000);
@@ -11690,7 +11695,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui
 		struct skill_condition require = skill_get_requirement(sd, skill_id, skill_lv);
 		i_lv = skill_lv%11 - 1;
 		j = pc_search_inventory(sd, require.itemid[i_lv]);
-		if (j < 0 || require.itemid[i_lv] <= 0 || sd->inventory_data[j] == NULL || sd->status.inventory[j].amount < require.amount[i_lv])
+		if (j < 0 || require.itemid[i_lv] <= 0 || sd->inventory_data[j] == NULL || sd->inventory.u.items_inventory[j].amount < require.amount[i_lv])
 			{
 				clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
 				return 1;
@@ -14645,10 +14650,10 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i
 		else
 		{ // When a target was selected, consume items that were skipped in pc_use_item [Skotlex]
 			if( (i = sd->itemindex) == -1 ||
-				sd->status.inventory[i].nameid != sd->itemid ||
+				sd->inventory.u.items_inventory[i].nameid != sd->itemid ||
 				sd->inventory_data[i] == NULL ||
 				!sd->inventory_data[i]->flag.delay_consume ||
-				sd->status.inventory[i].amount < 1
+				sd->inventory.u.items_inventory[i].amount < 1
 				)
 			{	//Something went wrong, item exploit?
 				sd->itemid = sd->itemindex = -1;
@@ -14658,7 +14663,7 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i
 			sd->itemid = sd->itemindex = -1;
 			if( skill_id == WZ_EARTHSPIKE && sc && sc->data[SC_EARTHSCROLL] && rnd()%100 > sc->data[SC_EARTHSCROLL]->val2 ) // [marquis007]
 				; //Do not consume item.
-			else if( sd->status.inventory[i].expire_time == 0 )
+			else if( sd->inventory.u.items_inventory[i].expire_time == 0 )
 				pc_delitem(sd,i,1,0,0,LOG_TYPE_CONSUME); // Rental usable items are not consumed until expiration
 		}
 		if(!sd->skillitem_keep_requirement)
@@ -15046,8 +15051,8 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i
 				int count = 0;
 
 				for( i = 0; i < MAX_INVENTORY; i++ )
-					if( sd->status.inventory[i].nameid == ITEMID_ANCILLA )
-						count += sd->status.inventory[i].amount;
+					if( sd->inventory.u.items_inventory[i].nameid == ITEMID_ANCILLA )
+						count += sd->inventory.u.items_inventory[i].amount;
 				if( count >= 3 ) {
 					clif_skill_fail(sd, skill_id, USESKILL_FAIL_ANCILLA_NUMOVER, 0);
 					return false;
@@ -15071,7 +15076,7 @@ bool skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_i
 		case WL_COMET:
 			if( skill_check_pc_partner(sd,skill_id,&skill_lv,1,0) <= 0 && require.itemid[0]
 				&& sd->special_state.no_gemstone == 0
-				&& ((i = pc_search_inventory(sd,require.itemid[0])) < 0 || sd->status.inventory[i].amount < require.amount[0]) ) {
+				&& ((i = pc_search_inventory(sd,require.itemid[0])) < 0 || sd->inventory.u.items_inventory[i].amount < require.amount[0]) ) {
 				//clif_skill_fail(sd,skill_id,USESKILL_FAIL_NEED_ITEM,require.amount[0],require.itemid[0]);
 				clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
 				return false;
@@ -15605,7 +15610,7 @@ bool skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id,
 		if((i=sd->equip_index[EQI_AMMO]) < 0 || !sd->inventory_data[i] ) {
 			clif_arrow_fail(sd,0);
 			return false;
-		} else if( sd->status.inventory[i].amount < require.ammo_qty + extra_ammo ) {
+		} else if( sd->inventory.u.items_inventory[i].amount < require.ammo_qty + extra_ammo ) {
 			char e_msg[100];
 			if (require.ammo&(1<<AMMO_BULLET|1<<AMMO_GRENADE|1<<AMMO_SHELL)) {
 				clif_skill_fail(sd,skill_id,USESKILL_FAIL_NEED_MORE_BULLET,0);
@@ -15618,7 +15623,7 @@ bool skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id,
 			sprintf(e_msg,msg_txt(sd,381), //Skill Failed. [%s] requires %dx %s.
 						skill_get_desc(skill_id),
 						require.ammo_qty,
-						itemdb_jname(sd->status.inventory[i].nameid));
+						itemdb_jname(sd->inventory.u.items_inventory[i].nameid));
 			clif_colormes(sd->fd,color_table[COLOR_RED],e_msg);
 			return false;
 		}
@@ -15634,7 +15639,7 @@ bool skill_check_condition_castend(struct map_session_data* sd, uint16 skill_id,
 		if( !require.itemid[i] )
 			continue;
 		index[i] = pc_search_inventory(sd,require.itemid[i]);
-		if( index[i] < 0 || sd->status.inventory[index[i]].amount < require.amount[i] ) {
+		if( index[i] < 0 || sd->inventory.u.items_inventory[index[i]].amount < require.amount[i] ) {
 			if( require.itemid[i] == ITEMID_HOLY_WATER )
 				clif_skill_fail(sd,skill_id,USESKILL_FAIL_HOLYWATER,0); //Holy water is required.
 			else if( require.itemid[i] == ITEMID_RED_GEMSTONE )
@@ -15927,7 +15932,7 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, uint16
 					if ((skill_id >= HT_SKIDTRAP && skill_id <= HT_TALKIEBOX && pc_checkskill(sd, RA_RESEARCHTRAP) > 0) || skill_id == SC_ESCAPE) {
 						int16 itIndex;
 
-						if ((itIndex = pc_search_inventory(sd,req.itemid[i])) < 0 || ( itIndex >= 0 && sd->status.inventory[itIndex].amount < req.amount[i])) {
+						if ((itIndex = pc_search_inventory(sd,req.itemid[i])) < 0 || ( itIndex >= 0 && sd->inventory.u.items_inventory[itIndex].amount < req.amount[i])) {
 							if (skill_id == SC_ESCAPE) // Alloy Trap has priority over normal Trap
 								req.itemid[i] = ITEMID_TRAP;
 							else
@@ -16426,7 +16431,7 @@ void skill_repairweapon(struct map_session_data *sd, int idx) {
 	if( idx < 0 || idx >= MAX_INVENTORY )
 		return; //Invalid index??
 
-	item = &target_sd->status.inventory[idx];
+	item = &target_sd->inventory.u.items_inventory[idx];
 	if( !item->nameid || !item->attribute )
 		return; //Again invalid item....
 
@@ -16470,9 +16475,9 @@ void skill_identify(struct map_session_data *sd, int idx)
 	sd->state.workinprogress = WIP_DISABLE_NONE;
 
 	if(idx >= 0 && idx < MAX_INVENTORY) {
-		if(sd->status.inventory[idx].nameid > 0 && sd->status.inventory[idx].identify == 0 ){
+		if(sd->inventory.u.items_inventory[idx].nameid > 0 && sd->inventory.u.items_inventory[idx].identify == 0 ){
 			flag=0;
-			sd->status.inventory[idx].identify=1;
+			sd->inventory.u.items_inventory[idx].identify = 1;
 		}
 	}
 	clif_item_identified(sd,idx,flag);
@@ -16489,7 +16494,7 @@ void skill_weaponrefine(struct map_session_data *sd, int idx)
 	{
 		struct item *item;
 		struct item_data *ditem = sd->inventory_data[idx];
-		item = &sd->status.inventory[idx];
+		item = &sd->inventory.u.items_inventory[idx];
 
 		if(item->nameid > 0 && ditem->type == IT_WEAPON) {
 			int i = 0, per;
@@ -18583,8 +18588,8 @@ short skill_can_produce_mix(struct map_session_data *sd, unsigned short nameid,
 			unsigned short idx, amt;
 
 			for (idx = 0, amt = 0; idx < MAX_INVENTORY; idx++)
-				if (sd->status.inventory[idx].nameid == nameid_produce)
-					amt += sd->status.inventory[idx].amount;
+				if (sd->inventory.u.items_inventory[idx].nameid == nameid_produce)
+					amt += sd->inventory.u.items_inventory[idx].amount;
 			if (amt < qty * skill_produce_db[i].mat_amount[j])
 				return 0;
 		}
@@ -18669,14 +18674,14 @@ bool skill_produce_mix(struct map_session_data *sd, uint16 skill_id, unsigned sh
 
 		if (data->stack.inventory) {
 			for (i = 0; i < MAX_INVENTORY; i++) {
-				if (sd->status.inventory[i].nameid == nameid) {
-					if (sd->status.inventory[i].amount >= data->stack.amount) {
+				if (sd->inventory.u.items_inventory[i].nameid == nameid) {
+					if (sd->inventory.u.items_inventory[i].amount >= data->stack.amount) {
 						clif_msg(sd,RUNE_CANT_CREATE);
 						return 0;
 					} else {
 						// The amount fits, say we got temp_qty 4 and 19 runes, we trim temp_qty to 1.
-						if (temp_qty + sd->status.inventory[i].amount >= data->stack.amount)
-							temp_qty = data->stack.amount - sd->status.inventory[i].amount;
+						if (temp_qty + sd->inventory.u.items_inventory[i].amount >= data->stack.amount)
+							temp_qty = data->stack.amount - sd->inventory.u.items_inventory[i].amount;
 					}
 					break;
 				}
@@ -18698,7 +18703,7 @@ bool skill_produce_mix(struct map_session_data *sd, uint16 skill_id, unsigned sh
 			j = pc_search_inventory(sd,id);
 
 			if (j >= 0) {
-				y = sd->status.inventory[j].amount;
+				y = sd->inventory.u.items_inventory[j].amount;
 				if (y > x)
 					y = x;
 				pc_delitem(sd,j,y,0,0,LOG_TYPE_PRODUCE);
@@ -19485,7 +19490,7 @@ int skill_elementalanalysis(struct map_session_data* sd, int n, uint16 skill_lv,
 			del_amount -= (del_amount % 10);
 		add_amount = (skill_lv == 1) ? del_amount * (5 + rnd()%5) : del_amount / 10 ;
 
-		if( (nameid = sd->status.inventory[idx].nameid) <= 0 || del_amount > sd->status.inventory[idx].amount ) {
+		if( (nameid = sd->inventory.u.items_inventory[idx].nameid) <= 0 || del_amount > sd->inventory.u.items_inventory[idx].amount ) {
 			clif_skill_fail(sd,SO_EL_ANALYSIS,USESKILL_FAIL_LEVEL,0);
 			return 1;
 		}
@@ -19552,9 +19557,9 @@ int skill_changematerial(struct map_session_data *sd, int n, unsigned short *ite
 					if( skill_produce_db[i].mat_id[j] > 0 ) {
 						for( k = 0; k < n; k++ ) {
 							int idx = item_list[k*2+0]-2;
-							nameid = sd->status.inventory[idx].nameid;
+							nameid = sd->inventory.u.items_inventory[idx].nameid;
 							amount = item_list[k*2+1];
-							if( nameid > 0 && sd->status.inventory[idx].identify == 0 ){
+							if( nameid > 0 && sd->inventory.u.items_inventory[idx].identify == 0 ){
 								clif_msg_skill(sd,GN_CHANGEMATERIAL,ITEM_UNIDENTIFIED);
 								return 0;
 							}

+ 116 - 56
src/map/status.c

@@ -3079,6 +3079,105 @@ static unsigned int status_calc_maxhpsp_pc(struct map_session_data* sd, unsigned
 	return cap_value((unsigned int)dmax,1,UINT_MAX);
 }
 
+/**
+ * Calculates player's weight
+ * @param sd: Player object
+ * @param flag: Calculation type
+ *   1 - Item weight
+ *   2 - Skill/Status/Configuration max weight bonus
+ * @return false - failed, true - success
+ */
+bool status_calc_weight(struct map_session_data *sd, uint8 flag)
+{
+	int b_weight, b_max_weight, skill, i;
+	struct status_change *sc;
+
+	nullpo_retr(false, sd);
+
+	sc = &sd->sc;
+	b_max_weight = sd->max_weight; // Store max weight for later comparison
+	b_weight = sd->weight; // Store current weight for later comparison
+	sd->max_weight = job_info[pc_class2idx(sd->status.class_)].max_weight_base + sd->status.str * 300; // Recalculate max weight
+
+	if (flag&1) {
+		sd->weight = 0; // Reset current weight
+
+		for(i = 0; i < MAX_INVENTORY; i++) {
+			if (!sd->inventory.u.items_inventory[i].nameid || sd->inventory_data[i] == NULL)
+				continue;
+			sd->weight += sd->inventory_data[i]->weight * sd->inventory.u.items_inventory[i].amount;
+		}
+	}
+
+	if (flag&2) {
+		// Skill/Status bonus weight increases
+		if ((skill = pc_checkskill(sd, MC_INCCARRY)) > 0)
+			sd->max_weight += 2000 * skill;
+		if (pc_isriding(sd) && pc_checkskill(sd, KN_RIDING) > 0)
+			sd->max_weight += 10000;
+		else if (pc_isridingdragon(sd))
+			sd->max_weight += 5000 + 2000 * pc_checkskill(sd, RK_DRAGONTRAINING);
+		if (sc->data[SC_KNOWLEDGE])
+			sd->max_weight += sd->max_weight * sc->data[SC_KNOWLEDGE]->val1 / 10;
+		if ((skill = pc_checkskill(sd, ALL_INCCARRY)) > 0)
+			sd->max_weight += 2000 * skill;
+	}
+
+	// Update the client if the new weight calculations don't match
+	if (b_weight != sd->weight)
+		clif_updatestatus(sd, SP_WEIGHT);
+	if (b_max_weight != sd->max_weight) {
+		clif_updatestatus(sd, SP_MAXWEIGHT);
+		pc_updateweightstatus(sd);
+	}
+
+	return true;
+}
+
+/**
+ * Calculates player's cart weight
+ * @param sd: Player object
+ * @param flag: Calculation type
+ *   1 - Cart item weight
+ *   2 - Skill/Status/Configuration max weight bonus
+ *   4 - Whether to check for cart status
+ * @return false - failed, true - success
+ */
+bool status_calc_cart_weight(struct map_session_data *sd, uint8 flag)
+{
+	int b_cart_weight_max, i;
+
+	nullpo_retr(false, sd);
+
+	if (!pc_iscarton(sd) && !(flag&4))
+		return false;
+
+	b_cart_weight_max = sd->cart_weight_max; // Store cart max weight for later comparison
+	sd->cart_weight_max = battle_config.max_cart_weight; // Recalculate max weight
+
+	if (flag&1) {
+		sd->cart_weight = 0; // Reset current cart weight
+		sd->cart_num = 0; // Reset current cart item count
+
+		for(i = 0; i < MAX_CART; i++) {
+			if (!sd->cart.u.items_cart[i].nameid)
+				continue;
+			sd->cart_weight += itemdb_weight(sd->cart.u.items_cart[i].nameid) * sd->cart.u.items_cart[i].amount; // Recalculate current cart weight
+			sd->cart_num++; // Recalculate current cart item count
+		}
+	}
+
+	// Skill bonus max weight increases
+	if (flag&2)
+		sd->cart_weight_max += (pc_checkskill(sd, GN_REMODELING_CART) * 5000);
+
+	// Update the client if the new weight calculations don't match
+	if (b_cart_weight_max != sd->cart_weight_max)
+		clif_updatestatus(sd, SP_CARTINFO);
+
+	return true;
+}
+
 /**
  * Calculates player data from scratch without counting SC adjustments
  * Should be invoked whenever players raise stats, learn passive skills or change equipment
@@ -3092,8 +3191,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 	struct status_data *base_status; ///< Pointer to the player's base status
 	const struct status_change *sc = &sd->sc;
 	struct s_skill b_skill[MAX_SKILL]; ///< Previous skill tree
-	int b_weight, b_max_weight, b_cart_weight_max, ///< Previous weight
-	i, skill,refinedef=0;
+	int i, skill, refinedef = 0;
 	short index = -1;
 
 	if (++calculating > 10) // Too many recursive calls!
@@ -3101,34 +3199,15 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 
 	// Remember player-specific values that are currently being shown to the client (for refresh purposes)
 	memcpy(b_skill, &sd->status.skill, sizeof(b_skill));
-	b_weight = sd->weight;
-	b_max_weight = sd->max_weight;
-	b_cart_weight_max = sd->cart_weight_max;
 
 	pc_calc_skilltree(sd);	// SkillTree calculation
 
-	sd->max_weight = job_info[pc_class2idx(sd->status.class_)].max_weight_base+sd->status.str*300;
-
 	if (opt&SCO_FIRST) {
 		// Load Hp/SP from char-received data.
 		sd->battle_status.hp = sd->status.hp;
 		sd->battle_status.sp = sd->status.sp;
 		sd->regen.sregen = &sd->sregen;
 		sd->regen.ssregen = &sd->ssregen;
-		sd->weight=0;
-		for(i=0;i<MAX_INVENTORY;i++) {
-			if(sd->status.inventory[i].nameid==0 || sd->inventory_data[i] == NULL)
-				continue;
-			sd->weight += sd->inventory_data[i]->weight*sd->status.inventory[i].amount;
-		}
-		sd->cart_weight=0;
-		sd->cart_num=0;
-		for(i=0;i<MAX_CART;i++) {
-			if(sd->status.cart[i].nameid==0)
-				continue;
-			sd->cart_weight+=itemdb_weight(sd->status.cart[i].nameid)*sd->status.cart[i].amount;
-			sd->cart_num++;
-		}
 	}
 
 	base_status = &sd->base_status;
@@ -3294,17 +3373,17 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 		}
 
 		// Sanitize the refine level in case someone decreased the value inbetween
-		if (sd->status.inventory[index].refine > MAX_REFINE)
-			sd->status.inventory[index].refine = MAX_REFINE;
+		if (sd->inventory.u.items_inventory[index].refine > MAX_REFINE)
+			sd->inventory.u.items_inventory[index].refine = MAX_REFINE;
 
 		if (sd->inventory_data[index]->type == IT_WEAPON) {
-			int r = sd->status.inventory[index].refine, wlv = sd->inventory_data[index]->wlv;
+			int r = sd->inventory.u.items_inventory[index].refine, wlv = sd->inventory_data[index]->wlv;
 			struct weapon_data *wd;
 			struct weapon_atk *wa;
 
 			if(wlv >= REFINE_TYPE_MAX)
 				wlv = REFINE_TYPE_MAX - 1;
-			if(i == EQI_HAND_L && sd->status.inventory[index].equip == EQP_HAND_L) {
+			if(i == EQI_HAND_L && sd->inventory.u.items_inventory[index].equip == EQP_HAND_L) {
 				wd = &sd->left_weapon; // Left-hand weapon
 				wa = &base_status->lhw;
 			} else {
@@ -3335,18 +3414,18 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 				if (!calculating) // Abort, run_script retriggered this. [Skotlex]
 					return 1;
 			}
-			if(sd->status.inventory[index].card[0]==CARD0_FORGE) { // Forged weapon
-				wd->star += (sd->status.inventory[index].card[1]>>8);
+			if(sd->inventory.u.items_inventory[index].card[0] == CARD0_FORGE) { // Forged weapon
+				wd->star += (sd->inventory.u.items_inventory[index].card[1]>>8);
 				if(wd->star >= 15) wd->star = 40; // 3 Star Crumbs now give +40 dmg
-				if(pc_famerank(MakeDWord(sd->status.inventory[index].card[2],sd->status.inventory[index].card[3]) ,MAPID_BLACKSMITH))
+				if(pc_famerank(MakeDWord(sd->inventory.u.items_inventory[index].card[2],sd->inventory.u.items_inventory[index].card[3]) ,MAPID_BLACKSMITH))
 					wd->star += 10;
 				if (!wa->ele) // Do not overwrite element from previous bonuses.
-					wa->ele = (sd->status.inventory[index].card[1]&0x0f);
+					wa->ele = (sd->inventory.u.items_inventory[index].card[1]&0x0f);
 			}
 		} else if(sd->inventory_data[index]->type == IT_ARMOR) {
 			int r;
 
-			if ( (r = sd->status.inventory[index].refine) )
+			if ( (r = sd->inventory.u.items_inventory[index].refine) )
 				refinedef += refine_info[REFINE_TYPE_ARMOR].bonus[r-1];
 			if(sd->inventory_data[index]->script && (pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) || !itemdb_isNoEquip(sd->inventory_data[index],sd->bl.m))) {
 				if( i == EQI_HAND_L ) // Shield
@@ -3431,10 +3510,10 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 			struct item_data *data;
 
 			// Card script execution.
-			if (itemdb_isspecial(sd->status.inventory[index].card[0]))
+			if (itemdb_isspecial(sd->inventory.u.items_inventory[index].card[0]))
 				continue;
 			for (j = 0; j < MAX_SLOTS; j++) { // Uses MAX_SLOTS to support Soul Bound system [Inkfish]
-				int c = sd->status.inventory[index].card[j];
+				int c = sd->inventory.u.items_inventory[index].card[j];
 				current_equip_card_id= c;
 				if(!c)
 					continue;
@@ -3450,7 +3529,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 					continue;
 				if(!pc_has_permission(sd,PC_PERM_USE_ALL_EQUIPMENT) && itemdb_isNoEquip(data,sd->bl.m)) // Card restriction checks.
 					continue;
-				if(i == EQI_HAND_L && sd->status.inventory[index].equip == EQP_HAND_L) { // Left hand status.
+				if(i == EQI_HAND_L && sd->inventory.u.items_inventory[index].equip == EQP_HAND_L) { // Left hand status.
 					sd->state.lr_flag = 1;
 					run_script(data->script,0,sd->bl.id,0);
 					sd->state.lr_flag = 0;
@@ -3480,7 +3559,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 			int j;
 			struct s_random_opt_data *data;
 			for (j = 0; j < MAX_ITEM_RDM_OPT; j++) {
-				short opt_id = sd->status.inventory[index].option[j].id;
+				short opt_id = sd->inventory.u.items_inventory[index].option[j].id;
 
 				if (!opt_id)
 					continue;
@@ -3490,7 +3569,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 					continue;
 				if (!pc_has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT) && itemdb_isNoEquip(sd->inventory_data[index], sd->bl.m))
 					continue;
-				if (i == EQI_HAND_L && sd->status.inventory[index].equip == EQP_HAND_L) { // Left hand status.
+				if (i == EQI_HAND_L && sd->inventory.u.items_inventory[index].equip == EQP_HAND_L) { // Left hand status.
 					sd->state.lr_flag = 1;
 					run_script(data->script, 0, sd->bl.id, 0);
 					sd->state.lr_flag = 0;
@@ -3819,18 +3898,8 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 // ----- MISC CALCULATIONS -----
 
 	// Weight
-	if((skill=pc_checkskill(sd,MC_INCCARRY))>0)
-		sd->max_weight += 2000*skill;
-	if(pc_isriding(sd) && pc_checkskill(sd,KN_RIDING)>0)
-		sd->max_weight += 10000;
-	else if(pc_isridingdragon(sd))
-		sd->max_weight += 5000+2000*pc_checkskill(sd,RK_DRAGONTRAINING);
-	if(sc->data[SC_KNOWLEDGE])
-		sd->max_weight += sd->max_weight*sc->data[SC_KNOWLEDGE]->val1/10;
-	if((skill=pc_checkskill(sd,ALL_INCCARRY))>0)
-		sd->max_weight += 2000*skill;
-
-	sd->cart_weight_max = battle_config.max_cart_weight + (pc_checkskill(sd, GN_REMODELING_CART)*5000);
+	status_calc_weight(sd, 2);
+	status_calc_cart_weight(sd, 2);
 
 	if (pc_checkskill(sd,SM_MOVINGRECOVERY)>0)
 		sd->regen.state.walk = 1;
@@ -3964,15 +4033,6 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
 	}
 	if(memcmp(b_skill,sd->status.skill,sizeof(sd->status.skill)))
 		clif_skillinfoblock(sd);
-	if(b_weight != sd->weight)
-		clif_updatestatus(sd,SP_WEIGHT);
-	if(b_max_weight != sd->max_weight) {
-		clif_updatestatus(sd,SP_MAXWEIGHT);
-		pc_updateweightstatus(sd);
-	}
-	if( b_cart_weight_max != sd->cart_weight_max ) {
-		clif_updatestatus(sd,SP_CARTINFO);
-	}
 
 	// If the skill is learned, the status is infinite.
 	if( (skill = pc_checkskill(sd,SU_SPRITEMABLE)) > 0 )

+ 2 - 0
src/map/status.h

@@ -2271,6 +2271,8 @@ void status_change_clear_onChangeMap(struct block_list *bl, struct status_change
 #define status_calc_elemental(ed, opt) status_calc_bl_(&(ed)->bl, SCB_ALL, opt)
 #define status_calc_npc(nd, opt) status_calc_bl_(&(nd)->bl, SCB_ALL, opt)
 
+bool status_calc_weight(struct map_session_data *sd, uint8 flag);
+bool status_calc_cart_weight(struct map_session_data *sd, uint8 flag);
 void status_calc_bl_(struct block_list *bl, enum scb_flag flag, enum e_status_calc_opt opt);
 int status_calc_mob_(struct mob_data* md, enum e_status_calc_opt opt);
 void status_calc_pet_(struct pet_data* pd, enum e_status_calc_opt opt);

+ 402 - 204
src/map/storage.c

@@ -20,6 +20,41 @@
 
 
 static DBMap* guild_storage_db; ///Databases of guild_storage : int guild_id -> struct guild_storage*
+struct s_storage_table *storage_db;
+int storage_count;
+
+/**
+ * Get storage name
+ * @param id Storage ID
+ * @return Storage name or "Storage" if not found
+ * @author [Cydh]
+ **/
+const char *storage_getName(uint8 id) {
+	if (storage_db && storage_count) {
+		int i;
+		for (i = 0; i < storage_count; i++) {
+			if (&storage_db[i] && storage_db[i].id == id && storage_db[i].name && storage_db[i].name[0] != '\0')
+				return storage_db[i].name;
+		}
+	}
+	return "Storage";
+}
+
+/**
+ * Check if sotrage ID is valid
+ * @param id Storage ID
+ * @return True:Valid, False:Invalid
+ **/
+bool storage_exists(uint8 id) {
+	if (storage_db && storage_count) {
+		int i;
+		for (i = 0; i < storage_count; i++) {
+			if (storage_db[i].id == id)
+				return true;
+		}
+	}
+	return false;
+}
 
 /**
  * Storage item comparator (for qsort)
@@ -64,6 +99,8 @@ void storage_sortitem(struct item* items, unsigned int size)
 void do_init_storage(void)
 {
 	guild_storage_db = idb_alloc(DB_OPT_RELEASE_DATA);
+	storage_db = NULL;
+	storage_count = 0;
 }
 
 /**
@@ -74,6 +111,10 @@ void do_init_storage(void)
 void do_final_storage(void)
 {
 	guild_storage_db->destroy(guild_storage_db,NULL);
+	if (storage_db)
+		aFree(storage_db);
+	storage_db = NULL;
+	storage_count = 0;
 }
 
 /**
@@ -84,10 +125,10 @@ void do_final_storage(void)
  */
 static int storage_reconnect_sub(DBKey key, DBData *data, va_list ap)
 {
-	struct guild_storage *stor = (struct guild_storage *)db_data2ptr(data);
+	struct s_storage *stor = db_data2ptr(data);
 
-	if (stor->dirty && stor->opened == 0) //Save closed storages.
-		gstorage_storagesave(0, stor->guild_id,0);
+	if (stor->dirty && stor->status == 0) //Save closed storages.
+		storage_guild_storagesave(0, stor->id, 0);
 
 	return 0;
 }
@@ -119,9 +160,9 @@ int storage_storageopen(struct map_session_data *sd)
 	}
 
 	sd->state.storage_flag = 1;
-	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, sd->storage_size);
+	storage_sortitem(sd->storage.u.items_storage, sd->storage.max_amount);
+	clif_storagelist(sd, sd->storage.u.items_storage, sd->storage.max_amount, storage_getName(0));
+	clif_updatestorageamount(sd, sd->storage.amount, sd->storage.max_amount);
 
 	return 0;
 }
@@ -153,45 +194,99 @@ int compare_item(struct item *a, struct item *b)
 	return 0;
 }
 
+/**
+ * Check if item can be added to storage
+ * @param stor Storage data
+ * @param idx Index item from inventory/cart
+ * @param items List of items from inventory/cart
+ * @param amount Amount of item will be added
+ * @param max_num Max inventory/cart
+ * @return @see enum e_storage_add
+ **/
+static enum e_storage_add storage_canAddItem(struct s_storage *stor, int idx, struct item items[], int amount, int max_num) {
+	if (stor->amount >= stor->max_amount)
+		return STORAGE_ADD_NOROOM; // storage full
+
+	if (idx < 0 || idx >= max_num)
+		return STORAGE_ADD_INVALID;
+
+	if (items[idx].nameid <= 0)
+		return STORAGE_ADD_INVALID; // No item on that spot
+
+	if (amount < 1 || amount > items[idx].amount)
+		return STORAGE_ADD_INVALID;
+
+	if (!stor->state.put)
+		return STORAGE_ADD_NOACCESS;
+
+	return STORAGE_ADD_OK;
+}
+
+/**
+ * Check if item can be moved from storage
+ * @param stor Storage data
+ * @param idx Index from storage
+ * @param amount Number of item
+ * @return @see enum e_storage_add
+ **/
+static enum e_storage_add storage_canGetItem(struct s_storage *stor, int idx, int amount) {
+	// If last index check is sd->storage_size, if player isn't VIP anymore but there's item, player can't take it
+	// Example the storage size when not VIP anymore is 350/300, player still can take the 301st~349th item.
+	if( idx < 0 || idx >= ARRAYLENGTH(stor->u.items_storage) )
+		return STORAGE_ADD_INVALID;
+
+	if( stor->u.items_storage[idx].nameid <= 0 )
+		return STORAGE_ADD_INVALID; //Nothing there
+
+	if( amount < 1 || amount > stor->u.items_storage[idx].amount )
+		return STORAGE_ADD_INVALID;
+
+	if (!stor->state.get)
+		return STORAGE_ADD_NOACCESS;
+
+	return STORAGE_ADD_OK;
+}
+
 /**
  * Make a player add an item to his storage
  * @param sd : player
+ * @param stor : Storage data
  * @param item_data : item to add
  * @param amount : quantity of items
  * @return 0:success, 1:failed
  */
-static int storage_additem(struct map_session_data* sd, struct item* item_data, int amount)
+static int storage_additem(struct map_session_data* sd, struct s_storage *stor, struct item *it, int amount)
 {
-	struct storage_data* stor = &sd->status.storage;
 	struct item_data *data;
 	int i;
 
-	if( item_data->nameid == 0 || amount <= 0 )
+	if( it->nameid == 0 || amount <= 0 )
 		return 1;
 
-	data = itemdb_search(item_data->nameid);
+	data = itemdb_search(it->nameid);
 
 	if( data->stack.storage && amount > data->stack.amount ) // item stack limitation
 		return 1;
 
-	if( !itemdb_canstore(item_data, pc_get_group_level(sd)) ) { // Check if item is storable. [Skotlex]
+	if( !itemdb_canstore(it, pc_get_group_level(sd)) ) { // Check if item is storable. [Skotlex]
 		clif_displaymessage (sd->fd, msg_txt(sd,264));
 		return 1;
 	}
 
-	if( (item_data->bound > BOUND_ACCOUNT) && !pc_can_give_bounded_items(sd) ) {
+	if( (it->bound > BOUND_ACCOUNT) && !pc_can_give_bounded_items(sd) ) {
 		clif_displaymessage(sd->fd, msg_txt(sd,294));
 		return 1;
 	}
 
 	if( itemdb_isstackable2(data) ) { // Stackable
-		for( i = 0; i < sd->storage_size; i++ ) {
-			if( compare_item(&stor->items[i], item_data) ) { // existing items found, stack them
-				if( amount > MAX_AMOUNT - stor->items[i].amount || ( data->stack.storage && amount > data->stack.amount - stor->items[i].amount ) )
+		for( i = 0; i < stor->max_amount; i++ ) {
+			if( compare_item(&stor->u.items_storage[i], it) ) { // existing items found, stack them
+				if( amount > MAX_AMOUNT - stor->u.items_storage[i].amount || ( data->stack.storage && amount > data->stack.amount - stor->u.items_storage[i].amount ) )
 					return 1;
 
-				stor->items[i].amount += amount;
-				clif_storageitemadded(sd,&stor->items[i],i,amount);
+				stor->u.items_storage[i].amount += amount;
+				stor->dirty = true;
+				clif_storageitemadded(sd,&stor->u.items_storage[i],i,amount);
 
 				return 0;
 			}
@@ -199,16 +294,17 @@ static int storage_additem(struct map_session_data* sd, struct item* item_data,
 	}
 
 	// find free slot
-	ARR_FIND( 0, sd->storage_size, i, stor->items[i].nameid == 0 );
-	if( i >= sd->storage_size )
+	ARR_FIND( 0, stor->max_amount, i, stor->u.items_storage[i].nameid == 0 );
+	if( i >= stor->max_amount )
 		return 1;
 
 	// add item to slot
-	memcpy(&stor->items[i],item_data,sizeof(stor->items[0]));
-	stor->storage_amount++;
-	stor->items[i].amount = amount;
-	clif_storageitemadded(sd,&stor->items[i],i,amount);
-	clif_updatestorageamount(sd, stor->storage_amount, sd->storage_size);
+	memcpy(&stor->u.items_storage[i],it,sizeof(stor->u.items_storage[0]));
+	stor->amount++;
+	stor->u.items_storage[i].amount = amount;
+	stor->dirty = true;
+	clif_storageitemadded(sd,&stor->u.items_storage[i],i,amount);
+	clif_updatestorageamount(sd, stor->amount, stor->max_amount);
 
 	return 0;
 }
@@ -220,23 +316,23 @@ static int storage_additem(struct map_session_data* sd, struct item* item_data,
  * @param amount :number of item to remove
  * @return 0:sucess, 1:fail
  */
-int storage_delitem(struct map_session_data* sd, int n, int amount)
+int storage_delitem(struct map_session_data* sd, struct s_storage *stor, int index, int amount)
 {
-	if( sd->status.storage.items[n].nameid == 0 || sd->status.storage.items[n].amount < amount )
+	if( stor->u.items_storage[index].nameid == 0 || stor->u.items_storage[index].amount < amount )
 		return 1;
 
-	sd->status.storage.items[n].amount -= amount;
-
-	if( sd->status.storage.items[n].amount == 0 ) {
-		memset(&sd->status.storage.items[n],0,sizeof(sd->status.storage.items[0]));
-		sd->status.storage.storage_amount--;
+	stor->u.items_storage[index].amount -= amount;
+	stor->dirty = true;
 
-		if( sd->state.storage_flag == 1 )
-			clif_updatestorageamount(sd, sd->status.storage.storage_amount, sd->storage_size);
+	if( stor->u.items_storage[index].amount == 0 ) {
+		memset(&stor->u.items_storage[index],0,sizeof(stor->u.items_storage[0]));
+		stor->amount--;
+		if( sd->state.storage_flag == 1 || sd->state.storage_flag == 3 )
+			clif_updatestorageamount(sd, stor->amount, sd->storage.max_amount);
 	}
 
-	if( sd->state.storage_flag == 1 )
-		clif_storageitemremoved(sd,n,amount);
+	if( sd->state.storage_flag == 1 || sd->state.storage_flag == 3 )
+		clif_storageitemremoved(sd,index,amount);
 
 	return 0;
 }
@@ -244,32 +340,27 @@ int storage_delitem(struct map_session_data* sd, int n, int amount)
 /**
  * Add an item to the storage from the inventory.
  * @param sd : player
+ * @param stor : Storage data
  * @param index : inventory index to take the item from
  * @param amount : number of item to take
  * @return 0:fail, 1:success
  */
-void storage_storageadd(struct map_session_data* sd, int index, int amount)
+void storage_storageadd(struct map_session_data* sd, struct s_storage *stor, int index, int amount)
 {
-	nullpo_retv(sd);
-
-	if( sd->status.storage.storage_amount > sd->storage_size )
-		return; // storage full
-
-	if( index < 0 || index >= MAX_INVENTORY )
-		return;
+	enum e_storage_add result;
 
-	if( sd->status.inventory[index].nameid <= 0 )
-		return; // No item on that spot
+	nullpo_retv(sd);
 
-	if( amount < 1 || amount > sd->status.inventory[index].amount )
+	result = storage_canAddItem(stor, index, sd->inventory.u.items_inventory, amount, MAX_INVENTORY);
+	if (result == STORAGE_ADD_INVALID)
 		return;
-
-	if( storage_additem(sd,&sd->status.inventory[index],amount) == 0 )
+	else if (result == STORAGE_ADD_OK && storage_additem(sd,stor,&sd->inventory.u.items_inventory[index],amount) == 0) {
 		pc_delitem(sd,index,amount,0,4,LOG_TYPE_STORAGE);
-	else {
-		clif_storageitemremoved(sd,index,0);
-		clif_dropitem(sd,index,0);
+		return;
 	}
+
+	clif_storageitemremoved(sd,index,0);
+	clif_dropitem(sd,index,0);
 }
 
 /**
@@ -279,21 +370,19 @@ void storage_storageadd(struct map_session_data* sd, int index, int amount)
  * @param amount : number of item to take
  * @return 0:fail, 1:success
  */
-void storage_storageget(struct map_session_data* sd, int index, int amount)
+void storage_storageget(struct map_session_data *sd, struct s_storage *stor, int index, int amount)
 {
 	unsigned char flag = 0;
+	enum e_storage_add result;
 
-	if( index < 0 || index >= sd->storage_size )
-		return;
-
-	if( sd->status.storage.items[index].nameid <= 0 )
-		return; //Nothing there
+	nullpo_retv(sd);
 
-	if( amount < 1 || amount > sd->status.storage.items[index].amount )
+	result = storage_canGetItem(stor, index, amount);
+	if (result != STORAGE_ADD_OK)
 		return;
 
-	if( (flag = pc_additem(sd,&sd->status.storage.items[index],amount,LOG_TYPE_STORAGE)) == 0 )
-		storage_delitem(sd,index,amount);
+	if ((flag = pc_additem(sd,&stor->u.items_storage[index],amount,LOG_TYPE_STORAGE)) == ADDITEM_SUCCESS)
+		storage_delitem(sd,stor,index,amount);
 	else {
 		clif_storageitemremoved(sd,index,0);
 		clif_additem(sd,0,0,flag);
@@ -303,58 +392,49 @@ void storage_storageget(struct map_session_data* sd, int index, int amount)
 /**
  * Move an item from cart to storage.
  * @param sd : player
+ * @param stor : Storage data
  * @param index : cart index to take the item from
  * @param amount : number of item to take
  * @return 0:fail, 1:success
  */
-void storage_storageaddfromcart(struct map_session_data* sd, int index, int amount)
+void storage_storageaddfromcart(struct map_session_data *sd, struct s_storage *stor, int index, int amount)
 {
+	enum e_storage_add result;
 	nullpo_retv(sd);
 
-	if( sd->status.storage.storage_amount > sd->storage_size )
-		return; // storage full / storage closed
-
-	if( index < 0 || index >= MAX_CART )
-		return;
-
-	if( sd->status.cart[index].nameid <= 0 )
-		return; //No item there.
-
-	if( amount < 1 || amount > sd->status.cart[index].amount )
+	result = storage_canAddItem(stor, index, sd->cart.u.items_inventory, amount, MAX_INVENTORY);
+	if (result == STORAGE_ADD_INVALID)
 		return;
-
-	if( storage_additem(sd,&sd->status.cart[index],amount) == 0 )
+	else if (result == STORAGE_ADD_OK && storage_additem(sd,stor,&sd->cart.u.items_cart[index],amount) == 0) {
 		pc_cart_delitem(sd,index,amount,0,LOG_TYPE_STORAGE);
-	else {
-		clif_storageitemremoved(sd,index,0);
-		clif_dropitem(sd,index,0);
+		return;
 	}
+
+	clif_storageitemremoved(sd,index,0);
+	clif_dropitem(sd,index,0);
 }
 
 /**
  * Get from Storage to the Cart inventory
  * @param sd : player
+ * @param stor : Storage data
  * @param index : storage index to take the item from
  * @param amount : number of item to take
  * @return 0:fail, 1:success
  */
-void storage_storagegettocart(struct map_session_data* sd, int index, int amount)
+void storage_storagegettocart(struct map_session_data* sd, struct s_storage *stor, int index, int amount)
 {
-	unsigned char flag;
+	unsigned char flag = 0;
+	enum e_storage_add result;
 
 	nullpo_retv(sd);
 
-	if( index < 0 || index >= sd->storage_size )
-		return;
-
-	if( sd->status.storage.items[index].nameid <= 0 )
-		return; //Nothing there.
-
-	if( amount < 1 || amount > sd->status.storage.items[index].amount )
+	result = storage_canGetItem(stor, index, amount);
+	if (result != STORAGE_ADD_OK)
 		return;
 
-	if( (flag = pc_cart_additem(sd,&sd->status.storage.items[index],amount,LOG_TYPE_STORAGE)) == 0 )
-		storage_delitem(sd,index,amount);
+	if ((flag = pc_cart_additem(sd,&stor->u.items_storage[index],amount,LOG_TYPE_STORAGE)) == 0)
+		storage_delitem(sd,stor,index,amount);
 	else {
 		clif_storageitemremoved(sd,index,0);
 		clif_cart_additem_ack(sd,(flag==1)?ADDITEM_TO_CART_FAIL_WEIGHT:ADDITEM_TO_CART_FAIL_COUNT);
@@ -373,15 +453,15 @@ void storage_storageclose(struct map_session_data* sd)
 
 	clif_storageclose(sd);
 
-	if( save_settings&4 )
-		chrif_save(sd,0); //Invokes the storage saving as well.
+	if (save_settings&CHARSAVE_STORAGE)
+		chrif_save(sd,0);
 
 	sd->state.storage_flag = 0;
 }
 
 /**
  * Force closing the storage for player without displaying result
- * (exemple when quitting the game)
+ * (example when quitting the game)
  * @param sd : player to close storage
  * @param flag :
  *  1: Character is quitting
@@ -391,8 +471,8 @@ void storage_storage_quit(struct map_session_data* sd, int flag)
 {
 	nullpo_retv(sd);
 
-	if (save_settings&4)
-		chrif_save(sd, flag); //Invokes the storage saving as well.
+	if (save_settings&CHARSAVE_STORAGE)
+		chrif_save(sd,0);
 
 	sd->state.storage_flag = 0;
 }
@@ -406,10 +486,11 @@ void storage_storage_quit(struct map_session_data* sd, int flag)
  */
 static DBData create_guildstorage(DBKey key, va_list args)
 {
-	struct guild_storage *gs = NULL;
+	struct s_storage *gs = NULL;
 
-	gs = (struct guild_storage *) aCalloc(sizeof(struct guild_storage), 1);
-	gs->guild_id=key.i;
+	gs = (struct s_storage *) aCalloc(sizeof(struct s_storage), 1);
+	gs->type = TABLE_GUILD_STORAGE;
+	gs->id = key.i;
 
 	return db_ptr2data(gs);
 }
@@ -418,27 +499,27 @@ static DBData create_guildstorage(DBKey key, va_list args)
  * Retrieve the guild_storage of a guild
  * will create a new storage if none found for the guild
  * @param guild_id : id of the guild
- * @return guild_storage
+ * @return s_storage
  */
-struct guild_storage *gstorage_guild2storage(int guild_id)
+struct s_storage *guild2storage(int guild_id)
 {
-	struct guild_storage *gs = NULL;
+	struct s_storage *gs = NULL;
 
 	if (guild_search(guild_id) != NULL)
-		gs = (struct guild_storage *)idb_ensure(guild_storage_db,guild_id,create_guildstorage);
+		gs = (struct s_storage *)idb_ensure(guild_storage_db,guild_id,create_guildstorage);
 
 	return gs;
 }
 
 /**
- * See if the guild_storage exist in db and fetch it if it,s the case
+ * See if the guild_storage exist in db and fetch it if it's the case
  * @author : [Skotlex]
  * @param guild_id : guild_id to search the storage
- * @return guild_storage or NULL
+ * @return s_storage or NULL
  */
-struct guild_storage *gstorage_get_storage(int guild_id)
+struct s_storage *guild2storage2(int guild_id)
 {
-	return (struct guild_storage*)idb_get(guild_storage_db,guild_id);
+	return (struct s_storage*)idb_get(guild_storage_db,guild_id);
 }
 
 /**
@@ -446,7 +527,7 @@ struct guild_storage *gstorage_get_storage(int guild_id)
  * @param guild_id : guild to remove the storage from
  * @return 0
  */
-void gstorage_delete(int guild_id)
+void storage_guild_delete(int guild_id)
 {
 	idb_remove(guild_storage_db,guild_id);
 }
@@ -456,9 +537,9 @@ void gstorage_delete(int guild_id)
  * @param sd : player
  * @return 0 : success, 1 : fail, 2 : no guild found
  */
-char gstorage_storageopen(struct map_session_data* sd)
+char storage_guild_storageopen(struct map_session_data* sd)
 {
-	struct guild_storage *gstor;
+	struct s_storage *gstor;
 
 	nullpo_ret(sd);
 
@@ -473,22 +554,22 @@ char gstorage_storageopen(struct map_session_data* sd)
 		return 1;
 	}
 
-	if((gstor = gstorage_get_storage(sd->status.guild_id)) == NULL) {
+	if((gstor = guild2storage2(sd->status.guild_id)) == NULL) {
 		intif_request_guild_storage(sd->status.account_id,sd->status.guild_id);
 		return 0;
 	}
 
-	if(gstor->opened)
+	if(gstor->status)
 		return 1;
 
-	if( gstor->locked )
+	if( gstor->lock )
 		return 1;
 
-	gstor->opened = sd->status.char_id;
+	gstor->status = true;
 	sd->state.storage_flag = 2;
-	storage_sortitem(gstor->items, ARRAYLENGTH(gstor->items));
-	clif_storagelist(sd, gstor->items, ARRAYLENGTH(gstor->items));
-	clif_updatestorageamount(sd, gstor->storage_amount, MAX_GUILD_STORAGE);
+	storage_sortitem(gstor->u.items_guild, ARRAYLENGTH(gstor->u.items_guild));
+	clif_storagelist(sd, gstor->u.items_guild, ARRAYLENGTH(gstor->u.items_guild), "Guild Storage");
+	clif_updatestorageamount(sd, gstor->amount, MAX_GUILD_STORAGE);
 
 	return 0;
 }
@@ -501,41 +582,41 @@ char gstorage_storageopen(struct map_session_data* sd)
  * @param amount : number of item to add
  * @return True : success, False : fail
  */
-bool gstorage_additem(struct map_session_data* sd, struct guild_storage* stor, struct item* item, int amount)
+bool storage_guild_additem(struct map_session_data* sd, struct s_storage* stor, struct item* item_data, int amount)
 {
 	struct item_data *id;
 	int i;
 
 	nullpo_ret(sd);
 	nullpo_ret(stor);
-	nullpo_ret(item);
+	nullpo_ret(item_data);
 
-	if(item->nameid == 0 || amount <= 0)
+	if(item_data->nameid == 0 || amount <= 0)
 		return false;
 
-	id = itemdb_search(item->nameid);
+	id = itemdb_search(item_data->nameid);
 
 	if( id->stack.guildstorage && amount > id->stack.amount ) // item stack limitation
 		return false;
 
-	if( !itemdb_canguildstore(item, pc_get_group_level(sd)) || item->expire_time ) { // Check if item is storable. [Skotlex]
+	if (!itemdb_canguildstore(item_data, pc_get_group_level(sd)) || item_data->expire_time) { // Check if item is storable. [Skotlex]
 		clif_displaymessage (sd->fd, msg_txt(sd,264));
 		return false;
 	}
 
-	if( (item->bound == BOUND_ACCOUNT || item->bound > BOUND_GUILD) && !pc_can_give_bounded_items(sd) ) {
+	if ((item_data->bound == BOUND_ACCOUNT || item_data->bound > BOUND_GUILD) && !pc_can_give_bounded_items(sd)) {
 		clif_displaymessage(sd->fd, msg_txt(sd,294));
 		return false;
 	}
 
 	if(itemdb_isstackable2(id)) { //Stackable
-		for(i = 0; i < MAX_GUILD_STORAGE; i++){
-			if(compare_item(&stor->items[i], item)) {
-				if( amount > MAX_AMOUNT - stor->items[i].amount || ( id->stack.guildstorage && amount > id->stack.amount - stor->items[i].amount ) )
+		for(i = 0; i < MAX_GUILD_STORAGE; i++) {
+			if(compare_item(&stor->u.items_guild[i], item_data)) {
+				if( amount > MAX_AMOUNT - stor->u.items_guild[i].amount || ( id->stack.guildstorage && amount > id->stack.amount - stor->u.items_guild[i].amount ) )
 					return false;
-	
-				stor->items[i].amount+=amount;
-				clif_storageitemadded(sd,&stor->items[i],i,amount);
+
+				stor->u.items_guild[i].amount += amount;
+				clif_storageitemadded(sd,&stor->u.items_guild[i],i,amount);
 				stor->dirty = true;
 				return true;
 			}
@@ -543,15 +624,15 @@ bool gstorage_additem(struct map_session_data* sd, struct guild_storage* stor, s
 	}
 
 	//Add item
-	for(i = 0; i < MAX_GUILD_STORAGE && stor->items[i].nameid; i++);
+	for(i = 0; i < MAX_GUILD_STORAGE && stor->u.items_guild[i].nameid; i++);
 	if(i >= MAX_GUILD_STORAGE)
 		return false;
 
-	memcpy(&stor->items[i],item,sizeof(stor->items[0]));
-	stor->items[i].amount = amount;
-	stor->storage_amount++;
-	clif_storageitemadded(sd,&stor->items[i],i,amount);
-	clif_updatestorageamount(sd, stor->storage_amount, MAX_GUILD_STORAGE);
+	memcpy(&stor->u.items_guild[i],item_data,sizeof(stor->u.items_guild[0]));
+	stor->u.items_guild[i].amount = amount;
+	stor->amount++;
+	clif_storageitemadded(sd,&stor->u.items_guild[i],i,amount);
+	clif_updatestorageamount(sd, stor->amount, MAX_GUILD_STORAGE);
 	stor->dirty = true;
 	return true;
 }
@@ -563,7 +644,7 @@ bool gstorage_additem(struct map_session_data* sd, struct guild_storage* stor, s
  * @param amount : number of item to add
  * @return True : success, False : fail
  */
-bool gstorage_additem2(struct guild_storage* stor, struct item* item, int amount) {
+bool storage_guild_additem2(struct s_storage* stor, struct item* item, int amount) {
 	struct item_data *id;
 	int i;
 
@@ -578,13 +659,12 @@ bool gstorage_additem2(struct guild_storage* stor, struct item* item, int amount
 
 	if (itemdb_isstackable2(id)) { // Stackable
 		for (i = 0; i < MAX_GUILD_STORAGE; i++) {
-			if (compare_item(&stor->items[i], item)) {
+			if (compare_item(&stor->u.items_guild[i], item)) {
 				// Set the amount, make it fit with max amount
-                                int da = ((id->stack.guildstorage) ? id->stack.amount : MAX_AMOUNT) - stor->items[i].amount;
-				amount = min(amount, da);
+				amount = min(amount, ((id->stack.guildstorage) ? id->stack.amount : MAX_AMOUNT) - stor->u.items_guild[i].amount);
 				if (amount != item->amount)
-					ShowWarning("gstorage_additem2: Stack limit reached! Altered amount of item \""CL_WHITE"%s"CL_RESET"\" (%d). '"CL_WHITE"%d"CL_RESET"' -> '"CL_WHITE"%d"CL_RESET"'.\n", id->name, id->nameid, item->amount, amount);
-				stor->items[i].amount += amount;
+					ShowWarning("storage_guild_additem2: Stack limit reached! Altered amount of item \""CL_WHITE"%s"CL_RESET"\" (%d). '"CL_WHITE"%d"CL_RESET"' -> '"CL_WHITE"%d"CL_RESET"'.\n", id->name, id->nameid, item->amount, amount);
+				stor->u.items_guild[i].amount += amount;
 				stor->dirty = true;
 				return true;
 			}
@@ -592,13 +672,13 @@ bool gstorage_additem2(struct guild_storage* stor, struct item* item, int amount
 	}
 
 	// Add the item
-	for (i = 0; i < MAX_GUILD_STORAGE && stor->items[i].nameid; i++);
+	for (i = 0; i < MAX_GUILD_STORAGE && stor->u.items_guild[i].nameid; i++);
 	if (i >= MAX_GUILD_STORAGE)
 		return false;
 
-	memcpy(&stor->items[i], item, sizeof(stor->items[0]));
-	stor->items[i].amount = amount;
-	stor->storage_amount++;
+	memcpy(&stor->u.items_guild[i], item, sizeof(stor->u.items_guild[0]));
+	stor->u.items_guild[i].amount = amount;
+	stor->amount++;
 	stor->dirty = true;
 	return true;
 }
@@ -611,20 +691,20 @@ bool gstorage_additem2(struct guild_storage* stor, struct item* item, int amount
  * @param amount : number of item to delete
  * @return True : success, False : fail
  */
-bool gstorage_delitem(struct map_session_data* sd, struct guild_storage* stor, int n, int amount)
+bool storage_guild_delitem(struct map_session_data* sd, struct s_storage* stor, int n, int amount)
 {
 	nullpo_retr(1, sd);
 	nullpo_retr(1, stor);
 
-	if(stor->items[n].nameid == 0 || stor->items[n].amount < amount)
+	if(!stor->u.items_guild[n].nameid || stor->u.items_guild[n].amount < amount)
 		return false;
 
-	stor->items[n].amount -= amount;
+	stor->u.items_guild[n].amount -= amount;
 
-	if(stor->items[n].amount == 0) {
-		memset(&stor->items[n],0,sizeof(stor->items[0]));
-		stor->storage_amount--;
-		clif_updatestorageamount(sd, stor->storage_amount, MAX_GUILD_STORAGE);
+	if(!stor->u.items_guild[n].amount) {
+		memset(&stor->u.items_guild[n],0,sizeof(stor->u.items_guild[0]));
+		stor->amount--;
+		clif_updatestorageamount(sd, stor->amount, MAX_GUILD_STORAGE);
 	}
 
 	clif_storageitemremoved(sd,n,amount);
@@ -637,31 +717,31 @@ bool gstorage_delitem(struct map_session_data* sd, struct guild_storage* stor, i
  * @param sd : player
  * @param amount : number of item to delete
  */
-void gstorage_storageadd(struct map_session_data* sd, int index, int amount)
+void storage_guild_storageadd(struct map_session_data* sd, int index, int amount)
 {
-	struct guild_storage *stor;
+	struct s_storage *stor;
 
 	nullpo_retv(sd);
-	nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
+	nullpo_retv(stor = guild2storage2(sd->status.guild_id));
 
-	if( !stor->opened || stor->opened != sd->status.char_id || stor->storage_amount > MAX_GUILD_STORAGE )
+	if( !stor->status || stor->amount > MAX_GUILD_STORAGE )
 		return;
 
 	if( index < 0 || index >= MAX_INVENTORY )
 		return;
 
-	if( sd->status.inventory[index].nameid == 0 )
+	if( sd->inventory.u.items_inventory[index].nameid == 0 )
 		return;
 
-	if( amount < 1 || amount > sd->status.inventory[index].amount )
+	if( amount < 1 || amount > sd->inventory.u.items_inventory[index].amount )
 		return;
 
-	if( stor->locked ) {
-		gstorage_storageclose(sd);
+	if( stor->lock ) {
+		storage_guild_storageclose(sd);
 		return;
 	}
 
-	if(gstorage_additem(sd,stor,&sd->status.inventory[index],amount))
+	if(storage_guild_additem(sd,stor,&sd->inventory.u.items_inventory[index],amount))
 		pc_delitem(sd,index,amount,0,4,LOG_TYPE_GSTORAGE);
 	else {
 		clif_storageitemremoved(sd,index,0);
@@ -676,33 +756,33 @@ void gstorage_storageadd(struct map_session_data* sd, int index, int amount)
  * @param amount : number of item to get
  * @return 1:success, 0:fail
  */
-void gstorage_storageget(struct map_session_data* sd, int index, int amount)
+void storage_guild_storageget(struct map_session_data* sd, int index, int amount)
 {
-	struct guild_storage *stor;
+	struct s_storage *stor;
 	unsigned char flag = 0;
 
 	nullpo_retv(sd);
-	nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
+	nullpo_retv(stor = guild2storage2(sd->status.guild_id));
 
-	if(!stor->opened || stor->opened != sd->status.char_id)
+	if(!stor->status)
 		return;
 
 	if(index < 0 || index >= MAX_GUILD_STORAGE)
 		return;
 
-	if(stor->items[index].nameid == 0)
+	if(stor->u.items_guild[index].nameid == 0)
 		return;
 
-	if(amount < 1 || amount > stor->items[index].amount)
+	if(amount < 1 || amount > stor->u.items_guild[index].amount)
 		return;
 
-	if( stor->locked ) {
-		gstorage_storageclose(sd);
+	if( stor->lock ) {
+		storage_guild_storageclose(sd);
 		return;
 	}
 
-	if((flag = pc_additem(sd,&stor->items[index],amount,LOG_TYPE_GSTORAGE)) == 0)
-		gstorage_delitem(sd,stor,index,amount);
+	if((flag = pc_additem(sd,&stor->u.items_guild[index],amount,LOG_TYPE_GSTORAGE)) == 0)
+		storage_guild_delitem(sd,stor,index,amount);
 	else { // inform fail
 		clif_storageitemremoved(sd,index,0);
 		clif_additem(sd,0,0,flag);
@@ -715,26 +795,26 @@ void gstorage_storageget(struct map_session_data* sd, int index, int amount)
  * @param index : index of item in cart
  * @param amount : number of item to transfer
  */
-void gstorage_storageaddfromcart(struct map_session_data* sd, int index, int amount)
+void storage_guild_storageaddfromcart(struct map_session_data* sd, int index, int amount)
 {
-	struct guild_storage *stor;
+	struct s_storage *stor;
 
 	nullpo_retv(sd);
-	nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
+	nullpo_retv(stor = guild2storage2(sd->status.guild_id));
 
-	if( !stor->opened || stor->opened != sd->status.char_id || stor->storage_amount > MAX_GUILD_STORAGE )
+	if( !stor->status || stor->amount > MAX_GUILD_STORAGE )
 		return;
 
 	if( index < 0 || index >= MAX_CART )
 		return;
 
-	if( sd->status.cart[index].nameid == 0 )
+	if( sd->cart.u.items_cart[index].nameid == 0 )
 		return;
 
-	if( amount < 1 || amount > sd->status.cart[index].amount )
+	if( amount < 1 || amount > sd->cart.u.items_cart[index].amount )
 		return;
 
-	if(gstorage_additem(sd,stor,&sd->status.cart[index],amount))
+	if(storage_guild_additem(sd,stor,&sd->cart.u.items_cart[index],amount))
 		pc_cart_delitem(sd,index,amount,0,LOG_TYPE_GSTORAGE);
 	else {
 		clif_storageitemremoved(sd,index,0);
@@ -749,28 +829,28 @@ void gstorage_storageaddfromcart(struct map_session_data* sd, int index, int amo
  * @param amount : number of item to transfer
  * @return 1:fail, 0:success
  */
-void gstorage_storagegettocart(struct map_session_data* sd, int index, int amount)
+void storage_guild_storagegettocart(struct map_session_data* sd, int index, int amount)
 {
 	short flag;
-	struct guild_storage *stor;
+	struct s_storage *stor;
 
 	nullpo_retv(sd);
-	nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
+	nullpo_retv(stor = guild2storage2(sd->status.guild_id));
 
-	if(!stor->opened || stor->opened != sd->status.char_id)
+	if(!stor->status)
 		return;
 
 	if(index < 0 || index >= MAX_GUILD_STORAGE)
 		return;
 
-	if(stor->items[index].nameid == 0)
+	if(stor->u.items_guild[index].nameid == 0)
 		return;
 
-	if(amount < 1 || amount > stor->items[index].amount)
+	if(amount < 1 || amount > stor->u.items_guild[index].amount)
 		return;
 
-	if((flag = pc_cart_additem(sd,&stor->items[index],amount,LOG_TYPE_GSTORAGE)) == 0)
-		gstorage_delitem(sd,stor,index,amount);
+	if((flag = pc_cart_additem(sd,&stor->u.items_guild[index],amount,LOG_TYPE_GSTORAGE)) == 0)
+		storage_guild_delitem(sd,stor,index,amount);
 	else {
 		clif_storageitemremoved(sd,index,0);
 		clif_cart_additem_ack(sd,(flag == 1) ? ADDITEM_TO_CART_FAIL_WEIGHT:ADDITEM_TO_CART_FAIL_COUNT);
@@ -784,13 +864,13 @@ void gstorage_storagegettocart(struct map_session_data* sd, int index, int amoun
  * @param flag : 1=char quitting, close the storage
  * @return False : fail (no storage), True : success (requested)
  */
-bool gstorage_storagesave(uint32 account_id, int guild_id, int flag)
+bool storage_guild_storagesave(uint32 account_id, int guild_id, int flag)
 {
-	struct guild_storage *stor = gstorage_get_storage(guild_id);
+	struct s_storage *stor = guild2storage2(guild_id);
 
 	if (stor) {
 		if (flag) //Char quitting, close it.
-			stor->opened = 0;
+			stor->status = false;
 
 		if (stor->dirty)
 			intif_send_guild_storage(account_id,stor);
@@ -805,12 +885,12 @@ bool gstorage_storagesave(uint32 account_id, int guild_id, int flag)
  * ACK save of guild storage
  * @param guild_id : guild to use the storage
  */
-void gstorage_storagesaved(int guild_id)
+void storage_guild_storagesaved(int guild_id)
 {
-	struct guild_storage *stor;
+	struct s_storage *stor;
 
-	if ((stor = gstorage_get_storage(guild_id)) != NULL) {
-		if (stor->dirty && stor->opened == 0) // Storage has been correctly saved.
+	if ((stor = guild2storage2(guild_id)) != NULL) {
+		if (stor->dirty && !stor->status) // Storage has been correctly saved.
 			stor->dirty = false;
 	}
 }
@@ -819,21 +899,21 @@ void gstorage_storagesaved(int guild_id)
  * Close storage for player then save it
  * @param sd : player
  */
-void gstorage_storageclose(struct map_session_data* sd)
+void storage_guild_storageclose(struct map_session_data* sd)
 {
-	struct guild_storage *stor;
+	struct s_storage *stor;
 
 	nullpo_retv(sd);
-	nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
+	nullpo_retv(stor = guild2storage2(sd->status.guild_id));
 
 	clif_storageclose(sd);
-	if (stor->opened) {
+	if (stor->status) {
 		if (save_settings&CHARSAVE_STORAGE)
 			chrif_save(sd, 0); //This one also saves the storage. [Skotlex]
 		else
-			gstorage_storagesave(sd->status.account_id, sd->status.guild_id,0);
+			storage_guild_storagesave(sd->status.account_id, sd->status.guild_id,0);
 
-		stor->opened = 0;
+		stor->status = false;
 	}
 
 	sd->state.storage_flag = 0;
@@ -844,31 +924,149 @@ void gstorage_storageclose(struct map_session_data* sd)
  * @param sd
  * @param flag
  */
-void gstorage_storage_quit(struct map_session_data* sd, int flag)
+void storage_guild_storage_quit(struct map_session_data* sd, int flag)
 {
-	struct guild_storage *stor;
+	struct s_storage *stor;
 
 	nullpo_retv(sd);
-	nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
+	nullpo_retv(stor = guild2storage2(sd->status.guild_id));
 
-	if (flag) { // Only during a guild break flag is 1 (don't save storage)
-		sd->state.storage_flag = 0;
-		stor->opened = 0;
+	if (flag) {	//Only during a guild break flag is 1 (don't save storage)
 		clif_storageclose(sd);
 
 		if (save_settings&CHARSAVE_STORAGE)
 			chrif_save(sd,0);
 
+		sd->state.storage_flag = 0;
+		stor->status = false;
 		return;
 	}
 
-	if (stor->opened) {
+	if (stor->status) {
 		if (save_settings&CHARSAVE_STORAGE)
 			chrif_save(sd,0);
 		else
-			gstorage_storagesave(sd->status.account_id,sd->status.guild_id,1);
+			storage_guild_storagesave(sd->status.account_id,sd->status.guild_id,1);
 	}
 
 	sd->state.storage_flag = 0;
-	stor->opened = 0;
+	stor->status = false;
+}
+
+/**
+ * Open premium storage
+ * @param sd Player
+ **/
+void storage_premiumStorage_open(struct map_session_data *sd) {
+	nullpo_retv(sd);
+
+	if (!&sd->premiumStorage)
+		return;
+
+	sd->state.storage_flag = 3;
+	storage_sortitem(sd->premiumStorage.u.items_storage, sd->premiumStorage.max_amount);
+	clif_storagelist(sd, sd->premiumStorage.u.items_storage, sd->premiumStorage.max_amount, storage_getName(sd->premiumStorage.stor_id));
+	clif_updatestorageamount(sd, sd->premiumStorage.amount, sd->premiumStorage.max_amount);
+}
+
+/**
+ * Request to open premium storage
+ * @param sd Player who request
+ * @param num Storage number
+ * @param mode Storage mode @see enum e_storage_mode
+ * @return 1:Success to request, 0:Failed
+ * @author [Cydh]
+ **/
+bool storage_premiumStorage_load(struct map_session_data *sd, uint8 num, uint8 mode) {
+	nullpo_ret(sd);
+
+	if (sd->state.storage_flag)
+		return 0;
+
+	if (sd->state.vending || sd->state.buyingstore || sd->state.prevend || sd->state.autotrade)
+		return 0;
+
+	if (sd->state.banking || sd->state.callshop)
+		return 0;
+
+	if (!pc_can_give_items(sd)) { // check is this GM level is allowed to put items to storage
+		clif_displaymessage(sd->fd, msg_txt(sd,246));
+		return 0;
+	}
+
+	if (!&sd->premiumStorage || sd->premiumStorage.stor_id != num)
+		return intif_storage_request(sd, TABLE_STORAGE, num, mode);
+	else {
+		sd->premiumStorage.state.put = (mode&STOR_MODE_PUT) ? 1 : 0;
+		sd->premiumStorage.state.get = (mode&STOR_MODE_GET) ? 1 : 0;
+		storage_premiumStorage_open(sd);
+	}
+	return 1;
+}
+
+/**
+ * Request to save premium storage
+ * @param sd Player who has the storage
+ * @author [Cydh]
+ **/
+void storage_premiumStorage_save(struct map_session_data *sd) {
+	nullpo_retv(sd);
+
+	if (!&sd->premiumStorage)
+		return;
+
+	intif_storage_save(sd, &sd->premiumStorage);
+}
+
+/**
+ * Ack of secondary premium has been saved
+ * @param sd Player who has the storage
+ **/
+void storage_premiumStorage_saved(struct map_session_data *sd) {
+	if (!sd)
+		return;
+
+	if (&sd->premiumStorage) {
+		sd->premiumStorage.dirty = 0;
+	}
+	if (sd->state.storage_flag == 3) {
+		sd->state.storage_flag = 0;
+		clif_storageclose(sd);
+	}
+}
+
+/**
+ * Request to close premium storage
+ * @param sd Player who has the storage
+ * @author [Cydh]
+ **/
+void storage_premiumStorage_close(struct map_session_data *sd) {
+	nullpo_retv(sd);
+
+	if (!&sd->premiumStorage)
+		return;
+
+	if (sd->premiumStorage.dirty) {
+		intif_storage_save(sd, &sd->premiumStorage);
+		if (sd->state.storage_flag == 3) {
+			sd->state.storage_flag = 0;
+			clif_storageclose(sd);
+		}
+	}
+	else 
+		storage_premiumStorage_saved(sd);
+}
+
+/**
+ * Force save then close the premium storage
+ * @param sd Player who has the storage
+ * @author [Cydh]
+ **/
+void storage_premiumStorage_quit(struct map_session_data *sd) {
+	nullpo_retv(sd);
+
+	if (!&sd->premiumStorage)
+		return;
+
+	intif_storage_save(sd, &sd->premiumStorage);
 }

+ 42 - 22
src/map/storage.h

@@ -5,18 +5,30 @@
 #define _STORAGE_H_
 
 //#include "../common/mmo.h"
-struct storage_data;
-struct guild_storage;
+struct s_storage;
 struct item;
 //#include "map.h"
 struct map_session_data;
 
-int storage_delitem(struct map_session_data* sd, int n, int amount);
+extern struct s_storage_table *storage_db;
+extern int storage_count;
+
+enum e_storage_add {
+	STORAGE_ADD_OK,
+	STORAGE_ADD_NOROOM,
+	STORAGE_ADD_NOACCESS,
+	STORAGE_ADD_INVALID,
+};
+
+const char *storage_getName(uint8 id);
+bool storage_exists(uint8 id);
+
+int storage_delitem(struct map_session_data* sd, struct s_storage *stor, int index, int amount);
 int storage_storageopen(struct map_session_data *sd);
-void storage_storageadd(struct map_session_data *sd,int index,int amount);
-void storage_storageget(struct map_session_data *sd,int index,int amount);
-void storage_storageaddfromcart(struct map_session_data *sd,int index,int amount);
-void storage_storagegettocart(struct map_session_data *sd,int index,int amount);
+void storage_storageadd(struct map_session_data *sd, struct s_storage *stor, int index, int amount);
+void storage_storageget(struct map_session_data *sd, struct s_storage *stor, int index, int amount);
+void storage_storageaddfromcart(struct map_session_data *sd, struct s_storage *stor, int index, int amount);
+void storage_storagegettocart(struct map_session_data *sd, struct s_storage *stor, int index, int amount);
 void storage_storageclose(struct map_session_data *sd);
 void storage_sortitem(struct item* items, unsigned int size);
 void do_init_storage(void);
@@ -24,21 +36,29 @@ void do_final_storage(void);
 void do_reconnect_storage(void);
 void storage_storage_quit(struct map_session_data *sd, int flag);
 
-struct guild_storage* gstorage_guild2storage(int guild_id);
-struct guild_storage *gstorage_get_storage(int guild_id);
-void gstorage_delete(int guild_id);
-char gstorage_storageopen(struct map_session_data *sd);
-bool gstorage_additem(struct map_session_data *sd,struct guild_storage *stor,struct item *item,int amount);
-bool gstorage_additem2(struct guild_storage *stor, struct item *item, int amount);
-bool gstorage_delitem(struct map_session_data *sd,struct guild_storage *stor,int n,int amount);
-void gstorage_storageadd(struct map_session_data *sd,int index,int amount);
-void gstorage_storageget(struct map_session_data *sd,int index,int amount);
-void gstorage_storageaddfromcart(struct map_session_data *sd,int index,int amount);
-void gstorage_storagegettocart(struct map_session_data *sd,int index,int amount);
-void gstorage_storageclose(struct map_session_data *sd);
-void gstorage_storage_quit(struct map_session_data *sd,int flag);
-bool gstorage_storagesave(uint32 account_id, int guild_id, int flag);
-void gstorage_storagesaved(int guild_id);
+struct s_storage* guild2storage(int guild_id);
+struct s_storage* guild2storage2(int guild_id);
+void storage_guild_delete(int guild_id);
+char storage_guild_storageopen(struct map_session_data *sd);
+bool storage_guild_additem(struct map_session_data *sd,struct s_storage *stor,struct item *item_data,int amount);
+bool storage_guild_additem2(struct s_storage* stor, struct item* item, int amount);
+bool storage_guild_delitem(struct map_session_data *sd,struct s_storage *stor,int n,int amount);
+void storage_guild_storageadd(struct map_session_data *sd,int index,int amount);
+void storage_guild_storageget(struct map_session_data *sd,int index,int amount);
+void storage_guild_storageaddfromcart(struct map_session_data *sd,int index,int amount);
+void storage_guild_storagegettocart(struct map_session_data *sd,int index,int amount);
+void storage_guild_storageclose(struct map_session_data *sd);
+void storage_guild_storage_quit(struct map_session_data *sd,int flag);
+bool storage_guild_storagesave(uint32 account_id, int guild_id, int flag);
+void storage_guild_storagesaved(int guild_id); //Ack from char server that guild store was saved.
+
+// Premium Storage [Cydh]
+void storage_premiumStorage_open(struct map_session_data *sd);
+bool storage_premiumStorage_load(struct map_session_data *sd, uint8 num, uint8 mode);
+void storage_premiumStorage_save(struct map_session_data *sd);
+void storage_premiumStorage_saved(struct map_session_data *sd);
+void storage_premiumStorage_close(struct map_session_data *sd);
+void storage_premiumStorage_quit(struct map_session_data *sd);
 
 int compare_item(struct item *a, struct item *b);
 

+ 9 - 9
src/map/trade.c

@@ -182,7 +182,7 @@ int impossible_trade_check(struct map_session_data *sd)
 	}
 
 	// get inventory of player
-	memcpy(&inventory, &sd->status.inventory, sizeof(struct item) * MAX_INVENTORY);
+	memcpy(&inventory, &sd->inventory.u.items_inventory, sizeof(struct item) * MAX_INVENTORY);
 
 	// remove this part: arrows can be trade and equipped
 	// re-added! [celest]
@@ -248,8 +248,8 @@ int trade_check(struct map_session_data *sd, struct map_session_data *tsd)
 		return 0;
 
 	// get inventory of player
-	memcpy(&inventory, &sd->status.inventory, sizeof(struct item) * MAX_INVENTORY);
-	memcpy(&inventory2, &tsd->status.inventory, sizeof(struct item) * MAX_INVENTORY);
+	memcpy(&inventory, &sd->inventory.u.items_inventory, sizeof(struct item) * MAX_INVENTORY);
+	memcpy(&inventory2, &tsd->inventory.u.items_inventory, sizeof(struct item) * MAX_INVENTORY);
 
 	// check free slot in both inventory
 	for(trade_i = 0; trade_i < 10; trade_i++) {
@@ -365,10 +365,10 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount)
 	// Item checks...
 	if( index < 0 || index >= MAX_INVENTORY )
 		return;
-	if( amount < 0 || amount > sd->status.inventory[index].amount )
+	if( amount < 0 || amount > sd->inventory.u.items_inventory[index].amount )
 		return;
 
-	item = &sd->status.inventory[index];
+	item = &sd->inventory.u.items_inventory[index];
 	src_lv = pc_get_group_level(sd);
 	dst_lv = pc_get_group_level(target_sd);
 
@@ -408,8 +408,8 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount)
 	}
 
 	if( sd->deal.item[trade_i].index == index ) { // The same item as before is being readjusted.
-		if( sd->deal.item[trade_i].amount + amount > sd->status.inventory[index].amount ) { // packet deal exploit check
-			amount = sd->status.inventory[index].amount - sd->deal.item[trade_i].amount;
+		if( sd->deal.item[trade_i].amount + amount > sd->inventory.u.items_inventory[index].amount ) { // packet deal exploit check
+			amount = sd->inventory.u.items_inventory[index].amount - sd->deal.item[trade_i].amount;
 			trade_weight = sd->inventory_data[index]->weight * amount;
 		}
 
@@ -594,7 +594,7 @@ void trade_tradecommit(struct map_session_data *sd)
 		if (sd->deal.item[trade_i].amount) {
 			n = sd->deal.item[trade_i].index;
 
-			flag = pc_additem(tsd, &sd->status.inventory[n], sd->deal.item[trade_i].amount,LOG_TYPE_TRADE);
+			flag = pc_additem(tsd, &sd->inventory.u.items_inventory[n], sd->deal.item[trade_i].amount,LOG_TYPE_TRADE);
 			if (flag == 0)
 				pc_delitem(sd, n, sd->deal.item[trade_i].amount, 1, 6, LOG_TYPE_TRADE);
 			else
@@ -606,7 +606,7 @@ void trade_tradecommit(struct map_session_data *sd)
 		if (tsd->deal.item[trade_i].amount) {
 			n = tsd->deal.item[trade_i].index;
 
-			flag = pc_additem(sd, &tsd->status.inventory[n], tsd->deal.item[trade_i].amount,LOG_TYPE_TRADE);
+			flag = pc_additem(sd, &tsd->inventory.u.items_inventory[n], tsd->deal.item[trade_i].amount,LOG_TYPE_TRADE);
 			if (flag == 0)
 				pc_delitem(tsd, n, tsd->deal.item[trade_i].amount, 1, 6, LOG_TYPE_TRADE);
 			else

+ 3 - 1
src/map/unit.c

@@ -2911,7 +2911,9 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file,
 				if (sd->state.storage_flag == 1)
 					storage_storage_quit(sd,0);
 				else if (sd->state.storage_flag == 2)
-					gstorage_storage_quit(sd,0);
+					storage_guild_storage_quit(sd, 0);
+				else if (sd->state.storage_flag == 3)
+					storage_premiumStorage_quit(sd);
 
 				sd->state.storage_flag = 0; //Force close it when being warped.
 			}

+ 18 - 30
src/map/vending.c

@@ -157,15 +157,15 @@ void vending_purchasereq(struct map_session_data* sd, int aid, int uid, const ui
 			return;
 
 		}
-		w += itemdb_weight(vsd->status.cart[idx].nameid) * amount;
+		w += itemdb_weight(vsd->cart.u.items_cart[idx].nameid) * amount;
 		if( w + sd->weight > sd->max_weight ) {
 			clif_buyvending(sd, idx, amount, 2); // you can not buy, because overweight
 			return;
 		}
 
 		//Check to see if cart/vend info is in sync.
-		if( vending[j].amount > vsd->status.cart[idx].amount )
-			vending[j].amount = vsd->status.cart[idx].amount;
+		if( vending[j].amount > vsd->cart.u.items_cart[idx].amount )
+			vending[j].amount = vsd->cart.u.items_cart[idx].amount;
 
 		// if they try to add packets (example: get twice or more 2 apples if marchand has only 3 apples).
 		// here, we check cumulative amounts
@@ -177,7 +177,7 @@ void vending_purchasereq(struct map_session_data* sd, int aid, int uid, const ui
 
 		vending[j].amount -= amount;
 
-		switch( pc_checkadditem(sd, vsd->status.cart[idx].nameid, amount) ) {
+		switch( pc_checkadditem(sd, vsd->cart.u.items_cart[idx].nameid, amount) ) {
 		case CHKADDITEM_EXIST:
 			break;	//We'd add this item to the existing one (in buyers inventory)
 		case CHKADDITEM_NEW:
@@ -202,16 +202,16 @@ void vending_purchasereq(struct map_session_data* sd, int aid, int uid, const ui
 		z = 0.; // zeny counter
 
 		// vending item
-		pc_additem(sd, &vsd->status.cart[idx], amount, LOG_TYPE_VENDING);
+		pc_additem(sd, &vsd->cart.u.items_cart[idx], amount, LOG_TYPE_VENDING);
 		vsd->vending[vend_list[i]].amount -= amount;
 		z += ((double)vsd->vending[i].value * (double)amount);
 
 		if( vsd->vending[vend_list[i]].amount ) {
-			if( Sql_Query( mmysql_handle, "UPDATE `%s` SET `amount` = %d WHERE `vending_id` = %d and `cartinventory_id` = %d", vending_items_db, vsd->vending[vend_list[i]].amount, vsd->vender_id, vsd->status.cart[idx].id ) != SQL_SUCCESS ) {
+			if( Sql_Query( mmysql_handle, "UPDATE `%s` SET `amount` = %d WHERE `vending_id` = %d and `cartinventory_id` = %d", vending_items_db, vsd->vending[vend_list[i]].amount, vsd->vender_id, vsd->cart.u.items_cart[idx].id ) != SQL_SUCCESS ) {
 				Sql_ShowDebug( mmysql_handle );
 			}
 		} else {
-			if( Sql_Query( mmysql_handle, "DELETE FROM `%s` WHERE `vending_id` = %d and `cartinventory_id` = %d", vending_items_db, vsd->vender_id, vsd->status.cart[idx].id ) != SQL_SUCCESS ) {
+			if( Sql_Query( mmysql_handle, "DELETE FROM `%s` WHERE `vending_id` = %d and `cartinventory_id` = %d", vending_items_db, vsd->vender_id, vsd->cart.u.items_cart[idx].id ) != SQL_SUCCESS ) {
 				Sql_ShowDebug( mmysql_handle );
 			}
 		}
@@ -315,28 +315,16 @@ int8 vending_openvending(struct map_session_data* sd, const char* message, const
 		if( index < 0 || index >= MAX_CART // invalid position
 		||  pc_cartitem_amount(sd, index, amount) < 0 // invalid item or insufficient quantity
 		//NOTE: official server does not do any of the following checks!
-		||  !sd->status.cart[index].identify // unidentified item
-		||  sd->status.cart[index].attribute == 1 // broken item
-		||  sd->status.cart[index].expire_time // It should not be in the cart but just in case
-		||  (sd->status.cart[index].bound && !pc_can_give_bounded_items(sd)) // can't trade account bound items and has no permission
-		||  !itemdb_cantrade(&sd->status.cart[index], pc_get_group_level(sd), pc_get_group_level(sd)) ) // untradeable item
+		||  !sd->cart.u.items_cart[index].identify // unidentified item
+		||  sd->cart.u.items_cart[index].attribute == 1 // broken item
+		||  sd->cart.u.items_cart[index].expire_time // It should not be in the cart but just in case
+		||  (sd->cart.u.items_cart[index].bound && !pc_can_give_bounded_items(sd)) // can't trade account bound items and has no permission
+		||  !itemdb_cantrade(&sd->cart.u.items_cart[index], pc_get_group_level(sd), pc_get_group_level(sd)) ) // untradeable item
 			continue;
 
 		sd->vending[i].index = index;
 		sd->vending[i].amount = amount;
 		sd->vending[i].value = min(value, (unsigned int)battle_config.vending_max_value);
-
-		// Player just moved item to cart and we don't have the correct cart ID yet.
-		if (sd->status.cart[sd->vending[i].index].id == 0) {
-			struct item_data *idb = itemdb_search(sd->status.cart[index].nameid);
-			char msg[256];
-
-			sprintf(msg, msg_txt(sd, 733), idb->jname);
-			clif_displaymessage(sd->fd, msg);
-			clif_skill_fail(sd, MC_VENDING, USESKILL_FAIL_LEVEL, 0);
-			return 4;
-		}
-
 		i++; // item successfully added
 	}
 
@@ -366,7 +354,7 @@ int8 vending_openvending(struct map_session_data* sd, const char* message, const
 	StringBuf_Init(&buf);
 	StringBuf_Printf(&buf, "INSERT INTO `%s`(`vending_id`,`index`,`cartinventory_id`,`amount`,`price`) VALUES", vending_items_db);
 	for (i = 0; i < count; i++) {
-		StringBuf_Printf(&buf, "(%d,%d,%d,%d,%d)", sd->vender_id, i, sd->status.cart[sd->vending[i].index].id, sd->vending[i].amount, sd->vending[i].value);
+		StringBuf_Printf(&buf, "(%d,%d,%d,%d,%d)", sd->vender_id, i, sd->cart.u.items_cart[sd->vending[i].index].id, sd->vending[i].amount, sd->vending[i].value);
 		if (i < count-1)
 			StringBuf_AppendStr(&buf, ",");
 	}
@@ -396,7 +384,7 @@ bool vending_search(struct map_session_data* sd, unsigned short nameid)
 		return false;
 	}
 
-	ARR_FIND( 0, sd->vend_num, i, sd->status.cart[sd->vending[i].index].nameid == (short)nameid );
+	ARR_FIND( 0, sd->vend_num, i, sd->cart.u.items_cart[sd->vending[i].index].nameid == (short)nameid );
 	if( i == sd->vend_num ) { // not found
 		return false;
 	}
@@ -420,11 +408,11 @@ bool vending_searchall(struct map_session_data* sd, const struct s_search_store_
 		return true;
 
 	for( idx = 0; idx < s->item_count; idx++ ) {
-		ARR_FIND( 0, sd->vend_num, i, sd->status.cart[sd->vending[i].index].nameid == (short)s->itemlist[idx] );
+		ARR_FIND( 0, sd->vend_num, i, sd->cart.u.items_cart[sd->vending[i].index].nameid == (short)s->itemlist[idx] );
 		if( i == sd->vend_num ) { // not found
 			continue;
 		}
-		it = &sd->status.cart[sd->vending[i].index];
+		it = &sd->cart.u.items_cart[sd->vending[i].index];
 
 		if( s->min_price && s->min_price > sd->vending[i].value ) { // too low price
 			continue;
@@ -486,7 +474,7 @@ void vending_reopen( struct map_session_data* sd )
 			uint32 *value = (uint32*)(p + 4);
 
 			// Find item position in cart
-			ARR_FIND(0, MAX_CART, entry->index, sd->status.cart[entry->index].id == entry->cartinventory_id);
+			ARR_FIND(0, MAX_CART, entry->index, sd->cart.u.items_cart[entry->index].id == entry->cartinventory_id);
 
 			if (entry->index == MAX_CART) {
 				count--;
@@ -494,7 +482,7 @@ void vending_reopen( struct map_session_data* sd )
 			}
 
 			*index = entry->index + 2;
-			*amount = itemdb_isstackable(sd->status.cart[entry->index].nameid) ? entry->amount : 1;
+			*amount = itemdb_isstackable(sd->cart.u.items_cart[entry->index].nameid) ? entry->amount : 1;
 			*value = entry->price;
 
 			p += 8;

+ 1 - 0
vcproj-10/map-server.vcxproj

@@ -282,6 +282,7 @@
     <Copy SourceFiles="..\conf\import-tmpl\battle_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\battle_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\char_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\char_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\inter_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\inter_conf.txt')" />
+    <Copy SourceFiles="..\conf\import-tmpl\inter_server.conf" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\inter_server.conf')" />
     <Copy SourceFiles="..\conf\import-tmpl\log_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\log_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\login_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\login_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\map_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\map_conf.txt')" />

+ 1 - 0
vcproj-12/map-server.vcxproj

@@ -286,6 +286,7 @@
     <Copy SourceFiles="..\conf\import-tmpl\battle_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\battle_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\char_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\char_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\inter_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\inter_conf.txt')" />
+    <Copy SourceFiles="..\conf\import-tmpl\inter_server.conf" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\inter_server.conf')" />
     <Copy SourceFiles="..\conf\import-tmpl\log_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\log_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\login_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\login_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\map_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\map_conf.txt')" />

+ 1 - 0
vcproj-13/map-server.vcxproj

@@ -286,6 +286,7 @@
     <Copy SourceFiles="..\conf\import-tmpl\battle_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\battle_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\char_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\char_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\inter_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\inter_conf.txt')" />
+    <Copy SourceFiles="..\conf\import-tmpl\inter_server.conf" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\inter_server.conf')" />
     <Copy SourceFiles="..\conf\import-tmpl\log_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\log_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\login_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\login_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\map_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\map_conf.txt')" />

+ 1 - 0
vcproj-14/map-server.vcxproj

@@ -284,6 +284,7 @@
     <Copy SourceFiles="..\conf\import-tmpl\battle_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\battle_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\char_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\char_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\inter_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\inter_conf.txt')" />
+    <Copy SourceFiles="..\conf\import-tmpl\inter_server.conf" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\inter_server.conf')" />
     <Copy SourceFiles="..\conf\import-tmpl\log_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\log_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\login_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\login_conf.txt')" />
     <Copy SourceFiles="..\conf\import-tmpl\map_conf.txt" DestinationFolder="..\conf\import\" ContinueOnError="true" Condition="!Exists('..\conf\import\map_conf.txt')" />