Ver código fonte

Changed Guild/Party Bound Item Retrieval Methods:
* Bug Fixes bug:9338
* Now resend the list to map-server from char/inter-server to avoid "weird" item allocation on guild storage. Example, previously you will meet stacked item like GUID does, but it shouldn't!
* Also will check the maximum amount that can be store in guild store. If guild storage is full (the slots or item stack limit is reach) the rest value/item will be dropped.
* Account of kicked guild member won't be kicked from server anymore if the player idle on character select window (just prevents player to login when retriving items are in progress)
* Delete guild bound items from guild master when guild is disbanded! Previously, the bound type just changed to NONE. Also for party bound item.
* If kicked guild/party member is trading bound item when be kicked, the trade will be canceled!
* If the guild member is being kicked when open guild storage, storage will be closed first waiting for next item retrieval.
* Now when guild storage is opened, storage_status (changed the var to 'opened') will be used to hold char_id who opens it.
Misc:
* Cleanup guild storage prefix functions, changed them to "gstorage_*"
* Added `picklog` type 'B' for logging deleted bound item because of kicked from guild/party.
* Updated documentation for new used packet 0x3857

NOTE: Please import upgrade-20150103_log.sql
Signed-off-by: Cydh Ramdh <house.bad@gmail.com>

Cydh Ramdh 10 anos atrás
pai
commit
022d72891e

+ 14 - 0
doc/packet_interserv.txt

@@ -2021,6 +2021,20 @@ Currently the max packet size is 0xFFFF (see 'WFIFOSET()' in 'src/common/socket.
 	desc:
 		- Acknowledge the good deletion of the bound item
 
+0x3857
+	Type: IZ
+	Structure: <cmd>.W <size>.W <count>.W <guild_id>.W { <items>.?B }*MAX_INVENTORY
+	index: 0,2,4,6,8
+	len: variable: 8+items
+	parameter:
+		- cmd : packet identification (0x3856)
+		- size
+		- count : number of item retrieved
+		- guild_id
+		- items: retreived guild bound items
+	desc:
+		- Ask map-server to process the retreived guild bound items from expelled member
+
 0x3860
 	Type: IZ
 	Structure: <cmd>.W <size>.W <char_id>.L <quest>.?B

+ 1 - 0
sql-files/upgrades/upgrade_20150103_log.sql

@@ -0,0 +1 @@
+ALTER TABLE `picklog` MODIFY `type` ENUM('M','P','L','T','V','S','N','C','A','R','G','E','B','O','I','X','D','U','$') NOT NULL DEFAULT 'S';

+ 17 - 0
src/char/char.c

@@ -1809,7 +1809,24 @@ void char_disconnect_player(uint32 account_id)
 		set_eof(i);
 }
 
+/**
+* Set 'flag' value of char_session_data
+* @param account_id
+* @param value
+* @param set True: set the value by using '|= val', False: unset the value by using '&= ~val'
+**/
+void char_set_session_flag_(int account_id, int val, bool set) {
+	int i;
+	struct char_session_data* sd;
 
+	ARR_FIND(0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == account_id);
+	if (i < fd_max) {
+		if (set)
+			sd->flag |= val;
+		else
+			sd->flag &= ~val;
+	}
+}
 
 void char_auth_ok(int fd, struct char_session_data *sd) {
 	struct online_char_data* character;

+ 5 - 0
src/char/char.h

@@ -199,6 +199,7 @@ struct char_session_data {
 	uint8 isvip;
 	time_t unban_time[MAX_CHARS];
 	int charblock_timer;
+	uint8 flag; // &1 - Retrieving guild bound items
 };
 
 
@@ -263,6 +264,10 @@ int char_make_new_char_sql(struct char_session_data* sd, char* name_, int slot,
 int char_make_new_char_sql(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style);
 #endif
 
+void char_set_session_flag_(int account_id, int val, bool set);
+#define char_set_session_flag(account_id, val)   ( char_set_session_flag_((account_id), (val), true)  )
+#define char_unset_session_flag(account_id, val) ( char_set_session_flag_((account_id), (val), false) )
+
 //For use in packets that depend on an sd being present [Skotlex]
 #define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } }
 

+ 9 - 0
src/char/char_clif.c

@@ -704,6 +704,15 @@ int chclif_parse_charselect(int fd, struct char_session_data* sd,uint32 ipl){
 		char_id = atoi(data);
 		Sql_FreeResult(sql_handle);
 
+		// Prevent select a char while retrieving guild bound items
+		if (sd->flag&1) {
+			WFIFOHEAD(fd,3);
+			WFIFOW(fd,0) = 0x6c;
+			WFIFOB(fd,2) = 0; // rejected from server
+			WFIFOSET(fd,3);
+			return 1;
+		}
+
 		/* client doesn't let it get to this point if you're banned, so its a forged packet */
 		if( sd->found_char[slot] == char_id && sd->unban_time[slot] > time(NULL) ) {
 			WFIFOHEAD(fd,3);

+ 102 - 134
src/char/int_storage.c

@@ -229,47 +229,81 @@ int mapif_parse_SaveGuildStorage(int fd)
 	mapif_save_guild_storage_ack(fd, RFIFOL(fd,4), guild_id, 1);
 	return 0;
 }
+
 #ifdef BOUND_ITEMS
-int mapif_itembound_ack(int fd, int aid, int guild_id)
+/**
+* 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);
 	WFIFOW(fd,0) = 0x3856;
-	WFIFOL(fd,2) = aid;
+	WFIFOL(fd,2) = account_id;
 	WFIFOW(fd,6) = guild_id;
 	WFIFOSET(fd,8);
-	return 0;
+	char_unset_session_flag(account_id, 1);
+}
+
+/**
+* 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;
+
+	WFIFOHEAD(fd, size);
+	WFIFOW(fd, 0) = 0x3857;
+	WFIFOW(fd, 2) = size;
+	WFIFOW(fd, 6) = guild_id;
+	for (i = 0; i < count && i < MAX_INVENTORY; i++) {
+		if (!&items[i])
+			continue;
+		memcpy(WFIFOP(fd, 8 + (i * sizeof(struct item))), &items[i], sizeof(struct item));
+	}
+	WFIFOW(fd, 4) = i;
+	WFIFOSET(fd, size);
 }
 
-//------------------------------------------------
-//Guild bound items pull for offline characters [Akinari]
-//------------------------------------------------
+/**
+* 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)
 {
 	StringBuf buf;
 	SqlStmt* stmt;
-	struct item item;
-	int j, i = 0, s = 0, bound_qt = 0;
 	bool found = false;
-	struct item items[MAX_INVENTORY];
-	unsigned int bound_item[MAX_INVENTORY] = { 0 };
-	uint32 char_id = RFIFOL(fd,2);
-	int aid = RFIFOL(fd,6);
-	int guild_id = RFIFOW(fd,10);
+	unsigned short i = 0, count = 0, size = 0;
+	struct item item, items[MAX_INVENTORY] = { 0 };
+	int j, guild_id = RFIFOW(fd,10);
+	uint32 char_id = RFIFOL(fd,2), account_id = RFIFOL(fd,6);
 
 	StringBuf_Init(&buf);
+
+	// Get bound items from player's inventory
 	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`");
 	for( j = 0; j < MAX_SLOTS; ++j )
 		StringBuf_Printf(&buf, ", `card%d`", j);
-	StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'",schema_config.inventory_db,char_id);
+	StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d' AND `bound` = %d", schema_config.inventory_db,char_id, BOUND_GUILD);
 
 	stmt = SqlStmt_Malloc(sql_handle);
-	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
-	||  SQL_ERROR == SqlStmt_Execute(stmt) )
+	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) ||
+		SQL_ERROR == SqlStmt_Execute(stmt) )
 	{
 		SqlStmt_ShowDebug(stmt);
 		SqlStmt_Free(stmt);
 		StringBuf_Destroy(&buf);
-		mapif_itembound_ack(fd,aid,guild_id);
+		mapif_itembound_ack(fd,account_id,guild_id);
 		return 1;
 	}
 
@@ -285,83 +319,67 @@ int mapif_parse_itembound_retrieve(int fd)
 	for( j = 0; j < MAX_SLOTS; ++j )
 		SqlStmt_BindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
 
-	while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) {
-		if(item.bound == BOUND_GUILD) {
-			memcpy(&items[i],&item,sizeof(struct item));
-			i++;
-		}
-	}
+	while( SQL_SUCCESS == SqlStmt_NextRow(stmt) )
+		memcpy(&items[count++], &item, sizeof(struct item));
 	Sql_FreeResult(sql_handle);
 
-	if(!i) { //No items found - No need to continue
+	ShowInfo("Found '"CL_WHITE"%d"CL_RESET"' guild bound item(s) from CID = "CL_WHITE"%d"CL_RESET", AID = %d, Guild ID = "CL_WHITE"%d"CL_RESET".\n", count, char_id, account_id, guild_id);
+	if (!count) { //No items found - No need to continue
 		StringBuf_Destroy(&buf);
 		SqlStmt_Free(stmt);
-		mapif_itembound_ack(fd,aid,guild_id);
-		return 0;
+		mapif_itembound_ack(fd,account_id,guild_id);
+		return 1;
 	}
 
-	//First we delete the character's items
-	StringBuf_Clear(&buf);
-	StringBuf_Printf(&buf, "DELETE FROM `%s` WHERE",schema_config.inventory_db);
-	for(j=0; j<i; j++) {
-		if( found )
-			StringBuf_AppendStr(&buf, " OR");
-		else
-			found = true;
-		StringBuf_Printf(&buf, " `id`=%d",items[j].id);
-
-		if( items[j].bound && items[j].equip ) {
-			//Only the items that are also stored in `char` `equip`
-			if( (items[j].equip&EQP_HAND_R) ||
-				(items[j].equip&EQP_HAND_L) ||
-				(items[j].equip&EQP_HEAD_TOP) ||
-				(items[j].equip&EQP_HEAD_MID) ||
-				(items[j].equip&EQP_HEAD_LOW) ||
-				(items[j].equip&EQP_GARMENT) ||
-				(items[j].equip&EQP_COSTUME_HEAD_TOP) ||
-				(items[j].equip&EQP_COSTUME_HEAD_MID) ||
-				(items[j].equip&EQP_COSTUME_HEAD_LOW) ||
-				(items[j].equip&EQP_COSTUME_GARMENT) )
-			{
-				bound_item[bound_qt] = items[j].equip;
-				bound_qt++;
-			}
-		}
-	}
+	char_set_session_flag(account_id, 1);
 
-	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
-	||  SQL_ERROR == SqlStmt_Execute(stmt) )
+	// Delete bound items from player's inventory
+	StringBuf_Clear(&buf);
+	StringBuf_Printf(&buf, "DELETE FROM `%s` WHERE `bound` = %d",schema_config.inventory_db, BOUND_GUILD);
+	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) ||
+		SQL_ERROR == SqlStmt_Execute(stmt) )
 	{
 		SqlStmt_ShowDebug(stmt);
 		SqlStmt_Free(stmt);
 		StringBuf_Destroy(&buf);
-		mapif_itembound_ack(fd,aid,guild_id);
+		mapif_itembound_ack(fd,account_id,guild_id);
 		return 1;
 	}
 
-	if( bound_qt ) { //Removes any view id that was set by an item that was removed
-/* Verifies equip bitmasks (see item.equip) and handles the sql statement */
-#define CHECK_REMOVE(var,mask,token) do { \
-	if( (var)&(mask) ) { \
-		if( (var) != (mask) && s ) StringBuf_AppendStr(&buf, ","); \
-		StringBuf_AppendStr(&buf, "`"#token"`='0'"); \
-		(var) &= ~(mask); \
-		s++; \
-	} \
-} while( 0 )
-
-		StringBuf_Clear(&buf);
-		StringBuf_Printf(&buf, "UPDATE `%s` SET ", schema_config.char_db);
-		for( j = 0; j < bound_qt; j++ ) {
-			//Equips can be at more than one slot at the same time
-			CHECK_REMOVE(bound_item[j],EQP_HAND_R,weapon);
-			CHECK_REMOVE(bound_item[j],EQP_HAND_L,shield);
-			CHECK_REMOVE(bound_item[j],EQP_HEAD_TOP|EQP_COSTUME_HEAD_TOP,head_top);
-			CHECK_REMOVE(bound_item[j],EQP_HEAD_MID|EQP_COSTUME_HEAD_MID,head_mid);
-			CHECK_REMOVE(bound_item[j],EQP_HEAD_LOW|EQP_COSTUME_HEAD_LOW,head_bottom);
-			CHECK_REMOVE(bound_item[j],EQP_GARMENT|EQP_COSTUME_GARMENT,robe);
-		}
-		StringBuf_Printf(&buf, " WHERE `char_id`='%d'", char_id);
+	// Send the deleted items to map-server to store them in guild storage [Cydh]
+	mapif_itembound_store2gstorage(fd, guild_id, items, count);
+
+	// Verifies equip bitmasks (see item.equip) and handles the sql statement
+#define CHECK_REMOVE(var,mask,token,num) {\
+	if ((var)&(mask) && !(j&(num))) {\
+		if (j)\
+			StringBuf_AppendStr(&buf, ",");\
+		StringBuf_AppendStr(&buf, "`"#token"`='0'");\
+		j |= (1<<num);\
+	}\
+}
+
+	StringBuf_Clear(&buf);
+	j = 0;
+	for (i = 0; i < count && i < MAX_INVENTORY; i++) {
+		if (!&items[i] || !items[i].equip)
+			continue;
+		// Equips can be at more than one slot at the same time
+		CHECK_REMOVE(items[i].equip, EQP_HAND_R, weapon, 0);
+		CHECK_REMOVE(items[i].equip, EQP_HAND_L, shield, 1);
+		CHECK_REMOVE(items[i].equip, EQP_HEAD_TOP|EQP_COSTUME_HEAD_TOP, head_top, 2);
+		CHECK_REMOVE(items[i].equip, EQP_HEAD_MID|EQP_COSTUME_HEAD_MID, head_mid, 3);
+		CHECK_REMOVE(items[i].equip, EQP_HEAD_LOW|EQP_COSTUME_HEAD_LOW, head_bottom, 4);
+		CHECK_REMOVE(items[i].equip, EQP_GARMENT|EQP_COSTUME_GARMENT, robe, 5);
+	}
+
+#undef CHECK_REMOVE
+
+	// Update player's view
+	if (j) {
+		StringBuf buf2;
+		StringBuf_Init(&buf2);
+		StringBuf_Printf(&buf2, "UPDATE `%s` SET %s WHERE `char_id`='%d", schema_config.char_db, StringBuf_Value(&buf), char_id);
 
 		if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf)) ||
 			SQL_ERROR == SqlStmt_Execute(stmt) )
@@ -369,67 +387,17 @@ int mapif_parse_itembound_retrieve(int fd)
 			SqlStmt_ShowDebug(stmt);
 			SqlStmt_Free(stmt);
 			StringBuf_Destroy(&buf);
-			mapif_itembound_ack(fd,aid,guild_id);
+			StringBuf_Destroy(&buf2);
+			mapif_itembound_ack(fd,account_id,guild_id);
 			return 1;
 		}
