* Item GUID Updates:

* Removed `ENABLE_ITEM_GUID` from src/config/core.h, after long time introduction it's worth to be enabled by default. Just remove all items with GUID flag if want to remove it generates GUID .
  * Implemented client interface to merge the items. Packet struct credits: 856b6f1feb
  * Edited `mergeitem` script command to use the interface, moved the 'old' `mergeitem` to `mergeitem2`.
  * Fixed the behavior to add GUID'd item to inventory in Cash Shop.
  * Updated item_flag.txt for listing `IT_CASH` items (item type 18).
  * NOTE: `IT_CASH` items which defined in item_flag.txt with flag `4`, cannot be merged.
  * NOTE: Please check the packets for older clients. Tested work on 2012-04-10, 2013-08-07 and 2014-10-22.
  * NOTE: Please import 'upgrade_20150804.sql' for MySQL Log Database.
* Removed duplicate clif functions:
  * `clif_msgtable()` -> `clif_msg()`
  * `clif_msgtable_num()` -> `clif_msg_value()`
* Item DB Updates:
  * Indonesia_Box2 (17079) should gives 5x Wing_Of_Butterfly (602).
  * Changed some item types to 18.

Signed-off-by: Cydh Ramdh <cydh@pservero.com>
This commit is contained in:
Cydh Ramdh 2015-08-04 20:57:49 +07:00
parent 031c522c8a
commit e1b658e462
19 changed files with 1398 additions and 129 deletions

View File

@ -1776,6 +1776,11 @@ packet_keys: 0x01581359,0x452D6FFA,0x6AFB6E2E // [Shakto]
0x0916,26,guildinvite2,2
0x091d,41,bookingregreq,2:4:6
0x08cb,10,ZC_PERSONAL_INFOMATION,2:4:6:8:10:11:13:15 //Still need further information
// Merge Item
0x096D,-1,ZC_MERGE_ITEM_OPEN,2:4 // ZC_MERGE_ITEM_OPEN
0x096E,-1,mergeitem_req,2:4 // CZ_REQ_MERGE_ITEM
0x096F,7,ZC_ACK_MERGE_ITEM,2:4:6:7 // ZC_ACK_MERGE_ITEM
0x0974,2,mergeitem_cancel,0 // CZ_CANCEL_MERGE_ITEM
//2012-04-18aRagexeRE [Special Thanks to Judas!]
packet_ver: 31
@ -2273,6 +2278,11 @@ packet_keys: 0x7E241DE0,0x5E805580,0x3D807D80 // [Shakto]
0x0361,5,hommenu,2:4
0x0887,36,storagepassword,2:4:20
0x09C1,10,ZC_C_MARKERINFO,2:6:8
// Merge Item
0x096D,-1,ZC_MERGE_ITEM_OPEN,2:4 // ZC_MERGE_ITEM_OPEN
0x096E,-1,mergeitem_req,2:4 // CZ_REQ_MERGE_ITEM
0x096F,7,ZC_ACK_MERGE_ITEM,2:4:6:7 // ZC_ACK_MERGE_ITEM
0x0974,2,mergeitem_cancel,0 // CZ_CANCEL_MERGE_ITEM
//2013-12-23Ragexe
packet_ver: 46

View File

@ -4,7 +4,7 @@
// <Flag>:
// 1 - As Dead Branch item (will be logged at `branchlog` table and cannot be used at 'nobranch' mapflag)
// 2 - As item group container, check player's inventory and weight before consumed
// 4 - GUID item, cannot be stacked even same or stackable item
// 4 - GUID Item: When this item is obtained, will generates GUID that cannot be stacked even same or stackable item
// 8 - Item will be bound item when equipped
// NOTE: For removing flag by import file, use "-" to remove the flag. Example, 604,-1 will removes flag 1 from Branch_Of_Dead_Tree

View File

