From 856b6f1feb25ca74d716a4c22fff650e0ff065a0 Mon Sep 17 00:00:00 2001 From: Ibrahim Hossam Date: Mon, 6 Jul 2015 21:38:11 +0200 Subject: Update Unique ID system to match official now it cover all cash items include stackable ones. Implement ForceSerial option in Package Item Database to force serial for any item. Implement ForceSerial option in item database to force serial for any item. Implement Merge Client interface to merge stackable items with serial numbers ( check npc/other/item_merge.txt ). --- db/item_db2.conf | 1 + db/pre-re/item_db.conf | 1 + db/re/item_db.conf | 1 + npc/other/item_merge.txt | 71 ++++++++++++++ npc/re/other/item_merge.txt | 69 -------------- npc/re/scripts.conf | 1 - npc/scripts.conf | 1 + sql-files/item_db.sql | 1 + sql-files/item_db2.sql | 1 + sql-files/item_db_re.sql | 1 + sql-files/main.sql | 1 + sql-files/upgrades/2015-07-02--18-14.sql | 56 +++++++++++ sql-files/upgrades/index.txt | 3 +- src/map/clif.c | 157 +++++++++++++++++++++++++++++++ src/map/clif.h | 21 +++++ src/map/itemdb.c | 64 ++++++++----- src/map/itemdb.h | 3 + src/map/packets.h | 2 + src/map/pc.c | 7 +- src/map/script.c | 12 +++ src/map/storage.c | 4 +- src/plugins/db2sql.c | 6 +- 22 files changed, 387 insertions(+), 97 deletions(-) create mode 100644 npc/other/item_merge.txt delete mode 100644 npc/re/other/item_merge.txt create mode 100644 sql-files/upgrades/2015-07-02--18-14.sql diff --git a/db/item_db2.conf b/db/item_db2.conf index b209b0f79..1138bd944 100644 --- a/db/item_db2.conf +++ b/db/item_db2.conf @@ -29,6 +29,7 @@ item_db: ( Refine: Refineable (boolean, defaults to true) View: View ID (int, defaults to 0) BindOnEquip: true/false (boolean, defaults to false) + ForceSerial: true/false (boolean, defaults to false) BuyingStore: true/false (boolean, defaults to false) Delay: Delay to use item (int, defaults to 0) KeepAfterUse: true/false (boolean, defaults to false) diff --git a/db/pre-re/item_db.conf b/db/pre-re/item_db.conf index ab7adae4e..48d9b091d 100644 --- a/db/pre-re/item_db.conf +++ b/db/pre-re/item_db.conf @@ -29,6 +29,7 @@ item_db: ( Refine: Refineable (boolean, defaults to true) View: View ID (int, defaults to 0) BindOnEquip: true/false (boolean, defaults to false) + ForceSerial: true/false (boolean, defaults to false) BuyingStore: true/false (boolean, defaults to false) Delay: Delay to use item (int, defaults to 0) KeepAfterUse: true/false (boolean, defaults to false) diff --git a/db/re/item_db.conf b/db/re/item_db.conf index 0b06a61db..be1253e25 100644 --- a/db/re/item_db.conf +++ b/db/re/item_db.conf @@ -29,6 +29,7 @@ item_db: ( Refine: Refineable (boolean, defaults to true) View: View ID (int, defaults to 0) BindOnEquip: true/false (boolean, defaults to false) + ForceSerial: true/false (boolean, defaults to false) BuyingStore: true/false (boolean, defaults to false) Delay: Delay to use item (int, defaults to 0) KeepAfterUse: true/false (boolean, defaults to false) diff --git a/npc/other/item_merge.txt b/npc/other/item_merge.txt new file mode 100644 index 000000000..151251edc --- /dev/null +++ b/npc/other/item_merge.txt @@ -0,0 +1,71 @@ +//===== Hercules Script ====================================== +//= Mergician +//===== By: ================================================== +//= Euphy +//===== Current Version: ===================================== +//= 1.0 +//===== Description: ========================================= +//= [Official Conversion] +//= Merges items taking up multiple slots in a player's +//= inventory. +//===== Additional Comments: ================================= +//= 1.0 First version, currently useless/disabled. +//= 1.1 Add support for merging items +//============================================================ + +prontera,146,95,3 script Mergician#pron 1_M_WIZARD,{ + if (checkweight(1301,1) == 0) { + mes "- Wait a second !! -"; + mes "- You are carrying too many items -"; + mes "- or too much weight to proceed. -"; + mes "- Come back after -"; + mes "- arranging your inventory. -"; + close; + } + mes "[Mergician]"; + mes "Do you believe in the miracle of Merge god?? If so, repeat my spell loudly as I pronunce it!!!"; + mes "Merge Merge, Merrrrge!!!"; + next; + switch(select("What is the miracle of Merge?:Merrrrge!!!!:Abandon...")) { + case 1: + mes "[Mergician]"; + mes "There is an order which rules the world and keeps the world to go well."; + next; + mes "[Mergician]"; + mes "But there has been a bad factor which totally jeopardised this rule!!"; + next; + mes "[Mergician]"; + mes "Those things which are separated even if they are composed by the same material!!"; + next; + mes "[Mergician]"; + mes "Have you never experienced this bad incident??"; + mes "The fact that I had ^3131FFthe same potion, but appearing more than twice in your inventory!!^000000 So unpleasant!!!"; + next; + mes "[Mergician]"; + mes "Believe in Mergism. That is the truth."; + mes "Then I can help you be happy and content."; + close; + case 2: + mes "[Mergician]"; + mes "This is the total holy ritual to pray to the Great God, Merge! and I am borrowing the power for a while!!"; + next; + mes "[Mergician]"; + mes "And if you eagerly want to be blessed by Merge, be humble and shout out loud! Merge Merge, Merrrrge!!!"; + next; + switch(select("Merrrrge!:Don't follow what he says.")) { + case 1: + mes "[Mergician]"; + mes "Merge just heard your wish and let it be realised!"; + mes "Open your inventory to check the miracle!"; + close2; + mergeitem(); + end; + case 2: + mes "[Mergician]"; + mes "You jerk!!! You just broke the whole rhythm! Why can't you get my flow and follow me?! Idiot!"; + close; + } + case 3: + close; + } +} diff --git a/npc/re/other/item_merge.txt b/npc/re/other/item_merge.txt deleted file mode 100644 index f823f5c3c..000000000 --- a/npc/re/other/item_merge.txt +++ /dev/null @@ -1,69 +0,0 @@ -//===== Hercules Script ====================================== -//= Mergician -//===== By: ================================================== -//= Euphy -//===== Current Version: ===================================== -//= 1.0 -//===== Description: ========================================= -//= [Official Conversion] -//= Merges items taking up multiple slots in a player's -//= inventory. -//===== Additional Comments: ================================= -//= 1.0 First version, currently useless/disabled. -//============================================================ - -prontera,146,95,3 script Mergician#pron 1_M_WIZARD,{ - if (checkweight(1301,1) == 0) { - mes "- Wait a second !! -"; - mes "- You are carrying too many items -"; - mes "- or too much weight to proceed. -"; - mes "- Come back after -"; - mes "- arranging your inventory. -"; - close; - } - mes "[Mergician]"; - mes "Do you believe in the miracle of Merge god?? If so, repeat my spell loudly as I pronunce it!!!"; - mes "Merge Merge, Merrrrge!!!"; - next; - switch(select("What is the miracle of Merge?:Merrrrge!!!!:Abandon...")) { - case 1: - mes "[Mergician]"; - mes "There is an order which rules the world and keeps the world to go well."; - next; - mes "[Mergician]"; - mes "But there has been a bad factor which totally jeopardised this rule!!"; - next; - mes "[Mergician]"; - mes "Those things which are separated even if they are composed by the same material!!"; - next; - mes "[Mergician]"; - mes "Have you never experienced this bad incident??"; - mes "The fact that I had ^3131FFthe same potion, but appearing more than twice in your inventory!!^000000 So unpleasant!!!"; - next; - mes "[Mergician]"; - mes "Believe in Mergism. That is the truth."; - mes "Then I can help you be happy and content."; - close; - case 2: - mes "[Mergician]"; - mes "This is the total holy ritual to pray to the Great God, Merge! and I am borrowing the power for a while!!"; - next; - mes "[Mergician]"; - mes "And if you eagerly want to be blessed by Merge, be humble and shout out loud! Merge Merge, Merrrrge!!!"; - next; - switch(select("Merrrrge!:Don't follow what he says.")) { - case 1: -// MergeItem - mes "[Mergician]"; - mes "Merge just heard your wish and let it be realised!"; - mes "Open your inventory to check the miracle!"; - close; - case 2: - mes "[Mergician]"; - mes "You jerk!!! You just broke the whole rhythm! Why can't you get my flow and follow me?! Idiot!"; - close; - } - case 3: - close; - } -} diff --git a/npc/re/scripts.conf b/npc/re/scripts.conf index b498960f1..e0c12c2e5 100644 --- a/npc/re/scripts.conf +++ b/npc/re/scripts.conf @@ -93,7 +93,6 @@ npc: npc/re/merchants/ninja_craftsman.txt // --------------------------- Others --------------------------- npc: npc/re/other/bulletin_boards.txt -//npc: npc/re/other/item_merge.txt npc: npc/re/other/mail.txt npc: npc/re/other/mercenary_rent.txt npc: npc/re/other/pvp.txt diff --git a/npc/scripts.conf b/npc/scripts.conf index b8f427ca1..fd16b357b 100644 --- a/npc/scripts.conf +++ b/npc/scripts.conf @@ -200,6 +200,7 @@ npc: npc/other/powernpc.txt npc: npc/other/pvp.txt // - Turbo Track Arena npc: npc/other/turbo_track.txt +npc: npc/other/item_merge.txt // --------------------------- Quests --------------------------- // - Quests-Tutorials for basic classes (1st class quests) ------ diff --git a/sql-files/item_db.sql b/sql-files/item_db.sql index c4f21d41a..8ffb0f51a 100644 --- a/sql-files/item_db.sql +++ b/sql-files/item_db.sql @@ -31,6 +31,7 @@ CREATE TABLE `item_db` ( `refineable` tinyint(1) UNSIGNED DEFAULT NULL, `view` smallint(3) UNSIGNED DEFAULT NULL, `bindonequip` tinyint(1) UNSIGNED DEFAULT NULL, + `forceserial` tinyint(1) unsigned DEFAULT NULL, `buyingstore` tinyint(1) UNSIGNED DEFAULT NULL, `delay` mediumint(9) UNSIGNED DEFAULT NULL, `trade_flag` smallint(4) UNSIGNED DEFAULT NULL, diff --git a/sql-files/item_db2.sql b/sql-files/item_db2.sql index 05a8121e6..b72c60a85 100644 --- a/sql-files/item_db2.sql +++ b/sql-files/item_db2.sql @@ -31,6 +31,7 @@ CREATE TABLE `item_db2` ( `refineable` tinyint(1) UNSIGNED DEFAULT NULL, `view` smallint(3) UNSIGNED DEFAULT NULL, `bindonequip` tinyint(1) UNSIGNED DEFAULT NULL, + `forceserial` tinyint(1) unsigned DEFAULT NULL, `buyingstore` tinyint(1) UNSIGNED DEFAULT NULL, `delay` mediumint(9) UNSIGNED DEFAULT NULL, `trade_flag` smallint(4) UNSIGNED DEFAULT NULL, diff --git a/sql-files/item_db_re.sql b/sql-files/item_db_re.sql index 3e5a6c3c4..d06d06ddc 100644 --- a/sql-files/item_db_re.sql +++ b/sql-files/item_db_re.sql @@ -31,6 +31,7 @@ CREATE TABLE `item_db` ( `refineable` tinyint(1) UNSIGNED DEFAULT NULL, `view` smallint(3) UNSIGNED DEFAULT NULL, `bindonequip` tinyint(1) UNSIGNED DEFAULT NULL, + `forceserial` tinyint(1) unsigned DEFAULT NULL, `buyingstore` tinyint(1) UNSIGNED DEFAULT NULL, `delay` mediumint(9) UNSIGNED DEFAULT NULL, `trade_flag` smallint(4) UNSIGNED DEFAULT NULL, diff --git a/sql-files/main.sql b/sql-files/main.sql index a00a3319b..646805d1b 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -808,6 +808,7 @@ INSERT INTO `sql_updates` (`timestamp`) VALUES (1398477600); -- 2014-04-26--10-0 INSERT INTO `sql_updates` (`timestamp`) VALUES (1400256139); -- 2014-05-17--00-06.sql INSERT INTO `sql_updates` (`timestamp`) VALUES (1409590380); -- 2014-09-01--16-53.sql INSERT INTO `sql_updates` (`timestamp`) VALUES (1414975503); -- 2014-11-03--00-45.sql +INSERT INTO `sql_updates` (`timestamp`) VALUES (1435860840); -- 2015-07-02--18-14.sql -- -- Table structure for table `sstatus` diff --git a/sql-files/upgrades/2015-07-02--18-14.sql b/sql-files/upgrades/2015-07-02--18-14.sql new file mode 100644 index 000000000..49094a5df --- /dev/null +++ b/sql-files/upgrades/2015-07-02--18-14.sql @@ -0,0 +1,56 @@ +#1435860840 + +DELIMITER $$ + +DROP PROCEDURE IF EXISTS alter_if_not_exists $$ +DROP PROCEDURE IF EXISTS alter_if_exists $$ + +CREATE PROCEDURE alter_if_not_exists(my_table TINYTEXT, my_column TINYTEXT, my_command TINYTEXT, my_predicate TEXT) +BEGIN + set @dbname = DATABASE(); + IF EXISTS ( + SELECT * FROM information_schema.TABLES + WHERE TABLE_SCHEMA = @dbname + AND TABLE_NAME = my_table + ) AND NOT EXISTS ( + SELECT * FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = @dbname + AND TABLE_NAME = my_table + AND COLUMN_NAME = my_column + ) + THEN + SET @q = CONCAT('ALTER TABLE ', @dbname, '.', my_table, ' ', + my_command, ' `', my_column, '` ', my_predicate); + PREPARE STMT FROM @q; + EXECUTE STMT; + END IF; + +END $$ + +CREATE PROCEDURE alter_if_exists(my_table TINYTEXT, my_column TINYTEXT, my_command TINYTEXT, my_predicate TEXT) +BEGIN + set @dbname = DATABASE(); + IF EXISTS ( + SELECT * FROM information_schema.COLUMNS + WHERE TABLE_SCHEMA = @dbname + AND TABLE_NAME = my_table + AND COLUMN_NAME = my_column + ) + THEN + SET @q = CONCAT('ALTER TABLE ', @dbname, '.', my_table, ' ', + my_command, ' `', my_column, '` ', my_predicate); + PREPARE STMT FROM @q; + EXECUTE STMT; + END IF; + +END $$ + +CALL alter_if_not_exists('item_db', 'forceserial', 'ADD COLUMN', 'TINYINT(1) UNSIGNED DEFAULT NULL AFTER `bindonequip`') $$ +CALL alter_if_not_exists('item_db2', 'forceserial', 'ADD COLUMN', 'TINYINT(1) UNSIGNED DEFAULT NULL AFTER `bindonequip`') $$ + +DROP PROCEDURE IF EXISTS alter_if_not_exists $$ +DROP PROCEDURE IF EXISTS alter_if_exists $$ + +DELIMITER ';' + +INSERT INTO `sql_updates` (`timestamp`) VALUES (1435860840); diff --git a/sql-files/upgrades/index.txt b/sql-files/upgrades/index.txt index 13495c82d..0e6917f16 100644 --- a/sql-files/upgrades/index.txt +++ b/sql-files/upgrades/index.txt @@ -24,4 +24,5 @@ 2014-04-26--10-00.sql 2014-05-17--00-06.sql 2014-09-01--16-53.sql -2014-11-03--00-45.sql \ No newline at end of file +2014-11-03--00-45.sql +2015-07-02--18-14.sql \ No newline at end of file diff --git a/src/map/clif.c b/src/map/clif.c index d9b20e570..f01b59fda 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -18123,6 +18123,157 @@ void clif_roulette_generate_ack(struct map_session_data *sd, unsigned char resul clif->send(&p,sizeof(p), &sd->bl, SELF); } +/** +* Stackable items merger +**/ +void clif_openmergeitem(int fd, struct map_session_data *sd) +{ + int i = 0, n = 0, j = 0; + struct merge_item merge_items[MAX_INVENTORY]; + struct merge_item *merge_items_[MAX_INVENTORY] = {0}; + + memset(&merge_items,'\0',sizeof(merge_items)); + + for (i = 0; i < MAX_INVENTORY; i++) { + struct item *item_data = &sd->status.inventory[i]; + + if (item_data->nameid == 0 || !itemdb->isstackable(item_data->nameid)) + continue; + + merge_items[n].nameid = item_data->nameid; + merge_items[n].position = i + 2; + n++; + + + } + + qsort(merge_items,n,sizeof(struct merge_item),clif->comparemergeitem); + + for (i = 0, j = 0; i < n; i++) { + if (i > 0 && merge_items[i].nameid == merge_items[i-1].nameid) + { + merge_items_[j] = &merge_items[i]; + j++; + continue; + } + + if (i < n - 1 && merge_items[i].nameid == merge_items[i+1].nameid) + { + merge_items_[j] = &merge_items[i]; + j++; + continue; + } + } + + WFIFOHEAD(fd,2*j+4); + WFIFOW(fd,0) = 0x96d; + WFIFOW(fd,2) = 2*j+4; + for ( i = 0; i < j; i++ ) + WFIFOW(fd,i*2+4) = merge_items_[i]->position; + WFIFOSET(fd,2*j+4); +} + +int clif_comparemergeitem(const void *a, const void *b) +{ + const struct merge_item *a_ = a; + const struct merge_item *b_ = b; + + if (a_->nameid == b_->nameid) + return 0; + return a_->nameid > b_->nameid ? -1 : 1; +} + +void clif_ackmergeitems(int fd, struct map_session_data *sd) +{ + int i = 0, n = 0, length = 0, count = 0; + int16 nameid = 0, indexes[MAX_INVENTORY] = {0}, amounts[MAX_INVENTORY] = {0}; + struct item item_data; + + length = (RFIFOW(fd,2) - 4)/2; + + if (length >= MAX_INVENTORY || length < 2) { + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x96f; + WFIFOW(fd,2) = 0; + WFIFOW(fd,4) = 0; + WFIFOB(fd,6) = MERGEITEM_FAILD; + WFIFOSET(fd,7); + return; + } + + for (i = 0, n = 0; i < length; i++) { + int16 idx = RFIFOW(fd,i*2+4) - 2; + struct item *it = NULL; + + if (idx < 0 || idx >= MAX_INVENTORY) + continue; + + it = &sd->status.inventory[idx]; + + if (it->nameid == 0 || !itemdb->isstackable(it->nameid)) + continue; + + if (nameid == 0) + nameid = it->nameid; + + if (nameid != it->nameid) + continue; + + count += it->amount; + indexes[n] = idx; + amounts[n] = it->amount; + n++; + } + + + if (n < 2 || count == 0) { + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x96f; + WFIFOW(fd,2) = 0; + WFIFOW(fd,4) = 0; + WFIFOB(fd,6) = MERGEITEM_FAILD; + WFIFOSET(fd,7); + return; + } + + if (count > MAX_AMOUNT) { + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x96f; + WFIFOW(fd,2) = 0; + WFIFOW(fd,4) = 0; + WFIFOB(fd,6) = MERGEITEM_MAXCOUNTFAILD; + WFIFOSET(fd,7); + return; + } + + for (i = 0; i < n; i++) + pc->delitem(sd,indexes[i],amounts[i],0,DELITEM_NORMAL,LOG_TYPE_NPC); + + + memset(&item_data,'\0',sizeof(item_data)); + + item_data.nameid = nameid; + item_data.identify = 1; + item_data.unique_id = itemdb->unique_id(sd); + pc->additem(sd,&item_data,count,LOG_TYPE_NPC); + + ARR_FIND(0,MAX_INVENTORY,i,item_data.unique_id == sd->status.inventory[i].unique_id); + + WFIFOHEAD(fd,7); + WFIFOW(fd,0) = 0x96f; + WFIFOW(fd,2) = i+2; + WFIFOW(fd,4) = count; + WFIFOB(fd,6) = MERGEITEM_SUCCESS; + WFIFOSET(fd,7); + +} + +void clif_cancelmergeitem (int fd, struct map_session_data *sd) +{ + //Track The merge item cancelation ? + return; +} + /* */ unsigned short clif_decrypt_cmd( int cmd, struct map_session_data *sd ) { if( sd ) { @@ -18912,6 +19063,12 @@ void clif_defaults(void) { /* */ clif->parse_roulette_db = clif_parse_roulette_db; clif->roulette_generate_ack = clif_roulette_generate_ack; + /* Merge Items */ + clif->openmergeitem = clif_openmergeitem; + clif->cancelmergeitem = clif_cancelmergeitem; + clif->comparemergeitem = clif_comparemergeitem; + clif->ackmergeitems = clif_ackmergeitems; + /*------------------------ *- Parse Incoming Packet *------------------------*/ diff --git a/src/map/clif.h b/src/map/clif.h index 66dd13304..c827406ca 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -522,6 +522,16 @@ enum delitem_reason { DELITEM_ANALYSIS = 7, /// Consumed by Four Spirit Analysis (SO_EL_ANALYSIS) skill }; +/* +* Merge items reasons +*/ + +enum mergeitem_reason { + MERGEITEM_SUCCESS = 0x0, + MERGEITEM_FAILD = 0x1, + MERGEITEM_MAXCOUNTFAILD = 0x2, +}; + /** * Structures **/ @@ -542,6 +552,11 @@ struct cdelayed_damage { struct block_list bl; }; +struct merge_item { + int16 position; + int16 nameid; +}; + /** * Vars **/ @@ -1062,6 +1077,12 @@ struct clif_interface { /* */ bool (*parse_roulette_db) (void); void (*roulette_generate_ack) (struct map_session_data *sd, unsigned char result, short stage, short prizeIdx, short bonusItemID); + /* Merge Items */ + void (*openmergeitem) (int fd, struct map_session_data *sd); + void (*cancelmergeitem) (int fd, struct map_session_data *sd); + int (*comparemergeitem) (const void *a, const void *b); + void (*ackmergeitems) (int fd, struct map_session_data *sd); + /*------------------------ *- Parse Incoming Packet *------------------------*/ diff --git a/src/map/itemdb.c b/src/map/itemdb.c index b02da1e0d..4ebe282a2 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -199,6 +199,9 @@ void itemdb_package_item(struct map_session_data *sd, struct item_package *packa if( package->must_items[i].announce ) clif->package_announce(sd,package->must_items[i].id,package->id); + if ( package->must_items[i].force_serial ) + it.unique_id = itemdb->unique_id(sd); + get_count = itemdb->isstackable(package->must_items[i].id) ? package->must_items[i].qty : 1; it.amount = get_count == 1 ? 1 : get_count; @@ -719,7 +722,7 @@ void itemdb_write_cached_packages(const char *config_filename) { //now we loop into must for(c = 0; c < must_qty; c++) { struct item_package_must_entry *entry = &itemdb->packages[i].must_items[c]; - unsigned char announce = entry->announce == 1 ? 1 : 0, named = entry->named == 1 ? 1 : 0; + unsigned char announce = entry->announce == 1 ? 1 : 0, named = entry->named == 1 ? 1 : 0, force_serial = entry->force_serial == 1 ? 1 : 0; //first 2 byte = item id hwrite(&entry->id,sizeof(entry->id),1,file); //next 2 byte = qty @@ -729,7 +732,9 @@ void itemdb_write_cached_packages(const char *config_filename) { //next 1 byte = announce (1:0) hwrite(&announce,sizeof(announce),1,file); //next 1 byte = named (1:0) - hwrite(&named,sizeof(announce),1,file); + hwrite(&named,sizeof(named),1,file); + //next 1 byte = ForceSerial (1:0) + hwrite(&force_serial,sizeof(force_serial),1,file); } //now we loop into random groups for(c = 0; c < random_qty; c++) { @@ -741,7 +746,7 @@ void itemdb_write_cached_packages(const char *config_filename) { //now we loop into the group's list for(h = 0; h < group_qty; h++) { struct item_package_rand_entry *entry = &itemdb->packages[i].random_groups[c].random_list[h]; - unsigned char announce = entry->announce == 1 ? 1 : 0, named = entry->named == 1 ? 1 : 0; + unsigned char announce = entry->announce == 1 ? 1 : 0, named = entry->named == 1 ? 1 : 0, force_serial = entry->force_serial == 1 ? 1 : 0; //first 2 byte = item id hwrite(&entry->id,sizeof(entry->id),1,file); //next 2 byte = qty @@ -753,7 +758,9 @@ void itemdb_write_cached_packages(const char *config_filename) { //next 1 byte = announce (1:0) hwrite(&announce,sizeof(announce),1,file); //next 1 byte = named (1:0) - hwrite(&named,sizeof(announce),1,file); + hwrite(&named,sizeof(named),1,file); + //next 1 byte = ForceSerial (1:0) + hwrite(&force_serial,sizeof(force_serial),1,file); } } } @@ -807,7 +814,7 @@ bool itemdb_read_cached_packages(const char *config_filename) { for(c = 0; c < package->must_qty; c++) { struct item_package_must_entry *entry = &itemdb->packages[i].must_items[c]; unsigned short mid = 0, qty = 0, hours = 0; - unsigned char announce = 0, named = 0; + unsigned char announce = 0, named = 0, force_serial = 0; struct item_data *data; //first 2 byte = item id hread(&mid,sizeof(mid),1,file); @@ -818,8 +825,10 @@ bool itemdb_read_cached_packages(const char *config_filename) { //next 1 byte = announce (1:0) hread(&announce,sizeof(announce),1,file); //next 1 byte = named (1:0) - hread(&named,sizeof(announce),1,file); - + hread(&named,sizeof(named),1,file); + //next 1 byte = ForceSerial (1:0) + hread(&force_serial,sizeof(force_serial),1,file); + if( !(data = itemdb->exists(mid)) ) ShowWarning("itemdb_read_cached_packages: unknown item '%d' in package '%s'!\n",mid,itemdb_name(package->id)); @@ -828,6 +837,7 @@ bool itemdb_read_cached_packages(const char *config_filename) { entry->qty = qty; entry->announce = announce ? 1 : 0; entry->named = named ? 1 : 0; + entry->force_serial = force_serial ? 1 : 0; } } if( package->random_qty ) { @@ -847,7 +857,7 @@ bool itemdb_read_cached_packages(const char *config_filename) { for(h = 0; h < group_qty; h++) { struct item_package_rand_entry *entry = &itemdb->packages[i].random_groups[c].random_list[h]; unsigned short mid = 0, qty = 0, hours = 0, rate = 0; - unsigned char announce = 0, named = 0; + unsigned char announce = 0, named = 0, force_serial = 0; struct item_data *data; if( prev ) prev->next = entry; @@ -863,8 +873,10 @@ bool itemdb_read_cached_packages(const char *config_filename) { //next 1 byte = announce (1:0) hread(&announce,sizeof(announce),1,file); //next 1 byte = named (1:0) - hread(&named,sizeof(announce),1,file); - + hread(&named,sizeof(named),1,file); + //next 1 byte = ForceSerial (1:0) + hread(&force_serial,sizeof(force_serial),1,file); + if( !(data = itemdb->exists(mid)) ) ShowWarning("itemdb_read_cached_packages: unknown item '%d' in package '%s'!\n",mid,itemdb_name(package->id)); @@ -874,7 +886,7 @@ bool itemdb_read_cached_packages(const char *config_filename) { entry->qty = qty; entry->announce = announce ? 1 : 0; entry->named = named ? 1 : 0; - + entry->force_serial = force_serial ? 1 : 0; prev = entry; } if( prev ) @@ -1020,7 +1032,7 @@ void itemdb_read_packages(void) { c = 0; while( (it = libconfig->setting_get_elem(itg,c++)) ) { int icount = 1, expire = 0, rate = 10000, gid = 0; - bool announce = false, named = false; + bool announce = false, named = false, force_serial = false; itname = config_setting_name(it); @@ -1049,6 +1061,9 @@ void itemdb_read_packages(void) { if( ( t = libconfig->setting_get_member(it, "Named")) && libconfig->setting_get_bool(t) ) named = true; + if( ( t = libconfig->setting_get_member(it, "ForceSerial")) && libconfig->setting_get_bool(t) ) + force_serial = true; + if( !( t = libconfig->setting_get_member(it, "Random") ) ) { ShowWarning("itemdb_read_packages: missing 'Random' field for item '%s' in package '%s', defaulting to must!\n",itname,config_setting_name(itg)); gid = 0; @@ -1061,6 +1076,7 @@ void itemdb_read_packages(void) { itemdb->packages[count].must_items[m].hours = expire; itemdb->packages[count].must_items[m].announce = announce == true ? 1 : 0; itemdb->packages[count].must_items[m].named = named == true ? 1 : 0; + itemdb->packages[count].must_items[m].force_serial = force_serial == true ? 1 : 0; m++; } else { int gidx = gid - 1; @@ -1078,6 +1094,7 @@ void itemdb_read_packages(void) { itemdb->packages[count].random_groups[gidx].random_list[r].hours = expire; itemdb->packages[count].random_groups[gidx].random_list[r].announce = announce == true ? 1 : 0; itemdb->packages[count].random_groups[gidx].random_list[r].named = named == true ? 1 : 0; + itemdb->packages[count].random_groups[gidx].random_list[r].force_serial = force_serial == true ? 1 : 0; itemdb->packages[count].random_groups[gidx].random_qty += 1; prev[gidx] = &itemdb->packages[count].random_groups[gidx].random_list[r]; @@ -1583,14 +1600,15 @@ int itemdb_readdb_sql_sub(Sql *handle, int n, const char *source) { SQL->GetData(handle, 19, &data, NULL); id.flag.no_refine = data && atoi(data) ? 0 : 1; SQL->GetData(handle, 20, &data, NULL); id.look = data ? atoi(data) : 0; SQL->GetData(handle, 21, &data, NULL); id.flag.bindonequip = data && atoi(data) ? 1 : 0; - SQL->GetData(handle, 22, &data, NULL); id.flag.buyingstore = data && atoi(data) ? 1 : 0; - SQL->GetData(handle, 23, &data, NULL); id.delay = data ? atoi(data) : 0; - SQL->GetData(handle, 24, &data, NULL); id.flag.trade_restriction = data ? atoi(data) : ITR_NONE; - SQL->GetData(handle, 25, &data, NULL); id.gm_lv_trade_override = data ? atoi(data) : 0; - SQL->GetData(handle, 26, &data, NULL); id.item_usage.flag = data ? atoi(data) : INR_NONE; - SQL->GetData(handle, 27, &data, NULL); id.item_usage.override = data ? atoi(data) : 0; - SQL->GetData(handle, 28, &data, NULL); id.stack.amount = data ? atoi(data) : 0; - SQL->GetData(handle, 29, &data, NULL); + SQL->GetData(handle, 22, &data, NULL); id.flag.force_serial = data && atoi(data) ? 1 : 0; + SQL->GetData(handle, 23, &data, NULL); id.flag.buyingstore = data && atoi(data) ? 1 : 0; + SQL->GetData(handle, 24, &data, NULL); id.delay = data ? atoi(data) : 0; + SQL->GetData(handle, 25, &data, NULL); id.flag.trade_restriction = data ? atoi(data) : ITR_NONE; + SQL->GetData(handle, 26, &data, NULL); id.gm_lv_trade_override = data ? atoi(data) : 0; + SQL->GetData(handle, 27, &data, NULL); id.item_usage.flag = data ? atoi(data) : INR_NONE; + SQL->GetData(handle, 28, &data, NULL); id.item_usage.override = data ? atoi(data) : 0; + SQL->GetData(handle, 29, &data, NULL); id.stack.amount = data ? atoi(data) : 0; + SQL->GetData(handle, 30, &data, NULL); if (data) { int stack_flag = atoi(data); id.stack.inventory = (stack_flag&1)!=0; @@ -1657,6 +1675,7 @@ int itemdb_readdb_libconfig_sub(config_setting_t *it, int n, const char *source) * BindOnEquip: (true or false) * BuyingStore: (true or false) * Delay: Delay to use item + * ForceSerial: (true or false) * Trade: { * override: Group to override * nodrop: (true or false) @@ -1790,6 +1809,9 @@ int itemdb_readdb_libconfig_sub(config_setting_t *it, int n, const char *source) if( (t = libconfig->setting_get_member(it, "BindOnEquip")) ) id.flag.bindonequip = libconfig->setting_get_bool(t) ? 1 : 0; + + if( (t = libconfig->setting_get_member(it, "ForceSerial")) ) + id.flag.force_serial = libconfig->setting_get_bool(t) ? 1 : 0; if ( (t = libconfig->setting_get_member(it, "BuyingStore")) ) id.flag.buyingstore = libconfig->setting_get_bool(t) ? 1 : 0; @@ -1992,7 +2014,7 @@ int itemdb_readdb_sql(const char *tablename) { " `matk`, `defence`, `range`, `slots`," " `equip_jobs`, `equip_upper`, `equip_genders`, `equip_locations`," " `weapon_level`, `equip_level_min`, `equip_level_max`, `refineable`," - " `view`, `bindonequip`, `buyingstore`, `delay`," + " `view`, `bindonequip`, `forceserial`, `buyingstore`, `delay`," " `trade_flag`, `trade_group`, `nouse_flag`, `nouse_group`," " `stack_amount`, `stack_flag`, `sprite`, `script`," " `equip_script`, `unequip_script`" diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 624080c3a..e50ebfd3d 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -398,6 +398,7 @@ struct item_package_rand_entry { unsigned short hours; unsigned int announce : 1; unsigned int named : 1; + unsigned int force_serial: 1; struct item_package_rand_entry *next; }; @@ -407,6 +408,7 @@ struct item_package_must_entry { unsigned short hours; unsigned int announce : 1; unsigned int named : 1; + unsigned int force_serial : 1; }; struct item_package_rand_group { @@ -466,6 +468,7 @@ struct item_data { unsigned buyingstore : 1; unsigned bindonequip : 1; unsigned keepafteruse : 1; + unsigned force_serial : 1; } flag; struct {// item stacking limitation unsigned short amount; diff --git a/src/map/packets.h b/src/map/packets.h index 53278f66e..6623c091c 100644 --- a/src/map/packets.h +++ b/src/map/packets.h @@ -448,6 +448,8 @@ packet(0x020a,10); //packet(0x020b,-1); //packet(0x020c,-1); packet(0x020d,-1); +packet(0x974,2,clif->cancelmergeitem); +packet(0x96e,-1,clif->ackmergeitems); //2004-07-05aSakexe #if PACKETVER >= 20040705 diff --git a/src/map/pc.c b/src/map/pc.c index 9e9f993d0..4dac559e2 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -4448,6 +4448,7 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l if( sd->status.inventory[i].nameid == item_data->nameid && sd->status.inventory[i].bound == item_data->bound && sd->status.inventory[i].expire_time == 0 && + sd->status.inventory[i].unique_id == item_data->unique_id && 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; @@ -4475,8 +4476,8 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount,e_l clif->additem(sd,i,amount,0); } - if( !itemdb->isstackable2(data) && !item_data->unique_id ) - sd->status.inventory[i].unique_id = itemdb->unique_id(sd); + if( ( !itemdb->isstackable2(data) || data->flag.force_serial || data->type == IT_CASH) && !item_data->unique_id ) + sd->status.inventory[i].unique_id = itemdb->unique_id(sd); logs->pick_pc(sd, log_type, amount, &sd->status.inventory[i],sd->inventory_data[i]); @@ -5028,7 +5029,7 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun sd->status.cart[i].card[2] == item_data->card[2] && sd->status.cart[i].card[3] == item_data->card[3] ); }; - if( i < MAX_CART ) + if( i < MAX_CART && item_data->unique_id == sd->status.cart[i].unique_id) {// item already in cart, stack it if( amount > MAX_AMOUNT - sd->status.cart[i].amount || ( data->stack.cart && amount > data->stack.amount - sd->status.cart[i].amount ) ) return 2; // no room diff --git a/src/map/script.c b/src/map/script.c index 47ac151ed..f2fce3a8f 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -19691,6 +19691,17 @@ BUILDIN(showscript) { return true; } +BUILDIN(mergeitem) +{ + struct map_session_data *sd = script->rid2sd(st); + + if (sd == NULL) + return true; + + clif->openmergeitem(sd->fd, sd); + + return true; +} /** place holder for the translation macro **/ BUILDIN(_) { return true; @@ -20329,6 +20340,7 @@ void script_parse_builtin(void) { BUILDIN_DEF(channelmes, "ss"), BUILDIN_DEF(showscript, "s?"), + BUILDIN_DEF(mergeitem,""), BUILDIN_DEF(_,"s"), }; int i, len = ARRAYLENGTH(BUILDIN); diff --git a/src/map/storage.c b/src/map/storage.c index 0a22b9ec6..95194bc47 100644 --- a/src/map/storage.c +++ b/src/map/storage.c @@ -109,7 +109,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 ) + a->bound == b->bound && + a->unique_id == b->unique_id) { int i; for (i = 0; i < MAX_SLOTS && (a->card[i] == b->card[i]); i++); @@ -155,6 +156,7 @@ int storage_additem(struct map_session_data* sd, struct item* item_data, int amo {// existing items found, stack them if( amount > MAX_AMOUNT - stor->items[i].amount || ( data->stack.storage && amount > data->stack.amount - stor->items[i].amount ) ) return 1; + stor->items[i].amount += amount; clif->storageitemadded(sd,&stor->items[i],i,amount); return 0; diff --git a/src/plugins/db2sql.c b/src/plugins/db2sql.c index 7cef173d2..2741ce468 100644 --- a/src/plugins/db2sql.c +++ b/src/plugins/db2sql.c @@ -139,7 +139,10 @@ int db2sql(config_setting_t *entry, int n, const char *source) { // bindonequip StrBuf->Printf(&buf, "'%u',", it->flag.bindonequip?1:0); - + + // forceserial + StrBuf->Printf(&buf, "'%u',", it->flag.force_serial?1:0); + // buyingstore StrBuf->Printf(&buf, "'%u',", it->flag.buyingstore?1:0); @@ -269,6 +272,7 @@ void totable(void) { " `refineable` tinyint(1) UNSIGNED DEFAULT NULL,\n" " `view` smallint(3) UNSIGNED DEFAULT NULL,\n" " `bindonequip` tinyint(1) UNSIGNED DEFAULT NULL,\n" + " `forceserial` tinyint(1) UNSIGNED DEFAULT NULL,\n" " `buyingstore` tinyint(1) UNSIGNED DEFAULT NULL,\n" " `delay` mediumint(9) UNSIGNED DEFAULT NULL,\n" " `trade_flag` smallint(4) UNSIGNED DEFAULT NULL,\n" -- cgit v1.2.3-70-g09d2