-#undef CHECK_REMOVE
-	}
-
-	//Now let's update the guild storage with those deleted items
-	//@TODO/FIXME:
-	//This approach is basically the same as the one from memitemdata_to_sql, but
-	//the latter compares current database values and this is not needed in this case
-	//maybe sometime separate memitemdata_to_sql into different methods in order to use
-	//call that function here as well [Panikon]
-	found = false;
-	StringBuf_Clear(&buf);
-	StringBuf_Printf(&buf, "INSERT INTO `%s` (`guild_id`, `nameid`, `amount`, `equip`, `identify`, `refine`,"
-		"`attribute`, `expire_time`, `bound`", schema_config.guild_storage_db);
-	for( s = 0; s < MAX_SLOTS; ++s )
-		StringBuf_Printf(&buf, ", `card%d`", s);
-	StringBuf_AppendStr(&buf, ") VALUES ");
-
-	for( j = 0; j < i; ++j ) {
-		if( found )
-			StringBuf_AppendStr(&buf, ",");
-		else
-			found = true;
-
-		StringBuf_Printf(&buf, "('%d', '%hu', '%d', '%d', '%d', '%d', '%d', '%d', '%d'",
-			guild_id, items[j].nameid, items[j].amount, items[j].equip, items[j].identify, items[j].refine,
-			items[j].attribute, items[j].expire_time, items[j].bound);
-		for( s = 0; s < MAX_SLOTS; ++s )
-			StringBuf_Printf(&buf, ", '%hu'", items[j].card[s]);
-		StringBuf_AppendStr(&buf, ")");
-	}
-
-	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
-	||  SQL_ERROR == SqlStmt_Execute(stmt) )
-	{
-		SqlStmt_ShowDebug(stmt);
-		SqlStmt_Free(stmt);
-		StringBuf_Destroy(&buf);
-		mapif_itembound_ack(fd,aid,guild_id);
-		return 1;
+		StringBuf_Destroy(&buf2);
 	}
 
 	StringBuf_Destroy(&buf);
 	SqlStmt_Free(stmt);
 
-	//Finally reload storage and tell map we're done
-	mapif_load_guild_storage(fd,aid,guild_id,0);
-
-	//If character is logged in char, disconnect, 
-	/* @CHECKME [lighta]
-	 * I suppose this was an attempt to avoid item duplication if the expelled user reconnect during the operation.
-	 * well it's kinda ugly to expel someone like this, so I consider this as a hack.
-	 * we better flag them so that they not allowed to reconnect during operation or flag it so we will flush those item on ram with the map ack.
-	 * both way seem nicer for player.
-	 */
-	char_disconnect_player(aid);
-
-	//Tell map-server the operation is over and it can unlock the storage
-	mapif_itembound_ack(fd,aid,guild_id);
+	char_unset_session_flag(account_id, 1);
 	return 0;
 }
 #endif

+ 3 - 3
src/common/mmo.h

@@ -278,12 +278,12 @@ struct storage_data {
 };
 
 struct guild_storage {
-	int dirty;
+	bool dirty;
 	int guild_id;
-	short storage_status;
 	short storage_amount;
 	struct item items[MAX_GUILD_STORAGE];
-	unsigned short lock;
+	bool locked;
+	int opened; /// Holds the char_id that open the storage
 };
 
 struct s_pet {

+ 12 - 6
src/map/atcommand.c

@@ -920,7 +920,7 @@ ACMD_FUNC(guildstorage)
 		return -1;
 	}
 
-	storage_guild_storageopen(sd);
+	gstorage_storageopen(sd);
 	clif_displaymessage(fd, msg_txt(sd,920)); // Guild storage opened.
 	return 0;
 }
@@ -5436,18 +5436,24 @@ ACMD_FUNC(cleargstorage)
 		return -1;
 	}
 
-	gstorage = guild2storage2(sd->status.guild_id);
+	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.
 		return -1;
 	}
 
+	if (gstorage->opened) {
+		struct map_session_data *tsd = map_charid2sd(gstorage->opened);
+		if (tsd)
+			gstorage_storageclose(tsd);
+	}
+
 	j = gstorage->storage_amount;
-	gstorage->lock = 1; // Lock @gstorage: do not allow any item to be retrieved or stored from any guild member
+	gstorage->locked = true; // Lock @gstorage: do not allow any item to be retrieved or stored from any guild member
 	for (i = 0; i < j; ++i) {
-		guild_storage_delitem(sd, gstorage, i, gstorage->items[i].amount);
+		gstorage_delitem(sd, gstorage, i, gstorage->items[i].amount);
 	}