@ -8782,29 +8782,36 @@
17076,Empty_Bottle_Box500,Empty Bottle Box500,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 713,500; },{},{}
17077,Taurus_Crown_Scroll,Taurus Crown Scroll,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Taurus_Crown_Scroll); },{},{}
17078,Taurus_Crown_Scroll_Box,Taurus Crown Scroll Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Taurus_Crown_Scroll_Box); },{},{}
17079,Indonesia_Box2,Indonesia Box2,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 602,1; getitem 601,50; getitem 12118,3; getitem 12119,3; getitem 12120,3; getitem 12121,3; },{},{}
17079,Indonesia_Box2,Indonesia Box2,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 602,5; getitem 601,50; getitem 12118,3; getitem 12119,3; getitem 12120,3; getitem 12121,3; },{},{}
17080,Scorpio_Scroll3,Scorpio Scroll3,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17081,Yggdrasil_Crown_Box,Yggdrasil Crown Box,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 18580,1; },{},{}
17082,Gemi_Diadem_Scroll,Gemi Diadem Scroll,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Gemi_Diadem_Scroll); },{},{}
17083,Gemi_Diadem_Scroll_Box,Gemi Diadem Scroll Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Gemi_Diadem_Scroll_Box); },{},{}
17084,Upg_Katar_Box,Upg Katar Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 1292,1; },{},{}
17085,Upg_Two_Handed_Axe_Box,Upg Two Handed Axe Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 1394,1; },{},{}
17086,Upg_Lance_Box,Upg Lance Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 1491,1; },{},{}
17087,Upg_Book_Box,Upg Book Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 1585,1; },{},{}
17088,Upg_Staff_Box,Upg Staff Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 2015,1; },{},{}
17089,Upg_Dagger_Box,Upg Dagger Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 13071,1; },{},{}
17090,Upg_Revolver_Box,Upg Revolver,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 13115,1; },{},{}
17091,Upg_Mace_Box,Upg Mace Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 16019,1; },{},{}
17092,Upg_Bow_Box,Upg Bow Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 18112,1; },{},{}
17093,Upg_Twohand_Sword_Box,Upg Two-Handed Sword Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 21000,1; },{},{}
17094,Upg_Katar_Box2,Upg Katar Box,2,20,,0,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17095,Upg_Two_Handed_Axe_Box2,Upg Two-Hand Axe Box,2,20,,0,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17096,Upg_Lance_Box2,Upg Lance Box,2,20,,0,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17104,HD_Oridecon_50Box,HD Oridecon 50 Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 6240,50; },{},{}
17105,HD_Elunium_50Box,HD Elunium 50 Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 6241,50; },{},{}
17084,Upg_Katar_Box,Upg Katar Box,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 1292,1; },{},{}
17085,Upg_Two_Handed_Axe_Box,Upg Two Handed Axe Box,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 1394,1; },{},{}
17086,Upg_Lance_Box,Upg Lance Box,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 1491,1; },{},{}
17087,Upg_Book_Box,Upg Book Box,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 1585,1; },{},{}
17088,Upg_Staff_Box,Upg Staff Box,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 2015,1; },{},{}
17089,Upg_Dagger_Box,Upg Dagger Box,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 13071,1; },{},{}
17090,Upg_Revolver_Box,Upg Revolver,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 13115,1; },{},{}
17091,Upg_Mace_Box,Upg Mace Box,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 16019,1; },{},{}
17092,Upg_Bow_Box,Upg Bow Box,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 18112,1; },{},{}
17093,Upg_Twohand_Sword_Box,Upg Two-Handed Sword Box,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 21000,1; },{},{}
17094,Upg_Katar_Box2,Upg Katar Box,18,20,,0,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17095,Upg_Two_Handed_Axe_Box2,Upg Two-Hand Axe Box2,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17096,Upg_Lance_Box2,Upg Lance Box2,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17097,Upg_Book_Box2,Upg_Book_Box2,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17098,Upg_Staff_Box2,Upg_Staff_Box2,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17099,Upg_Dagger_Box2,Upg_Dagger_Box2,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17100,Upg_Revolver_Box2,Upg_Revolver_Box2,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17101,Upg_Mace_Box2,Upg_Mace_Box2,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17102,Upg_Bow_Box2,Upg_Bow_Box2,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17103,Upg_Twohand_Sword_Box2,Upg_Twohand_Sword_Box2,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17104,HD_Oridecon_50Box,HD Oridecon 50 Box,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 6240,50; },{},{}
17105,HD_Elunium_50Box,HD Elunium 50 Box,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 6241,50; },{},{}
17106,Max_Weight_Up_10Box,Heavy Lifter Box,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 7776,10; },{},{}
17107,Gemi_Crown_Scroll,Gemi Crown Scroll,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Gemi_Crown_Scroll); },{},{}
17108,Gemi_Crown_Scroll_Box,Gemi Crown Scroll Box,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Gemi_Crown_Scroll_Box); },{},{}
17107,Gemi_Crown_Scroll,Gemi Crown Scroll,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Gemi_Crown_Scroll); },{},{}
17108,Gemi_Crown_Scroll_Box,Gemi Crown Scroll Box,18,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ getgroupitem(IG_Gemi_Crown_Scroll_Box); },{},{}
17109,Capri_Scroll,Capri Scroll,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17110,Aquarius_Scroll,Aquarius Scroll,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}
17113,Pisces_Scroll,Pisces Scroll,2,20,,10,,,,,0xFFFFFFFF,63,2,,,,,,{},{},{}

File diff suppressed because it is too large Load Diff

View File

@ -2860,15 +2860,27 @@ It's useful for when you want to check whether an item contains cards or if it's
---------------------------------------
*mergeitem({<item_id>{,<char_id>}});
*mergeitem({"<item name>"{,<char_id>}});
*mergeitem({,<char_id>});
Open merge item window to merge available item can be merged.
Examples
1. See the NPC 'npc/re/other/merge_item.txt'.
2. Simple usage:
mes "Let's check if any item can be merged.";
close2;
mergeitem;
end;
---------------------------------------
*mergeitem2({<item_id>{,<char_id>}});
*mergeitem2({"<item name>"{,<char_id>}});
Merge all stackable items that separated by GUID flags
(either by flag 4 item_flag.txt or GUID in item_group).
If no item ID/name given, all possible items in player's inventory will be merged.
Example, just see the NPC 'npc/re/other/merge_item.txt'.
---------------------------------------
//
2,1.- End of item-related commands.

View File

