Introducing the Account/Guild/Party Bounded Items System - Suggestion tid:70372
- Thanks for Xantara for providing initial diff as well as Lighta for guild bound help - Adds script commands 'getitembound', 'getitembound2', and 'countbound' - Adds at commands @itembound and @itembound2 - Adds permission pc_can_traded_bounded - Documentation updated Don't forget to run the SQL upgrade file! git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@17351 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
parent
e8dcdf9ecb
commit
4742adac12
@ -310,6 +310,13 @@
|
||||
290: The player is no longer killable.
|
||||
291: Weather effects will dispell on warp/refresh
|
||||
292: Killer state reset.
|
||||
//Item Bound System
|
||||
293: This bounded item cannot be traded to that character.
|
||||
294: This bounded item cannot be stored there.
|
||||
295: Please enter an item name or ID (usage: @item <item name/ID> <quantity> <bound_type>).
|
||||
296: Please enter all parameters (usage: @item2 <item name/ID> <quantity>
|
||||
297: <identify_flag> <refine> <attribute> <card1> <card2> <card3> <card4> <bound_type>).
|
||||
298: Invalid bound type. Valid types are - 1:Account 2:Guild 3:Party
|
||||
// Guild Castles Number
|
||||
// --------------------
|
||||
//299: ?? Castles
|
||||
|
@ -644,6 +644,22 @@ attribute: 0 = not broken, 1 = broken
|
||||
|
||||
---------------------------------------
|
||||
|
||||
@itembound <item name/ID> <amount> <bound_type>
|
||||
|
||||
Creates the specified item and bounds it to the account.
|
||||
bound_type: 1 = Account, 2 = Guild, 3 = Party
|
||||
|
||||
---------------------------------------
|
||||
|
||||
@itembound2 <item name/ID> <quantity> <identify_flag> <refine> <attribute> <card1> <card2> <card3> <card4> <bound_type>
|
||||
|
||||
Creates an item with the given parameters (the 'cards' can be any item) and bounds it to the account.
|
||||
identify_flag: 0 = unidentified, 1 = identified
|
||||
attribute: 0 = not broken, 1 = broken
|
||||
bound_type: 1 = Account, 2 = Guild, 3 = Party
|
||||
|
||||
---------------------------------------
|
||||
|
||||
@produce <equip name/ID> <element> <# of Very's>
|
||||
|
||||
Creates a weapon with the given parameters.
|
||||
|
@ -172,3 +172,9 @@ Allows player to use the client command /check (displays character status).
|
||||
Allows player to use the client command /changemaptype.
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*can_trade_bounded
|
||||
|
||||
Allows player to do normal item actions (sell, trade, store, vend, auction, mail) with bounded items.
|
||||
|
||||
---------------------------------------
|
||||
|
@ -2687,6 +2687,7 @@ recreate these items perfectly if they are destroyed. Here's what you get:
|
||||
@inventorylist_card4[] if the character owns an item made by a specific
|
||||
craftsman.
|
||||
@inventorylist_expire[] - expire time (Unix time stamp). 0 means never expires.
|
||||
@inventorylist_bound[] - whether it is bound to the character
|
||||
@inventorylist_count - the number of items in these lists.
|
||||
|
||||
This could be handy to save/restore a character's inventory, since no other
|
||||
@ -4248,6 +4249,46 @@ command, creating a pet which is the same, but simultaneously exists in two
|
||||
eggs, and may hatch from either, although, I'm not sure what kind of a mess will
|
||||
this really cause.
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*getitembound <item id>,<amount>,<bound_type>{,<account ID>};
|
||||
*getitembound "<item name>",<amount>,<bound_type>{,<account ID>};
|
||||
|
||||
This command will give an amount of specified items to the invoking character.
|
||||
If an optional account ID is specified, and the target character is currently
|
||||
online, items will be created in their inventory instead. If they are not
|
||||
online, nothing will happen.
|
||||
|
||||
It works essentially the same as 'getitem', except that items created using
|
||||
this command will bound the item to the player's account. Depending on the bound type issued,
|
||||
the character may not be able to trade or store these items, however all bounded types
|
||||
cannot be sold, vended, auctioned, or mailed.
|
||||
|
||||
Bound Types:
|
||||
1 - Account Bound
|
||||
2 - Guild Bound
|
||||
3 - Party Bound
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*getitembound2 <item id>,<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound_type>{,<account ID>};
|
||||
*getitembound2 "<item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>,<bound_type>{,<account ID>};
|
||||
|
||||
This command will give an amount of specified items to the invoking character.
|
||||
If an optional account ID is specified, and the target character is currently
|
||||
online, items will be created in their inventory instead. If they are not
|
||||
online, nothing will happen.
|
||||
|
||||
It works essentially the same as 'getitem2', except that items created using
|
||||
this command will bound the item to the player's account. Depending on the bound type issued,
|
||||
the character may not be able to trade or store these items, however all bounded types
|
||||
cannot be sold, vended, auctioned, or mailed.
|
||||
|
||||
Bound Types:
|
||||
1 - Account Bound
|
||||
2 - Guild Bound
|
||||
3 - Party Bound
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*getnameditem <item id>,<character name|character ID>;
|
||||
@ -4389,6 +4430,30 @@ Check 'getitem2' to understand the arguments of the function.
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*countbound({<bound_type>})
|
||||
|
||||
This function will return a number of bounded items on the character.
|
||||
Optionally, you may count a specific type of bounded item on the character.
|
||||
|
||||
countbound will also build an array of items in the form of @bound_items.
|
||||
Using countbound without a type counts all types of bounded items.
|
||||
|
||||
Available types are:
|
||||
1 - Account Bound
|
||||
2 - Guild Bound
|
||||
3 - Party Bound
|
||||
|
||||
Example:
|
||||
mes "[Bound Counter]";
|
||||
mes "I see you currently have "+countbound+" bounded items.";
|
||||
next;
|
||||
mes "The list of bounded items include:";
|
||||
for(.@i = 0; .@i<getarraysize(@bound_items); .@i++)
|
||||
mes getitemname(@bound_items[.@i]);
|
||||
close;
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*groupranditem <group id>;
|
||||
|
||||
Returns the item_id of a random item picked from the group specified. The
|
||||
|
@ -43,6 +43,7 @@ CREATE TABLE IF NOT EXISTS `cart_inventory` (
|
||||
`card2` smallint(11) NOT NULL default '0',
|
||||
`card3` smallint(11) NOT NULL default '0',
|
||||
`expire_time` int(11) unsigned NOT NULL default '0',
|
||||
`bound` tinyint(3) unsigned NOT NULL default '0',
|
||||
`unique_id` bigint(20) unsigned NOT NULL default '0',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `char_id` (`char_id`)
|
||||
@ -340,6 +341,7 @@ CREATE TABLE IF NOT EXISTS `guild_storage` (
|
||||
`card2` smallint(11) NOT NULL default '0',
|
||||
`card3` smallint(11) NOT NULL default '0',
|
||||
`expire_time` int(11) unsigned NOT NULL default '0',
|
||||
`bound` tinyint(3) unsigned NOT NULL default '0',
|
||||
`unique_id` bigint(20) unsigned NOT NULL default '0',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `guild_id` (`guild_id`)
|
||||
@ -404,6 +406,7 @@ CREATE TABLE IF NOT EXISTS `inventory` (
|
||||
`card3` smallint(11) NOT NULL default '0',
|
||||
`expire_time` int(11) unsigned NOT NULL default '0',
|
||||
`favorite` tinyint(3) unsigned NOT NULL default '0',
|
||||
`bound` tinyint(3) unsigned NOT NULL default '0',
|
||||
`unique_id` bigint(20) unsigned NOT NULL default '0',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `char_id` (`char_id`)
|
||||
@ -665,6 +668,7 @@ CREATE TABLE IF NOT EXISTS `storage` (
|
||||
`card2` smallint(11) NOT NULL default '0',
|
||||
`card3` smallint(11) NOT NULL default '0',
|
||||
`expire_time` int(11) unsigned NOT NULL default '0',
|
||||
`bound` tinyint(3) unsigned NOT NULL default '0',
|
||||
`unique_id` bigint(20) unsigned NOT NULL default '0',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `account_id` (`account_id`)
|
||||
|
4
sql-files/upgrades/upgrade_svn17351.sql
Normal file
4
sql-files/upgrades/upgrade_svn17351.sql
Normal file
@ -0,0 +1,4 @@
|
||||
ALTER TABLE `inventory` ADD COLUMN `bound` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0' AFTER `favorite`;
|
||||
ALTER TABLE `cart_inventory` ADD COLUMN `bound` TINYINT(3) UNSIGNED NOT NULL default '0' AFTER `expire_time`;
|
||||
ALTER TABLE `storage` ADD COLUMN `bound` TINYINT(3) UNSIGNED NOT NULL default '0' AFTER `expire_time`;
|
||||
ALTER TABLE `guild_storage` ADD COLUMN `bound` TINYINT(3) UNSIGNED NOT NULL default '0' AFTER `expire_time`;
|
@ -775,7 +775,7 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
|
||||
// it significantly reduces cpu load on the database server.
|
||||
|
||||
StringBuf_Init(&buf);
|
||||
StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`");
|
||||
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 `%s`='%d'", tablename, selectoption, id);
|
||||
@ -798,8 +798,9 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
|
||||
SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 8, SQLDT_UINT, &item.bound, 0, NULL, NULL);
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
SqlStmt_BindColumn(stmt, 8+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
|
||||
|
||||
// bit array indicating which inventory items have already been matched
|
||||
flag = (bool*) aCalloc(max, sizeof(bool));
|
||||
@ -826,14 +827,15 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
|
||||
items[i].identify == item.identify &&
|
||||
items[i].refine == item.refine &&
|
||||
items[i].attribute == item.attribute &&
|
||||
items[i].expire_time == item.expire_time )
|
||||
items[i].expire_time == item.expire_time &&
|
||||
items[i].bound == item.bound )
|
||||
; //Do nothing.
|
||||
else
|
||||
{
|
||||
// update all fields.
|
||||
StringBuf_Clear(&buf);
|
||||
StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u'",
|
||||
tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time);
|
||||
StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `bound`='%d'",
|
||||
tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound);
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]);
|
||||
StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id);
|
||||
@ -861,7 +863,7 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
|
||||
SqlStmt_Free(stmt);
|
||||
|
||||
StringBuf_Clear(&buf);
|
||||
StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `unique_id`", tablename, selectoption);
|
||||
StringBuf_Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`", tablename, selectoption);
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
StringBuf_Printf(&buf, ", `card%d`", j);
|
||||
StringBuf_AppendStr(&buf, ") VALUES ");
|
||||
@ -879,8 +881,8 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
|
||||
else
|
||||
found = true;
|
||||
|
||||
StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%"PRIu64"'",
|
||||
id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].unique_id);
|
||||
StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%"PRIu64"'",
|
||||
id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound, items[i].unique_id);
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
StringBuf_Printf(&buf, ", '%d'", items[i].card[j]);
|
||||
StringBuf_AppendStr(&buf, ")");
|
||||
@ -919,7 +921,7 @@ int inventory_to_sql(const struct item items[], int max, int id) {
|
||||
// it significantly reduces cpu load on the database server.
|
||||
|
||||
StringBuf_Init(&buf);
|
||||
StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`");
|
||||
StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`");
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
StringBuf_Printf(&buf, ", `card%d`", j);
|
||||
StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`='%d'", inventory_db, id);
|
||||
@ -943,8 +945,9 @@ int inventory_to_sql(const struct item items[], int max, int id) {
|
||||
SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &item.favorite, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 9, SQLDT_CHAR, &item.bound, 0, NULL, NULL);
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
SqlStmt_BindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 10+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
|
||||
|
||||
// bit array indicating which inventory items have already been matched
|
||||
flag = (bool*) aCalloc(max, sizeof(bool));
|
||||
@ -970,13 +973,14 @@ int inventory_to_sql(const struct item items[], int max, int id) {
|
||||
items[i].refine == item.refine &&
|
||||
items[i].attribute == item.attribute &&
|
||||
items[i].expire_time == item.expire_time &&
|
||||
items[i].favorite == item.favorite )
|
||||
items[i].favorite == item.favorite &&
|
||||
items[i].bound == item.bound )
|
||||
; //Do nothing.
|
||||
else {
|
||||
// update all fields.
|
||||
StringBuf_Clear(&buf);
|
||||
StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d'",
|
||||
inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite);
|
||||
StringBuf_Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d', `bound`='%d'",
|
||||
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);
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
StringBuf_Printf(&buf, ", `card%d`=%d", j, items[i].card[j]);
|
||||
StringBuf_Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id);
|
||||
@ -1001,7 +1005,7 @@ int inventory_to_sql(const struct item items[], int max, int id) {
|
||||
SqlStmt_Free(stmt);
|
||||
|
||||
StringBuf_Clear(&buf);
|
||||
StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `unique_id`", inventory_db);
|
||||
StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`", inventory_db);
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
StringBuf_Printf(&buf, ", `card%d`", j);
|
||||
StringBuf_AppendStr(&buf, ") VALUES ");
|
||||
@ -1018,8 +1022,8 @@ int inventory_to_sql(const struct item items[], int max, int id) {
|
||||
else
|
||||
found = true;
|
||||
|
||||
StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%"PRIu64"'",
|
||||
id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].unique_id);
|
||||
StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%d', '%"PRIu64"'",
|
||||
id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].bound, items[i].unique_id);
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
StringBuf_Printf(&buf, ", '%d'", items[i].card[j]);
|
||||
StringBuf_AppendStr(&buf, ")");
|
||||
@ -1282,7 +1286,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
|
||||
//read inventory
|
||||
//`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `expire_time`, `favorite`, `unique_id`)
|
||||
StringBuf_Init(&buf);
|
||||
StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `unique_id`");
|
||||
StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`");
|
||||
for( i = 0; i < MAX_SLOTS; ++i )
|
||||
StringBuf_Printf(&buf, ", `card%d`", i);
|
||||
StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY);
|
||||
@ -1299,10 +1303,11 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &tmp_item.favorite, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_ULONGLONG, &tmp_item.unique_id, 0, NULL, NULL) )
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_CHAR, &tmp_item.bound, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt,10, SQLDT_ULONGLONG, &tmp_item.unique_id, 0, NULL, NULL) )
|
||||
SqlStmt_ShowDebug(stmt);
|
||||
for( i = 0; i < MAX_SLOTS; ++i )
|
||||
if( SQL_ERROR == SqlStmt_BindColumn(stmt, 10+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
|
||||
if( SQL_ERROR == SqlStmt_BindColumn(stmt, 11+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
|
||||
SqlStmt_ShowDebug(stmt);
|
||||
|
||||
for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
|
||||
@ -1313,7 +1318,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
|
||||
//read cart
|
||||
//`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, expire_time`, `unique_id`)
|
||||
StringBuf_Clear(&buf);
|
||||
StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `unique_id`");
|
||||
StringBuf_AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`");
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
StringBuf_Printf(&buf, ", `card%d`", j);
|
||||
StringBuf_Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART);
|
||||
@ -1329,10 +1334,11 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_ULONGLONG, &tmp_item.unique_id, 0, NULL, NULL) )
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 8, SQLDT_CHAR, &tmp_item.bound, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 9, SQLDT_ULONGLONG, &tmp_item.unique_id, 0, NULL, NULL) )
|
||||
SqlStmt_ShowDebug(stmt);
|
||||
for( i = 0; i < MAX_SLOTS; ++i )
|
||||
if( SQL_ERROR == SqlStmt_BindColumn(stmt, 9+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
|
||||
if( SQL_ERROR == SqlStmt_BindColumn(stmt, 10+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
|
||||
SqlStmt_ShowDebug(stmt);
|
||||
|
||||
for( i = 0; i < MAX_CART && SQL_SUCCESS == SqlStmt_NextRow(stmt); ++i )
|
||||
@ -2962,7 +2968,7 @@ int parse_frommap(int fd)
|
||||
break;
|
||||
}
|
||||
//Check account only if this ain't final save. Final-save goes through because of the char-map reconnect
|
||||
if (RFIFOB(fd,12) || (
|
||||
if (RFIFOB(fd,12) || RFIFOB(fd,13) || (
|
||||
(character = (struct online_char_data*)idb_get(online_char_db, aid)) != NULL &&
|
||||
character->char_id == cid))
|
||||
{
|
||||
|
@ -63,6 +63,7 @@ static int mail_fromsql(int char_id, struct mail_data* md)
|
||||
Sql_GetData(sql_handle,14, &data, NULL); item->identify = atoi(data);
|
||||
Sql_GetData(sql_handle,15, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
|
||||
item->expire_time = 0;
|
||||
item->bound = 0;
|
||||
|
||||
for (j = 0; j < MAX_SLOTS; j++)
|
||||
{
|
||||
@ -183,6 +184,7 @@ static bool mail_loadmessage(int mail_id, struct mail_message* msg)
|
||||
Sql_GetData(sql_handle,14, &data, NULL); msg->item.identify = atoi(data);
|
||||
Sql_GetData(sql_handle,15, &data, NULL); msg->item.unique_id = strtoull(data, NULL, 10);
|
||||
msg->item.expire_time = 0;
|
||||
msg->item.bound = 0;
|
||||
|
||||
for( j = 0; j < MAX_SLOTS; j++ )
|
||||
{
|
||||
|
@ -38,7 +38,7 @@ int storage_fromsql(int account_id, struct storage_data* p)
|
||||
|
||||
// storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`}
|
||||
StringBuf_Init(&buf);
|
||||
StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`,`unique_id`");
|
||||
StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`,`bound`,`unique_id`");
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
StringBuf_Printf(&buf, ",`card%d`", j);
|
||||
StringBuf_Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id);
|
||||
@ -59,10 +59,11 @@ int storage_fromsql(int account_id, struct storage_data* p)
|
||||
Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data);
|
||||
Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data);
|
||||
Sql_GetData(sql_handle, 7, &data, NULL); item->expire_time = (unsigned int)atoi(data);
|
||||
Sql_GetData(sql_handle, 8, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
|
||||
Sql_GetData(sql_handle, 8, &data, NULL); item->bound = atoi(data);
|
||||
Sql_GetData(sql_handle, 9, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
{
|
||||
Sql_GetData(sql_handle, 9+j, &data, NULL); item->card[j] = atoi(data);
|
||||
Sql_GetData(sql_handle, 10+j, &data, NULL); item->card[j] = atoi(data);
|
||||
}
|
||||
}
|
||||
p->storage_amount = i;
|
||||
@ -95,7 +96,7 @@ int guild_storage_fromsql(int guild_id, struct guild_storage* p)
|
||||
|
||||
// storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`}
|
||||
StringBuf_Init(&buf);
|
||||
StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`unique_id`");
|
||||
StringBuf_AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`bound`,`unique_id`");
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
StringBuf_Printf(&buf, ",`card%d`", j);
|
||||
StringBuf_Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id);
|
||||
@ -115,11 +116,12 @@ int guild_storage_fromsql(int guild_id, struct guild_storage* p)
|
||||
Sql_GetData(sql_handle, 4, &data, NULL); item->identify = atoi(data);
|
||||
Sql_GetData(sql_handle, 5, &data, NULL); item->refine = atoi(data);
|
||||
Sql_GetData(sql_handle, 6, &data, NULL); item->attribute = atoi(data);
|
||||
Sql_GetData(sql_handle, 7, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
|
||||
Sql_GetData(sql_handle, 7, &data, NULL); item->bound = atoi(data);
|
||||
Sql_GetData(sql_handle, 8, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
|
||||
item->expire_time = 0;
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
{
|
||||
Sql_GetData(sql_handle, 8+j, &data, NULL); item->card[j] = atoi(data);
|
||||
Sql_GetData(sql_handle, 9+j, &data, NULL); item->card[j] = atoi(data);
|
||||
}
|
||||
}
|
||||
p->storage_amount = i;
|
||||
@ -158,18 +160,19 @@ int inter_guild_storage_delete(int guild_id)
|
||||
//---------------------------------------------------------
|
||||
// packet from map server
|
||||
|
||||
int mapif_load_guild_storage(int fd,int account_id,int guild_id)
|
||||
int mapif_load_guild_storage(int fd,int account_id,int guild_id, char flag)
|
||||
{
|
||||
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `guild_id` FROM `%s` WHERE `guild_id`='%d'", guild_db, guild_id) )
|
||||
Sql_ShowDebug(sql_handle);
|
||||
else if( Sql_NumRows(sql_handle) > 0 )
|
||||
{// guild exists
|
||||
WFIFOHEAD(fd, sizeof(struct guild_storage)+12);
|
||||
WFIFOHEAD(fd, sizeof(struct guild_storage)+13);
|
||||
WFIFOW(fd,0) = 0x3818;
|
||||
WFIFOW(fd,2) = sizeof(struct guild_storage)+12;
|
||||
WFIFOW(fd,2) = sizeof(struct guild_storage)+13;
|
||||
WFIFOL(fd,4) = account_id;
|
||||
WFIFOL(fd,8) = guild_id;
|
||||
guild_storage_fromsql(guild_id, (struct guild_storage*)WFIFOP(fd,12));
|
||||
WFIFOB(fd,12) = flag; //1 open storage, 0 don't open
|
||||
guild_storage_fromsql(guild_id, (struct guild_storage*)WFIFOP(fd,13));
|
||||
WFIFOSET(fd, WFIFOW(fd,2));
|
||||
return 0;
|
||||
}
|
||||
@ -200,7 +203,7 @@ int mapif_save_guild_storage_ack(int fd,int account_id,int guild_id,int fail)
|
||||
int mapif_parse_LoadGuildStorage(int fd)
|
||||
{
|
||||
RFIFOHEAD(fd);
|
||||
mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6));
|
||||
mapif_load_guild_storage(fd,RFIFOL(fd,2),RFIFOL(fd,6),1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -234,6 +237,126 @@ int mapif_parse_SaveGuildStorage(int fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mapif_itembound_ack(int fd, int aid, int guild_id)
|
||||
{
|
||||
WFIFOHEAD(fd,8);
|
||||
WFIFOW(fd,0) = 0x3856;
|
||||
WFIFOL(fd,2) = aid;
|
||||
WFIFOW(fd,6) = guild_id;
|
||||
WFIFOSET(fd,8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
//Guild bound items pull for offline characters [Akinari]
|
||||
//------------------------------------------------
|
||||
int mapif_parse_itembound_retrieve(int fd)
|
||||
{
|
||||
StringBuf buf;
|
||||
SqlStmt* stmt;
|
||||
struct item item;
|
||||
int j, i=0, s;
|
||||
bool found=false;
|
||||
struct item items[MAX_INVENTORY];
|
||||
int char_id = RFIFOL(fd,2);
|
||||
int aid = RFIFOL(fd,6);
|
||||
int guild_id = RFIFOW(fd,10);
|
||||
|
||||
StringBuf_Init(&buf);
|
||||
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'",inventory_db,char_id);
|
||||
|
||||
stmt = SqlStmt_Malloc(sql_handle);
|
||||
if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
|
||||
|| SQL_ERROR == SqlStmt_Execute(stmt) )
|
||||
{
|
||||
SqlStmt_ShowDebug(stmt);
|
||||
SqlStmt_Free(stmt);
|
||||
StringBuf_Destroy(&buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SqlStmt_BindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL);
|
||||
SqlStmt_BindColumn(stmt, 8, SQLDT_UINT, &item.bound, 0, NULL, NULL);
|
||||
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 == 2) {
|
||||
memcpy(&items[i],&item,sizeof(struct item));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if(!i) //No items found - No need to continue
|
||||
return 0;
|
||||
|
||||
//First we delete the character's items
|
||||
StringBuf_Clear(&buf);
|
||||
StringBuf_Printf(&buf, "DELETE FROM `%s` WHERE",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);
|
||||
}
|
||||
|
||||
stmt = SqlStmt_Malloc(sql_handle);
|
||||
if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
|
||||
|| SQL_ERROR == SqlStmt_Execute(stmt) )
|
||||
{
|
||||
SqlStmt_ShowDebug(stmt);
|
||||
SqlStmt_Free(stmt);
|
||||
StringBuf_Destroy(&buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//Now let's update the guild storage with those deleted items
|
||||
found = false;
|
||||
StringBuf_Clear(&buf);
|
||||
StringBuf_Printf(&buf, "INSERT INTO `%s` (`guild_id`, `nameid`, `amount`, `identify`, `refine`, `attribute`, `expire_time`, `bound`", guild_storage_db);
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
StringBuf_Printf(&buf, ", `card%d`", j);
|
||||
StringBuf_AppendStr(&buf, ") VALUES ");
|
||||
|
||||
for( j = 0; j < i; ++j ) {
|
||||
if( found )
|
||||
StringBuf_AppendStr(&buf, ",");
|
||||
else
|
||||
found = true;
|
||||
|
||||
StringBuf_Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d'",
|
||||
guild_id, items[j].nameid, items[j].amount, 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, ", '%d'", items[j].card[s]);
|
||||
StringBuf_AppendStr(&buf, ")");
|
||||
}
|
||||
|
||||
stmt = SqlStmt_Malloc(sql_handle);
|
||||
if( SQL_ERROR == SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
|
||||
|| SQL_ERROR == SqlStmt_Execute(stmt) )
|
||||
{
|
||||
SqlStmt_ShowDebug(stmt);
|
||||
SqlStmt_Free(stmt);
|
||||
StringBuf_Destroy(&buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//Finally reload storage and tell map we're done
|
||||
mapif_load_guild_storage(fd,aid,guild_id,0);
|
||||
mapif_itembound_ack(fd,aid,guild_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int inter_storage_parse_frommap(int fd)
|
||||
{
|
||||
@ -241,6 +364,7 @@ int inter_storage_parse_frommap(int fd)
|
||||
switch(RFIFOW(fd,0)){
|
||||
case 0x3018: mapif_parse_LoadGuildStorage(fd); break;
|
||||
case 0x3019: mapif_parse_SaveGuildStorage(fd); break;
|
||||
case 0x3056: mapif_parse_itembound_retrieve(fd); break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ int inter_recv_packet_length[] = {
|
||||
-1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, // 3020- Party
|
||||
-1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030-
|
||||
-1, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040-
|
||||
-1,-1,10,10, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus]
|
||||
-1,-1,10,10, 0,-1,12, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus]
|
||||
6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish]
|
||||
-1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, -1,10, 6,-1, // 3070- Mercenary packets [Zephyrus], Elemental packets [pakpil]
|
||||
48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3080-
|
||||
|
@ -204,7 +204,7 @@ struct item {
|
||||
char attribute;
|
||||
short card[MAX_SLOTS];
|
||||
unsigned int expire_time;
|
||||
char favorite;
|
||||
char favorite, bound;
|
||||
uint64 unique_id;
|
||||
};
|
||||
|
||||
|
@ -1112,11 +1112,12 @@ ACMD_FUNC(heal)
|
||||
|
||||
/*==========================================
|
||||
* @item command (usage: @item <name/id_of_item> <quantity>) (modified by [Yor] for pet_egg)
|
||||
* @itembound command (usage: @itembound <name/id_of_item> <quantity> <bound_type>)
|
||||
*------------------------------------------*/
|
||||
ACMD_FUNC(item)
|
||||
{
|
||||
char item_name[100];
|
||||
int number = 0, item_id, flag = 0;
|
||||
int number = 0, item_id, flag = 0, bound = 0;
|
||||
struct item item_tmp;
|
||||
struct item_data *item_data;
|
||||
int get_count, i;
|
||||
@ -1124,7 +1125,13 @@ ACMD_FUNC(item)
|
||||
|
||||
memset(item_name, '\0', sizeof(item_name));
|
||||
|
||||
if (!message || !*message || (
|
||||
if (!strcmpi(command+1,"itembound") && (!message || !*message || (
|
||||
sscanf(message, "\"%99[^\"]\" %d %d", item_name, &number, &bound) < 2 &&
|
||||
sscanf(message, "%99s %d %d", item_name, &number, &bound) < 2
|
||||
))) {
|
||||
clif_displaymessage(fd, msg_txt(sd,295)); // Please enter an item name or ID (usage: @item <item name/ID> <quantity> <bound_type>).
|
||||
return -1;
|
||||
} else if (!message || !*message || (
|
||||
sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 1 &&
|
||||
sscanf(message, "%99s %d", item_name, &number) < 1
|
||||
)) {
|
||||
@ -1142,6 +1149,11 @@ ACMD_FUNC(item)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( bound < 0 || bound > 3 ) {
|
||||
clif_displaymessage(fd, msg_txt(sd,298)); // Invalid bound type
|
||||
return -1;
|
||||
}
|
||||
|
||||
item_id = item_data->nameid;
|
||||
get_count = number;
|
||||
//Check if it's stackable.
|
||||
@ -1154,6 +1166,7 @@ ACMD_FUNC(item)
|
||||
memset(&item_tmp, 0, sizeof(item_tmp));
|
||||
item_tmp.nameid = item_id;
|
||||
item_tmp.identify = 1;
|
||||
item_tmp.bound = bound;
|
||||
|
||||
if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND)))
|
||||
clif_additem(sd, 0, 0, flag);
|
||||
@ -1173,17 +1186,23 @@ ACMD_FUNC(item2)
|
||||
struct item item_tmp;
|
||||
struct item_data *item_data;
|
||||
char item_name[100];
|
||||
int item_id, number = 0;
|
||||
int item_id, number = 0, bound = 0;
|
||||
int identify = 0, refine = 0, attr = 0;
|
||||
int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
|
||||
nullpo_retr(-1, sd);
|
||||
|
||||
memset(item_name, '\0', sizeof(item_name));
|
||||
|
||||
if (!message || !*message || (
|
||||
if (!strcmpi(command+1,"itembound2") && (!message || !*message || (
|
||||
sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 &&
|
||||
sscanf(message, "%99s %d %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 ))) {
|
||||
clif_displaymessage(fd, msg_txt(sd,296)); // Please enter all parameters (usage: @item2 <item name/ID> <quantity>
|
||||
clif_displaymessage(fd, msg_txt(sd,297)); // <identify_flag> <refine> <attribute> <card1> <card2> <card3> <card4> <bound_type>).
|
||||
return -1;
|
||||
} else if ( !message || !*message || (
|
||||
sscanf(message, "\"%99[^\"]\" %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9 &&
|
||||
sscanf(message, "%99s %d %d %d %d %d %d %d %d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9
|
||||
)) {
|
||||
)) {
|
||||
clif_displaymessage(fd, msg_txt(sd,984)); // Please enter all parameters (usage: @item2 <item name/ID> <quantity>
|
||||
clif_displaymessage(fd, msg_txt(sd,985)); // <identify_flag> <refine> <attribute> <card1> <card2> <card3> <card4>).
|
||||
return -1;
|
||||
@ -1192,6 +1211,11 @@ ACMD_FUNC(item2)
|
||||
if (number <= 0)
|
||||
number = 1;
|
||||
|
||||
if( bound < 0 || bound > 3 ) {
|
||||
clif_displaymessage(fd, msg_txt(sd,298)); // Invalid bound type
|
||||
return -1;
|
||||
}
|
||||
|
||||
item_id = 0;
|
||||
if ((item_data = itemdb_searchname(item_name)) != NULL ||
|
||||
(item_data = itemdb_exists(atoi(item_name))) != NULL)
|
||||
@ -1228,6 +1252,7 @@ ACMD_FUNC(item2)
|
||||
item_tmp.card[1] = c2;
|
||||
item_tmp.card[2] = c3;
|
||||
item_tmp.card[3] = c4;
|
||||
item_tmp.bound = bound;
|
||||
if ((flag = pc_additem(sd, &item_tmp, get_count, LOG_TYPE_COMMAND)))
|
||||
clif_additem(sd, 0, 0, flag);
|
||||
}
|
||||
@ -9012,6 +9037,8 @@ void atcommand_basecommands(void) {
|
||||
ACMD_DEF(heal),
|
||||
ACMD_DEF(item),
|
||||
ACMD_DEF(item2),
|
||||
ACMD_DEF2("itembound",item),
|
||||
ACMD_DEF2("itembound2",item2),
|
||||
ACMD_DEF(itemreset),
|
||||
ACMD_DEF(clearstorage),
|
||||
ACMD_DEF(cleargstorage),
|
||||
|
@ -311,7 +311,7 @@ void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int
|
||||
return;
|
||||
}
|
||||
|
||||
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)) )
|
||||
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)) )
|
||||
{// non-tradable item
|
||||
clif_buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, nameid);
|
||||
return;
|
||||
|
@ -1790,8 +1790,11 @@ void clif_selllist(struct map_session_data *sd)
|
||||
if( !itemdb_cansell(&sd->status.inventory[i], pc_get_group_level(sd)) )
|
||||
continue;
|
||||
|
||||
if( sd->status.inventory[i].expire_time )
|
||||
continue; // Cannot Sell Rental Items
|
||||
if( sd->status.inventory[i].expire_time || (sd->status.inventory[i].bound && !pc_can_give_bounded_items(sd)) )
|
||||
continue; // Cannot Sell Rental Items or Account Bounded Items
|
||||
|
||||
if( sd->status.inventory[i].bound && !pc_can_give_bounded_items(sd))
|
||||
continue; // Don't allow sale of bound items
|
||||
|
||||
val=sd->inventory_data[i]->value_sell;
|
||||
if( val < 0 )
|
||||
@ -2194,7 +2197,7 @@ void clif_additem(struct map_session_data *sd, int n, int amount, int fail)
|
||||
WFIFOL(fd,offs+23)=sd->status.inventory[n].expire_time;
|
||||
#endif
|
||||
#if PACKETVER >= 20071002
|
||||
WFIFOW(fd,offs+27)=0; // HireExpireDate
|
||||
WFIFOW(fd,offs+27)=sd->status.inventory[n].bound ? 2 : 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -2300,7 +2303,7 @@ void clif_item_sub(unsigned char *buf, int n, int idx, struct item *i, struct it
|
||||
clif_addcards(WBUFP(buf, n+12), i); //8B
|
||||
#if PACKETVER >= 20071002
|
||||
WBUFL(buf,n+20)=i->expire_time;
|
||||
WBUFW(buf,n+24)=0; //Unknown
|
||||
WBUFW(buf,n+24)=i->bound ? 2 : 0;
|
||||
#endif
|
||||
#if PACKETVER >= 20100629
|
||||
WBUFW(buf,n+26)= (id->equip&EQP_VISIBLE)?id->look:0;
|
||||
@ -14199,6 +14202,11 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd)
|
||||
}
|
||||
|
||||
// Auction checks...
|
||||
if( sd->status.inventory[sd->auction.index].bound && !pc_can_give_bounded_items(sd) ) {
|
||||
clif_displaymessage(sd->fd, msg_txt(sd,293));
|
||||
clif_Auction_message(fd, 2); // The auction has been canceled
|
||||
return;
|
||||
}
|
||||
if( sd->status.zeny < (auction.hours * battle_config.auction_feeperhour) ) {
|
||||
clif_Auction_message(fd, 5); // You do not have enough zeny to pay the Auction Fee.
|
||||
return;
|
||||
|
@ -106,6 +106,7 @@ void guild_flag_remove(struct npc_data *nd);
|
||||
void guild_flags_clear(void);
|
||||
|
||||
void guild_guildaura_refresh(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv);
|
||||
void guild_retrieveitembound(int char_id,int aid,int guild_id);
|
||||
|
||||
void do_final_guild(void);
|
||||
|
||||
|
@ -39,7 +39,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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3850 Auctions [Zephyrus]
|
||||
-1,-1, 7, 7, 7,11, 8, 0, 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]
|
||||
11,-1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3880
|
||||
@ -1002,15 +1002,19 @@ int intif_parse_LoadGuildStorage(int fd)
|
||||
{
|
||||
struct guild_storage *gstor;
|
||||
struct map_session_data *sd;
|
||||
int guild_id;
|
||||
int guild_id, flag;
|
||||
|
||||
guild_id = RFIFOL(fd,8);
|
||||
flag = RFIFOL(fd,12);
|
||||
if(guild_id <= 0)
|
||||
return 1;
|
||||
|
||||
sd=map_id2sd( RFIFOL(fd,4) );
|
||||
if(sd==NULL){
|
||||
ShowError("intif_parse_LoadGuildStorage: user not found %d\n",RFIFOL(fd,4));
|
||||
return 1;
|
||||
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));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
gstor=guild2storage(guild_id);
|
||||
if(!gstor) {
|
||||
@ -1018,21 +1022,23 @@ int intif_parse_LoadGuildStorage(int fd)
|
||||
return 1;
|
||||
}
|
||||
if (gstor->storage_status == 1) { // Already open.. lets ignore this update
|
||||
ShowWarning("intif_parse_LoadGuildStorage: storage received for a client already open (User %d:%d)\n", sd->status.account_id, sd->status.char_id);
|
||||
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 1;
|
||||
}
|
||||
if (gstor->dirty) { // Already have storage, and it has been modified and not saved yet! Exploit! [Skotlex]
|
||||
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);
|
||||
ShowWarning("intif_parse_LoadGuildStorage: received storage for an already modified non-saved storage! (User %d:%d)\n", flag?sd->status.account_id:1, flag?sd->status.char_id:1);
|
||||
return 1;
|
||||
}
|
||||
if( RFIFOW(fd,2)-12 != sizeof(struct guild_storage) ){
|
||||
ShowError("intif_parse_LoadGuildStorage: data size error %d %d\n",RFIFOW(fd,2)-12 , sizeof(struct guild_storage));
|
||||
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;
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(gstor,RFIFOP(fd,12),sizeof(struct guild_storage));
|
||||
storage_guild_storageopen(sd);
|
||||
memcpy(gstor,RFIFOP(fd,13),sizeof(struct guild_storage));
|
||||
if( flag )
|
||||
storage_guild_storageopen(sd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2152,6 +2158,31 @@ void intif_parse_MessageToFD(int fd) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
* Item Bound System
|
||||
*------------------------------------------*/
|
||||
|
||||
void intif_itembound_req(int char_id,int aid,int guild_id) {
|
||||
struct guild_storage *gstor = guild2storage2(guild_id);
|
||||
WFIFOHEAD(inter_fd,12);
|
||||
WFIFOW(inter_fd,0) = 0x3056;
|
||||
WFIFOL(inter_fd,2) = char_id;
|
||||
WFIFOL(inter_fd,6) = aid;
|
||||
WFIFOW(inter_fd,10) = guild_id;
|
||||
WFIFOSET(inter_fd,12);
|
||||
if(gstor)
|
||||
gstor->lock = 1; //Lock for retrieval process
|
||||
}
|
||||
|
||||
//3856
|
||||
void intif_parse_itembound_ack(int fd) {
|
||||
struct guild_storage *gstor;
|
||||
int guild_id = RFIFOW(char_fd,6);
|
||||
|
||||
gstor = guild2storage2(guild_id);
|
||||
if(gstor) gstor->lock = 0; //Unlock now that operation is completed
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
// Communication from the inter server
|
||||
// Return a 0 (false) if there were any errors.
|
||||
@ -2235,6 +2266,9 @@ int intif_parse(int fd)
|
||||
case 0x3854: intif_parse_Auction_message(fd); break;
|
||||
case 0x3855: intif_parse_Auction_bid(fd); break;
|
||||
|
||||
//Bound items
|
||||
case 0x3856: intif_parse_itembound_ack(fd); break;
|
||||
|
||||
// Mercenary System
|
||||
case 0x3870: intif_parse_mercenary_received(fd); break;
|
||||
case 0x3871: intif_parse_mercenary_deleted(fd); break;
|
||||
|
@ -60,6 +60,7 @@ int intif_guild_notice(int guild_id, const char *mes1, const char *mes2);
|
||||
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);
|
||||
void intif_itembound_req(int char_id, int aid, int guild_id);
|
||||
|
||||
int intif_create_pet(int account_id, int char_id, short pet_type, short pet_lv, short pet_egg_id,
|
||||
short pet_equip, short intimate, short hungry, char rename_flag, char incuvate, char *pet_name);
|
||||
|
@ -78,8 +78,9 @@ unsigned char mail_setitem(struct map_session_data *sd, int idx, int amount) {
|
||||
return 1;
|
||||
if( amount < 0 || amount > sd->status.inventory[idx].amount )
|
||||
return 1;
|
||||
if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time ||
|
||||
!itemdb_canmail(&sd->status.inventory[idx],pc_get_group_level(sd)) )
|
||||
if( !pc_can_give_items(sd) || sd->status.inventory[idx].expire_time
|
||||
|| !itemdb_canmail(&sd->status.inventory[idx],pc_get_group_level(sd))
|
||||
|| (sd->status.inventory[idx].bound && !pc_can_give_bounded_items(sd)) )
|
||||
return 1;
|
||||
|
||||
sd->mail.index = idx;
|
||||
|
@ -552,12 +552,10 @@ int party_member_withdraw(int party_id, int account_id, int char_id)
|
||||
struct map_session_data* sd = map_id2sd(account_id);
|
||||
struct party_data* p = party_search(party_id);
|
||||
|
||||
if( p )
|
||||
{
|
||||
if( p ) {
|
||||
int i;
|
||||
ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == account_id && p->party.member[i].char_id == char_id );
|
||||
if( i < MAX_PARTY )
|
||||
{
|
||||
if( i < MAX_PARTY ) {
|
||||
clif_party_withdraw(p,sd,account_id,p->party.member[i].name,0x0);
|
||||
memset(&p->party.member[i], 0, sizeof(p->party.member[0]));
|
||||
memset(&p->data[i], 0, sizeof(p->data[0]));
|
||||
@ -566,8 +564,12 @@ int party_member_withdraw(int party_id, int account_id, int char_id)
|
||||
}
|
||||
}
|
||||
|
||||
if( sd && sd->status.party_id == party_id && sd->status.char_id == char_id )
|
||||
{
|
||||
if( sd && sd->status.party_id == party_id && sd->status.char_id == char_id ) {
|
||||
int idxlist[MAX_INVENTORY]; //or malloc to reduce consumtion
|
||||
int j,i;
|
||||
j = pc_bound_chk(sd,3,idxlist);
|
||||
for(i=0;i<j;i++)
|
||||
pc_delitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_OTHER);
|
||||
sd->status.party_id = 0;
|
||||
clif_charnameupdate(sd); //Update name display [Skotlex]
|
||||
//TODO: hp bars should be cleared too
|
||||
|
44
src/map/pc.c
44
src/map/pc.c
@ -509,6 +509,14 @@ bool pc_can_give_items(struct map_session_data *sd)
|
||||
return pc_has_permission(sd, PC_PERM_TRADE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if player can give / drop / trade / vend bounded items
|
||||
*/
|
||||
bool pc_can_give_bounded_items(struct map_session_data *sd)
|
||||
{
|
||||
return pc_has_permission(sd, PC_PERM_TRADE_BOUNDED);
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
* prepares character for saving.
|
||||
*------------------------------------------*/
|
||||
@ -914,7 +922,8 @@ int pc_isequip(struct map_session_data *sd,int n)
|
||||
*------------------------------------------*/
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
int i, j;
|
||||
int idxlist[MAX_INVENTORY];
|
||||
unsigned long tick = gettick();
|
||||
uint32 ip = session[sd->fd]->client_addr;
|
||||
|
||||
@ -1091,6 +1100,12 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
|
||||
**/
|
||||
pc_itemcd_do(sd,true);
|
||||
|
||||
// Party bound item check
|
||||
if(sd->status.party_id == 0 && (j = pc_bound_chk(sd,3,idxlist))) { // Party was deleted while character offline
|
||||
for(i=0;i<j;i++)
|
||||
pc_delitem(sd,idxlist[i],sd->status.inventory[idxlist[i]].amount,0,1,LOG_TYPE_OTHER);
|
||||
}
|
||||
|
||||
// Request all registries (auth is considered completed whence they arrive)
|
||||
intif_request_registry(sd,7);
|
||||
return true;
|
||||
@ -3878,7 +3893,7 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l
|
||||
{ // Stackable | Non Rental
|
||||
for( i = 0; i < MAX_INVENTORY; i++ )
|
||||
{
|
||||
if( sd->status.inventory[i].nameid == item_data->nameid && memcmp(&sd->status.inventory[i].card, &item_data->card, sizeof(item_data->card)) == 0 )
|
||||
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 )
|
||||
{
|
||||
if( amount > MAX_AMOUNT - sd->status.inventory[i].amount || ( data->stack.inventory && amount > data->stack.amount - sd->status.inventory[i].amount ) )
|
||||
return 5;
|
||||
@ -4418,7 +4433,7 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun
|
||||
return 1;
|
||||
}
|
||||
|
||||
if( !itemdb_cancartstore(item_data, pc_get_group_level(sd)) )
|
||||
if( !itemdb_cancartstore(item_data, pc_get_group_level(sd)) || ((item_data->bound == 2 || item_data->bound == 3) && !pc_can_give_bounded_items(sd)))
|
||||
{ // Check item trade restrictions [Skotlex]
|
||||
clif_displaymessage (sd->fd, msg_txt(sd,264));
|
||||
return 1;
|
||||
@ -4431,7 +4446,7 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun
|
||||
if( itemdb_isstackable2(data) && !item_data->expire_time )
|
||||
{
|
||||
ARR_FIND( 0, MAX_CART, i,
|
||||
sd->status.cart[i].nameid == item_data->nameid &&
|
||||
sd->status.cart[i].nameid == item_data->nameid && sd->status.cart[i].bound == item_data->bound &&
|
||||
sd->status.cart[i].card[0] == item_data->card[0] && sd->status.cart[i].card[1] == item_data->card[1] &&
|
||||
sd->status.cart[i].card[2] == item_data->card[2] && sd->status.cart[i].card[3] == item_data->card[3] );
|
||||
};
|
||||
@ -4566,6 +4581,25 @@ int pc_getitemfromcart(struct map_session_data *sd,int idx,int amount)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
* Bound Item Check
|
||||
* Type:
|
||||
* 1 Account Bound
|
||||
* 2 Guild Bound
|
||||
* 3 Party Bound
|
||||
*------------------------------------------*/
|
||||
int pc_bound_chk(TBL_PC *sd,int type,int *idxlist)
|
||||
{
|
||||
int i=0, j=0;
|
||||
for(i=0;i<MAX_INVENTORY;i++){
|
||||
if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0 && sd->status.inventory[i].bound == type) {
|
||||
idxlist[j] = i;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
* Display item stolen msg to player sd
|
||||
*------------------------------------------*/
|
||||
@ -7880,7 +7914,7 @@ int pc_setmadogear(TBL_PC* sd, int flag)
|
||||
*------------------------------------------*/
|
||||
int pc_candrop(struct map_session_data *sd, struct item *item)
|
||||
{
|
||||
if( item && item->expire_time )
|
||||
if( item && (item->expire_time || (item->bound && !pc_can_give_bounded_items(sd))) )
|
||||
return 0;
|
||||
if( !pc_can_give_items(sd) ) //check if this GM level can drop items
|
||||
return 0;
|
||||
|
@ -705,6 +705,7 @@ int pc_get_group_level(struct map_session_data *sd);
|
||||
int pc_get_group_id(struct map_session_data *sd);
|
||||
int pc_getrefinebonus(int lv,int type);
|
||||
bool pc_can_give_items(struct map_session_data *sd);
|
||||
bool pc_can_give_bounded_items(struct map_session_data *sd);
|
||||
|
||||
bool pc_can_use_command(struct map_session_data *sd, const char *command, AtCommandType type);
|
||||
#define pc_has_permission(sd, permission) ( ((sd)->permissions&permission) != 0 )
|
||||
@ -748,6 +749,9 @@ int pc_additem(struct map_session_data*,struct item*,int,e_log_pick_type);
|
||||
int pc_getzeny(struct map_session_data*,int, enum e_log_pick_type, struct map_session_data*);
|
||||
int pc_delitem(struct map_session_data*,int,int,int,short,e_log_pick_type);
|
||||
|
||||
//Bound items
|
||||
int pc_bound_chk(TBL_PC *sd,int type,int *idxlist);
|
||||
|
||||
// Special Shop System
|
||||
int pc_paycash( struct map_session_data *sd, int price, int points, e_log_pick_type type );
|
||||
int pc_getcash( struct map_session_data *sd, int cash, int points, e_log_pick_type type );
|
||||
|
@ -44,6 +44,7 @@ enum e_pc_permission {
|
||||
PC_PERM_DISABLE_PVP = 0x080000,
|
||||
PC_PERM_DISABLE_CMD_DEAD = 0x100000,
|
||||
PC_PERM_CHANNEL_ADMIN = 0x200000,
|
||||
PC_PERM_TRADE_BOUNDED = 0x400000,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
@ -72,6 +73,7 @@ static const struct {
|
||||
{ "disable_pvp", PC_PERM_DISABLE_PVP },
|
||||
{ "disable_commands_when_dead", PC_PERM_DISABLE_CMD_DEAD },
|
||||
{ "channel_admin", PC_PERM_CHANNEL_ADMIN },
|
||||
{ "can_trade_bounded", PC_PERM_TRADE_BOUNDED },
|
||||
};
|
||||
|
||||
#endif // _PC_GROUPS_H_
|
||||
|
@ -6270,6 +6270,13 @@ BUILDIN_FUNC(checkweight2){
|
||||
/*==========================================
|
||||
* getitem <item id>,<amount>{,<account ID>};
|
||||
* getitem "<item name>",<amount>{,<account ID>};
|
||||
*
|
||||
* getitembound <item id>,<amount>,<type>{,<account ID>};
|
||||
* getitembound "<item id>",<amount>,<type>{,<account ID>};
|
||||
* Type:
|
||||
* 1 - Account Bound
|
||||
* 2 - Guild Bound
|
||||
* 3 - Party Bound
|
||||
*------------------------------------------*/
|
||||
BUILDIN_FUNC(getitem)
|
||||
{
|
||||
@ -6280,8 +6287,7 @@ BUILDIN_FUNC(getitem)
|
||||
|
||||
data=script_getdata(st,2);
|
||||
get_val(st,data);
|
||||
if( data_isstring(data) )
|
||||
{// "<item name>"
|
||||
if( data_isstring(data) ) {// "<item name>"
|
||||
const char *name=conv_str(st,data);
|
||||
struct item_data *item_data = itemdb_searchname(name);
|
||||
if( item_data == NULL ){
|
||||
@ -6289,8 +6295,7 @@ BUILDIN_FUNC(getitem)
|
||||
return 1; //No item created.
|
||||
}
|
||||
nameid=item_data->nameid;
|
||||
} else if( data_isint(data) )
|
||||
{// <item id>
|
||||
} else if( data_isint(data) ) {// <item id>
|
||||
nameid=conv_num(st,data);
|
||||
//Violet Box, Blue Box, etc - random item pick
|
||||
if( nameid < 0 ) {
|
||||
@ -6317,7 +6322,18 @@ BUILDIN_FUNC(getitem)
|
||||
else
|
||||
it.identify=itemdb_isidentified(nameid);
|
||||
|
||||
if( script_hasdata(st,4) )
|
||||
if( !strcmp(script_getfuncname(st),"getitembound") ) {
|
||||
char bound = script_getnum(st,4);
|
||||
if( bound < 1 || bound > 3) { //Not a correct bound type
|
||||
ShowError("script_getitembound: Not a correct bound type! Type=%d\n",bound);
|
||||
return 1;
|
||||
}
|
||||
it.bound = bound;
|
||||
if( script_hasdata(st,5) )
|
||||
sd=map_id2sd(script_getnum(st,5));
|
||||
else
|
||||
sd=script_rid2sd(st); // Attached player
|
||||
} else if( script_hasdata(st,4) )
|
||||
sd=map_id2sd(script_getnum(st,4)); // <Account ID>
|
||||
else
|
||||
sd=script_rid2sd(st); // Attached player
|
||||
@ -6355,12 +6371,23 @@ BUILDIN_FUNC(getitem2)
|
||||
{
|
||||
int nameid,amount,get_count,i,flag = 0;
|
||||
int iden,ref,attr,c1,c2,c3,c4;
|
||||
char bound=0;
|
||||
struct item_data *item_data;
|
||||
struct item item_tmp;
|
||||
TBL_PC *sd;
|
||||
struct script_data *data;
|
||||
|
||||
if( script_hasdata(st,11) )
|
||||
if( !strcmp(script_getfuncname(st),"getitembound2") ) {
|
||||
bound = script_getnum(st,11);
|
||||
if( bound < 1 || bound > 3) { //Not a correct bound type
|
||||
ShowError("script_getitembound2: Not a correct bound type! Type=%d\n",bound);
|
||||
return 1;
|
||||
}
|
||||
if( script_hasdata(st,12) )
|
||||
sd=map_id2sd(script_getnum(st,12));
|
||||
else
|
||||
sd=script_rid2sd(st); // Attached player
|
||||
} else if( script_hasdata(st,11) )
|
||||
sd=map_id2sd(script_getnum(st,11)); // <Account ID>
|
||||
else
|
||||
sd=script_rid2sd(st); // Attached player
|
||||
@ -6370,14 +6397,14 @@ BUILDIN_FUNC(getitem2)
|
||||
|
||||
data=script_getdata(st,2);
|
||||
get_val(st,data);
|
||||
if( data_isstring(data) ){
|
||||
if( data_isstring(data) ) {
|
||||
const char *name=conv_str(st,data);
|
||||
struct item_data *item_data = itemdb_searchname(name);
|
||||
if( item_data )
|
||||
nameid=item_data->nameid;
|
||||
else
|
||||
nameid=UNKNOWN_ITEM_ID;
|
||||
}else
|
||||
} else
|
||||
nameid=conv_num(st,data);
|
||||
|
||||
amount=script_getnum(st,3);
|
||||
@ -6422,6 +6449,7 @@ BUILDIN_FUNC(getitem2)
|
||||
item_tmp.card[1]=(short)c2;
|
||||
item_tmp.card[2]=(short)c3;
|
||||
item_tmp.card[3]=(short)c4;
|
||||
item_tmp.bound=bound;
|
||||
|
||||
//Check if it's stackable.
|
||||
if (!itemdb_isstackable(nameid))
|
||||
@ -6496,6 +6524,7 @@ BUILDIN_FUNC(rentitem)
|
||||
it.nameid = nameid;
|
||||
it.identify = 1;
|
||||
it.expire_time = (unsigned int)(time(NULL) + seconds);
|
||||
it.bound = 0;
|
||||
|
||||
if( (flag = pc_additem(sd, &it, 1, LOG_TYPE_SCRIPT)) )
|
||||
{
|
||||
@ -11371,6 +11400,7 @@ BUILDIN_FUNC(successremovecards) {
|
||||
item_tmp.refine = sd->status.inventory[i].refine;
|
||||
item_tmp.attribute = sd->status.inventory[i].attribute;
|
||||
item_tmp.expire_time = sd->status.inventory[i].expire_time;
|
||||
item_tmp.bound = sd->status.inventory[i].bound;
|
||||
|
||||
for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++)
|
||||
item_tmp.card[j]=sd->status.inventory[i].card[j];
|
||||
@ -11444,6 +11474,7 @@ BUILDIN_FUNC(failedremovecards) {
|
||||
item_tmp.refine = sd->status.inventory[i].refine;
|
||||
item_tmp.attribute = sd->status.inventory[i].attribute;
|
||||
item_tmp.expire_time = sd->status.inventory[i].expire_time;
|
||||
item_tmp.bound = sd->status.inventory[i].bound;
|
||||
|
||||
for (j = sd->inventory_data[i]->slot; j < MAX_SLOTS; j++)
|
||||
item_tmp.card[j]=sd->status.inventory[i].card[j];
|
||||
@ -12107,6 +12138,7 @@ BUILDIN_FUNC(getinventorylist)
|
||||
pc_setreg(sd,reference_uid(add_str(card_var), j),sd->status.inventory[i].card[k]);
|
||||
}
|
||||
pc_setreg(sd,reference_uid(add_str("@inventorylist_expire"), j),sd->status.inventory[i].expire_time);
|
||||
pc_setreg(sd,reference_uid(add_str("@inventorylist_bound"), j),sd->status.inventory[i].bound);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
@ -17660,6 +17692,40 @@ BUILDIN_FUNC(sit)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
* countbound {<type>};
|
||||
* Creates an array of bounded item IDs
|
||||
* Returns amount of items found
|
||||
* Type:
|
||||
* 1 - Account Bound
|
||||
* 2 - Guild Bound
|
||||
* 3 - Party Bound
|
||||
*------------------------------------------*/
|
||||
BUILDIN_FUNC(countbound)
|
||||
{
|
||||
int i, type, j=0, k=0;
|
||||
TBL_PC *sd;
|
||||
|
||||
if( (sd = script_rid2sd(st)) == NULL )
|
||||
return 0;
|
||||
|
||||
type = script_hasdata(st,2)?script_getnum(st,2):0;
|
||||
|
||||
for(i=0;i<MAX_INVENTORY;i++){
|
||||
if(sd->status.inventory[i].nameid > 0 && (
|
||||
(!type && sd->status.inventory[i].bound > 0) ||
|
||||
(type && sd->status.inventory[i].bound == type)
|
||||
)) {
|
||||
pc_setreg(sd,reference_uid(add_str("@bound_items"), k),sd->status.inventory[i].nameid);
|
||||
k++;
|
||||
j += sd->status.inventory[i].amount;
|
||||
}
|
||||
}
|
||||
|
||||
script_pushint(st,j);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// declarations that were supposed to be exported from npc_chat.c
|
||||
#ifdef PCRE_SUPPORT
|
||||
BUILDIN_FUNC(defpattern);
|
||||
@ -18125,5 +18191,10 @@ struct script_function buildin_func[] = {
|
||||
BUILDIN_DEF(checkquest, "i?"),
|
||||
BUILDIN_DEF(changequest, "ii"),
|
||||
BUILDIN_DEF(showevent, "ii"),
|
||||
|
||||
//Bound items [Xantara] & [Akinari]
|
||||
BUILDIN_DEF2(getitem,"getitembound","vii?"),
|
||||
BUILDIN_DEF2(getitem2,"getitembound2","viiiiiiiii?"),
|
||||
BUILDIN_DEF(countbound, "?"),
|
||||
{NULL,NULL,NULL},
|
||||
};
|
||||
|
@ -120,7 +120,8 @@ int compare_item(struct item *a, struct item *b)
|
||||
a->identify == b->identify &&
|
||||
a->refine == b->refine &&
|
||||
a->attribute == b->attribute &&
|
||||
a->expire_time == b->expire_time )
|
||||
a->expire_time == b->expire_time &&
|
||||
a->bound == b->bound )
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_SLOTS && (a->card[i] == b->card[i]); i++);
|
||||
@ -154,6 +155,11 @@ static int storage_additem(struct map_session_data* sd, struct item* item_data,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if( (item_data->bound == 2 || item_data->bound == 3) && !pc_can_give_bounded_items(sd) ) {
|
||||
clif_displaymessage(sd->fd, msg_txt(sd,294));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if( itemdb_isstackable2(data) )
|
||||
{//Stackable
|
||||
for( i = 0; i < MAX_STORAGE; i++ )
|
||||
@ -448,6 +454,11 @@ int guild_storage_additem(struct map_session_data* sd, struct guild_storage* sto
|
||||
return 1;
|
||||
}
|
||||
|
||||
if( (item_data->bound == 1 || item_data->bound == 3) && !pc_can_give_bounded_items(sd) ) {
|
||||
clif_displaymessage(sd->fd, msg_txt(sd,294));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(itemdb_isstackable2(data)){ //Stackable
|
||||
for(i=0;i<MAX_GUILD_STORAGE;i++){
|
||||
if(compare_item(&stor->items[i], item_data)) {
|
||||
|
@ -368,6 +368,12 @@ void trade_tradeadditem(struct map_session_data *sd, short index, short amount)
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
clif_displaymessage(sd->fd, msg_txt(sd,293));
|
||||
clif_tradeitemok(sd, index+2, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
//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
|
||||
|
@ -267,6 +267,7 @@ void vending_openvending(struct map_session_data* sd, const char* message, const
|
||||
|| !sd->status.cart[index].identify // unidentified item
|
||||
|| sd->status.cart[index].attribute == 1 // broken item
|
||||
|| sd->status.cart[index].expire_time // It should not be in the cart but just in case
|
||||
|| (sd->status.cart[index].bound && !pc_can_give_bounded_items(sd)) // can't trade account bound items and has no permission
|
||||
|| !itemdb_cantrade(&sd->status.cart[index], pc_get_group_level(sd), pc_get_group_level(sd)) ) // untradeable item
|
||||
continue;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user