-	storage_guild_storageclose(sd);
-	gstorage->lock = 0; // Cleaning done, release lock
+	gstorage_storageclose(sd);
+	gstorage->locked = false; // Cleaning done, release lock
 
 	clif_displaymessage(fd, msg_txt(sd,1395)); // Your guild storage was cleaned.
 	return 0;

+ 1 - 1
src/map/chrif.c

@@ -293,7 +293,7 @@ int chrif_save(struct map_session_data *sd, int flag) {
 
 	//For data sync
 	if (sd->state.storage_flag == 2)
-		storage_guild_storagesave(sd->status.account_id, sd->status.guild_id, flag);
+		gstorage_storagesave(sd->status.account_id, sd->status.guild_id, flag);
 
 	if (flag)
 		sd->state.storage_flag = 0; //Force close it.

+ 37 - 37
src/map/clif.c

@@ -2198,30 +2198,30 @@ void clif_additem(struct map_session_data *sd, int n, int amount, unsigned char
 	WFIFOHEAD(fd,packet_len(header));
 	if( fail )
 	{
-		WFIFOW(fd,offs+0)=header;
-		WFIFOW(fd,offs+2)=n+2;
-		WFIFOW(fd,offs+4)=amount;
-		WFIFOW(fd,offs+6)=0;
-		WFIFOB(fd,offs+8)=0;
-		WFIFOB(fd,offs+9)=0;
-		WFIFOB(fd,offs+10)=0;
-		WFIFOW(fd,offs+11)=0;
-		WFIFOW(fd,offs+13)=0;
-		WFIFOW(fd,offs+15)=0;
-		WFIFOW(fd,offs+17)=0;
+		WFIFOW(fd,offs+0) = header;
+		WFIFOW(fd,offs+2) = n+2;
+		WFIFOW(fd,offs+4) = amount;
+		WFIFOW(fd,offs+6) = 0;
+		WFIFOB(fd,offs+8) = 0;
+		WFIFOB(fd,offs+9) = 0;
+		WFIFOB(fd,offs+10) = 0;
+		WFIFOW(fd,offs+11) = 0;
+		WFIFOW(fd,offs+13) = 0;
+		WFIFOW(fd,offs+15) = 0;
+		WFIFOW(fd,offs+17) = 0;
 #if PACKETVER < 20120925
-		WFIFOW(fd,offs+19)=0;
+		WFIFOW(fd,offs+19) = 0;
 #else
-		WFIFOL(fd,offs+19)=0;
+		WFIFOL(fd,offs+19) = 0;
 		offs += 2;
 #endif
-		WFIFOB(fd,offs+21)=0;
-		WFIFOB(fd,offs+22)=fail;
+		WFIFOB(fd,offs+21) = 0;
+		WFIFOB(fd,offs+22) = fail;
 #if PACKETVER >= 20061218
-		WFIFOL(fd,offs+23)=0;
+		WFIFOL(fd,offs+23) = 0;
 #endif
 #if PACKETVER >= 20071002
-		WFIFOW(fd,offs+27)=0;  //  HireExpireDate
+		WFIFOW(fd,offs+27) = 0;  //  HireExpireDate
 #endif
 	}
 	else
@@ -2229,31 +2229,31 @@ void clif_additem(struct map_session_data *sd, int n, int amount, unsigned char
 		if( n < 0 || n >= MAX_INVENTORY || sd->status.inventory[n].nameid <=0 || sd->inventory_data[n] == NULL )
 			return;
 
-		WFIFOW(fd,offs+0)=header;
-		WFIFOW(fd,offs+2)=n+2;
-		WFIFOW(fd,offs+4)=amount;
+		WFIFOW(fd,offs+0) = header;
+		WFIFOW(fd,offs+2) = n+2;
+		WFIFOW(fd,offs+4) = amount;
 		if (sd->inventory_data[n]->view_id > 0)
-			WFIFOW(fd,offs+6)=sd->inventory_data[n]->view_id;
+			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;
+			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]);
 #if PACKETVER < 20120925
-		WFIFOW(fd,offs+19)=pc_equippoint(sd,n);
+		WFIFOW(fd,offs+19) = pc_equippoint(sd,n);
 #else
-		WFIFOL(fd,offs+19)=pc_equippoint(sd,n);
+		WFIFOL(fd,offs+19) = pc_equippoint(sd,n);
 		offs += 2;
 #endif
-		WFIFOB(fd,offs+21)=itemtype(sd->inventory_data[n]->nameid);
-		WFIFOB(fd,offs+22)=fail;
+		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->status.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 : 0;
+		WFIFOW(fd,offs+27) = (sd->status.inventory[n].bound && !itemdb_isstackable(sd->status.inventory[n].nameid)) ? BOUND_DISPYELLOW : 0;
 #endif
 	}
 
@@ -8676,7 +8676,7 @@ void clif_refresh_storagewindow(struct map_session_data *sd) {
 	// 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 = guild2storage2(sd->status.guild_id);
+		struct guild_storage *gstor = gstorage_get_storage(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);
@@ -11915,7 +11915,7 @@ void clif_parse_MoveToKafra(int fd, struct map_session_data *sd)
 		storage_storageadd(sd, item_index, item_amount);
 	else
 	if (sd->state.storage_flag == 2)
-		storage_guild_storageadd(sd, item_index, item_amount);
+		gstorage_storageadd(sd, item_index, item_amount);
 }
 
 
@@ -11934,7 +11934,7 @@ void clif_parse_MoveFromKafra(int fd,struct map_session_data *sd)
 	if (sd->state.storage_flag == 1)
 		storage_storageget(sd, item_index, item_amount);
 	else if(sd->state.storage_flag == 2)
-		storage_guild_storageget(sd, item_index, item_amount);
+		gstorage_storageget(sd, item_index, item_amount);
 }
 
 
@@ -11954,7 +11954,7 @@ void clif_parse_MoveToKafraFromCart(int fd, struct map_session_data *sd){
 	if (sd->state.storage_flag == 1)
 		storage_storageaddfromcart(sd, idx, amount);
 	else if (sd->state.storage_flag == 2)
-		storage_guild_storageaddfromcart(sd, idx, amount);
+		gstorage_storageaddfromcart(sd, idx, amount);
 }
 
 
@@ -11974,7 +11974,7 @@ void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd){
 		storage_storagegettocart(sd, idx, amount);
 	else
 	if (sd->state.storage_flag == 2)
-		storage_guild_storagegettocart(sd, idx, amount);
+		gstorage_storagegettocart(sd, idx, amount);
 }
 
 
@@ -11986,7 +11986,7 @@ void clif_parse_CloseKafra(int fd, struct map_session_data *sd)
 		storage_storageclose(sd);
 	else
 	if( sd->state.storage_flag == 2 )
-		storage_guild_storageclose(sd);
+		gstorage_storageclose(sd);
 }
 
 

+ 92 - 41
src/map/guild.c

@@ -19,6 +19,8 @@
 #include "pc.h"
 #include "intif.h"
 #include "channel.h"
+#include "log.h"
+#include "trade.h"
 
 #include <stdlib.h>
 