@ -2,7 +2,8 @@
# Players (T)rade Give/Take, Players (V)ending Sell/Take, (S)hop Sell/Take, (N)PC Give/Take,
# (C)onsumable Items, (A)dministrators Create/Delete, Sto(R)age, (G)uild Storage,
# (E)mail attachment,(B)uying Store, Pr(O)duced Items/Ingredients, Auct(I)oned Items,
# (X) Other, (D) Stolen from mobs, (U) MVP Prizes, F:Guild/Party Bound retrieval
# (X) Other, (D) Stolen from mobs, (U) MVP Prizes, (F) Guild/Party Bound retrieval
# Lotter(Y), (Z) Merged Items
#Database: ragnarok
#Table: picklog
@ -10,7 +11,7 @@ CREATE TABLE IF NOT EXISTS `picklog` (
`id` int(11) NOT NULL auto_increment,
`time` datetime NOT NULL default '0000-00-00 00:00:00',
`char_id` int(11) NOT NULL default '0',
`type` enum('M','P','L','T','V','S','N','C','A','R','G','E','B','O','I','X','D','U','$','F') NOT NULL default 'P',
`type` enum('M','P','L','T','V','S','N','C','A','R','G','E','B','O','I','X','D','U','$','F','Z') NOT NULL default 'P',
`nameid` smallint(5) unsigned NOT NULL default '0',
`amount` int(11) NOT NULL default '1',
`refine` tinyint(3) unsigned NOT NULL default '0',

View File

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

View File

@ -64,14 +64,6 @@
/// Uncomment to enable the job base HP/SP table (job_basehpsp_db.txt)
#define HP_SP_TABLES
/// Enable separated item by `guid`. [Cydh]
/// See db/[pre-]re/item_flag.txt and doc/item_group.txt for the `guid` explanation.
/// NOTE:
/// If this feature is disabled "in the middle" of your game, the separated is still
/// separated in inventory, storage, or guild storage until player move the item
/// to/from storage/inventory to restack them.
#define ENABLE_ITEM_GUID
/// Uncomment to enable VIP system.
//#define VIP_ENABLE

View File

@ -268,30 +268,40 @@ bool cashshop_buylist( struct map_session_data* sd, uint32 kafrapoints, int n, u
for( i = 0; i < n; ++i ){
unsigned short nameid = *( item_list + i * 5 );
uint32 quantity = *( item_list + i * 5 + 2 );
struct item_data *id = itemdb_search(nameid);
if (!itemdb_isstackable(nameid) && quantity > 1)
if (!id)
continue;
if (!itemdb_isstackable2(id) && quantity > 1)
quantity = 1;
if (!pet_create_egg(sd, nameid)) {
struct item item_tmp;
memset( &item_tmp, 0, sizeof( item_tmp ) );
unsigned short get_amt = quantity, j;
item_tmp.nameid = nameid;
item_tmp.identify = 1;
if (id->flag.guid)
get_amt = 1;
switch( pc_additem( sd, &item_tmp, quantity, LOG_TYPE_CASH ) ){
case ADDITEM_OVERWEIGHT:
clif_cashshop_result( sd, nameid, CASHSHOP_RESULT_ERROR_INVENTORY_WEIGHT );
return false;
case ADDITEM_OVERITEM:
clif_cashshop_result( sd, nameid, CASHSHOP_RESULT_ERROR_INVENTORY_ITEMCNT );
return false;
case ADDITEM_OVERAMOUNT:
clif_cashshop_result( sd, nameid, CASHSHOP_RESULT_ERROR_OVER_PRODUCT_TOTAL_CNT );
return false;
case ADDITEM_STACKLIMIT:
clif_cashshop_result( sd, nameid, CASHSHOP_RESULT_ERROR_RUNE_OVERCOUNT );
return false;
for (j = 0; j < quantity; j += get_amt) {
struct item item_tmp = { 0 };
item_tmp.nameid = nameid;
item_tmp.identify = 1;
switch( pc_additem( sd, &item_tmp, get_amt, LOG_TYPE_CASH ) ){
case ADDITEM_OVERWEIGHT:
clif_cashshop_result( sd, nameid, CASHSHOP_RESULT_ERROR_INVENTORY_WEIGHT );
return false;
case ADDITEM_OVERITEM:
clif_cashshop_result( sd, nameid, CASHSHOP_RESULT_ERROR_INVENTORY_ITEMCNT );
return false;
case ADDITEM_OVERAMOUNT:
clif_cashshop_result( sd, nameid, CASHSHOP_RESULT_ERROR_OVER_PRODUCT_TOTAL_CNT );
return false;
case ADDITEM_STACKLIMIT:
clif_cashshop_result( sd, nameid, CASHSHOP_RESULT_ERROR_RUNE_OVERCOUNT );
return false;
}
}
}
}

View File

@ -13443,11 +13443,9 @@ void clif_parse_GM_Item_Monster(int fd, struct map_session_data *sd)
if( !itemdb_isstackable2(id) ) //Nonstackable
StringBuf_Printf(&command, "%citem2 %d 1 0 0 0 0 0 0 0", atcommand_symbol, id->nameid);
else {
#ifdef ENABLE_ITEM_GUID
if (id->flag.guid)
StringBuf_Printf(&command, "%citem %d 1", atcommand_symbol, id->nameid);
else
#endif
StringBuf_Printf(&command, "%citem %d 20", atcommand_symbol, id->nameid);
}
is_atcommand(fd, sd, StringBuf_Value(&command), 1);
@ -16331,7 +16329,9 @@ void clif_parse_LessEffect(int fd, struct map_session_data* sd){
sd->state.lesseffect = ( isLess != 0 );
}
/// S 07e4 <length>.w <option>.l <val>.l {<index>.w <amount>.w).4b*
/// S 07e4 <length>.w <option>.l <val>.l {<index>.w <amount>.w).4b* (CZ_ITEMLISTWIN_RES)
/// S 0945 <length>.w <option>.l <val>.l {<index>.w <amount>.w).4b* (CZ_* RagexeRE 2012-04-10a)
/// S 0281 <length>.w <option>.l <val>.l {<index>.w <amount>.w).4b* (CZ_* Ragexe 2013-08-07)
void clif_parse_ItemListWindowSelected(int fd, struct map_session_data* sd) {
struct s_packet_db* info = &packet_db[sd->packet_ver][RFIFOW(fd,0)];
int n = (RFIFOW(fd,info->pos[0])-12) / 4;
@ -17160,27 +17160,6 @@ int clif_skill_itemlistwindow( struct map_session_data *sd, uint16 skill_id, uin
return 1;
}
// msgstringtable.txt
// 0x291 <line>.W
void clif_msgtable(int fd, int line) {
WFIFOHEAD(fd, packet_len(0x291));
WFIFOW(fd, 0) = 0x291;
WFIFOW(fd, 2) = line;
WFIFOSET(fd, packet_len(0x291));
}
// msgstringtable.txt
// 0x7e2 <line>.W <value>.L
void clif_msgtable_num(int fd, int line, int num) {
#if PACKETVER >= 20090805
WFIFOHEAD(fd, packet_len(0x7e2));
WFIFOW(fd, 0) = 0x7e2;
WFIFOW(fd, 2) = line;
WFIFOL(fd, 4) = num;
WFIFOSET(fd, packet_len(0x7e2));
#endif
}
/*==========================================
* Select a skill into a given list (used by SC_AUTOSHADOWSPELL)
* 0443 <type>.L <skill_id>.W (CZ_SKILL_SELECT_RESPONSE)
@ -18026,6 +18005,188 @@ void clif_roulette_generate_ack(struct map_session_data *sd, unsigned char resul
WFIFOSET(fd,packet_len(0xa20));
}
/// MERGE ITEM
/**
* Acknowledge the client about item merger result
* ZC 096F <index>.W <total>.W <result>.B (ZC_ACK_MERGE_ITEM)
* @param fd
* @param sd
**/
void clif_merge_item_ack(struct map_session_data *sd, unsigned short index, unsigned short count, enum MERGE_ITEM_ACK type) {
unsigned char buf[9];
struct s_packet_db *info = NULL;
short cmd = 0;
nullpo_retv(sd);
if (!clif_session_isValid(sd))
return;
if (!(cmd = packet_db_ack[sd->packet_ver][ZC_ACK_MERGE_ITEM]))
return;
if (!(info = &packet_db[sd->packet_ver][cmd]) || info->len == 0)
return;
WBUFW(buf, 0) = cmd;
WBUFW(buf, info->pos[0]) = index;
WBUFW(buf, info->pos[1]) = count;
WBUFB(buf, info->pos[2]) = type;
clif_send(buf, info->len, &sd->bl, SELF);
}
/**
* Check if item has the pair to be merged
* @param sd
* @param it Item
* @return True if has pair, False if not
**/
static bool clif_merge_item_has_pair(struct map_session_data *sd, struct item *it) {
struct item *it_;
unsigned short i;
nullpo_retr(false, sd);
ARR_FIND(0, MAX_INVENTORY, i, (it_ = &sd->status.inventory[i]) && it->nameid == it_->nameid && it->bound == it_->bound && memcmp(it_, it, sizeof(struct item)) != 0);
if (i < MAX_INVENTORY)
return true;
return false;
}
/**
* Check if item can be merged
* @param id Item Data
* @param it Item
* @return True if can be merged, False if not
**/
static bool clif_merge_item_check(struct item_data *id, struct item *it) {
if (!id || !it)
return false;
if (id->type == IT_CASH)
return false;
if (!itemdb_isstackable2(id))
return false;
if (itemdb_isspecial(it->card[0]))
return false;
if (!it->unique_id)
return false;
return true;
}
/**
* Open available item to be merged.
* Only show 1 item in 1 process.
* ZC 096D <size>.W { <index>.W }* (ZC_MERGE_ITEM_OPEN)
* @param sd
**/
void clif_merge_item_open(struct map_session_data *sd) {
unsigned char buf[4 + MAX_INVENTORY*2] = { 0 };
unsigned short cmd = 0, n = 0, i = 0, indexes[MAX_INVENTORY] = { 0 };
int len = 0;
struct s_packet_db *info = NULL;
struct item *it;
nullpo_retv(sd);
if (!clif_session_isValid(sd))
return;
if (!(cmd = packet_db_ack[sd->packet_ver][ZC_MERGE_ITEM_OPEN]))
return;
if (!(info = &packet_db[sd->packet_ver][cmd]) || info->len == 0)
return;
// Get entries
for (i = 0; i < MAX_INVENTORY; i++) {
if (!clif_merge_item_check(sd->inventory_data[i], (it = &sd->status.inventory[i])))
continue;
if (clif_merge_item_has_pair(sd, it))
indexes[n++] = i;
}
if (n < 2) { // No item need to be merged
clif_msg(sd, MERGE_ITEM_NOT_AVAILABLE);
return;
}
WBUFW(buf, 0) = cmd;
WBUFW(buf, info->pos[0]) = (len = 4 + n*2);
for (i = 0; i < n; i++) {
WBUFW(buf, info->pos[1] + i*2) = indexes[i]+2;
}
clif_send(buf, len, &sd->bl, SELF);
}
/**
* Process item merger
* CZ 096E <size>.W { <index>.W }* (CZ_REQ_MERGE_ITEM)
* @param fd
* @param sd
**/
void clif_parse_merge_item_req(int fd, struct map_session_data* sd) {
struct s_packet_db *info = NULL;
unsigned short n = 0, indexes[MAX_INVENTORY] = { 0 }, i, j;
unsigned int count = 0;
struct item_data *id = NULL;
nullpo_retv(sd);
if (!clif_session_isValid(sd))
return;
if (!(info = &packet_db[sd->packet_ver][RFIFOW(fd,0)]) || info->len == 0)
return;
n = (RFIFOW(fd, info->pos[0]) - 4) / 2;
if (n < 2) { // No item need to be merged
clif_msg(sd, MERGE_ITEM_NOT_AVAILABLE);
return;
}
for (i = 0, j = 0; i < n; i++) {
unsigned short idx = RFIFOW(fd, info->pos[1] + i*2) - 2;
if (!clif_merge_item_check((id = sd->inventory_data[idx]), &sd->status.inventory[idx]))
continue;
indexes[j] = idx;
if (j && id->nameid != sd->inventory_data[indexes[0]]->nameid) { // Only can merge 1 kind at once
clif_merge_item_ack(sd, 0, 0, MERGE_ITEM_FAILED_NOT_MERGE);
return;
}
count += sd->status.inventory[idx].amount;
j++;
}
if (n != j || !(id = sd->inventory_data[indexes[0]])) {
clif_msg(sd, MERGE_ITEM_NOT_AVAILABLE);
return;
}
if (count >= (id->stack.amount ? id->stack.amount : MAX_AMOUNT)) {
clif_merge_item_ack(sd, 0, 0, MERGE_ITEM_FAILED_MAX_COUNT);
return;
}
// Merrrrge!!!!
for (i = 1; i < n; i++) {
unsigned short idx = indexes[i], amt = sd->status.inventory[idx].amount;
log_pick_pc(sd, LOG_TYPE_MERGE_ITEM, -amt, &sd->status.inventory[idx]);
memset(&sd->status.inventory[idx], 0, sizeof(sd->status.inventory[0]));
sd->inventory_data[idx] = NULL;
clif_delitem(sd, idx, amt, 0);
}
sd->status.inventory[indexes[0]].amount = count;
clif_merge_item_ack(sd, indexes[0]+2, count, MERGE_ITEM_SUCCESS);
}
/**
* Cancel item merge
* CZ 0974 (CZ_CANCEL_MERGE_ITEM)
* @param fd
* @param sd
**/
void clif_parse_merge_item_cancel(int fd, struct map_session_data* sd) {
return; // Nothing todo yet
}
/*==========================================
* Main client packet processing function
*------------------------------------------*/
@ -18407,8 +18568,8 @@ void packetdb_readdb(bool reload)
//#0x0940
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 14, 6, 50, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 7,
0, 0, 0, 0, 2, 0, 0, 14, 6, 50, 0, 0, 0, 0, 0, 0,
//#0x0980
0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
31, 0, 0, 0, 0, 0, 0, -1, 8, 11, 9, 8, 0, 0, 0, 22,
@ -18659,6 +18820,9 @@ void packetdb_readdb(bool reload)
{ clif_parse_RouletteClose, "rouletteclose" },
{ clif_parse_RouletteGenerate, "roulettegenerate" },
{ clif_parse_RouletteRecvItem, "rouletterecvitem" },
// Merge Item
{ clif_parse_merge_item_req, "mergeitem_req"},
{ clif_parse_merge_item_cancel, "mergeitem_cancel"},
{NULL,NULL}
};
struct {
@ -18676,6 +18840,8 @@ void packetdb_readdb(bool reload)
{ "ZC_C_MARKERINFO", ZC_C_MARKERINFO},
{ "ZC_NOTIFY_BIND_ON_EQUIP", ZC_NOTIFY_BIND_ON_EQUIP },
{ "ZC_WEAR_EQUIP_ACK", ZC_WEAR_EQUIP_ACK },
{ "ZC_MERGE_ITEM_OPEN", ZC_MERGE_ITEM_OPEN },
{ "ZC_ACK_MERGE_ITEM", ZC_ACK_MERGE_ITEM },
};
const char *filename[] = { "packet_db.txt", DBIMPORT"/packet_db.txt"};
int f;

View File

@ -50,6 +50,8 @@ enum e_packet_ack {
ZC_C_MARKERINFO,
ZC_NOTIFY_BIND_ON_EQUIP,
ZC_WEAR_EQUIP_ACK,
ZC_MERGE_ITEM_OPEN,
ZC_ACK_MERGE_ITEM,
//add other here
MAX_ACK_FUNC //auto upd len
};
@ -109,6 +111,12 @@ enum CLOSE_ROULETTE_ACK {
CLOSE_ROULETTE_FAILED = 0x1,
};
enum MERGE_ITEM_ACK {
MERGE_ITEM_SUCCESS = 0x0,
MERGE_ITEM_FAILED_NOT_MERGE = 0x1,
MERGE_ITEM_FAILED_MAX_COUNT = 0x2,
};
// packet_db[SERVER] is reserved for server use
#define SERVER 0
#define packet_len(cmd) packet_db[SERVER][cmd].len
@ -431,6 +439,7 @@ enum clif_messages {
ITEM_REUSE_LIMIT = 0x746,
USAGE_FAIL = 0x783,
NEED_REINS_OF_MOUNT = 0x78c,
MERGE_ITEM_NOT_AVAILABLE = 0x887,
};
enum e_personalinfo {
@ -899,12 +908,6 @@ void clif_parse_RouletteClose(int fd, struct map_session_data *sd);
void clif_parse_RouletteGenerate(int fd, struct map_session_data *sd);
void clif_parse_RouletteRecvItem(int fd, struct map_session_data *sd);
/**
* 3CeAM
**/
void clif_msgtable(int fd, int line);
void clif_msgtable_num(int fd, int line, int num);
int clif_elementalconverter_list(struct map_session_data *sd);
void clif_millenniumshield(struct block_list *bl, short shields);
@ -954,6 +957,8 @@ void clif_party_leaderchanged(struct map_session_data *sd, int prev_leader_aid,
void clif_account_name(int fd, uint32 account_id, const char* accname);
void clif_notify_bindOnEquip(struct map_session_data *sd, int n);
void clif_merge_item_open(struct map_session_data *sd);
//void clif_broadcast_obtain_special_item(); ///TODO!
#endif /* _CLIF_H_ */

View File

@ -181,18 +181,18 @@ static void itemdb_pc_get_itemgroup_sub(struct map_session_data *sd, struct s_it
// Do loop for non-stackable item
for (i = 0; i < data->amount; i++) {
char flag = 0;
#ifdef ENABLE_ITEM_GUID
tmp.unique_id = data->GUID ? pc_generate_unique_id(sd) : 0; // Generate UID
#endif
if ((flag = pc_additem(sd, &tmp, tmp.amount, LOG_TYPE_SCRIPT)))
if ((flag = pc_additem(sd, &tmp, tmp.amount, LOG_TYPE_SCRIPT))) {
clif_additem(sd, 0, 0, flag);
if (pc_candrop(sd, &tmp))
map_addflooritem(&tmp, tmp.amount, sd->bl.m, sd->bl.x,sd->bl.y, 0, 0, 0, 0);
}
else if (!flag && data->isAnnounced) {
char output[CHAT_SIZE_MAX];
sprintf(output, msg_txt(NULL, 717), sd->status.name, itemdb_jname(data->nameid), itemdb_jname(sd->itemid));
//! TODO: Move this broadcast to proper packet
//! TODO: Move this broadcast to proper packet. ZI -> IZ (all Zones) -> ZC (clif_broadcast_obtain_special_item)
intif_broadcast(output, strlen(output) + 1, BC_DEFAULT);
//clif_broadcast_obtain_special_item();
}
if (itemdb_isstackable(data->nameid))
break;
@ -654,9 +654,7 @@ static void itemdb_read_itemgroup_sub(const char* filename, bool silent)
if (str[3] != NULL) entry.amount = cap_value(atoi(str[3]),1,MAX_AMOUNT);
if (str[5] != NULL) entry.isAnnounced= atoi(str[5]);
if (str[6] != NULL) entry.duration = cap_value(atoi(str[6]),0,UINT16_MAX);
#ifdef ENABLE_ITEM_GUID
if (str[7] != NULL) entry.GUID = atoi(str[7]);
#endif
if (str[8] != NULL) entry.bound = cap_value(atoi(str[8]),BOUND_NONE,BOUND_MAX-1);
if (str[9] != NULL) entry.isNamed = atoi(str[9]);
@ -904,9 +902,7 @@ static bool itemdb_read_flag(char* fields[], int columns, int current) {
if (flag&1) id->flag.dead_branch = set ? 1 : 0;
if (flag&2) id->flag.group = set ? 1 : 0;
#ifdef ENABLE_ITEM_GUID
if (flag&4 && itemdb_isstackable2(id)) id->flag.guid = set ? 1 : 0;
#endif
if (flag&8) id->flag.bindOnEquip = true;
return true;

View File

@ -76,6 +76,7 @@ static char log_picktype2char(e_log_pick_type type)
case LOG_TYPE_CASH: return '$'; // Cash
case LOG_TYPE_BOUND_REMOVAL: return 'F'; // Removed bound items when guild/party is broken
case LOG_TYPE_ROULETTE: return 'Y'; // Roulette Lotter(Y)
case LOG_TYPE_MERGE_ITEM: return 'Z'; // Merged Item
}
// should not get here, fallback

View File

@ -45,6 +45,7 @@ typedef enum e_log_pick_type
LOG_TYPE_BANK = 0x040000,
LOG_TYPE_BOUND_REMOVAL = 0x080000,
LOG_TYPE_ROULETTE = 0x100000,
LOG_TYPE_MERGE_ITEM = 0x200000,
// combinations
LOG_TYPE_LOOT = LOG_TYPE_PICKDROP_MONSTER|LOG_TYPE_CONSUME,
// all

View File

@ -1428,20 +1428,23 @@ int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, uns
pc_paycash(sd,vt,points, LOG_TYPE_NPC);
// Delivery Process ----------------------------------------------------
for( i = 0; i < count; i++ )
{
struct item item_tmp;
for( i = 0; i < count; i++ ) {
nameid = item_list[i*2+1];
amount = item_list[i*2+0];
memset(&item_tmp,0,sizeof(item_tmp));
if( !pet_create_egg(sd,nameid) ) {
struct item item_tmp;
unsigned short get_amt = amount;
if( !pet_create_egg(sd,nameid) )
{
memset(&item_tmp, 0, sizeof(item_tmp));
item_tmp.nameid = nameid;
item_tmp.identify = 1;
pc_additem(sd,&item_tmp,amount,LOG_TYPE_NPC);
if ((itemdb_search(nameid))->flag.guid)
get_amt = 1;
for (j = 0; j < amount; j += get_amt)
pc_additem(sd,&item_tmp,get_amt,LOG_TYPE_NPC);
}
}
@ -1548,14 +1551,19 @@ int npc_cashshop_buy(struct map_session_data *sd, unsigned short nameid, int amo
pc_paycash(sd, price, points, LOG_TYPE_NPC);
if( !pet_create_egg(sd, nameid) )
{
if( !pet_create_egg(sd, nameid) ) {
struct item item_tmp;
memset(&item_tmp, 0, sizeof(struct item));
unsigned short get_amt = amount, j;
memset(&item_tmp, 0, sizeof(item_tmp));
item_tmp.nameid = nameid;
item_tmp.identify = 1;
pc_additem(sd,&item_tmp, amount, LOG_TYPE_NPC);
if (item->flag.guid)
get_amt = 1;
for (j = 0; j < amount; j += get_amt)
pc_additem(sd,&item_tmp, get_amt, LOG_TYPE_NPC);
}
return 0;
@ -1705,7 +1713,6 @@ uint8 npc_buylist(struct map_session_data* sd, uint16 n, struct s_npc_buy_list *
for( i = 0; i < n; ++i ) {
unsigned short nameid = item_list[i].nameid;
unsigned short amount = item_list[i].qty;
struct item item_tmp;
#if PACKETVER >= 20131223
if (nd->subtype == NPCTYPE_MARKETSHOP) {
@ -1720,11 +1727,19 @@ uint8 npc_buylist(struct map_session_data* sd, uint16 n, struct s_npc_buy_list *
if (itemdb_type(nameid) == IT_PETEGG)
pet_create_egg(sd, nameid);
else {
memset(&item_tmp,0,sizeof(item_tmp));
item_tmp.nameid = nameid;
item_tmp.identify = 1;
unsigned short get_amt = amount;
pc_additem(sd,&item_tmp,amount,LOG_TYPE_NPC);
if ((itemdb_search(nameid))->flag.guid)
get_amt = 1;
for (k = 0; k < amount; k += get_amt) {
struct item item_tmp;
memset(&item_tmp, 0, sizeof(item_tmp));
item_tmp.nameid = nameid;
item_tmp.identify = 1;
pc_additem(sd,&item_tmp,get_amt,LOG_TYPE_NPC);
}
}
}

View File

@ -4317,10 +4317,8 @@ char pc_additem(struct map_session_data *sd,struct item *item,int amount,e_log_p
i = MAX_INVENTORY;
#ifdef ENABLE_ITEM_GUID
if (id->flag.guid && !item->unique_id)
item->unique_id = pc_generate_unique_id(sd);
#endif
// Stackable | Non Rental
if( itemdb_isstackable2(id) && item->expire_time == 0 ) {
@ -4356,12 +4354,13 @@ char pc_additem(struct map_session_data *sd,struct item *item,int amount,e_log_p
sd->status.inventory[i].amount = amount;
sd->inventory_data[i] = id;
sd->last_addeditem_index = i;
if (!itemdb_isstackable2(id) || id->flag.guid)
sd->status.inventory[i].unique_id = item->unique_id ? item->unique_id : pc_generate_unique_id(sd);
clif_additem(sd,i,amount,0);
}
if (!itemdb_isstackable2(id) && !item->unique_id)
sd->status.inventory[i].unique_id = pc_generate_unique_id(sd);
log_pick_pc(sd, log_type, amount, &sd->status.inventory[i]);
sd->weight += w;
@ -4567,7 +4566,7 @@ bool pc_isUseitem(struct map_session_data *sd,int n)
return false;
if( (item->item_usage.flag&NOUSE_SITTING) && (pc_issit(sd) == 1) && (pc_get_group_level(sd) < item->item_usage.override) ) {
clif_msgtable(sd->fd,ITEM_NOUSE_SITTING);
clif_msg(sd,ITEM_NOUSE_SITTING);
return false; // You cannot use this item while sitting.
}
@ -4665,7 +4664,7 @@ bool pc_isUseitem(struct map_session_data *sd,int n)
if( item->flag.group || item->type == IT_CASH) { //safe check type cash disappear when overweight [Napster]
if( pc_is90overweight(sd) ) {
clif_msgtable(sd->fd, ITEM_CANT_OBTAIN_WEIGHT);
clif_msg(sd, ITEM_CANT_OBTAIN_WEIGHT);
return false;
}
if( !pc_inventoryblank(sd) ) {

View File

@ -18937,7 +18937,7 @@ BUILDIN_FUNC(setmounting) {
if (!script_charid2sd(2,sd))
return SCRIPT_CMD_FAILURE;
if( &sd->sc && sd->sc.option&(OPTION_WUGRIDER|OPTION_RIDING|OPTION_DRAGON|OPTION_MADOGEAR) ) {
clif_msgtable(sd->fd, NEED_REINS_OF_MOUNT);
clif_msg(sd, NEED_REINS_OF_MOUNT);
script_pushint(st,0); //can't mount with one of these
} else {
if( &sd->sc && sd->sc.data[SC_ALL_RIDING] )
@ -20125,13 +20125,28 @@ BUILDIN_FUNC(countspiritball) {
}
/** Merges separated stackable items because of guid
* mergeitem {<item_id>,{<char_id>}};
* mergeitem {"<item name>",{<char_id>}};
* @param item Item ID/Name for merging specific item (Optional)
* mergeitem {<char_id>};
* @param char_id Char ID (Optional)
* @author [Cydh]
*/
BUILDIN_FUNC(mergeitem) {
struct map_session_data *sd;
if (!script_charid2sd(2, sd))
return SCRIPT_CMD_FAILURE;
clif_merge_item_open(sd);
return SCRIPT_CMD_SUCCESS;
}
/** Merges separated stackable items because of guid (Unofficial)
* mergeitem2 {<item_id>,{<char_id>}};
* mergeitem2 {"<item name>",{<char_id>}};
* @param item Item ID/Name for merging specific item (Optional)
* @author [Cydh]
*/
BUILDIN_FUNC(mergeitem2) {
struct map_session_data *sd;
struct item *items = NULL;
uint16 i, count = 0;
int nameid = 0;
@ -20147,7 +20162,7 @@ BUILDIN_FUNC(mergeitem) {
if (data_isstring(data)) {// "<item name>"
const char *name = conv_str(st,data);
if (!(id = itemdb_searchname(name))) {
ShowError("buildin_mergeitem: Nonexistant item %s requested.\n", name);
ShowError("buildin_mergeitem2: Nonexistant item %s requested.\n", name);
script_pushint(st, count);
return SCRIPT_CMD_FAILURE;
}
@ -20156,7 +20171,7 @@ BUILDIN_FUNC(mergeitem) {
else if (data_isint(data)) {// <item id>
nameid = conv_num(st,data);
if (!(id = itemdb_exists(nameid))) {
ShowError("buildin_mergeitem: Nonexistant item %d requested.\n", nameid);
ShowError("buildin_mergeitem2: Nonexistant item %d requested.\n", nameid);
script_pushint(st, count);
return SCRIPT_CMD_FAILURE;
}
@ -20887,7 +20902,8 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(addspiritball,"ii?"),
BUILDIN_DEF(delspiritball,"i?"),
BUILDIN_DEF(countspiritball,"?"),
BUILDIN_DEF(mergeitem,"??"),
BUILDIN_DEF(mergeitem,"?"),
BUILDIN_DEF(mergeitem2,"??"),
BUILDIN_DEF(npcshopupdate,"sii?"),
BUILDIN_DEF(getattachedrid,""),
BUILDIN_DEF(getvar,"vi"),

View File

@ -18237,7 +18237,7 @@ bool skill_produce_mix(struct map_session_data *sd, uint16 skill_id, unsigned sh
for (i = 0; i < MAX_INVENTORY; i++) {
if (sd->status.inventory[i].nameid == nameid) {
if (sd->status.inventory[i].amount >= data->stack.amount) {
clif_msgtable(sd->fd,RUNE_CANT_CREATE);
clif_msg(sd,RUNE_CANT_CREATE);
return 0;
} else {
// The amount fits, say we got temp_qty 4 and 19 runes, we trim temp_qty to 1.

View File

@ -139,10 +139,8 @@ int compare_item(struct item *a, struct item *b)
a->refine == b->refine &&
a->attribute == b->attribute &&
a->expire_time == b->expire_time &&
a->bound == b->bound
#ifdef ENABLE_ITEM_GUID
&& a->unique_id == b->unique_id
#endif
a->bound == b->bound &&
a->unique_id == b->unique_id
)
{
int i;