viewing paste bound-beta | Diff

Posted on the
  1. Index: src/char/char.c
  2. ===================================================================
  3. --- src/char/char.c	(revision 17350)
  4. +++ src/char/char.c	(working copy)
  5. @@ -775,7 +775,7 @@
  6.  	// it significantly reduces cpu load on the database server.
  7.  
  8.  	StringBuf_Init(&buf);
  9. -	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`");
  10. +	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`");
  11.  	for( j = 0; j < MAX_SLOTS; ++j )
  12.  		StringBuf_Printf(&buf, ", `card%d`", j);
  13.  	StringBuf_Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id);
  14. @@ -798,8 +798,9 @@
  15.  	SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR,      &item.refine,      0, NULL, NULL);
  16.  	SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR,      &item.attribute,   0, NULL, NULL);
  17.  	SqlStmt_BindColumn(stmt, 7, SQLDT_UINT,      &item.expire_time, 0, NULL, NULL);
  18. +	SqlStmt_BindColumn(stmt, 8, SQLDT_UINT,      &item.bound,       0, NULL, NULL);
  19.  	for( j = 0; j < MAX_SLOTS; ++j )
  20. -		SqlStmt_BindColumn(stmt, 8+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
  21. +		SqlStmt_BindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
  22.  
  23.  	// bit array indicating which inventory items have already been matched
  24.  	flag = (bool*) aCalloc(max, sizeof(bool));
  25. @@ -826,14 +827,15 @@
  26.  				    items[i].identify == item.identify &&
  27.  				    items[i].refine == item.refine &&
  28.  				    items[i].attribute == item.attribute &&
  29. -				    items[i].expire_time == item.expire_time )
  30. +				    items[i].expire_time == item.expire_time &&
  31. +				    items[i].bound == item.bound )
  32.  				;	//Do nothing.
  33.  				else
  34.  				{
  35.  					// update all fields.
  36.  					StringBuf_Clear(&buf);
  37. -					StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u'",
  38. -						tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time);
  39. +					StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `bound`='%d'",
  40. +						tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound);
  41.  					for( j = 0; j < MAX_SLOTS; ++j )
  42.  						StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]);
  43.  					StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id);
  44. @@ -861,7 +863,7 @@
  45.  	SqlStmt_Free(stmt);
  46.  
  47.  	StringBuf_Clear(&buf);
  48. -	StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `unique_id`", tablename, selectoption);
  49. +	StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`", tablename, selectoption);
  50.  	for( j = 0; j < MAX_SLOTS; ++j )
  51.  		StringBuf_Printf(&buf, ", `card%d`", j);
  52.  	StringBuf_AppendStr(&buf, ") VALUES ");
  53. @@ -879,8 +881,8 @@
  54.  		else
  55.  			found = true;
  56.  
  57. -		StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%"PRIu64"'",
  58. -			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].unique_id);
  59. +		StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%"PRIu64"'",
  60. +			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);
  61.  		for( j = 0; j < MAX_SLOTS; ++j )
  62.  			StringBuf_Printf(&buf, ", '%d'", items[i].card[j]);
  63.  		StringBuf_AppendStr(&buf, ")");
  64. @@ -919,7 +921,7 @@
  65.  	// it significantly reduces cpu load on the database server.
  66.  
  67.  	StringBuf_Init(&buf);
  68. -	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`");
  69. +	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`");
  70.  	for( j = 0; j < MAX_SLOTS; ++j )
  71.  		StringBuf_Printf(&buf, ", `card%d`", j);
  72.  	StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'", inventory_db, id);
  73. @@ -943,8 +945,9 @@
  74.  	SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR,      &item.attribute,   0, NULL, NULL);
  75.  	SqlStmt_BindColumn(stmt, 7, SQLDT_UINT,      &item.expire_time, 0, NULL, NULL);
  76.  	SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR,      &item.favorite,    0, NULL, NULL);
  77. +	SqlStmt_BindColumn(stmt, 9, SQLDT_CHAR,      &item.bound,       0, NULL, NULL);
  78.  	for( j = 0; j < MAX_SLOTS; ++j )
  79. -		SqlStmt_BindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
  80. +		SqlStmt_BindColumn(stmt, 10+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
  81.  
  82.  	// bit array indicating which inventory items have already been matched
  83.  	flag = (bool*) aCalloc(max, sizeof(bool));
  84. @@ -970,13 +973,14 @@
  85.  				   items[i].refine == item.refine &&
  86.  				   items[i].attribute == item.attribute &&
  87.  				   items[i].expire_time == item.expire_time &&
  88. -				   items[i].favorite == item.favorite )
  89. +				   items[i].favorite == item.favorite &&
  90. +				   items[i].bound == item.bound )
  91.  					;	//Do nothing.
  92.  				else {
  93.  					// update all fields.
  94.  					StringBuf_Clear(&buf);
  95. -					StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d'",
  96. -									 inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite);
  97. +					StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d', `bound`='%d'",
  98. +									 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);
  99.  					for( j = 0; j < MAX_SLOTS; ++j )
  100.  						StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]);
  101.  					StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id);
  102. @@ -1001,7 +1005,7 @@
  103.  	SqlStmt_Free(stmt);
  104.  
  105.  	StringBuf_Clear(&buf);
  106. -	StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `unique_id`", inventory_db);
  107. +	StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`", inventory_db);
  108.  	for( j = 0; j < MAX_SLOTS; ++j )
  109.  		StringBuf_Printf(&buf, ", `card%d`", j);
  110.  	StringBuf_AppendStr(&buf, ") VALUES ");
  111. @@ -1018,8 +1022,8 @@
  112.  		else
  113.  			found = true;
  114.  
  115. -		StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%"PRIu64"'",
  116. -						 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].unique_id);
  117. +		StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%d', '%"PRIu64"'",
  118. +						 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);
  119.  		for( j = 0; j < MAX_SLOTS; ++j )
  120.  			StringBuf_Printf(&buf, ", '%d'", items[i].card[j]);
  121.  		StringBuf_AppendStr(&buf, ")");
  122. @@ -1282,7 +1286,7 @@
  123.  	//read inventory
  124.  	//`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `expire_time`, `favorite`, `unique_id`)
  125.  	StringBuf_Init(&buf);
  126. -	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `unique_id`");
  127. +	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`");
  128.  	for( i = 0; i < MAX_SLOTS; ++i )
  129.  		StringBuf_Printf(&buf, ", `card%d`", i);
  130.  	StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY);
  131. @@ -1299,10 +1303,11 @@
  132.  	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR,      &tmp_item.attribute, 0, NULL, NULL)
  133.  	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT,      &tmp_item.expire_time, 0, NULL, NULL)
  134.  	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR,      &tmp_item.favorite, 0, NULL, NULL)
  135. -	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_ULONGLONG, &tmp_item.unique_id, 0, NULL, NULL) )
  136. +	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_CHAR,      &tmp_item.bound, 0, NULL, NULL)
  137. +	||	SQL_ERROR == SqlStmt_BindColumn(stmt,10, SQLDT_ULONGLONG, &tmp_item.unique_id, 0, NULL, NULL) )
  138.  		SqlStmt_ShowDebug(stmt);
  139.  	for( i = 0; i < MAX_SLOTS; ++i )
  140. -		if( SQL_ERROR == SqlStmt_BindColumn(stmt, 10+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
  141. +		if( SQL_ERROR == SqlStmt_BindColumn(stmt, 11+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
  142.  			SqlStmt_ShowDebug(stmt);
  143.  
  144.  	for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
  145. @@ -1313,7 +1318,7 @@
  146.  	//read cart
  147.  	//`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, expire_time`, `unique_id`)
  148.  	StringBuf_Clear(&buf);
  149. -	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `unique_id`");
  150. +	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`");
  151.  	for( j = 0; j < MAX_SLOTS; ++j )
  152.  		StringBuf_Printf(&buf, ", `card%d`", j);
  153.  	StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART);
  154. @@ -1329,10 +1334,11 @@
  155.  	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR,        &tmp_item.refine, 0, NULL, NULL)
  156.  	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR,        &tmp_item.attribute, 0, NULL, NULL)
  157.  	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT,        &tmp_item.expire_time, 0, NULL, NULL)
  158. -	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_ULONGLONG,   &tmp_item.unique_id, 0, NULL, NULL) )
  159. +	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR,        &tmp_item.bound, 0, NULL, NULL)
  160. +	||	SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_ULONGLONG,   &tmp_item.unique_id, 0, NULL, NULL) )
  161.  		SqlStmt_ShowDebug(stmt);
  162.  	for( i = 0; i < MAX_SLOTS; ++i )
  163. -		if( SQL_ERROR == SqlStmt_BindColumn(stmt, 9+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
  164. +		if( SQL_ERROR == SqlStmt_BindColumn(stmt, 10+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
  165.  			SqlStmt_ShowDebug(stmt);
  166.  
  167.  	for( i = 0; i < MAX_CART && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
  168. Index: src/char/int_mail.c
  169. ===================================================================
  170. --- src/char/int_mail.c	(revision 17350)
  171. +++ src/char/int_mail.c	(working copy)
  172. @@ -63,6 +63,7 @@
  173.  		Sql_GetData(sql_handle,14, &data, NULL); item->identify = atoi(data);
  174.  		Sql_GetData(sql_handle,15, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
  175.  		item->expire_time = 0;
  176. +		item->bound = 0;
  177.  
  178.  		for (j = 0; j < MAX_SLOTS; j++)
  179.  		{
  180. @@ -183,6 +184,7 @@
  181.  		Sql_GetData(sql_handle,14, &data, NULL); msg->item.identify = atoi(data);
  182.  		Sql_GetData(sql_handle,15, &data, NULL); msg->item.unique_id = strtoull(data, NULL, 10);
  183.  		msg->item.expire_time = 0;
  184. +		msg->item.bound = 0;
  185.  
  186.  		for( j = 0; j < MAX_SLOTS; j++ )
  187.  		{
  188. Index: src/char/int_storage.c
  189. ===================================================================
  190. --- src/char/int_storage.c	(revision 17350)
  191. +++ src/char/int_storage.c	(working copy)
  192. @@ -38,7 +38,7 @@
  193.  
  194.  	// storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`}
  195.  	StringBuf_Init(&buf);
  196. -	StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`,`unique_id`");
  197. +	StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`,`bound`,`unique_id`");
  198.  	for( j = 0; j < MAX_SLOTS; ++j )
  199.  		StringBuf_Printf(&buf, ",`card%d`", j);
  200.  	StringBuf_Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id);
  201. @@ -59,10 +59,11 @@
  202.  		Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data);
  203.  		Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data);
  204.  		Sql_GetData(sql_handle, 7, &data, NULL); item->expire_time = (unsigned int)atoi(data);
  205. -		Sql_GetData(sql_handle, 8, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
  206. +		Sql_GetData(sql_handle, 8, &data, NULL); item->bound = atoi(data);
  207. +		Sql_GetData(sql_handle, 9, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
  208.  		for( j = 0; j < MAX_SLOTS; ++j )
  209.  		{
  210. -			Sql_GetData(sql_handle, 9+j, &data, NULL); item->card[j] = atoi(data);
  211. +			Sql_GetData(sql_handle, 10+j, &data, NULL); item->card[j] = atoi(data);
  212.  		}
  213.  	}
  214.  	p->storage_amount = i;
  215. @@ -95,7 +96,7 @@
  216.  
  217.  	// storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`}
  218.  	StringBuf_Init(&buf);
  219. -	StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`unique_id`");
  220. +	StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`bound`,`unique_id`");
  221.  	for( j = 0; j < MAX_SLOTS; ++j )
  222.  		StringBuf_Printf(&buf, ",`card%d`", j);
  223.  	StringBuf_Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id);
  224. @@ -115,11 +116,12 @@
  225.  		Sql_GetData(sql_handle, 4, &data, NULL); item->identify = atoi(data);
  226.  		Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data);
  227.  		Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data);
  228. -		Sql_GetData(sql_handle, 7, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
  229. +		Sql_GetData(sql_handle, 7, &data, NULL); item->bound = atoi(data);
  230. +		Sql_GetData(sql_handle, 8, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
  231.  		item->expire_time = 0;
  232.  		for( j = 0; j < MAX_SLOTS; ++j )
  233.  		{
  234. -			Sql_GetData(sql_handle, 8+j, &data, NULL); item->card[j] = atoi(data);
  235. +			Sql_GetData(sql_handle, 9+j, &data, NULL); item->card[j] = atoi(data);
  236.  		}
  237.  	}
  238.  	p->storage_amount = i;
  239. @@ -158,18 +160,19 @@
  240.  //---------------------------------------------------------
  241.  // packet from map server
  242.  
  243. -int mapif_load_guild_storage(int fd,int account_id,int guild_id)
  244. +int mapif_load_guild_storage(int fd,int account_id,int guild_id, char flag)
  245.  {
  246.  	if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id) )
  247.  		Sql_ShowDebug(sql_handle);
  248.  	else if( Sql_NumRows(sql_handle) > 0 )
  249.  	{// guild exists
  250. -		WFIFOHEAD(fd, sizeof(struct guild_storage)+12);
  251. +		WFIFOHEAD(fd, sizeof(struct guild_storage)+13);
  252.  		WFIFOW(fd,0) = 0x3818;
  253. -		WFIFOW(fd,2) = sizeof(struct guild_storage)+12;
  254. +		WFIFOW(fd,2) = sizeof(struct guild_storage)+13;
  255.  		WFIFOL(fd,4) = account_id;
  256.  		WFIFOL(fd,8) = guild_id;
  257. -		guild_storage_fromsql(guild_id, (struct guild_storage*)WFIFOP(fd,12));
  258. +		WFIFOB(fd,12) = flag; //1 open storage, 0 don't open
  259. +		guild_storage_fromsql(guild_id, (struct guild_storage*)WFIFOP(fd,13));
  260.  		WFIFOSET(fd, WFIFOW(fd,2));
  261.  		return 0;
  262.  	}
  263. @@ -200,7 +203,7 @@
  264.  int mapif_parse_LoadGuildStorage(int fd)
  265.  {
  266.  	RFIFOHEAD(fd);
  267. -	mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6));
  268. +	mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6),1);
  269.  	return 0;
  270.  }
  271.  
  272. @@ -234,13 +237,134 @@
  273.  	return 0;
  274.  }
  275.  
  276. +int mapif_itembound_ack(int fd, int aid, int guild_id)
  277. +{
  278. +	WFIFOHEAD(fd,8);
  279. +	WFIFOW(fd,0) = 0x3856;
  280. +	WFIFOL(fd,2) = aid;
  281. +	WFIFOW(fd,6) = guild_id;
  282. +	WFIFOSET(fd,8);
  283. +	return 0;
  284. +}
  285.  
  286. +//------------------------------------------------
  287. +//Guild bound items pull for offline characters [Akinari]
  288. +//------------------------------------------------
  289. +int mapif_parse_itembound_retrieve(int fd)
  290. +{
  291. +	StringBuf buf;
  292. +	SqlStmt* stmt;
  293. +	struct item item;
  294. +	int j, i=0, s;
  295. +	bool found=false;
  296. +	struct item items[MAX_INVENTORY];
  297. +	int char_id = RFIFOL(fd,2);
  298. +	int aid = RFIFOL(fd,6);
  299. +	int guild_id = RFIFOW(fd,10);
  300. +
  301. +	StringBuf_Init(&buf);
  302. +	StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`");
  303. +	for( j = 0; j < MAX_SLOTS; ++j )
  304. +		StringBuf_Printf(&buf, ", `card%d`", j);
  305. +	StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'",inventory_db,char_id);
  306. +
  307. +	stmt = SqlStmt_Malloc(sql_handle);
  308. +	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
  309. +	||  SQL_ERROR == SqlStmt_Execute(stmt) )
  310. +	{
  311. +		SqlStmt_ShowDebug(stmt);
  312. +		SqlStmt_Free(stmt);
  313. +		StringBuf_Destroy(&buf);
  314. +		return 1;
  315. +	}
  316. +
  317. +	SqlStmt_BindColumn(stmt, 0, SQLDT_INT,       &item.id,          0, NULL, NULL);
  318. +	SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT,     &item.nameid,      0, NULL, NULL);
  319. +	SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT,     &item.amount,      0, NULL, NULL);
  320. +	SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT,    &item.equip,       0, NULL, NULL);
  321. +	SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR,      &item.identify,    0, NULL, NULL);
  322. +	SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR,      &item.refine,      0, NULL, NULL);
  323. +	SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR,      &item.attribute,   0, NULL, NULL);
  324. +	SqlStmt_BindColumn(stmt, 7, SQLDT_UINT,      &item.expire_time, 0, NULL, NULL);
  325. +	SqlStmt_BindColumn(stmt, 8, SQLDT_UINT,      &item.bound,       0, NULL, NULL);
  326. +	for( j = 0; j < MAX_SLOTS; ++j )
  327. +		SqlStmt_BindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
  328. +
  329. +	while( SQL_SUCCESS == SqlStmt_NextRow(stmt) ) {
  330. +		if(item.bound == 2) {
  331. +			memcpy(&items[i],&item,sizeof(struct item));
  332. +			i++;
  333. +		}
  334. +	}
  335. +	
  336. +	if(!i) //No items found - No need to continue
  337. +		return 0;
  338. +
  339. +	//First we delete the character's items
  340. +	StringBuf_Clear(&buf);
  341. +	StringBuf_Printf(&buf, "DELETE FROM `%s` WHERE",inventory_db);
  342. +	for(j=0; j<i; j++) {
  343. +		if( found )
  344. +			StringBuf_AppendStr(&buf, " OR");
  345. +		else
  346. +			found = true;
  347. +		StringBuf_Printf(&buf, " `id`=%d",items[j].id);
  348. +	}
  349. +
  350. +	stmt = SqlStmt_Malloc(sql_handle);
  351. +	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
  352. +	||  SQL_ERROR == SqlStmt_Execute(stmt) )
  353. +	{
  354. +		SqlStmt_ShowDebug(stmt);
  355. +		SqlStmt_Free(stmt);
  356. +		StringBuf_Destroy(&buf);
  357. +		return 1;
  358. +	}
  359. +
  360. +	//Now let's update the guild storage with those deleted items
  361. +	found = false;
  362. +	StringBuf_Clear(&buf);
  363. +	StringBuf_Printf(&buf, "INSERT INTO `%s` (`guild_id`, `nameid`, `amount`, `identify`, `refine`, `attribute`, `expire_time`, `bound`", guild_storage_db);
  364. +	for( j = 0; j < MAX_SLOTS; ++j )
  365. +		StringBuf_Printf(&buf, ", `card%d`", j);
  366. +	StringBuf_AppendStr(&buf, ") VALUES ");
  367. +	
  368. +	for( j = 0; j < i; ++j ) {
  369. +		if( found )
  370. +			StringBuf_AppendStr(&buf, ",");
  371. +		else
  372. +			found = true;
  373. +
  374. +		StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d'",
  375. +			guild_id, items[j].nameid, items[j].amount, items[j].identify, items[j].refine, items[j].attribute, items[j].expire_time, items[j].bound);
  376. +		for( s = 0; s < MAX_SLOTS; ++s )
  377. +			StringBuf_Printf(&buf, ", '%d'", items[j].card[s]);
  378. +		StringBuf_AppendStr(&buf, ")");
  379. +	}
  380. +
  381. +	stmt = SqlStmt_Malloc(sql_handle);
  382. +	if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
  383. +	||  SQL_ERROR == SqlStmt_Execute(stmt) )
  384. +	{
  385. +		SqlStmt_ShowDebug(stmt);
  386. +		SqlStmt_Free(stmt);
  387. +		StringBuf_Destroy(&buf);
  388. +		return 1;
  389. +	}
  390. +
  391. +	//Finally reload storage and tell map we're done
  392. +	mapif_load_guild_storage(fd,aid,guild_id,0);
  393. +	mapif_itembound_ack(fd,aid,guild_id);
  394. +	return 0;
  395. +}
  396. +
  397.  int inter_storage_parse_frommap(int fd)
  398.  {
  399.  	RFIFOHEAD(fd);
  400.  	switch(RFIFOW(fd,0)){
  401.  	case 0x3018: mapif_parse_LoadGuildStorage(fd); break;
  402.  	case 0x3019: mapif_parse_SaveGuildStorage(fd); break;
  403. +	case 0x3056: mapif_parse_itembound_retrieve(fd); break;
  404.  	default:
  405.  		return 0;
  406.  	}
  407. Index: src/char/inter.c
  408. ===================================================================
  409. --- src/char/inter.c	(revision 17350)
  410. +++ src/char/inter.c	(working copy)
  411. @@ -51,7 +51,7 @@
  412.  	-1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0,  0, 0,  0, 0,	// 3020- Party
  413.  	-1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1,	// 3030-
  414.  	-1, 9, 0, 0,  0, 0, 0, 0,  7, 6,10,10, 10,-1,  0, 0,	// 3040-
  415. -	-1,-1,10,10,  0,-1, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3050-  Auction System [Zephyrus]
  416. +	-1,-1,10,10,  0,-1,12, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3050-  Auction System [Zephyrus]
  417.  	 6,-1, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3060-  Quest system [Kevin] [Inkfish]
  418.  	-1,10, 6,-1,  0, 0, 0, 0,  0, 0, 0, 0, -1,10,  6,-1,	// 3070-  Mercenary packets [Zephyrus], Elemental packets [pakpil]
  419.  	48,14,-1, 6,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,	// 3080-
  420. Index: src/common/mmo.h
  421. ===================================================================
  422. --- src/common/mmo.h	(revision 17350)
  423. +++ src/common/mmo.h	(working copy)
  424. @@ -204,7 +204,7 @@
  425.  	char attribute;
  426.  	short card[MAX_SLOTS];
  427.  	unsigned int expire_time;
  428. -	char favorite;
  429. +	char favorite, bound;
  430.  	uint64 unique_id;
  431.  };
  432.  
  433. Index: src/map/atcommand.c
  434. ===================================================================
  435. --- src/map/atcommand.c	(revision 17350)
  436. +++ src/map/atcommand.c	(working copy)
  437. @@ -1112,11 +1112,12 @@
  438.  
  439.  /*==========================================
  440.   * @item command (usage: @item <name/id_of_item> <quantity>) (modified by [Yor] for pet_egg)
  441. + * @itembound command (usage: @itembound <name/id_of_item> <quantity> <bound_type>)
  442.   *------------------------------------------*/
  443.  ACMD_FUNC(item)
  444.  {
  445.  	char item_name[100];
  446. -	int number = 0, item_id, flag = 0;
  447. +	int number = 0, item_id, flag = 0, bound = 0;
  448.  	struct item item_tmp;
  449.  	struct item_data *item_data;
  450.  	int get_count, i;
  451. @@ -1124,9 +1125,15 @@
  452.  
  453.  	memset(item_name, '\0', sizeof(item_name));
  454.  
  455. -	if (!message || !*message || (
  456. -		sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 &&
  457. -		sscanf(message, "%99s %d", item_name, &number) < 1
  458. +	if (!strcmpi(command+1,"itembound") && (!message || !*message || (
  459. +		sscanf(message, "\"%99[^\"]\" %d %d", item_name, &number, &bound) < 2 && 
  460. +		sscanf(message, "%99s %d %d", item_name, &number, &bound) < 2 
  461. +	))) {
  462. +		clif_displaymessage(fd, msg_txt(sd,295)); // Please enter an item name or ID (usage: @item <item name/ID> <quantity> <bound_type>).
  463. +		return -1;
  464. +	} else if (!message || !*message || (
  465. +		sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 && 
  466. +		sscanf(message, "%99s %d", item_name, &number) < 1 
  467.  	)) {
  468.  		clif_displaymessage(fd, msg_txt(sd,983)); // Please enter an item name or ID (usage: @item <item name/ID> <quantity>).
  469.  		return -1;
  470. @@ -1142,6 +1149,11 @@
  471.  		return -1;
  472.  	}
  473.  
  474. +	if( bound < 0 || bound > 3 ) {
  475. +		clif_displaymessage(fd, msg_txt(sd,298)); // Invalid bound type
  476. +		return -1;
  477. +	}
  478. +
  479.  	item_id = item_data->nameid;
  480.  	get_count = number;
  481.  	//Check if it's stackable.
  482. @@ -1154,6 +1166,7 @@
  483.  			memset(&item_tmp, 0, sizeof(item_tmp));
  484.  			item_tmp.nameid = item_id;
  485.  			item_tmp.identify = 1;
  486. +			item_tmp.bound = bound;
  487.  
  488.  			if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND)))
  489.  				clif_additem(sd, 0, 0, flag);
  490. @@ -1173,17 +1186,23 @@
  491.  	struct item item_tmp;
  492.  	struct item_data *item_data;
  493.  	char item_name[100];
  494. -	int item_id, number = 0;
  495. +	int item_id, number = 0, bound = 0;
  496.  	int identify = 0, refine = 0, attr = 0;
  497.  	int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
  498.  	nullpo_retr(-1, sd);
  499.  
  500.  	memset(item_name, '\0', sizeof(item_name));
  501.  
  502. -	if (!message || !*message || (
  503. +	if (!strcmpi(command+1,"itembound2") && (!message || !*message || (
  504. +		sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 &&
  505. +		sscanf(message, "%99s %d %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 ))) {
  506. +		clif_displaymessage(fd, msg_txt(sd,296)); // Please enter all parameters (usage: @item2 <item name/ID> <quantity>
  507. +		clif_displaymessage(fd, msg_txt(sd,297)); //   <identify_flag> <refine> <attribute> <card1> <card2> <card3> <card4> <bound_type>).
  508. +		return -1;
  509. +	} else if ( !message || !*message || (
  510.  		sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 &&
  511.  		sscanf(message, "%99s %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9
  512. -	)) {
  513. +		)) {
  514.  		clif_displaymessage(fd, msg_txt(sd,984)); // Please enter all parameters (usage: @item2 <item name/ID> <quantity>
  515.  		clif_displaymessage(fd, msg_txt(sd,985)); //   <identify_flag> <refine> <attribute> <card1> <card2> <card3> <card4>).
  516.  		return -1;
  517. @@ -1192,6 +1211,11 @@
  518.  	if (number <= 0)
  519.  		number = 1;
  520.  
  521. +	if( bound < 0 || bound > 3 ) {
  522. +		clif_displaymessage(fd, msg_txt(sd,298)); // Invalid bound type
  523. +		return -1;
  524. +	}
  525. +
  526.  	item_id = 0;
  527.  	if ((item_data = itemdb_searchname(item_name)) != NULL ||
  528.  	    (item_data = itemdb_exists(atoi(item_name))) != NULL)
  529. @@ -1228,6 +1252,7 @@
  530.  			item_tmp.card[1] = c2;
  531.  			item_tmp.card[2] = c3;
  532.  			item_tmp.card[3] = c4;
  533. +			item_tmp.bound = bound;
  534.  			if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND)))
  535.  				clif_additem(sd, 0, 0, flag);
  536.  		}
  537. @@ -9012,6 +9037,8 @@
  538.  		ACMD_DEF(heal),
  539.  		ACMD_DEF(item),
  540.  		ACMD_DEF(item2),
  541. +		ACMD_DEF2("itembound",item),
  542. +		ACMD_DEF2("itembound2",item2),
  543.  		ACMD_DEF(itemreset),
  544.  		ACMD_DEF(clearstorage),
  545.  		ACMD_DEF(cleargstorage),
  546. Index: src/map/buyingstore.c
  547. ===================================================================
  548. --- src/map/buyingstore.c	(revision 17350)
  549. +++ src/map/buyingstore.c	(working copy)
  550. @@ -311,7 +311,7 @@
  551.  			return;
  552.  		}
  553.  
  554. -		if( sd->status.inventory[index].expire_time || !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)) )
  555. +		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)) )
  556.  		{// non-tradable item
  557.  			clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
  558.  			return;
  559. Index: src/map/clif.c
  560. ===================================================================
  561. --- src/map/clif.c	(revision 17350)
  562. +++ src/map/clif.c	(working copy)
  563. @@ -1790,9 +1790,12 @@
  564.  			if( !itemdb_cansell(&sd->status.inventory[i], pc_get_group_level(sd)) )
  565.  				continue;
  566.  
  567. -			if( sd->status.inventory[i].expire_time )
  568. -				continue; // Cannot Sell Rental Items
  569. +			if( sd->status.inventory[i].expire_time || (sd->status.inventory[i].bound && !pc_can_give_bounded_items(sd)) )
  570. +				continue; // Cannot Sell Rental Items or Account Bounded Items
  571.  
  572. +			if( sd->status.inventory[i].bound && !pc_can_give_bounded_items(sd))
  573. +				continue; // Don't allow sale of bound items
  574. +
  575.  			val=sd->inventory_data[i]->value_sell;
  576.  			if( val < 0 )
  577.  				continue;
  578. @@ -2194,7 +2197,7 @@
  579.  		WFIFOL(fd,offs+23)=sd->status.inventory[n].expire_time;
  580.  #endif
  581.  #if PACKETVER >= 20071002
  582. -		WFIFOW(fd,offs+27)=0;  //  HireExpireDate
  583. +		WFIFOW(fd,offs+27)=sd->status.inventory[n].bound ? 2 : 0;
  584.  #endif
  585.  	}
  586.  
  587. @@ -2300,7 +2303,7 @@
  588.  		clif_addcards(WBUFP(buf, n+12), i); //8B
  589.  #if PACKETVER >= 20071002
  590.  		WBUFL(buf,n+20)=i->expire_time;
  591. -		WBUFW(buf,n+24)=0; //Unknown
  592. +		WBUFW(buf,n+24)=i->bound ? 2 : 0;
  593.  #endif
  594.  #if PACKETVER >= 20100629
  595.  		WBUFW(buf,n+26)= (id->equip&EQP_VISIBLE)?id->look:0;
  596. @@ -14199,6 +14202,14 @@
  597.  	}
  598.  
  599.  	// Auction checks...
  600. +	if( sd->status.inventory[sd->auction.index].bound && !pc_can_give_bounded_items(sd) ) {
  601. +		if( sd->status.inventory[sd->auction.index].bound == 1 )
  602. +			clif_displaymessage(sd->fd, msg_txt(sd,293));
  603. +		else
  604. +			clif_displaymessage(sd->fd, msg_txt(sd,294));
  605. +		clif_Auction_message(fd, 2); // The auction has been canceled
  606. +		return;
  607. +	}
  608.  	if( sd->status.zeny < (auction.hours * battle_config.auction_feeperhour) ) {
  609.  		clif_Auction_message(fd, 5); // You do not have enough zeny to pay the Auction Fee.
  610.  		return;
  611. Index: src/map/guild.c
  612. ===================================================================
  613. --- src/map/guild.c	(revision 17350)
  614. +++ src/map/guild.c	(working copy)
  615. @@ -860,6 +860,9 @@
  616.  	if(online_member_sd == NULL)
  617.  		return 0; // noone online to inform
  618.  
  619. +	//Guild bound item check
  620. +	guild_retrieveitembound(char_id,account_id,guild_id);
  621. +
  622.  	if(!flag)
  623.  		clif_guild_leave(online_member_sd, name, mes);
  624.  	else
  625. @@ -884,9 +887,40 @@
  626.  		clif_charnameupdate(sd); //Update display name [Skotlex]
  627.  		//TODO: send emblem update to self and people around
  628.  	}
  629. +
  630.  	return 0;
  631.  }
  632.  
  633. +void guild_retrieveitembound(int char_id,int aid,int guild_id)
  634. +{
  635. +	TBL_PC *sd = map_id2sd(aid);
  636. +	if(sd){ //Character is online
  637. +		int idxlist[MAX_INVENTORY];
  638. +		int j,i;
  639. +		j = pc_bound_chk(sd,2,idxlist);
  640. +		if(j) {
  641. +			struct guild_storage* stor = guild2storage(sd->status.guild_id);
  642. +			for(i=0;i<j;i++) { //Loop the matching items, guild_storage_additem takes care of opening storage
  643. +				guild_storage_additem(sd,stor,&sd->status.inventory[idxlist[i]],sd->status.inventory[idxlist[i]].amount);
  644. +				pc_delitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,4,LOG_TYPE_GSTORAGE);
  645. +			}
  646. +			storage_guild_storageclose(sd); //Close and save the storage
  647. +		}
  648. +	}
  649. +	else { //Character is offline, ask char server to do the job
  650. +		struct guild_storage* stor = guild2storage(guild_id);
  651. +		if(stor->storage_status == 1) { //Someone is in guild storage, close them
  652. +			struct s_mapiterator* iter;
  653. +			iter = mapit_getallusers();
  654. +			for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
  655. +				if(sd->state.storage_flag == 2)
  656. +					storage_guild_storageclose(sd);
  657. +			mapit_free(iter);
  658. +		}
  659. +		intif_itembound_req(char_id,aid,guild_id);
  660. +	}
  661. +}
  662. +
  663.  int guild_send_memberinfoshort(struct map_session_data *sd,int online)
  664.  { // cleaned up [LuzZza]
  665.  	struct guild *g;
  666. @@ -1696,7 +1730,8 @@
  667.  {
  668.  	struct guild *g = guild_search(guild_id);
  669.  	struct map_session_data *sd = NULL;
  670. -	int i;
  671. +	int i, j;
  672. +	int idxlist[MAX_INVENTORY];
  673.  
  674.  	if(flag!=0 || g==NULL)
  675.  		return 0;
  676. @@ -1712,6 +1747,13 @@
  677.  		}
  678.  	}
  679.  
  680. +	//Guild bound item check - Removes the bound flag
  681. +	j = pc_bound_chk(sd,2,idxlist);
  682. +	if(j) {
  683. +		for(i=0;i<j;i++)
  684. +			sd->status.inventory[idxlist[i]].bound = 0;
  685. +	}
  686. +
  687.  	guild_db->foreach(guild_db,guild_broken_sub,guild_id);
  688.  	castle_db->foreach(castle_db,castle_guild_broken_sub,guild_id);
  689.  	guild_storage_delete(guild_id);
  690. Index: src/map/guild.h
  691. ===================================================================
  692. --- src/map/guild.h	(revision 17350)
  693. +++ src/map/guild.h	(working copy)
  694. @@ -106,6 +106,7 @@
  695.  void guild_flags_clear(void);
  696.  
  697.  void guild_guildaura_refresh(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv);
  698. +void guild_retrieveitembound(int char_id,int aid,int guild_id);
  699.  
  700.  void do_final_guild(void);
  701.  
  702. Index: src/map/intif.c
  703. ===================================================================
  704. --- src/map/intif.c	(revision 17350)
  705. +++ src/map/intif.c	(working copy)
  706. @@ -39,7 +39,7 @@
  707.  	39,-1,15,15, 14,19, 7,-1,  0, 0, 0, 0,  0, 0,  0, 0, //0x3820
  708.  	10,-1,15, 0, 79,19, 7,-1,  0,-1,-1,-1, 14,67,186,-1, //0x3830
  709.  	-1, 0, 0,14,  0, 0, 0, 0, -1,74,-1,11, 11,-1,  0, 0, //0x3840
  710. -	-1,-1, 7, 7,  7,11, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, //0x3850  Auctions [Zephyrus]
  711. +	-1,-1, 7, 7,  7,11, 8, 0,  0, 0, 0, 0,  0, 0,  0, 0, //0x3850  Auctions [Zephyrus] itembound[Akinari]
  712.  	-1, 7, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, //0x3860  Quests [Kevin] [Inkfish]
  713.  	-1, 3, 3, 0,  0, 0, 0, 0,  0, 0, 0, 0, -1, 3,  3, 0, //0x3870  Mercenaries [Zephyrus] / Elemental [pakpil]
  714.  	11,-1, 7, 3,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, //0x3880
  715. @@ -1007,32 +1007,47 @@
  716.  	guild_id = RFIFOL(fd,8);
  717.  	if(guild_id <= 0)
  718.  		return 1;
  719. -	sd=map_id2sd( RFIFOL(fd,4) );
  720. -	if(sd==NULL){
  721. -		ShowError("intif_parse_LoadGuildStorage: user not found %d\n",RFIFOL(fd,4));
  722. -		return 1;
  723. -	}
  724. +
  725.  	gstor=guild2storage(guild_id);
  726.  	if(!gstor) {
  727.  		ShowWarning("intif_parse_LoadGuildStorage: error guild_id %d not exist\n",guild_id);
  728.  		return 1;
  729.  	}
  730.  	if (gstor->storage_status == 1) { // Already open.. lets ignore this update
  731. +		sd=map_id2sd( RFIFOL(fd,4) );
  732. +		if(sd==NULL){
  733. +			ShowError("intif_parse_LoadGuildStorage: user not found %d\n",RFIFOL(fd,4));
  734. +			return 1;
  735. +		}
  736.  		ShowWarning("intif_parse_LoadGuildStorage: storage received for a client already open (User %d:%d)\n", sd->status.account_id, sd->status.char_id);
  737.  		return 1;
  738.  	}
  739.  	if (gstor->dirty) { // Already have storage, and it has been modified and not saved yet! Exploit! [Skotlex]
  740. +		sd=map_id2sd( RFIFOL(fd,4) );
  741. +		if(sd==NULL){
  742. +			ShowError("intif_parse_LoadGuildStorage: user not found %d\n",RFIFOL(fd,4));
  743. +			return 1;
  744. +		}
  745.  		ShowWarning("intif_parse_LoadGuildStorage: received storage for an already modified non-saved storage! (User %d:%d)\n", sd->status.account_id, sd->status.char_id);
  746.  		return 1;
  747.  	}
  748. -	if( RFIFOW(fd,2)-12 != sizeof(struct guild_storage) ){
  749. -		ShowError("intif_parse_LoadGuildStorage: data size error %d %d\n",RFIFOW(fd,2)-12 , sizeof(struct guild_storage));
  750. +	if( RFIFOW(fd,2)-13 != sizeof(struct guild_storage) ){
  751. +		ShowError("intif_parse_LoadGuildStorage: data size error %d %d\n",RFIFOW(fd,2)-13 , sizeof(struct guild_storage));
  752.  		gstor->storage_status = 0;
  753.  		return 1;
  754.  	}
  755.  
  756. -	memcpy(gstor,RFIFOP(fd,12),sizeof(struct guild_storage));
  757. -	storage_guild_storageopen(sd);
  758. +	memcpy(gstor,RFIFOP(fd,13),sizeof(struct guild_storage));
  759. +
  760. +	if( RFIFOL(fd,12) ){ //if flag != 0 open it
  761. +		sd=map_id2sd( RFIFOL(fd,4) );
  762. +		if(sd==NULL){
  763. +			ShowError("intif_parse_LoadGuildStorage: user not found %d\n",RFIFOL(fd,4));
  764. +			return 1;
  765. +		}
  766. +		storage_guild_storageopen(sd);
  767. +	}
  768. +
  769.  	return 0;
  770.  }
  771.  
  772. @@ -2152,6 +2167,34 @@
  773.  	return;
  774.  }
  775.  
  776. +/*==========================================
  777. + * Item Bound System
  778. + *------------------------------------------*/
  779. +
  780. +void intif_itembound_req(int char_id,int aid,int guild_id) {
  781. +	struct guild_storage *gstor = guild2storage2(guild_id);
  782. +	WFIFOHEAD(inter_fd,12);
  783. +	WFIFOW(inter_fd,0) = 0x3056;
  784. +	WFIFOL(inter_fd,2) = char_id;
  785. +	WFIFOL(inter_fd,6) = aid;
  786. +	WFIFOW(inter_fd,10) = guild_id;
  787. +	WFIFOSET(inter_fd,12);
  788. +	if(gstor)
  789. +		gstor->lock = 1; //lock for retrive process
  790. +}
  791. +
  792. +//3856
  793. +void intif_parse_itembound_ack(int fd) {
  794. +	struct guild_storage *gstor;
  795. +	int aid = RFIFOL(char_fd,2);
  796. +	int guild_id = RFIFOW(char_fd,6);
  797. +	TBL_PC *sd = map_id2sd(aid);
  798. +
  799. +	gstor = guild2storage2(guild_id);
  800. +	if(gstor) gstor->lock = 0; //now could be used again
  801. +	if(sd) storage_guild_storageclose(sd); //at this point guild_storage should have been open
  802. +}
  803. +
  804.  //-----------------------------------------------------------------
  805.  // Communication from the inter server
  806.  // Return a 0 (false) if there were any errors.
  807. @@ -2235,6 +2278,9 @@
  808.  	case 0x3854:	intif_parse_Auction_message(fd); break;
  809.  	case 0x3855:	intif_parse_Auction_bid(fd); break;
  810.  
  811. +//Bound items
  812. +	case 0x3856:	intif_parse_itembound_ack(fd); break;
  813. +
  814.  	// Mercenary System
  815.  	case 0x3870:	intif_parse_mercenary_received(fd); break;
  816.  	case 0x3871:	intif_parse_mercenary_deleted(fd); break;
  817. Index: src/map/intif.h
  818. ===================================================================
  819. --- src/map/intif.h	(revision 17350)
  820. +++ src/map/intif.h	(working copy)
  821. @@ -60,6 +60,7 @@
  822.  int intif_guild_emblem(int guild_id, int len, const char *data);
  823.  int intif_guild_castle_dataload(int num, int *castle_ids);
  824.  int intif_guild_castle_datasave(int castle_id, int index, int value);
  825. +void intif_itembound_req(int char_id, int aid, int guild_id);
  826.  
  827.  int intif_create_pet(int account_id, int char_id, short pet_type, short pet_lv, short pet_egg_id,
  828.                       short pet_equip, short intimate, short hungry, char rename_flag, char incuvate, char *pet_name);
  829. Index: src/map/mail.c
  830. ===================================================================
  831. --- src/map/mail.c	(revision 17350)
  832. +++ src/map/mail.c	(working copy)
  833. @@ -78,8 +78,9 @@
  834.  			return 1;
  835.  		if( amount < 0 || amount > sd->status.inventory[idx].amount )
  836.  			return 1;
  837. -		if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time ||
  838. -				!itemdb_canmail(&sd->status.inventory[idx],pc_get_group_level(sd)) )
  839. +		if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time 
  840. +			|| !itemdb_canmail(&sd->status.inventory[idx],pc_get_group_level(sd)) 
  841. +			|| (sd->status.inventory[idx].bound && !pc_can_give_bounded_items(sd)) )
  842.  			return 1;
  843.  
  844.  		sd->mail.index = idx;
  845. Index: src/map/party.c
  846. ===================================================================
  847. --- src/map/party.c	(revision 17350)
  848. +++ src/map/party.c	(working copy)
  849. @@ -552,12 +552,10 @@
  850.  	struct map_session_data* sd = map_id2sd(account_id);
  851.  	struct party_data* p = party_search(party_id);
  852.  
  853. -	if( p )
  854. -	{
  855. +	if( p ) {
  856.  		int i;
  857.  		ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == account_id && p->party.member[i].char_id == char_id );
  858. -		if( i < MAX_PARTY )
  859. -		{
  860. +		if( i < MAX_PARTY ) {
  861.  			clif_party_withdraw(p,sd,account_id,p->party.member[i].name,0x0);
  862.  			memset(&p->party.member[i], 0, sizeof(p->party.member[0]));
  863.  			memset(&p->data[i], 0, sizeof(p->data[0]));
  864. @@ -566,8 +564,14 @@
  865.  		}
  866.  	}
  867.  
  868. -	if( sd && sd->status.party_id == party_id && sd->status.char_id == char_id )
  869. -	{
  870. +	if( sd && sd->status.party_id == party_id && sd->status.char_id == char_id ) {
  871. +		int idxlist[MAX_INVENTORY]; //or malloc to reduce consumtion
  872. +		int j,i;
  873. +		j = pc_bound_chk(sd,3,idxlist);
  874. +		if(j) {
  875. +			for(i=0;i<j;i++)
  876. +				pc_delitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_OTHER);
  877. +		}
  878.  		sd->status.party_id = 0;
  879.  		clif_charnameupdate(sd); //Update name display [Skotlex]
  880.  		//TODO: hp bars should be cleared too
  881. Index: src/map/pc.c
  882. ===================================================================
  883. --- src/map/pc.c	(revision 17350)
  884. +++ src/map/pc.c	(working copy)
  885. @@ -509,6 +509,14 @@
  886.  	return pc_has_permission(sd, PC_PERM_TRADE);
  887.  }
  888.  
  889. +/**
  890. + * Determines if player can give / drop / trade / vend bounded items
  891. + */
  892. +bool pc_can_give_bounded_items(struct map_session_data *sd)
  893. +{
  894. +	return pc_has_permission(sd, PC_PERM_TRADE_BOUNDED);
  895. +}
  896. +
  897.  /*==========================================
  898.   * prepares character for saving.
  899.   *------------------------------------------*/
  900. @@ -914,7 +922,8 @@
  901.   *------------------------------------------*/
  902.  bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int group_id, struct mmo_charstatus *st, bool changing_mapservers)
  903.  {
  904. -	int i;
  905. +	int i, j;
  906. +	int idxlist[MAX_INVENTORY];
  907.  	unsigned long tick = gettick();
  908.  	uint32 ip = session[sd->fd]->client_addr;
  909.  
  910. @@ -1091,6 +1100,12 @@
  911.  	 **/
  912.  	pc_itemcd_do(sd,true);
  913.  
  914. +	// Party bound item check
  915. +	if(sd->status.party_id == 0 && (j = pc_bound_chk(sd,3,idxlist))) { // Party was deleted while character offline
  916. +		for(i=0;i<j;i++)
  917. +			pc_delitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_OTHER);
  918. +	}
  919. +
  920.  	// Request all registries (auth is considered completed whence they arrive)
  921.  	intif_request_registry(sd,7);
  922.  	return true;
  923. @@ -3878,7 +3893,7 @@
  924.  	{ // Stackable | Non Rental
  925.  		for( i = 0; i < MAX_INVENTORY; i++ )
  926.  		{
  927. -			if( sd->status.inventory[i].nameid == item_data->nameid && memcmp(&sd->status.inventory[i].card, &item_data->card, sizeof(item_data->card)) == 0 )
  928. +			if( sd->status.inventory[i].nameid == item_data->nameid && sd->status.inventory[i].bound == item_data->bound && memcmp(&sd->status.inventory[i].card, &item_data->card, sizeof(item_data->card)) == 0 )
  929.  			{
  930.  				if( amount > MAX_AMOUNT - sd->status.inventory[i].amount || ( data->stack.inventory && amount > data->stack.amount - sd->status.inventory[i].amount ) )
  931.  					return 5;
  932. @@ -4418,7 +4433,7 @@
  933.  		return 1;
  934.  	}
  935.  
  936. -	if( !itemdb_cancartstore(item_data, pc_get_group_level(sd)) )
  937. +	if( !itemdb_cancartstore(item_data, pc_get_group_level(sd)) || ((item_data->bound == 2 || item_data->bound == 3) && !pc_can_give_bounded_items(sd)))
  938.  	{ // Check item trade restrictions	[Skotlex]
  939.  		clif_displaymessage (sd->fd, msg_txt(sd,264));
  940.  		return 1;
  941. @@ -4431,7 +4446,7 @@
  942.  	if( itemdb_isstackable2(data) && !item_data->expire_time )
  943.  	{
  944.  		ARR_FIND( 0, MAX_CART, i,
  945. -			sd->status.cart[i].nameid == item_data->nameid &&
  946. +			sd->status.cart[i].nameid == item_data->nameid && sd->status.cart[i].bound == item_data->bound &&
  947.  			sd->status.cart[i].card[0] == item_data->card[0] && sd->status.cart[i].card[1] == item_data->card[1] &&
  948.  			sd->status.cart[i].card[2] == item_data->card[2] && sd->status.cart[i].card[3] == item_data->card[3] );
  949.  	};
  950. @@ -4567,6 +4582,25 @@
  951.  }
  952.  
  953.  /*==========================================
  954. + * Bound Item Check
  955. + * Type:
  956. + * 1 Account Bound
  957. + * 2 Guild Bound
  958. + * 3 Party Bound
  959. + *------------------------------------------*/
  960. +int pc_bound_chk(TBL_PC *sd,int type,int *idxlist)
  961. +{
  962. +	int i=0, j=0;
  963. +	for(i=0;i<MAX_INVENTORY;i++){
  964. +		if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0 && sd->status.inventory[i].bound == type) {
  965. +			idxlist[j] = i;
  966. +			j++;
  967. +		}
  968. +	}
  969. +	return j;
  970. +}
  971. +
  972. +/*==========================================
  973.   *  Display item stolen msg to player sd
  974.   *------------------------------------------*/
  975.  int pc_show_steal(struct block_list *bl,va_list ap)
  976. @@ -7880,7 +7914,7 @@
  977.   *------------------------------------------*/
  978.  int pc_candrop(struct map_session_data *sd, struct item *item)
  979.  {
  980. -	if( item && item->expire_time )
  981. +	if( item && (item->expire_time || (item->bound && !pc_can_give_bounded_items(sd))) )
  982.  		return 0;
  983.  	if( !pc_can_give_items(sd) ) //check if this GM level can drop items
  984.  		return 0;
  985. Index: src/map/pc.h
  986. ===================================================================
  987. --- src/map/pc.h	(revision 17350)
  988. +++ src/map/pc.h	(working copy)
  989. @@ -705,6 +705,7 @@
  990.  int pc_get_group_id(struct map_session_data *sd);
  991.  int pc_getrefinebonus(int lv,int type);
  992.  bool pc_can_give_items(struct map_session_data *sd);
  993. +bool pc_can_give_bounded_items(struct map_session_data *sd);
  994.  
  995.  bool pc_can_use_command(struct map_session_data *sd, const char *command, AtCommandType type);
  996.  #define pc_has_permission(sd, permission) ( ((sd)->permissions&permission) != 0 )
  997. @@ -748,6 +749,9 @@
  998.  int pc_getzeny(struct map_session_data*,int, enum e_log_pick_type, struct map_session_data*);
  999.  int pc_delitem(struct map_session_data*,int,int,int,short,e_log_pick_type);
  1000.  
  1001. +//Bound items
  1002. +int pc_bound_chk(TBL_PC *sd,int type,int *idxlist);
  1003. +
  1004.  // Special Shop System
  1005.  int pc_paycash( struct map_session_data *sd, int price, int points, e_log_pick_type type );
  1006.  int pc_getcash( struct map_session_data *sd, int cash, int points, e_log_pick_type type );
  1007. Index: src/map/pc_groups.h
  1008. ===================================================================
  1009. --- src/map/pc_groups.h	(revision 17350)
  1010. +++ src/map/pc_groups.h	(working copy)
  1011. @@ -44,6 +44,7 @@
  1012.  	PC_PERM_DISABLE_PVP         = 0x080000,
  1013.  	PC_PERM_DISABLE_CMD_DEAD    = 0x100000,
  1014.  	PC_PERM_CHANNEL_ADMIN       = 0x200000,
  1015. +	PC_PERM_TRADE_BOUNDED       = 0x400000,
  1016.  };
  1017.  
  1018.  static const struct {
  1019. @@ -72,6 +73,7 @@
  1020.  	{ "disable_pvp", PC_PERM_DISABLE_PVP },
  1021.  	{ "disable_commands_when_dead", PC_PERM_DISABLE_CMD_DEAD },
  1022.  	{ "channel_admin", PC_PERM_CHANNEL_ADMIN },
  1023. +	{ "can_trade_bounded", PC_PERM_TRADE_BOUNDED },
  1024.  };
  1025.  
  1026.  #endif // _PC_GROUPS_H_
  1027. Index: src/map/script.c
  1028. ===================================================================
  1029. --- src/map/script.c	(revision 17350)
  1030. +++ src/map/script.c	(working copy)
  1031. @@ -6270,6 +6270,13 @@
  1032.  /*==========================================
  1033.   * getitem <item id>,<amount>{,<account ID>};
  1034.   * getitem "<item name>",<amount>{,<account ID>};
  1035. + *
  1036. + * getitembound <item id>,<amount>,<type>{,<account ID>};
  1037. + * getitembound "<item id>",<amount>,<type>{,<account ID>};
  1038. + * Type:
  1039. + *	1 - Account Bound
  1040. + *	2 - Guild Bound
  1041. + *	3 - Party Bound
  1042.   *------------------------------------------*/
  1043.  BUILDIN_FUNC(getitem)
  1044.  {
  1045. @@ -6280,8 +6287,7 @@
  1046.  
  1047.  	data=script_getdata(st,2);
  1048.  	get_val(st,data);
  1049. -	if( data_isstring(data) )
  1050. -	{// "<item name>"
  1051. +	if( data_isstring(data) ) {// "<item name>"
  1052.  		const char *name=conv_str(st,data);
  1053.  		struct item_data *item_data = itemdb_searchname(name);
  1054.  		if( item_data == NULL ){
  1055. @@ -6289,8 +6295,7 @@
  1056.  			return 1; //No item created.
  1057.  		}
  1058.  		nameid=item_data->nameid;
  1059. -	} else if( data_isint(data) )
  1060. -	{// <item id>
  1061. +	} else if( data_isint(data) ) {// <item id>
  1062.  		nameid=conv_num(st,data);
  1063.  		//Violet Box, Blue Box, etc - random item pick
  1064.  		if( nameid < 0 ) {
  1065. @@ -6317,7 +6322,18 @@
  1066.  	else
  1067.  		it.identify=itemdb_isidentified(nameid);
  1068.  
  1069. -	if( script_hasdata(st,4) )
  1070. +	if( !strcmp(script_getfuncname(st),"getitembound") ) {
  1071. +		char bound = script_getnum(st,4);
  1072. +		if( bound < 1 || bound > 3) { //Not a correct bound type
  1073. +			ShowError("script_getitembound: Not a correct bound type! Type=%d\n",bound);
  1074. +			return 1;
  1075. +		}
  1076. +		it.bound = bound;
  1077. +		if( script_hasdata(st,5) )
  1078. +			sd=map_id2sd(script_getnum(st,5));
  1079. +		else
  1080. +			sd=script_rid2sd(st); // Attached player
  1081. +	} else if( script_hasdata(st,4) )
  1082.  		sd=map_id2sd(script_getnum(st,4)); // <Account ID>
  1083.  	else
  1084.  		sd=script_rid2sd(st); // Attached player
  1085. @@ -6355,12 +6371,23 @@
  1086.  {
  1087.  	int nameid,amount,get_count,i,flag = 0;
  1088.  	int iden,ref,attr,c1,c2,c3,c4;
  1089. +	char bound=0;
  1090.  	struct item_data *item_data;
  1091.  	struct item item_tmp;
  1092.  	TBL_PC *sd;
  1093.  	struct script_data *data;
  1094.  
  1095. -	if( script_hasdata(st,11) )
  1096. +	if( !strcmp(script_getfuncname(st),"getitembound2") ) {
  1097. +		bound = script_getnum(st,11);
  1098. +		if( bound < 1 || bound > 3) { //Not a correct bound type
  1099. +			ShowError("script_getitembound2: Not a correct bound type! Type=%d\n",bound);
  1100. +			return 1;
  1101. +		}
  1102. +		if( script_hasdata(st,12) )
  1103. +			sd=map_id2sd(script_getnum(st,12));
  1104. +		else
  1105. +			sd=script_rid2sd(st); // Attached player
  1106. +	} else if( script_hasdata(st,11) )
  1107.  		sd=map_id2sd(script_getnum(st,11)); // <Account ID>
  1108.  	else
  1109.  		sd=script_rid2sd(st); // Attached player
  1110. @@ -6370,14 +6397,14 @@
  1111.  
  1112.  	data=script_getdata(st,2);
  1113.  	get_val(st,data);
  1114. -	if( data_isstring(data) ){
  1115. +	if( data_isstring(data) ) {
  1116.  		const char *name=conv_str(st,data);
  1117.  		struct item_data *item_data = itemdb_searchname(name);
  1118.  		if( item_data )
  1119.  			nameid=item_data->nameid;
  1120.  		else
  1121.  			nameid=UNKNOWN_ITEM_ID;
  1122. -	}else
  1123. +	} else
  1124.  		nameid=conv_num(st,data);
  1125.  
  1126.  	amount=script_getnum(st,3);
  1127. @@ -6422,6 +6449,7 @@
  1128.  		item_tmp.card[1]=(short)c2;
  1129.  		item_tmp.card[2]=(short)c3;
  1130.  		item_tmp.card[3]=(short)c4;
  1131. +		item_tmp.bound=bound;
  1132.  
  1133.  		//Check if it's stackable.
  1134.  		if (!itemdb_isstackable(nameid))
  1135. @@ -6496,6 +6524,7 @@
  1136.  	it.nameid = nameid;
  1137.  	it.identify = 1;
  1138.  	it.expire_time = (unsigned int)(time(NULL) + seconds);
  1139. +	it.bound = 0;
  1140.  
  1141.  	if( (flag = pc_additem(sd, &it, 1, LOG_TYPE_SCRIPT)) )
  1142.  	{
  1143. @@ -11371,6 +11400,7 @@
  1144.  		item_tmp.refine      = sd->status.inventory[i].refine;
  1145.  		item_tmp.attribute   = sd->status.inventory[i].attribute;
  1146.  		item_tmp.expire_time = sd->status.inventory[i].expire_time;
  1147. +		item_tmp.bound       = sd->status.inventory[i].bound;
  1148.  
  1149.  		for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++)
  1150.  			item_tmp.card[j]=sd->status.inventory[i].card[j];
  1151. @@ -11444,6 +11474,7 @@
  1152.  			item_tmp.refine      = sd->status.inventory[i].refine;
  1153.  			item_tmp.attribute   = sd->status.inventory[i].attribute;
  1154.  			item_tmp.expire_time = sd->status.inventory[i].expire_time;
  1155. +			item_tmp.bound       = sd->status.inventory[i].bound;
  1156.  
  1157.  			for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++)
  1158.  				item_tmp.card[j]=sd->status.inventory[i].card[j];
  1159. @@ -12107,6 +12138,7 @@
  1160.  				pc_setreg(sd,reference_uid(add_str(card_var), j),sd->status.inventory[i].card[k]);
  1161.  			}
  1162.  			pc_setreg(sd,reference_uid(add_str("@inventorylist_expire"), j),sd->status.inventory[i].expire_time);
  1163. +			pc_setreg(sd,reference_uid(add_str("@inventorylist_bound"), j),sd->status.inventory[i].bound);
  1164.  			j++;
  1165.  		}
  1166.  	}
  1167. @@ -17660,6 +17692,34 @@
  1168.  	return 0;
  1169.  }
  1170.  
  1171. +/*==========================================
  1172. + * hasbounded;
  1173. + * Creates an array of bounded item IDs
  1174. + * Returns amount of items found
  1175. + *------------------------------------------*/
  1176. +BUILDIN_FUNC(hasbounded)
  1177. +{
  1178. +	int i, j=0;
  1179. +	TBL_PC *sd;
  1180. +
  1181. +	if( (sd = script_rid2sd(st)) == NULL )
  1182. +		return 0;
  1183. +
  1184. +	for(i=0;i<MAX_INVENTORY;i++){
  1185. +		if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].bound > 0) {
  1186. +			pc_setreg(sd,reference_uid(add_str("@bound_items"), j),sd->status.inventory[i].bound);
  1187. +			j++;
  1188. +		}
  1189. +	}
  1190. +
  1191. +	if(j)
  1192. +		script_pushint(st,j);
  1193. +	else
  1194. +		script_pushint(st,0);
  1195. +
  1196. +	return 0;
  1197. +}
  1198. +
  1199.  // declarations that were supposed to be exported from npc_chat.c
  1200.  #ifdef PCRE_SUPPORT
  1201.  BUILDIN_FUNC(defpattern);
  1202. @@ -18125,5 +18185,10 @@
  1203.  	BUILDIN_DEF(checkquest, "i?"),
  1204.  	BUILDIN_DEF(changequest, "ii"),
  1205.  	BUILDIN_DEF(showevent, "ii"),
  1206. +
  1207. +	//Bound items [Xantara] & [Akinari]
  1208. +	BUILDIN_DEF2(getitem,"getitembound","vii?"),
  1209. +	BUILDIN_DEF2(getitem2,"getitembound2","viiiiiiiii?"),
  1210. +	BUILDIN_DEF(hasbounded, "?"),
  1211.  	{NULL,NULL,NULL},
  1212.  };
  1213. Index: src/map/storage.c
  1214. ===================================================================
  1215. --- src/map/storage.c	(revision 17350)
  1216. +++ src/map/storage.c	(working copy)
  1217. @@ -120,7 +120,8 @@
  1218.  		a->identify == b->identify &&
  1219.  		a->refine == b->refine &&
  1220.  		a->attribute == b->attribute &&
  1221. -		a->expire_time == b->expire_time )
  1222. +		a->expire_time == b->expire_time &&
  1223. +		a->bound == b->bound )
  1224.  	{
  1225.  		int i;
  1226.  		for (i = 0; i < MAX_SLOTS && (a->card[i] == b->card[i]); i++);
  1227. @@ -154,6 +155,11 @@
  1228.  		return 1;
  1229.  	}
  1230.  
  1231. +	if( (item_data->bound == 2 || item_data->bound == 3) && !pc_can_give_bounded_items(sd) ) {
  1232. +		clif_displaymessage(sd->fd, msg_txt(sd,294));
  1233. +		return 1;
  1234. +	}
  1235. +
  1236.  	if( itemdb_isstackable2(data) )
  1237.  	{//Stackable
  1238.  		for( i = 0; i < MAX_STORAGE; i++ )
  1239. @@ -448,6 +454,11 @@
  1240.  		return 1;
  1241.  	}
  1242.  
  1243. +	if( (item_data->bound == 1 || item_data->bound == 3) && !pc_can_give_bounded_items(sd) ) {
  1244. +		clif_displaymessage(sd->fd, msg_txt(sd,294));
  1245. +		return 1;
  1246. +	}
  1247. +
  1248.  	if(itemdb_isstackable2(data)){ //Stackable
  1249.  		for(i=0;i<MAX_GUILD_STORAGE;i++){
  1250.  			if(compare_item(&stor->items[i], item_data)) {
  1251. Index: src/map/trade.c
  1252. ===================================================================
  1253. --- src/map/trade.c	(revision 17350)
  1254. +++ src/map/trade.c	(working copy)
  1255. @@ -368,6 +368,12 @@
  1256.  		return;
  1257.  	}
  1258.  
  1259. +	if( ((item->bound == 1 || item->bound == 3) || (item->bound == 2 && sd->status.guild_id != target_sd->status.guild_id)) && !pc_can_give_bounded_items(sd) ) { // Item Bound
  1260. +		clif_displaymessage(sd->fd, msg_txt(sd,293));
  1261. +		clif_tradeitemok(sd, index+2, 1);
  1262. +		return;
  1263. +	}
  1264. +
  1265.  	//Locate a trade position
  1266.  	ARR_FIND( 0, 10, trade_i, sd->deal.item[trade_i].index == index || sd->deal.item[trade_i].amount == 0 );
  1267.  	if( trade_i == 10 ) //No space left
  1268. Index: src/map/vending.c
  1269. ===================================================================
  1270. --- src/map/vending.c	(revision 17350)
  1271. +++ src/map/vending.c	(working copy)
  1272. @@ -267,6 +267,7 @@
  1273.  		||  !sd->status.cart[index].identify // unidentified item
  1274.  		||  sd->status.cart[index].attribute == 1 // broken item
  1275.  		||  sd->status.cart[index].expire_time // It should not be in the cart but just in case
  1276. +		||  (sd->status.cart[index].bound && !pc_can_give_bounded_items(sd)) // can't trade account bound items and has no permission
  1277.  		||  !itemdb_cantrade(&sd->status.cart[index], pc_get_group_level(sd), pc_get_group_level(sd)) ) // untradeable item
  1278.  			continue;
  1279.  
Viewed 258 times, submitted by unknown.