@@ -39,7 +41,6 @@ struct eventlist {
 #define GUILD_PAYEXP_LIST 8192 //The maximum number of cache
 
 //Guild EXP cache
-
 struct guild_expcache {
 	int guild_id, account_id, char_id;
 	uint64 exp;
@@ -408,6 +409,20 @@ int guild_npc_request_info(int guild_id,const char *event) {
 	return guild_request_info(guild_id);
 }
 
+/**
+ * Close trade window if party member is kicked when trade a party bound item
+ * @param sd
+ **/
+static void guild_trade_bound_cancel(struct map_session_data *sd) {
+#ifdef BOUND_ITEMS
+	nullpo_retv(sd);
+	if (sd->state.isBoundTrading&(1<<BOUND_GUILD))
+		trade_tradecancel(sd);
+#else
+	;
+#endif
+}
+
 //Confirmation of the character belongs to guild
 int guild_check_member(struct guild *g) {
 	int i;
@@ -740,6 +755,7 @@ int guild_leave(struct map_session_data* sd, int guild_id, uint32 account_id, ui
 		((agit_flag || agit2_flag) && map[sd->bl.m].flag.gvg_castle))
 		return 0;
 
+	guild_trade_bound_cancel(sd);
 	intif_guild_leave(sd->status.guild_id, sd->status.account_id, sd->status.char_id,0,mes);
 	return 0;
 }
@@ -773,12 +789,24 @@ int guild_expulsion(struct map_session_data* sd, int guild_id, uint32 account_id
 
 	// find the member and perform expulsion
 	i = guild_getindex(g, account_id, char_id);
-	if( i != -1 && strcmp(g->member[i].name,g->master) != 0 ) //Can't expel the GL!
+	if( i != -1 && strcmp(g->member[i].name,g->master) != 0 ) { //Can't expel the GL!
+		if (tsd)
+			guild_trade_bound_cancel(tsd);
 		intif_guild_leave(g->guild_id,account_id,char_id,1,mes);
+	}
 
 	return 0;
 }
 
+/**
+* A confirmation from inter-serv that player is kicked successfully
+* @param guild_Id
+* @param account_id
+* @param char_id
+* @param flag
+* @param name
+* @param mes
+*/
 int guild_member_withdraw(int guild_id, uint32 account_id, uint32 char_id, int flag, const char* name, const char* mes) {
 	int i;
 	struct guild* g = guild_search(guild_id);
@@ -815,7 +843,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.
-			storage_guild_storageclose(sd);
+			gstorage_storageclose(sd);
 		guild_send_dot_remove(sd);
 		channel_pcquit(sd,3); //leave guild and ally chan
 		sd->status.guild_id = 0;
@@ -833,35 +861,44 @@ int guild_member_withdraw(int guild_id, uint32 account_id, uint32 char_id, int f
 }
 
 #ifdef BOUND_ITEMS
-void guild_retrieveitembound(uint32 char_id,int aid,int guild_id) {
-	TBL_PC *sd = map_id2sd(aid);
-	if(sd){ //Character is online
+/**
+* Retrieve guild bound items from kicked member
+* @param char_id
+* @param account_id
+* @param guild_id
+*/
+void guild_retrieveitembound(uint32 char_id, uint32 account_id, int guild_id) {
+	TBL_PC *sd = map_charid2sd(char_id);
+	if (sd) { //Character is online
 		int idxlist[MAX_INVENTORY];
 		int j;
 		j = pc_bound_chk(sd,BOUND_GUILD,idxlist);
-		if(j) {
-			struct guild_storage* stor = guild2storage(sd->status.guild_id);
+		if (j) {
+			struct guild_storage* stor = gstorage_guild2storage(sd->status.guild_id);
 			int i;
-			for(i=0;i<j;i++) { //Loop the matching items, guild_storage_additem takes care of opening storage
-				if(stor)
-					guild_storage_additem(sd,stor,&sd->status.inventory[idxlist[i]],sd->status.inventory[idxlist[i]].amount);
+			// 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);
+			}
+			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_storageclose(sd); //Close and save the storage
+			gstorage_storageclose(sd); //Close and save the storage
 		}
 	} else { //Character is offline, ask char server to do the job
-		struct guild_storage* stor = guild2storage2(guild_id);
+		struct guild_storage* stor = gstorage_get_storage(guild_id);
 		struct guild *g = guild_search(guild_id);
 		nullpo_retv(g);
-		if(stor && stor->storage_status == 1) { //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);
-			}
+		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);
 		}
-		intif_itembound_req(char_id,aid,guild_id);
+		intif_itembound_guild_retrieve(char_id,account_id,guild_id);
 	}
 }
 #endif
@@ -1643,14 +1680,14 @@ int guild_broken(int guild_id,int flag) {
 	struct guild *g = guild_search(guild_id);
 	int i;
 
-	if(flag!=0 || g==NULL)
+	if (flag != 0 || g == NULL)
 		return 0;
 
-	for(i=0;i<g->max_member;i++){	// Destroy all relationships
+	for (i = 0; i < g->max_member; i++){	// Destroy all relationships
 		struct map_session_data *sd = g->member[i].sd;
 		if(sd != NULL){
 			if(sd->state.storage_flag == 2)
-				storage_guild_storage_quit(sd,1);
+				gstorage_storage_quit(sd,1);
 			sd->status.guild_id=0;
 			sd->guild = NULL;
 			sd->state.gmaster_flag = 0;
@@ -1665,7 +1702,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);
-	guild_storage_delete(guild_id);
+	gstorage_delete(guild_id);
 	if( channel_config.ally_enable ) {
 		channel_delete(g->channel);
 	}
@@ -1673,7 +1710,10 @@ int guild_broken(int guild_id,int flag) {
 	return 0;
 }
 
-//Changes the Guild Master to the specified player. [Skotlex]
+/** Changes the Guild Master to the specified player. [Skotlex]
+* @param guild_id
+* @param sd New guild master
+*/
 int guild_gm_change(int guild_id, struct map_session_data *sd) {
 	struct guild *g;
 	nullpo_ret(sd);
@@ -1681,7 +1721,7 @@ int guild_gm_change(int guild_id, struct map_session_data *sd) {
 	if (sd->status.guild_id != guild_id)
 		return 0;
 
-	g=guild_search(guild_id);
+	g = guild_search(guild_id);
 
 	nullpo_ret(g);
 
@@ -1693,7 +1733,11 @@ int guild_gm_change(int guild_id, struct map_session_data *sd) {
 	return 1;
 }
 
-//Notification from Char server that a guild's master has changed. [Skotlex]
+/** Notification from Char server that a guild's master has changed. [Skotlex]
+* @param guild_id
+* @param account_id
+* @param char_id
+*/
 int guild_gm_changed(int guild_id, uint32 account_id, uint32 char_id) {
 	struct guild *g;
 	struct guild_member gm;
@@ -1743,9 +1787,10 @@ int guild_gm_changed(int guild_id, uint32 account_id, uint32 char_id) {
 	return 1;
 }
 
-/*====================================================
- * Guild disbanded
- *---------------------------------------------------*/
+/** Disband a guild
+* @param sd Player who breaks the guild
+* @param name Guild name
+*/
 int guild_break(struct map_session_data *sd,char *name) {
 	struct guild *g;
 	struct unit_data *ud;
@@ -1757,25 +1802,25 @@ int guild_break(struct map_session_data *sd,char *name) {
 
 	nullpo_ret(sd);
 
-	if( (g=sd->guild)==NULL )
+	if ((g=sd->guild)==NULL)
 		return 0;
-	if(strcmp(g->name,name)!=0)
+	if (strcmp(g->name,name) != 0)
 		return 0;
-	if(!sd->state.gmaster_flag)
+	if (!sd->state.gmaster_flag)
 		return 0;
-	for(i=0;i<g->max_member;i++){
+	for (i = 0; i < g->max_member; i++) {
 		if(	g->member[i].account_id>0 && (
 			g->member[i].account_id!=sd->status.account_id ||
 			g->member[i].char_id!=sd->status.char_id ))
 			break;
 	}
-	if(i<g->max_member){
+	if (i < g->max_member) {
 		clif_guild_broken(sd,2);
 		return 0;
 	}
 
 	/* Regardless of char server allowing it, we clear the guild master's auras */
-	if((ud = unit_bl2ud(&sd->bl))) {
+	if ((ud = unit_bl2ud(&sd->bl))) {
 		int count = 0;
 		struct skill_unit_group *group[4];
 
@@ -1792,15 +1837,15 @@ int guild_break(struct map_session_data *sd,char *name) {
 					break;
 			}
 		}
-		for(i = 0; i < count; i++)
+		for (i = 0; i < count; i++)
 			skill_delunitgroup(group[i]);
 	}
 
 #ifdef BOUND_ITEMS
 	//Guild bound item check - Removes the bound flag
 	j = pc_bound_chk(sd,BOUND_GUILD,idxlist);
-	for(i=0;i<j;i++)
-		sd->status.inventory[idxlist[i]].bound = BOUND_NONE;
+	for(i = 0; i < j; i++)
+		pc_delitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_BOUND_REMOVAL);
 #endif
 
 	intif_guild_break(g->guild_id);
@@ -1911,6 +1956,9 @@ void guild_castle_reconnect_sub(void *key, void *data, va_list ap) {
  * Saves pending guild castle data changes when char-server is
  * disconnected.
  * On reconnect pushes all changes to char-server for saving.
+ * @param castle_id
+ * @param index
+ * @param value
  */
 void guild_castle_reconnect(int castle_id, int index, int value) {
 	static struct linkdb_node *gc_save_pending = NULL;
@@ -1926,7 +1974,10 @@ void guild_castle_reconnect(int castle_id, int index, int value) {
 	}
 }
 
-// Load castle data then invoke OnAgitInit* on last
+/** Load castle data then invoke OnAgitInit* on last
+* @param len
+* @param gc Guild Castle data
+*/
 int guild_castledataloadack(int len, struct guild_castle *gc) {
 	int i;
 	int n = (len-4) / sizeof(struct guild_castle);

+ 1 - 1
src/map/guild.h

@@ -107,7 +107,7 @@ void guild_flags_clear(void);
 
 void guild_guildaura_refresh(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv);
 #ifdef BOUND_ITEMS
-void guild_retrieveitembound(uint32 char_id,int aid,int guild_id);
+void guild_retrieveitembound(uint32 char_id,uint32 account_id,int guild_id);
 #endif
 
 void do_final_guild(void);

+ 53 - 19
src/map/intif.c

@@ -30,7 +30,7 @@ static const int packet_len_table[]={
 	39,-1,15,15, 14,19, 7,-1,  0, 0, 0, 0,  0, 0,  0, 0, //0x3820
 	10,-1,15, 0, 79,19, 7,-1,  0,-1,-1,-1, 14,67,186,-1, //0x3830
 	-1, 0, 0,14,  0, 0, 0, 0, -1,74,-1,11, 11,-1,  0, 0, //0x3840
-	-1,-1, 7, 7,  7,11, 8, 0,  0, 0, 0, 0,  0, 0,  0, 0, //0x3850  Auctions [Zephyrus] itembound[Akinari]
+	-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
@@ -1333,22 +1333,22 @@ int intif_parse_LoadGuildStorage(int fd)
 
 	guild_id = RFIFOL(fd,8);
 	flag = RFIFOL(fd,12);
-	if(guild_id <= 0)
+	if (guild_id <= 0)
 		return 0;
 
-	sd=map_id2sd( RFIFOL(fd,4) );
-	if( flag ){ //If flag != 0, we attach a player and open the storage
-		if(sd==NULL){
-			ShowError("intif_parse_LoadGuildStorage: user not found %d\n",RFIFOL(fd,4));
+	sd = map_id2sd( RFIFOL(fd,4) );
+	if (flag){ //If flag != 0, we attach a player and open the storage
+		if(sd == NULL){
+			ShowError("intif_parse_LoadGuildStorage: user not found (AID: %d)\n",RFIFOL(fd,4));
 			return 0;
 		}
 	}
-	gstor=guild2storage(guild_id);
-	if(!gstor) {
+	gstor = gstorage_guild2storage(guild_id);
+	if (!gstor) {
 		ShowWarning("intif_parse_LoadGuildStorage: error guild_id %d not exist\n",guild_id);
 		return 0;
 	}
-	if (gstor->storage_status == 1) { // Already open.. lets ignore this update
+	if (gstor->opened) { // 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;
 	}
@@ -1358,13 +1358,13 @@ int intif_parse_LoadGuildStorage(int fd)
 	}
 	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->storage_status = 0;
+		gstor->opened = 0;
 		return 0;
 	}
 
 	memcpy(gstor,RFIFOP(fd,13),sizeof(struct guild_storage));
 	if( flag )
-		storage_guild_storageopen(sd);
+		gstorage_storageopen(sd);
 
 	return 1;
 }
@@ -1376,7 +1376,7 @@ int intif_parse_LoadGuildStorage(int fd)
  */
 int intif_parse_SaveGuildStorage(int fd)
 {
-	storage_guild_storagesaved(/*RFIFOL(fd,2), */RFIFOL(fd,6));
+	gstorage_storagesaved(/*RFIFOL(fd,2), */RFIFOL(fd,6));
 	return 1;
 }
 
@@ -2875,13 +2875,14 @@ void intif_parse_MessageToFD(int fd) {
 #ifdef BOUND_ITEMS
 
 /**
- * Request char-serv to delete some bound item, for non connected cid
+ * ZI 0x3056 <char_id>.L <account_id>.L <guild_id>.W
+ * Request inter-serv to delete some bound item, for non connected cid
  * @param char_id : Char to delete item ID
  * @param aid : Account to delete item ID
  * @param guild_id : Guild of char
  */
-void intif_itembound_req(uint32 char_id, uint32 aid,int guild_id) {
-	struct guild_storage *gstor = guild2storage2(guild_id);
+void intif_itembound_guild_retrieve(uint32 char_id,uint32 account_id,int guild_id) {
+	struct guild_storage *gstor = gstorage_get_storage(guild_id);
 	
 	if( CheckForCharServer() )
 		return;
@@ -2889,10 +2890,12 @@ void intif_itembound_req(uint32 char_id, uint32 aid,int guild_id) {
 	WFIFOHEAD(inter_fd,12);
 	WFIFOW(inter_fd,0) = 0x3056;
 	WFIFOL(inter_fd,2) = char_id;
-	WFIFOL(inter_fd,6) = aid;
+	WFIFOL(inter_fd,6) = account_id;
 	WFIFOW(inter_fd,10) = guild_id;
 	WFIFOSET(inter_fd,12);
-	if(gstor) gstor->lock = 1; //Lock for retrieval process
+	if (gstor)
+		gstor->locked = 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);
 }
 
 /**
@@ -2903,8 +2906,38 @@ void intif_itembound_req(uint32 char_id, uint32 aid,int guild_id) {
  */
 void intif_parse_itembound_ack(int fd) {
 	int guild_id = RFIFOW(fd,6);
-	struct guild_storage *gstor = guild2storage2(guild_id);
-	if(gstor) gstor->lock = 0; //Unlock now that operation is completed
+	struct guild_storage *gstor = gstorage_get_storage(guild_id);
+	if (gstor)
+		gstor->locked = 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]
+*/
+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);
+
+	if (!gstor) {
+		ShowError("intif_parse_itembound_store2gstorage: Guild '%d' not found.\n", guild_id);
+		return;
+	}
+
+	//@TODO: Gives some actions for item(s) that cannot be stored because storage is full or reach the limit of stack amount
+	for (i = 0; i < count; i++) {
+		struct item *item = (struct item*)RFIFOP(fd, 8 + i*sizeof(struct item));
+		if (!item)
+			continue;
+		if (!gstorage_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;
 }
 #endif
 
@@ -2998,6 +3031,7 @@ int intif_parse(int fd)
 	//Bound items
 #ifdef BOUND_ITEMS
 	case 0x3856:	intif_parse_itembound_ack(fd); break;
+	case 0x3857:	intif_parse_itembound_store2gstorage(fd); break;
 #endif
 
 	//Quest system

+ 1 - 1
src/map/intif.h

@@ -60,7 +60,7 @@ int intif_guild_emblem(int guild_id, int len, const char *data);
 int intif_guild_castle_dataload(int num, int *castle_ids);
 int intif_guild_castle_datasave(int castle_id, int index, int value);
 #ifdef BOUND_ITEMS
-void intif_itembound_req(uint32 char_id, uint32 aid, int guild_id);
+void intif_itembound_guild_retrieve(uint32 char_id, uint32 account_id, int guild_id);
 #endif
 
 int intif_create_pet(uint32 account_id, uint32 char_id, short pet_type, short pet_lv, short pet_egg_id,

+ 2 - 3
src/map/itemdb.c

@@ -419,10 +419,9 @@ struct item_data* itemdb_search(unsigned short nameid) {
 * @param id Item data
 * @return True if item is equip, false otherwise
 */
-bool itemdb_isequip2(struct item_data *id)
-{
+bool itemdb_isequip2(struct item_data *id) {
 	nullpo_ret(id);
-	switch(id->type) {
+	switch (id->type) {
 		case IT_WEAPON:
 		case IT_ARMOR:
 		case IT_AMMO:

+ 1 - 0
src/map/log.c

@@ -74,6 +74,7 @@ static char log_picktype2char(e_log_pick_type type)
 		case LOG_TYPE_BANK:             return 'K';  // Ban(K) Transactions
 		case LOG_TYPE_OTHER:			return 'X';  // Other
 		case LOG_TYPE_CASH:				return '$';  // Cash
+		case LOG_TYPE_BOUND_REMOVAL:	return 'B';  // Removed bound items when guild/party is broken
 	}
 
 	// should not get here, fallback

+ 1 - 0
src/map/log.h

@@ -43,6 +43,7 @@ typedef enum e_log_pick_type
 	LOG_TYPE_OTHER            = 0x10000,
 	LOG_TYPE_CASH             = 0x20000,
 	LOG_TYPE_BANK             = 0x40000,
+	LOG_TYPE_BOUND_REMOVAL    = 0x80000,
 	// combinations
 	LOG_TYPE_LOOT             = LOG_TYPE_PICKDROP_MONSTER|LOG_TYPE_CONSUME,
 	// all

+ 10 - 10
src/map/map.c

@@ -1524,16 +1524,16 @@ bool map_closest_freecell(int16 m, int16 *x, int16 *y, int type, int flag)
 int map_addflooritem(struct item *item,int amount,int16 m,int16 x,int16 y,int first_charid,int second_charid,int third_charid,int flags)
 {
 	int r;
-	struct flooritem_data *fitem=NULL;
+	struct flooritem_data *fitem = NULL;
 
 	nullpo_ret(item);
 
-	if(!(flags&4) && battle_config.item_onfloor && (itemdb_traderight(item->nameid)&1) )
+	if (!(flags&4) && battle_config.item_onfloor && (itemdb_traderight(item->nameid)&1))
 		return 0; //can't be dropped
 
-	if(!map_searchrandfreecell(m,&x,&y,flags&2?1:0))
+	if (!map_searchrandfreecell(m,&x,&y,flags&2?1:0))
 		return 0;
-	r=rnd();
+	r = rnd();
 
 	CREATE(fitem, struct flooritem_data, 1);
 	fitem->bl.type=BL_ITEM;
@@ -1542,7 +1542,7 @@ int map_addflooritem(struct item *item,int amount,int16 m,int16 x,int16 y,int fi
 	fitem->bl.x=x;
 	fitem->bl.y=y;
 	fitem->bl.id = map_get_new_object_id();
-	if(fitem->bl.id==0){
+	if (fitem->bl.id==0) {
 		aFree(fitem);
 		return 0;
 	}
@@ -1555,13 +1555,13 @@ int map_addflooritem(struct item *item,int amount,int16 m,int16 x,int16 y,int fi
 	fitem->third_get_tick = fitem->second_get_tick + (flags&1 ? battle_config.mvp_item_third_get_time : battle_config.item_third_get_time);
 
 	memcpy(&fitem->item,item,sizeof(*item));
-	fitem->item.amount=amount;
-	fitem->subx=(r&3)*3+3;
-	fitem->suby=((r>>2)&3)*3+3;
-	fitem->cleartimer=add_timer(gettick()+battle_config.flooritem_lifetime,map_clearflooritem_timer,fitem->bl.id,0);
+	fitem->item.amount = amount;
+	fitem->subx = (r&3)*3+3;
+	fitem->suby = ((r>>2)&3)*3+3;
+	fitem->cleartimer = add_timer(gettick()+battle_config.flooritem_lifetime,map_clearflooritem_timer,fitem->bl.id,0);
 
 	map_addiddb(&fitem->bl);
-	if(map_addblock(&fitem->bl))
+	if (map_addblock(&fitem->bl))
 		return 0;
 	clif_dropflooritem(fitem);
 

+ 27 - 7
src/map/party.c

@@ -17,6 +17,7 @@
 #include "instance.h"
 #include "intif.h"
 #include "mapreg.h"
+#include "trade.h"
 
 #include <stdlib.h>
 
@@ -188,6 +189,20 @@ int party_request_info(int party_id, uint32 char_id)
 	return intif_request_partyinfo(party_id, char_id);
 }
 
+/**
+ * Close trade window if party member is kicked when trade a party bound item
+ * @param sd
+ **/
+static void party_trade_bound_cancel(struct map_session_data *sd) {
+#ifdef BOUND_ITEMS
+	nullpo_retv(sd);
+	if (sd->state.isBoundTrading&(1<<BOUND_PARTY))
+		trade_tradecancel(sd);
+#else
+	;
+#endif
+}
+
 /// Invoked (from char-server) when the party info is not found.
 int party_recv_noinfo(int party_id, uint32 char_id)
 {
@@ -531,6 +546,7 @@ int party_removemember(struct map_session_data* sd, uint32 account_id, char* nam
 	if( i == MAX_PARTY )
 		return 0; // no such char in party
 
+	party_trade_bound_cancel(sd);
 	intif_party_leave(p->party.party_id,account_id,p->party.member[i].char_id);
 
 	return 1;
@@ -541,6 +557,8 @@ int party_removemember2(struct map_session_data *sd,uint32 char_id,int party_id)
 	if( sd ) {
 		if( !sd->status.party_id )
 			return -3;
+
+		party_trade_bound_cancel(sd);
 		intif_party_leave(sd->status.party_id,sd->status.account_id,sd->status.char_id);
 		return 1;
 	} else {
@@ -573,6 +591,7 @@ int party_leave(struct map_session_data *sd)
 	if( i == MAX_PARTY )
 		return 0;
 
+	party_trade_bound_cancel(sd);
 	intif_party_leave(p->party.party_id,sd->status.account_id,sd->status.char_id);
 	return 1;
 }
@@ -600,10 +619,11 @@ int party_member_withdraw(int party_id, uint32 account_id, uint32 char_id)
 		int idxlist[MAX_INVENTORY]; //or malloc to reduce consumtion
 		int j,i;
 
+		party_trade_bound_cancel(sd);
 		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_OTHER);
+			pc_delitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_BOUND_REMOVAL);
 #endif
 
 		sd->status.party_id = 0;
@@ -1057,7 +1077,7 @@ int party_exp_share(struct party_data* p, struct block_list* src, unsigned int b
 }
 
 //Does party loot. first_charid holds the charid of the player who has time priority to take the item.
-int party_share_loot(struct party_data* p, struct map_session_data* sd, struct item* item_data, int first_charid)
+int party_share_loot(struct party_data* p, struct map_session_data* sd, struct item* item, int first_charid)
 {
 	TBL_PC* target = NULL;
 	int i;
@@ -1077,7 +1097,7 @@ int party_share_loot(struct party_data* p, struct map_session_data* sd, struct i
 				if( (psd = p->data[i].sd) == NULL || sd->bl.m != psd->bl.m || pc_isdead(psd) || (battle_config.idle_no_share && pc_isidle(psd)) )
 					continue;
 
-				if (pc_additem(psd,item_data,item_data->amount,LOG_TYPE_PICKDROP_PLAYER))
+				if (pc_additem(psd,item,item->amount,LOG_TYPE_PICKDROP_PLAYER))
 					continue; //Chosen char can't pick up loot.
 
 				//Successful pick.
@@ -1100,7 +1120,7 @@ int party_share_loot(struct party_data* p, struct map_session_data* sd, struct i
 			while (count > 0) { //Pick a random member.
 				i = rnd()%count;
 
-				if (pc_additem(psd[i],item_data,item_data->amount,LOG_TYPE_PICKDROP_PLAYER)) { // Discard this receiver.
+				if (pc_additem(psd[i],item,item->amount,LOG_TYPE_PICKDROP_PLAYER)) { // Discard this receiver.
 					psd[i] = psd[count-1];
 					count--;
 				} else { // Successful pick.
@@ -1114,12 +1134,12 @@ int party_share_loot(struct party_data* p, struct map_session_data* sd, struct i
 	if (!target) {
 		target = sd; //Give it to the char that picked it up
 
-		if ((i = pc_additem(sd,item_data,item_data->amount,LOG_TYPE_PICKDROP_PLAYER)))
+		if ((i = pc_additem(sd,item,item->amount,LOG_TYPE_PICKDROP_PLAYER)))
 			return i;
 	}
 
-	if( p && battle_config.party_show_share_picker && battle_config.show_picker_item_type&(1<<itemdb_type(item_data->nameid)) )
-		clif_party_show_picker(target, item_data);
+	if( p && battle_config.party_show_share_picker && battle_config.show_picker_item_type&(1<<itemdb_type(item->nameid)) )
+		clif_party_show_picker(target, item);
 
 	return 0;
 }

+ 1 - 1
src/map/party.h

@@ -84,7 +84,7 @@ int party_recv_message(int party_id,uint32 account_id,const char *mes,int len);
 int party_skill_check(struct map_session_data *sd, int party_id, uint16 skill_id, uint16 skill_lv);
 int party_send_xy_clear(struct party_data *p);
 int party_exp_share(struct party_data *p,struct block_list *src,unsigned int base_exp,unsigned int job_exp,int zeny);
-int party_share_loot(struct party_data* p, struct map_session_data* sd, struct item* item_data, int first_charid);
+int party_share_loot(struct party_data* p, struct map_session_data* sd, struct item* item, int first_charid);
 int party_send_dot_remove(struct map_session_data *sd);
 int party_sub_count(struct block_list *bl, va_list ap);
 int party_sub_count_class(struct block_list *bl, va_list ap);

+ 13 - 13
src/map/pc.c

@@ -4430,47 +4430,47 @@ bool pc_dropitem(struct map_session_data *sd,int n,int amount)
  *------------------------------------------*/
 bool pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem)
 {
-	int flag=0;
+	int flag = 0;
 	unsigned int tick = gettick();
 	struct party_data *p = NULL;
 
 	nullpo_ret(sd);
 	nullpo_ret(fitem);
 
-	if(!check_distance_bl(&fitem->bl, &sd->bl, 2) && sd->ud.skill_id!=BS_GREED)
+	if (!check_distance_bl(&fitem->bl, &sd->bl, 2) && sd->ud.skill_id!=BS_GREED)
 		return false;	// Distance is too far
 
-	if( sd->sc.cant.pickup )
+	if (sd->sc.cant.pickup)
 		return false;
 
 	if (sd->status.party_id)
 		p = party_search(sd->status.party_id);
 
-	if(fitem->first_get_charid > 0 && fitem->first_get_charid != sd->status.char_id) {
+	if (fitem->first_get_charid > 0 && fitem->first_get_charid != sd->status.char_id) {
 		struct map_session_data *first_sd = map_charid2sd(fitem->first_get_charid);
-		if(DIFF_TICK(tick,fitem->first_get_tick) < 0) {
+		if (DIFF_TICK(tick,fitem->first_get_tick) < 0) {
 			if (!(p && p->party.item&1 &&
 				first_sd && first_sd->status.party_id == sd->status.party_id
-			))
+				))
 				return false;
 		}
-		else if(fitem->second_get_charid > 0 && fitem->second_get_charid != sd->status.char_id) {
+		else if (fitem->second_get_charid > 0 && fitem->second_get_charid != sd->status.char_id) {
 			struct map_session_data *second_sd = map_charid2sd(fitem->second_get_charid);
-			if(DIFF_TICK(tick, fitem->second_get_tick) < 0) {
-				if(!(p && p->party.item&1 &&
+			if (DIFF_TICK(tick, fitem->second_get_tick) < 0) {
+				if (!(p && p->party.item&1 &&
 					((first_sd && first_sd->status.party_id == sd->status.party_id) ||
 					(second_sd && second_sd->status.party_id == sd->status.party_id))
-				))
+					))
 					return false;
 			}
-			else if(fitem->third_get_charid > 0 && fitem->third_get_charid != sd->status.char_id){
+			else if (fitem->third_get_charid > 0 && fitem->third_get_charid != sd->status.char_id){
 				struct map_session_data *third_sd = map_charid2sd(fitem->third_get_charid);
-				if(DIFF_TICK(tick,fitem->third_get_tick) < 0) {
+				if (DIFF_TICK(tick,fitem->third_get_tick) < 0) {
 					if(!(p && p->party.item&1 &&
 						((first_sd && first_sd->status.party_id == sd->status.party_id) ||
 						(second_sd && second_sd->status.party_id == sd->status.party_id) ||
 						(third_sd && third_sd->status.party_id == sd->status.party_id))
-					))
+						))
 						return false;
 				}
 			}

+ 1 - 0
src/map/pc.h

@@ -229,6 +229,7 @@ struct map_session_data {
 		unsigned int banking : 1; //1 when we using the banking system 0 when closed
 		unsigned int hpmeter_visible : 1;
 		unsigned disable_atcommand_on_npc : 1; //Prevent to use atcommand while talking with NPC [Kichi]
+		uint8 isBoundTrading; // Player is currently add bound item to trade list [Cydh]
 	} state;
 	struct {
 		unsigned char no_weapon_damage, no_magic_damage, no_misc_damage;

+ 1 - 1
src/map/script.c

@@ -9232,7 +9232,7 @@ BUILDIN_FUNC(guildopenstorage)
 	if( sd == NULL )
 		return 0;
 
-	ret = storage_guild_storageopen(sd);
+	ret = gstorage_storageopen(sd);
 	script_pushint(st,ret);
 	return SCRIPT_CMD_SUCCESS;
 }

+ 141 - 113
src/map/storage.c

@@ -5,6 +5,7 @@
 #include "../common/db.h"
 #include "../common/nullpo.h"
 #include "../common/malloc.h"
+#include "../common/showmsg.h"
 
 #include "map.h" // struct map_session_data
 #include "storage.h"
@@ -85,8 +86,8 @@ static int storage_reconnect_sub(DBKey key, DBData *data, va_list ap)
 {
 	struct guild_storage *stor = db_data2ptr(data);
 
-	if (stor->dirty && stor->storage_status == 0) //Save closed storages.
-		storage_guild_storagesave(0, stor->guild_id,0);
+	if (stor->dirty && stor->opened == 0) //Save closed storages.
+		gstorage_storagesave(0, stor->guild_id,0);
 
 	return 0;
 }
@@ -421,12 +422,12 @@ static DBData create_guildstorage(DBKey key, va_list args)
  * @param guild_id : id of the guild
  * @return guild_storage
  */
-struct guild_storage *guild2storage(int guild_id)
+struct guild_storage *gstorage_guild2storage(int guild_id)
 {
 	struct guild_storage *gs = NULL;
 
-	if(guild_search(guild_id) != NULL)
-		gs = idb_ensure(guild_storage_db,guild_id,create_guildstorage);
+	if (guild_search(guild_id) != NULL)
+		gs = (struct guild_storage *)idb_ensure(guild_storage_db,guild_id,create_guildstorage);
 
 	return gs;
 }
@@ -437,7 +438,7 @@ struct guild_storage *guild2storage(int guild_id)
  * @param guild_id : guild_id to search the storage
  * @return guild_storage or NULL
  */
-struct guild_storage *guild2storage2(int guild_id)
+struct guild_storage *gstorage_get_storage(int guild_id)
 {
 	return (struct guild_storage*)idb_get(guild_storage_db,guild_id);
 }
@@ -447,11 +448,9 @@ struct guild_storage *guild2storage2(int guild_id)
  * @param guild_id : guild to remove the storage from
  * @return 0
  */
-int guild_storage_delete(int guild_id)
+void gstorage_delete(int guild_id)
 {
 	idb_remove(guild_storage_db,guild_id);
-
-	return 0;
 }
 
 /**
@@ -459,7 +458,7 @@ int guild_storage_delete(int guild_id)
  * @param sd : player
  * @return 0 : success, 1 : fail, 2 : no guild found
  */
-int storage_guild_storageopen(struct map_session_data* sd)
+char gstorage_storageopen(struct map_session_data* sd)
 {
 	struct guild_storage *gstor;
 
@@ -476,18 +475,18 @@ int storage_guild_storageopen(struct map_session_data* sd)
 		return 1;
 	}
 
-	if((gstor = guild2storage2(sd->status.guild_id)) == NULL) {
+	if((gstor = gstorage_get_storage(sd->status.guild_id)) == NULL) {
 		intif_request_guild_storage(sd->status.account_id,sd->status.guild_id);
 		return 0;
 	}
 
-	if(gstor->storage_status)
+	if(gstor->opened)
 		return 1;
 
-	if( gstor->lock )
+	if( gstor->locked )
 		return 1;
 
-	gstor->storage_status = 1;
+	gstor->opened = sd->status.char_id;
 	sd->state.storage_flag = 2;
 	storage_sortitem(gstor->items, ARRAYLENGTH(gstor->items));
 	clif_storagelist(sd, gstor->items, ARRAYLENGTH(gstor->items));
@@ -500,66 +499,109 @@ int storage_guild_storageopen(struct map_session_data* sd)
  * Attempt to add an item in guild storage, then refresh it
  * @param sd : player attempting to open the guild_storage
  * @param stor : guild_storage
- * @param item_data : item to add
+ * @param item : item to add
  * @param amount : number of item to add
- * @return 0 : success, 1 : fail
+ * @return True : success, False : fail
  */
-char guild_storage_additem(struct map_session_data* sd, struct guild_storage* stor, struct item* item_data, int amount)
+bool gstorage_additem(struct map_session_data* sd, struct guild_storage* stor, struct item* item, int amount)
 {
-	struct item_data *data;
+	struct item_data *id;
 	int i;
 
-	nullpo_retr(1, sd);
-	nullpo_retr(1, stor);
-	nullpo_retr(1, item_data);
+	nullpo_ret(sd);
+	nullpo_ret(stor);
+	nullpo_ret(item);
 
-	if(item_data->nameid == 0 || amount <= 0)
-		return 1;
+	if(item->nameid == 0 || amount <= 0)
+		return false;
 
-	data = itemdb_search(item_data->nameid);
+	id = itemdb_search(item->nameid);
 
-	if( data->stack.guildstorage && amount > data->stack.amount ) // item stack limitation
-		return 1;
+	if( id->stack.guildstorage && amount > id->stack.amount ) // item stack limitation
+		return false;
 
-	if( !itemdb_canguildstore(item_data, pc_get_group_level(sd)) || item_data->expire_time ) { // Check if item is storable. [Skotlex]
+	if( !itemdb_canguildstore(item, pc_get_group_level(sd)) || item->expire_time ) { // Check if item is storable. [Skotlex]
 		clif_displaymessage (sd->fd, msg_txt(sd,264));
-		return 1;
+		return false;
 	}
 
-	if( (item_data->bound == BOUND_ACCOUNT || item_data->bound > BOUND_GUILD) && !pc_can_give_bounded_items(sd) ) {
+	if( (item->bound == BOUND_ACCOUNT || item->bound > BOUND_GUILD) && !pc_can_give_bounded_items(sd) ) {
 		clif_displaymessage(sd->fd, msg_txt(sd,294));
-		return 1;
+		return false;
 	}
 
-	if(itemdb_isstackable2(data)) { //Stackable
+	if(itemdb_isstackable2(id)) { //Stackable
 		for(i = 0; i < MAX_GUILD_STORAGE; i++){
-			if(compare_item(&stor->items[i], item_data)) {
-				if( amount > MAX_AMOUNT - stor->items[i].amount || ( data->stack.guildstorage && amount > data->stack.amount - stor->items[i].amount ) )
-					return 1;
+			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 ) )
+					return false;
 	
 				stor->items[i].amount+=amount;
 				clif_storageitemadded(sd,&stor->items[i],i,amount);
-				stor->dirty = 1;
-
-				return 0;
+				stor->dirty = true;
+				return true;
 			}
 		}
 	}
 
 	//Add item
 	for(i = 0; i < MAX_GUILD_STORAGE && stor->items[i].nameid; i++);
-
 	if(i >= MAX_GUILD_STORAGE)
-		return 1;
+		return false;
 
-	memcpy(&stor->items[i],item_data,sizeof(stor->items[0]));
-	stor->items[i].amount=amount;
+	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);
-	stor->dirty = 1;
+	stor->dirty = true;
+	return true;
+}
 
-	return 0;
+/**
+ * Attempt to add an item in guild storage, then refresh i
+ * @param stor : guild_storage
+ * @param item : item to add
+ * @param amount : number of item to add
+ * @return True : success, False : fail
+ */
+bool gstorage_additem2(struct guild_storage* stor, struct item* item, int amount) {
+	struct item_data *id;
+	int i;
+
+	nullpo_ret(stor);
+	nullpo_ret(item);
+
+	if (item->nameid == 0 || amount <= 0 || !(id = itemdb_exists(item->nameid)))
+		return false;
+
+	if (item->expire_time)
+		return false;
+
+	if (itemdb_isstackable2(id)) { // Stackable
+		for (i = 0; i < MAX_GUILD_STORAGE; i++) {
+			if (compare_item(&stor->items[i], item)) {
+				// Set the amount, make it fit with max amount
+				amount = min(amount, ((id->stack.guildstorage) ? id->stack.amount : MAX_AMOUNT) - stor->items[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;
+				stor->dirty = true;
+				return true;
+			}
+		}
+	}
+
+	// Add the item
+	for (i = 0; i < MAX_GUILD_STORAGE && stor->items[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++;
+	stor->dirty = true;
+	return true;
 }
 
 /**
@@ -568,15 +610,15 @@ char guild_storage_additem(struct map_session_data* sd, struct guild_storage* st
  * @param stor : guild_storage
  * @param n : index of item in guild storage
  * @param amount : number of item to delete
- * @return 0 : success, 1 : fail
+ * @return True : success, False : fail
  */
-int guild_storage_delitem(struct map_session_data* sd, struct guild_storage* stor, int n, int amount)
+bool gstorage_delitem(struct map_session_data* sd, struct guild_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)
-		return 1;
+		return false;
 
 	stor->items[n].amount -= amount;
 
@@ -587,25 +629,23 @@ int guild_storage_delitem(struct map_session_data* sd, struct guild_storage* sto
 	}
 
 	clif_storageitemremoved(sd,n,amount);
-	stor->dirty = 1;
-
-	return 0;
+	stor->dirty = true;
+	return true;
 }
 
 /**
  * Attempt to add an item in guild storage from inventory, then refresh it
  * @param sd : player
  * @param amount : number of item to delete
- * @return 1:success, 0:fail
  */
-void storage_guild_storageadd(struct map_session_data* sd, int index, int amount)
+void gstorage_storageadd(struct map_session_data* sd, int index, int amount)
 {
 	struct guild_storage *stor;
 
 	nullpo_retv(sd);
-	nullpo_retv(stor = guild2storage2(sd->status.guild_id));
+	nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
 
-	if( !stor->storage_status || stor->storage_amount > MAX_GUILD_STORAGE )
+	if( !stor->opened || stor->opened != sd->status.char_id || stor->storage_amount > MAX_GUILD_STORAGE )
 		return;
 
 	if( index < 0 || index >= MAX_INVENTORY )
@@ -617,12 +657,12 @@ void storage_guild_storageadd(struct map_session_data* sd, int index, int amount
 	if( amount < 1 || amount > sd->status.inventory[index].amount )
 		return;
 
-	if( stor->lock ) {
-		storage_guild_storageclose(sd);
+	if( stor->locked ) {
+		gstorage_storageclose(sd);
 		return;
 	}
 
-	if(guild_storage_additem(sd,stor,&sd->status.inventory[index],amount) == 0)
+	if(gstorage_additem(sd,stor,&sd->status.inventory[index],amount))
 		pc_delitem(sd,index,amount,0,4,LOG_TYPE_GSTORAGE);
 	else {
 		clif_storageitemremoved(sd,index,0);
@@ -637,16 +677,16 @@ void storage_guild_storageadd(struct map_session_data* sd, int index, int amount
  * @param amount : number of item to get
  * @return 1:success, 0:fail
  */
-void storage_guild_storageget(struct map_session_data* sd, int index, int amount)
+void gstorage_storageget(struct map_session_data* sd, int index, int amount)
 {
 	struct guild_storage *stor;
 	unsigned char flag = 0;
 
 	nullpo_retv(sd);
-	nullpo_retv(stor = guild2storage2(sd->status.guild_id));
+	nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
 
-	if(!stor->storage_status)
-  		return;
+	if(!stor->opened || stor->opened != sd->status.char_id)
+		return;
 
 	if(index < 0 || index >= MAX_GUILD_STORAGE)
 		return;
@@ -655,15 +695,15 @@ void storage_guild_storageget(struct map_session_data* sd, int index, int amount
 		return;
 
 	if(amount < 1 || amount > stor->items[index].amount)
-	  	return;
+		return;
 
-	if( stor->lock ) {
-		storage_guild_storageclose(sd);
+	if( stor->locked ) {
+		gstorage_storageclose(sd);
 		return;
 	}
 
 	if((flag = pc_additem(sd,&stor->items[index],amount,LOG_TYPE_GSTORAGE)) == 0)
-		guild_storage_delitem(sd,stor,index,amount);
+		gstorage_delitem(sd,stor,index,amount);
 	else { // inform fail
 		clif_storageitemremoved(sd,index,0);
 		clif_additem(sd,0,0,flag);
@@ -675,16 +715,15 @@ void storage_guild_storageget(struct map_session_data* sd, int index, int amount
  * @param sd : player
  * @param index : index of item in cart
  * @param amount : number of item to transfer
- * @return 1:fail, 0:success
  */
-void storage_guild_storageaddfromcart(struct map_session_data* sd, int index, int amount)
+void gstorage_storageaddfromcart(struct map_session_data* sd, int index, int amount)
 {
 	struct guild_storage *stor;
 
 	nullpo_retv(sd);
-	nullpo_retv(stor = guild2storage2(sd->status.guild_id));
+	nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
 
-	if( !stor->storage_status || stor->storage_amount > MAX_GUILD_STORAGE )
+	if( !stor->opened || stor->opened != sd->status.char_id || stor->storage_amount > MAX_GUILD_STORAGE )
 		return;
 
 	if( index < 0 || index >= MAX_CART )
@@ -696,7 +735,7 @@ void storage_guild_storageaddfromcart(struct map_session_data* sd, int index, in
 	if( amount < 1 || amount > sd->status.cart[index].amount )
 		return;
 
-	if(guild_storage_additem(sd,stor,&sd->status.cart[index],amount) == 0)
+	if(gstorage_additem(sd,stor,&sd->status.cart[index],amount))
 		pc_cart_delitem(sd,index,amount,0,LOG_TYPE_GSTORAGE);
 	else {
 		clif_storageitemremoved(sd,index,0);
@@ -711,19 +750,19 @@ void storage_guild_storageaddfromcart(struct map_session_data* sd, int index, in
  * @param amount : number of item to transfer
  * @return 1:fail, 0:success
  */
-void storage_guild_storagegettocart(struct map_session_data* sd, int index, int amount)
+void gstorage_storagegettocart(struct map_session_data* sd, int index, int amount)
 {
 	short flag;
 	struct guild_storage *stor;
 
 	nullpo_retv(sd);
-	nullpo_retv(stor = guild2storage2(sd->status.guild_id));
+	nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
 
-	if(!stor->storage_status)
-	  	return;
+	if(!stor->opened || stor->opened != sd->status.char_id)
+		return;
 
 	if(index < 0 || index >= MAX_GUILD_STORAGE)
-	  	return;
+		return;
 
 	if(stor->items[index].nameid == 0)
 		return;
@@ -732,7 +771,7 @@ void storage_guild_storagegettocart(struct map_session_data* sd, int index, int
 		return;
 
 	if((flag = pc_cart_additem(sd,&stor->items[index],amount,LOG_TYPE_GSTORAGE)) == 0)
-		guild_storage_delitem(sd,stor,index,amount);
+		gstorage_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);
@@ -744,104 +783,93 @@ void storage_guild_storagegettocart(struct map_session_data* sd, int index, int
  * @param account_id : account requesting the save
  * @param guild_id : guild to take the guild_storage
  * @param flag : 1=char quitting, close the storage
- * @return 0 : fail (no storage), 1 : success (requested)
+ * @return False : fail (no storage), True : success (requested)
  */
-int storage_guild_storagesave(uint32 account_id, int guild_id, int flag)
+bool gstorage_storagesave(uint32 account_id, int guild_id, int flag)
 {
-	struct guild_storage *stor = guild2storage2(guild_id);
+	struct guild_storage *stor = gstorage_get_storage(guild_id);
 
-	if(stor) {
+	if (stor) {
 		if (flag) //Char quitting, close it.
-			stor->storage_status = 0;
+			stor->opened = 0;
 
-	 	if (stor->dirty)
+		if (stor->dirty)
 			intif_send_guild_storage(account_id,stor);
 
-		return 1;
+		return true;
 	}
 
-	return 0;
+	return false;
 }
 
 /**
  * ACK save of guild storage
  * @param guild_id : guild to use the storage
- * @return 0 : fail (no storage), 1 : success
  */
-int storage_guild_storagesaved(int guild_id)
+void gstorage_storagesaved(int guild_id)
 {
 	struct guild_storage *stor;
 
-	if((stor = guild2storage2(guild_id)) != NULL) {
-		if (stor->dirty && stor->storage_status == 0) // Storage has been correctly saved.
-			stor->dirty = 0;
-
-		return 1;
+	if ((stor = gstorage_get_storage(guild_id)) != NULL) {
+		if (stor->dirty && stor->opened == 0) // Storage has been correctly saved.
+			stor->dirty = false;
 	}
-
-	return 0;
 }
 
 /**
  * Close storage for player then save it
  * @param sd : player
- * @return 0
  */
-int storage_guild_storageclose(struct map_session_data* sd)
+void gstorage_storageclose(struct map_session_data* sd)
 {
 	struct guild_storage *stor;
 
-	nullpo_ret(sd);
-	nullpo_ret(stor = guild2storage2(sd->status.guild_id));
+	nullpo_retv(sd);
+	nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
 
 	clif_storageclose(sd);
-	if (stor->storage_status) {
+	if (stor->opened) {
 		if (save_settings&CHARSAVE_STORAGE)
 			chrif_save(sd, 0); //This one also saves the storage. [Skotlex]
 		else
-			storage_guild_storagesave(sd->status.account_id, sd->status.guild_id,0);
+			gstorage_storagesave(sd->status.account_id, sd->status.guild_id,0);
 
-		stor->storage_status=0;
+		stor->opened = 0;
 	}
 
 	sd->state.storage_flag = 0;
-
-	return 0;
 }
 
 /**
  * Close storage for player then save it
  * @param sd
  * @param flag
- * @return 
  */
-int storage_guild_storage_quit(struct map_session_data* sd, int flag)
+void gstorage_storage_quit(struct map_session_data* sd, int flag)
 {
 	struct guild_storage *stor;
 
-	nullpo_ret(sd);
-	nullpo_ret(stor=guild2storage2(sd->status.guild_id));
+	nullpo_retv(sd);
+	nullpo_retv(stor = gstorage_get_storage(sd->status.guild_id));
 
-	if(flag) { // Only during a guild break flag is 1 (don't save storage)
+	if (flag) { // Only during a guild break flag is 1 (don't save storage)
 		sd->state.storage_flag = 0;
-		stor->storage_status = 0;
+		stor->opened = 0;
 		clif_storageclose(sd);
 
 		if (save_settings&CHARSAVE_STORAGE)
 			chrif_save(sd,0);
 
-		return 0;
+		return;
 	}
 
-	if(stor->storage_status) {
+	if (stor->opened) {
 		if (save_settings&CHARSAVE_STORAGE)
 			chrif_save(sd,0);
 		else
-			storage_guild_storagesave(sd->status.account_id,sd->status.guild_id,1);
+			gstorage_storagesave(sd->status.account_id,sd->status.guild_id,1);
 	}
 
 	sd->state.storage_flag = 0;
-	stor->storage_status = 0;
-
-	return 0;
+	stor->opened = 0;
 }

+ 15 - 14
src/map/storage.h

@@ -24,20 +24,21 @@ void do_final_storage(void);
 void do_reconnect_storage(void);
 void storage_storage_quit(struct map_session_data *sd, int flag);
 
-struct guild_storage* guild2storage(int guild_id);
-struct guild_storage *guild2storage2(int guild_id);
-int guild_storage_delete(int guild_id);
-int storage_guild_storageopen(struct map_session_data *sd);
-char guild_storage_additem(struct map_session_data *sd,struct guild_storage *stor,struct item *item_data,int amount);
-int guild_storage_delitem(struct map_session_data *sd,struct guild_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);
-int storage_guild_storageclose(struct map_session_data *sd);
-int storage_guild_storage_quit(struct map_session_data *sd,int flag);
-int storage_guild_storagesave(uint32 account_id, int guild_id, int flag);
-int storage_guild_storagesaved(int guild_id); //Ack from char server that guild store was saved.
+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);
 
 int compare_item(struct item *a, struct item *b);
 

+ 10 - 0
src/map/trade.c

@@ -391,6 +391,9 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount)
 		return;
 	}
 
+	if (item->bound)
+		sd->state.isBoundTrading |= (1<<item->bound);
+
 	// Locate a trade position
 	ARR_FIND( 0, 10, trade_i, sd->deal.item[trade_i].index == index || sd->deal.item[trade_i].amount == 0 );
 	if( trade_i == 10 ) { // No space left
@@ -483,7 +486,10 @@ void trade_tradecancel(struct map_session_data *sd)
 	struct map_session_data *target_sd;
 	int trade_i;
 
+	nullpo_retv(sd);
+
 	target_sd = map_id2sd(sd->trade_partner);
+	sd->state.isBoundTrading = 0;
 
 	if(!sd->state.trading) { // Not trade accepted
 		if( target_sd ) {
@@ -546,6 +552,8 @@ void trade_tradecommit(struct map_session_data *sd)
 	struct map_session_data *tsd;
 	int trade_i;
 
+	nullpo_retv(sd);
+
 	if (!sd->state.trading || !sd->state.deal_locked) //Locked should be 1 (pressed ok) before you can press trade.
 		return;
 
@@ -624,10 +632,12 @@ void trade_tradecommit(struct map_session_data *sd)
 	sd->state.deal_locked = 0;
 	sd->trade_partner = 0;
 	sd->state.trading = 0;
+	sd->state.isBoundTrading = 0;
 
 	tsd->state.deal_locked = 0;
 	tsd->trade_partner = 0;
 	tsd->state.trading = 0;
+	tsd->state.isBoundTrading = 0;
 
 	clif_tradecompleted(sd, 0);
 	clif_tradecompleted(tsd, 0);

+ 1 - 1
src/map/unit.c

@@ -2855,7 +2855,7 @@ 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)
-					storage_guild_storage_quit(sd,0);
+					gstorage_storage_quit(sd,0);
 
 				sd->state.storage_flag = 0; //Force close it when being warped.
 			}