Merge pull request #143 from rathena/feature/separated_item_guid

Corrected `guid` implementation of item package in 51074a0. See http://rathena.org/board/topic/99743-item-guid/
This commit is contained in:
Cydh Ramdh 2014-12-16 20:26:16 +07:00
commit 7295bdc925
16 changed files with 469 additions and 43 deletions

View File

@ -4,4 +4,5 @@
// <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
// 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

@ -4,6 +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
// NOTE: For removing flag by import file, use "-" to remove the flag. Example, 604,-1 will removes flag 1 from Branch_Of_Dead_Tree
// Logged as Dead Branch item

View File

@ -4,6 +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
// NOTE: For removing flag by import file, use "-" to remove the flag. Example, 604,-1 will removes flag 1 from Branch_Of_Dead_Tree
// Logged as Dead Branch item
@ -213,11 +214,19 @@
13909,2 //MVP_Hunt_Box
13910,2 //Brewing_Box
13911,2 //Christmas_Pet_Scroll
13925,2 //Lucky_Scroll08
13945,2 //Br_SwordPackage
13946,2 //Br_MagePackage
13947,2 //Br_AcolPackage
13948,2 //Br_ArcherPackage
13949,2 //Br_MerPackage
13950,2 //Br_ThiefPackage
13953,2 //All_In_One_Ring_Box
13989,2 //Acidbomb_10_Box
14001,2 //Basic_Siege_Supply_Box
14002,2 //Adv_Siege_Supply_Box
14003,2 //Elite_Siege_Supply_Box
14229,2 //Sakura_Scroll
14242,2 //Beholder_Ring_Box
14243,2 //Hallow_Ring_Box
14244,2 //Clamorous_Ring_Box
@ -242,6 +251,7 @@
14469,2 //Ox_Tail_Scroll
14596,2 //Pierre_Treasurebox
14613,2 //RWC_Scroll_2012
14624,2 //Blue_Scroll
14626,2 //Indigo_Scroll
14643,2 //Violet_Scroll
14664,2 //Bi_Hwang_Scroll
@ -366,3 +376,259 @@
22558,2 //Lucky_Bag
22669,2 //HALLOWEEN_G_BOX
22685,2 //Solo_Christmas_Gift
// GUID
12915,4 //Aspersio_5_Scroll_Box
12923,4 //Pet_Egg_Scroll_Box1
12924,4 //Pet_Egg_Scroll_Box2
12925,4 //Pet_Egg_Scroll1
12926,4 //Pet_Egg_Scroll2
12929,4 //Pet_Egg_Scroll_Box3
12930,4 //Pet_Egg_Scroll_Box4
12931,4 //Pet_Egg_Scroll_Box5
12932,4 //Pet_Egg_Scroll3
12933,4 //Pet_Egg_Scroll4
12934,4 //Pet_Egg_Scroll5
12935,4 //Infiltrator_Box
12936,4 //Muramasa_Box
12937,4 //Excalibur_Box
12938,4 //Combat_Knife_Box
12939,4 //Counter_Dagger_Box
12940,4 //Kaiser_Knuckle_Box
12941,4 //Pole_Axe_Box
12942,4 //Mighty_Staff_Box
12943,4 //Right_Epsilon_Box
12944,4 //Balistar_Box
12945,4 //Diary_Of_Great_Sage_Box
12946,4 //Asura_Box
12947,4 //Apple_Of_Archer_Box
12948,4 //Bunny_Band_Box
12949,4 //Sahkkat_Box
12950,4 //Lord_Circlet_Box
12951,4 //Elven_Ears_Box
12952,4 //Steel_Flower_Box
12953,4 //Critical_Ring_Box
12954,4 //Earring_Box
12955,4 //Ring_Box
12956,4 //Necklace_Box
12957,4 //Glove_Box
12958,4 //Brooch_Box
12959,4 //Rosary_Box
12960,4 //Safety_Ring_Box
12961,4 //Vesper_Core01_Box
12962,4 //Vesper_Core02_Box
12963,4 //Vesper_Core03_Box
12964,4 //Vesper_Core04_Box
12983,4 //Pet_Egg_Scroll_Box6
12984,4 //Pet_Egg_Scroll_Box7
12985,4 //Pet_Egg_Scroll_Box8
12986,4 //Pet_Egg_Scroll_Box9
12987,4 //Pet_Egg_Scroll_Box10
12988,4 //Pet_Egg_Scroll_Box11
12989,4 //Pet_Egg_Scroll6
12990,4 //Pet_Egg_Scroll7
12991,4 //Pet_Egg_Scroll8
12992,4 //Pet_Egg_Scroll9
12993,4 //Pet_Egg_Scroll10
12994,4 //Pet_Egg_Scroll11
13543,4 //CP_Helm_Scroll_Box
13544,4 //CP_Shield_Scroll_Box
13545,4 //CP_Armor_Scroll_Box
13546,4 //CP_Weapon_Scroll_Box
13547,4 //Repair_Scroll_Box
13617,4 //Super_Pet_Egg1
13618,4 //Super_Pet_Egg2
13619,4 //Super_Pet_Egg3
13620,4 //Super_Pet_Egg4
13630,4 //Super_Card_Pet_Egg1
13631,4 //Super_Card_Pet_Egg2
13632,4 //Super_Card_Pet_Egg3
13633,4 //Super_Card_Pet_Egg4
13634,4 //Vigorgra_Package1
13635,4 //Vigorgra_Package2
13636,4 //Vigorgra_Package3
13637,4 //Vigorgra_Package4
13638,4 //Vigorgra_Package5
13639,4 //Vigorgra_Package6
13640,4 //Vigorgra_Package7
13641,4 //Vigorgra_Package8
13642,4 //Vigorgra_Package9
13643,4 //Vigorgra_Package10
13644,4 //Vigorgra_Package11
13645,4 //Vigorgra_Package12
13701,4 //Pet_Egg_Scroll12
13702,4 //Pet_Egg_Scroll13
13703,4 //Pet_Egg_Scroll14
13704,4 //Super_Pet_Egg5
13705,4 //Super_Pet_Egg6
13706,4 //Super_Pet_Egg7
13707,4 //Super_Pet_Egg8
13708,4 //Pet_Egg_Scroll_E
13725,4 //Ramen_Hat_Box
13773,4 //Fire_Brand_Box
13845,4 //Mysterious_Travel_Sack1
13846,4 //Mysterious_Travel_Sack2
13847,4 //Mysterious_Travel_Sack3
13848,4 //Mysterious_Travel_Sack4
13871,4 //Magician_Card_Box
13872,4 //Acolyte_Card_Box
13873,4 //Archer_Card_Box
13874,4 //Swordman_Card_Box
13875,4 //Thief_Card_Box
13876,4 //Merchant_Card_Box
13905,4 //Hard_Core_Set_Box
13906,4 //Kitty_Set_Box
13907,4 //Soft_Core_Set_Box
13908,4 //Deviruchi_Set_Box
13909,4 //MVP_Hunt_Box
13910,4 //Brewing_Box
13911,4 //Christmas_Pet_Scroll
13925,4 //Lucky_Scroll08
13945,4 //Br_SwordPackage
13946,4 //Br_MagePackage
13947,4 //Br_AcolPackage
13948,4 //Br_ArcherPackage
13949,4 //Br_MerPackage
13950,4 //Br_ThiefPackage
13953,4 //All_In_One_Ring_Box
13989,4 //Acidbomb_10_Box
14001,4 //Basic_Siege_Supply_Box
14002,4 //Adv_Siege_Supply_Box
14003,4 //Elite_Siege_Supply_Box
14229,4 //Sakura_Scroll
14242,4 //Beholder_Ring_Box
14243,4 //Hallow_Ring_Box
14244,4 //Clamorous_Ring_Box
14245,4 //Chemical_Ring_Box
14246,4 //Insecticide_Ring_Box
14247,4 //Fisher_Ring_Box
14248,4 //Decussate_Ring_Box
14249,4 //Bloody_Ring_Box
14250,4 //Satanic_Ring_Box
14251,4 //Dragoon_Ring_Box
14296,4 //Angel_Scroll
14297,4 //Devil_Scroll
14298,4 //Surprise_Scroll
14306,4 //RWC_Special_Scroll
14307,4 //RWC_Limited_Scroll
14316,4 //July7_Scroll
14317,4 //Bacsojin_Scroll
14345,4 //Animal_Scroll
14363,4 //Heart_Scroll
14408,4 //New_Year_Scroll
14466,4 //Valentine_Pledge_Box
14469,4 //Ox_Tail_Scroll
16245,4 //Tw_April_Scroll
16304,4 //Evil_Incarnation
16371,4 //Tw_Aug_Scroll
16372,4 //F_Clover_Box_Mouth
16374,4 //Mouth_Bubble_Gum_Box
16385,4 //F_Clover_Box_Mouth2
16386,4 //F_Clover_Box_Mouth4
16389,4 //BGum_Box_In_Mouth2
16390,4 //BGum_Box_In_Mouth4
16409,4 //Tw_Sep_Scroll
16446,4 //Tw_October_Scroll
16456,4 //My_Scroll1
16457,4 //Tw_Nov_Scroll
16466,4 //My_Scroll2
16542,4 //Xmas_Bless
16555,4 //Pr_Reset_Stone_Box
16556,4 //FPr_Reset_Stone_Box
16562,4 //Majestic_Devil_Scroll
16576,4 //Illusion_Nothing
16638,4 //Life_Ribbon_Box
16639,4 //Life_Ribbon_Box2
16640,4 //Life_Ribbon_Box3
16652,4 //Flame_Light
16666,4 //Magic_Candy_Box10
16673,4 //Libra_Scroll
16675,4 //Splash_Scroll
16681,4 //BR_Independence_Scroll
16682,4 //Boarding_Halter_Box
16687,4 //RWC2010_SuitcaseA
16688,4 //RWC2010_SuitcaseB
16741,4 //Hairtail_Box1
16742,4 //Hairtail_Box2
16743,4 //Spearfish_Box1
16744,4 //Spearfish_Box2
16745,4 //Saurel_Box1
16746,4 //Saurel_Box2
16747,4 //Tuna_Box1
16748,4 //Tuna_Box2
16749,4 //Malang_Crab_Box1
16750,4 //Malang_Crab_Box2
16751,4 //Brindle_Eel_Box1
16752,4 //Brindle_Eel_Box2
16757,4 //Hallo_Scroll
16760,4 //Umbala_Spirit_Box2
16761,4 //F_Umbala_Spirit_Box2
16763,4 //Ptotection_Seagod_Box2
16764,4 //Ptotection_Seagod_Box3
16765,4 //Octo_Hstick_Box
16766,4 //Octo_Hstick_Box2
16767,4 //Octo_Hstick_Box3
16770,4 //Silvervine_Fruit_Box10
16771,4 //Silvervine_Fruit_Box40
16774,4 //Asgard_Scroll
16775,4 //Sagittarius_Scroll
16826,4 //Sagittarius_Scr_Box
16972,4 //Weather_Report_Box
16974,4 //Comin_Actor_Box
16976,4 //Hen_Set_Box
16979,4 //Silvervine_Fruit_Box4
16990,4 //Sagittar_Diadem_Scroll
16991,4 //Sagittar_Di_Scroll_Box
16996,4 //Capri_Crown_Scroll
16997,4 //Capri_Crown_Scroll_Box
17011,4 //Capricon_Di_Scroll
17012,4 //Capricon_Di_Scroll_Box
17013,4 //Malang_Woe_Encard_Box
17016,4 //Aquarius_Diadem_Scroll
17017,4 //Aquarius_Di_Scroll_Box
17020,4 //Tw_Nov_Scroll2
17021,4 //Summer_Scroll3
17022,4 //Super_Pet_Egg1_2
17023,4 //Super_Pet_Egg4_2
17024,4 //Lovely_Aquarius_Scroll
17025,4 //Lovely_Aquarius_Box
17026,4 //Boitata_Scroll
17028,4 //Pisces_Diadem_Scroll
17029,4 //Pisces_Diadem_Box
17035,4 //Energetic_Pisces_Scroll
17036,4 //Energetic_Pisces_Box
17050,4 //Aries_Scroll
17051,4 //Aries_Scroll_Box
17062,4 //Taurus_Diadem_Scroll
17063,4 //Taurus_Di_Scroll_Box
17077,4 //Taurus_Crown_Scroll
17078,4 //Taurus_Crown_Scroll_Box
17082,4 //Gemi_Diadem_Scroll
17083,4 //Gemi_Diadem_Scroll_Box
17107,4 //Gemi_Crown_Scroll
17108,4 //Gemi_Crown_Scroll_Box
17138,4 //Ms_Cancer_Scroll
17139,4 //RWC_Super_Scroll
17140,4 //Leo_Scroll
17141,4 //Ms_Virgo_Scroll
17143,4 //Ms_Scorpio_Scroll
17156,4 //TCG_Card_Scroll
17165,4 //Challenge_Kit
17209,4 //Tw_Rainbow_Scroll
17210,4 //Tw_Red_Scroll
17211,4 //Tw_Orange_Scroll
17212,4 //Tw_Yellow_Scroll
17233,4 //Scroll_Of_Death
17234,4 //Scroll_Of_Life
17235,4 //Scroll_Of_Magic
17236,4 //Scroll_Of_Thews
17237,4 //Scroll_Of_Darkness
17238,4 //Scroll_Of_Holiness
17239,4 //Horned_Scroll
17240,4 //Mercury_Scroll
17251,4 //C_Wing_Of_Fly_3Day_Box
17252,4 //RWC_2012_Set_Box
17256,4 //Good_Student_Gift_Box
17257,4 //Bad_Student_Gift_Box
17262,4 //Ex_Def_Potion_Box
22558,4 //Lucky_Bag

View File

@ -1,7 +1,7 @@
// Item Package Database
//
// Structure of Database:
// GroupID,ItemID,Rate{,Amount,Random,isAnnounced,Duration,isNamed,isBound}
// GroupID,ItemID,Rate{,Amount,Random,isAnnounced,Duration,GUID,isBound,isNamed}
IG_Special_Box,Wrapped_Mask,3,1,1
IG_Special_Box,Poison_Bottle,10,2,1

View File

@ -29,10 +29,12 @@ accessed in each.
+===============+====================+================+
| Duration | no | YES |
+===============+====================+================+
| isNamed | no | YES |
| GUID | no | YES |
+===============+====================+================+
| isBound | no | YES |
+===============+====================+================+
| isNamed | no | YES |
+===============+====================+================+
---------------------------------------
@ -117,7 +119,12 @@ Duration: Makes the item a rental item, which will be expire in the given amount
---------------------------------------
isNamed: Inscribes the item with the obtainer's name.
GUID: Makes the given item(s) with Unique ID. Item will be stacked ONLY each group
when it obtained. Cannot be stacked with same item, even it's stackable item.
Example, there is Box (just call it Apple_Box) that contains 3x Apples with
GUID = 1. When Apples appear it will stack for each 3 even another 3x Apples
are appeared by same box. So it will be filled in inventory as:
3x Apples | 3x Apples | so on... | nx Apples (normal)
---------------------------------------
@ -126,6 +133,10 @@ isBound: Binds the obtained item.
---------------------------------------
isNamed: Inscribes the item with the obtainer's name.
---------------------------------------
Supports to import other file, usage:
import: db/path/filename.txt

View File

@ -2841,6 +2841,17 @@ Returns value from equipped item slot in the indicated slot (0, 1, 2, or 3).
This function returns CARD ID, 255,254,-255 (for card 0, if the item is produced).
It's useful for when you want to check whether an item contains cards or if it's signed.
---------------------------------------
*mergeitem({<item_id>});
*mergeitem({"<item name>"});
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

@ -3,7 +3,7 @@
//===== By: ==================================================
//= Euphy
//===== Current Version: =====================================
//= 1.0
//= 1.1
//===== Compatible With: =====================================
//= rAthena Project
//===== Description: =========================================
@ -12,6 +12,7 @@
//= inventory.
//===== Additional Comments: =================================
//= 1.0 First version, currently useless/disabled.
//= 1.1 Implemented the 'mergeitem' script command. [Cydh]
//============================================================
prontera,146,95,3 script Mergician#pron 64,{
@ -55,7 +56,7 @@ prontera,146,95,3 script Mergician#pron 64,{
next;
switch(select("Merrrrge!:Don't follow what he says.")) {
case 1:
// MergeItem
mergeitem;
mes "[Mergician]";
mes "Merge just heard your wish and let it be realised!";
mes "Open your inventory to check the miracle!";

View File

@ -90,7 +90,7 @@ npc: npc/re/merchants/shops.txt
// --------------------------- Others ---------------------------
npc: npc/re/other/bulletin_boards.txt
//npc: npc/re/other/item_merge.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

View File

@ -64,6 +64,14 @@
/// 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

@ -1271,7 +1271,6 @@ ACMD_FUNC(item)
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);
}

View File

@ -13207,8 +13207,14 @@ void clif_parse_GM_Item_Monster(int fd, struct map_session_data *sd)
StringBuf_Init(&command);
if( !itemdb_isstackable2(id) ) //Nonstackable
StringBuf_Printf(&command, "%citem2 %d 1 0 0 0 0 0 0 0", atcommand_symbol, id->nameid);
else
StringBuf_Printf(&command, "%citem %d 20", 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);
StringBuf_Destroy(&command);
return;

View File

@ -13,6 +13,7 @@
#include "cashshop.h"
#include "script.h" // item script processing
#include "pc.h" // W_MUSICAL, W_WHIP
#include "intif.h"
#include <stdio.h>
#include <stdlib.h>
@ -198,12 +199,17 @@ 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)))
clif_additem(sd, 0, 0, flag);
else if (!flag && data->isAnnounced) { ///TODO: Move this broadcast to proper behavior (it should on at different packet)
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));
clif_broadcast(&sd->bl, output, strlen(output), BC_DEFAULT, ALL_CLIENT);
//! TODO: Move this broadcast to proper packet
intif_broadcast(output, strlen(output) + 1, BC_DEFAULT);
//clif_broadcast_obtain_special_item();
}
if (itemdb_isstackable(data->nameid))
@ -438,17 +444,17 @@ bool itemdb_isequip2(struct item_data *id)
*/
bool itemdb_isstackable2(struct item_data *id)
{
nullpo_ret(id);
switch(id->type) {
case IT_WEAPON:
case IT_ARMOR:
case IT_PETEGG:
case IT_PETARMOR:
case IT_SHADOWGEAR:
return false;
default:
return true;
}
nullpo_ret(id);
switch(id->type) {
case IT_WEAPON:
case IT_ARMOR:
case IT_PETEGG:
case IT_PETARMOR:
case IT_SHADOWGEAR:
return false;
default:
return true;
}
}
@ -557,7 +563,7 @@ static bool itemdb_read_itemavail(char* str[], int columns, int current) {
}
/** Read item group data
* Structure: GroupID,ItemID,Rate{,Amount,isMust,isAnnounced,Duration,isNamed,isBound}
* Structure: GroupID,ItemID,Rate{,Amount,isMust,isAnnounced,Duration,GUID,isBound,isNamed}
*/
static void itemdb_read_itemgroup_sub(const char* filename, bool silent)
{
@ -574,7 +580,7 @@ static void itemdb_read_itemgroup_sub(const char* filename, bool silent)
int group_id = -1;
unsigned int j, prob = 1;
uint8 rand_group = 1;
char *str[9], *p;
char *str[10], *p;
struct s_item_group_random *random = NULL;
struct s_item_group_db *group = NULL;
struct s_item_group_entry entry;
@ -658,8 +664,11 @@ 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);
if (str[7] != NULL) entry.isNamed = atoi(str[7]);
#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]);
if (!(group = (struct s_item_group_db *) uidb_get(itemdb_group, group_id))) {
CREATE(group, struct s_item_group_db, 1);
@ -894,6 +903,7 @@ static bool itemdb_read_nouse(char* fields[], int columns, int current) {
* <item_id>,<flag>
* &1 - As dead branch item
* &2 - As item container
* &4 - GUID item, cannot be stacked even same or stackable item
*/
static bool itemdb_read_flag(char* fields[], int columns, int current) {
unsigned short nameid = atoi(fields[0]);
@ -911,6 +921,9 @@ 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
return true;
}

View File

@ -345,6 +345,7 @@ struct s_item_group_entry
duration, /// Duration if item as rental item (in minutes)
amount; /// Amount of item will be obtained
bool isAnnounced, /// Broadcast if player get this item
GUID, /// Gives Unique ID for items in each box opened
isNamed; /// Named the item (if possible)
char bound; /// Makes the item as bound item (according to bound type)
};
@ -414,6 +415,7 @@ struct item_data
unsigned buyingstore : 1;
unsigned dead_branch : 1; // As dead branch item. Logged at `branchlog` table and cannot be used at 'nobranch' mapflag [Cydh]
unsigned group : 1; // As item group container [Cydh]
unsigned guid : 1; // This item always be attached with GUID and make it as bound item! [Cydh]
} flag;
struct {// item stacking limitation
unsigned short amount;

View File

@ -4289,13 +4289,23 @@ 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 ) {
for( i = 0; i < MAX_INVENTORY; i++ ) {
if( sd->status.inventory[i].nameid == item->nameid &&
sd->status.inventory[i].bound == item->bound &&
sd->status.inventory[i].expire_time == 0 &&
memcmp(&sd->status.inventory[i].card, &item->card, sizeof(item->card)) == 0 ) {
sd->status.inventory[i].bound == item->bound &&
sd->status.inventory[i].expire_time == 0 &&
#ifdef ENABLE_ITEM_GUID
sd->status.inventory[i].unique_id == item->unique_id &&
#endif
memcmp(&sd->status.inventory[i].card, &item->card, sizeof(item->card)) == 0
)
{
if( amount > MAX_AMOUNT - sd->status.inventory[i].amount || ( id->stack.inventory && amount > id->stack.amount - sd->status.inventory[i].amount ) )
return ADDITEM_OVERAMOUNT;
sd->status.inventory[i].amount += amount;
@ -4324,7 +4334,7 @@ char pc_additem(struct map_session_data *sd,struct item *item,int amount,e_log_p
clif_additem(sd,i,amount,0);
}
if( !itemdb_isstackable2(id) && !item->unique_id )
sd->status.inventory[i].unique_id = pc_generate_unique_id(sd);
item->unique_id = pc_generate_unique_id(sd);
log_pick_pc(sd, log_type, amount, &sd->status.inventory[i]);
sd->weight += w;
@ -4858,11 +4868,17 @@ unsigned char pc_cart_additem(struct map_session_data *sd,struct item *item,int
i = MAX_CART;
if( itemdb_isstackable2(data) && !item->expire_time )
{
ARR_FIND( 0, MAX_CART, i,
sd->status.cart[i].nameid == item->nameid && sd->status.cart[i].bound == item->bound &&
sd->status.cart[i].card[0] == item->card[0] && sd->status.cart[i].card[1] == item->card[1] &&
sd->status.cart[i].card[2] == item->card[2] && sd->status.cart[i].card[3] == item->card[3] );
};
for (i = 0; i < MAX_CART; i++) {
if (sd->status.cart[i].nameid == item->nameid
&& sd->status.cart[i].bound == item->bound
#ifdef ENABLE_ITEM_GUID
&& sd->status.cart[i].unique_id == item->unique_id
#endif
&& memcmp(sd->status.cart[i].card, item->card, sizeof(item->card)) == 0
)
break;
}
}
if( i < MAX_CART )
{// item already in cart, stack it
@ -11274,6 +11290,7 @@ bool pc_is_same_equip_index(enum equip_index eqi, short *equip_index, short inde
* @return A generated Unique item ID
*/
uint64 pc_generate_unique_id(struct map_session_data *sd) {
nullpo_ret(sd);
return ((uint64)sd->status.char_id << 32) | sd->status.uniqueitem_counter++;
}

View File

@ -6497,20 +6497,21 @@ BUILDIN_FUNC(getitem)
struct script_data *data;
unsigned char flag = 0;
const char* command = script_getfuncname(st);
struct item_data *id = NULL;
data=script_getdata(st,2);
data = script_getdata(st,2);
get_val(st,data);
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 ){
id = itemdb_searchname(name);
if( id == NULL ){
ShowError("buildin_getitem: Nonexistant item %s requested.\n", name);
return SCRIPT_CMD_FAILURE; //No item created.
}
nameid = item_data->nameid;
nameid = id->nameid;
} else if( data_isint(data) ) {// <item id>
nameid = conv_num(st,data);
if( !itemdb_exists(nameid) ){
if( !(id = itemdb_exists(nameid)) ){
ShowError("buildin_getitem: Nonexistant item %d requested.\n", nameid);
return SCRIPT_CMD_FAILURE; //No item created.
}
@ -6548,7 +6549,7 @@ BUILDIN_FUNC(getitem)
return SCRIPT_CMD_SUCCESS;
//Check if it's stackable.
if (!itemdb_isstackable(nameid))
if (!itemdb_isstackable2(id))
get_count = 1;
else
get_count = amount;
@ -6666,7 +6667,7 @@ BUILDIN_FUNC(getitem2)
item_tmp.bound = bound;
//Check if it's stackable.
if (!itemdb_isstackable(nameid))
if (!itemdb_isstackable2(item_data))
get_count = 1;
else
get_count = amount;
@ -19111,6 +19112,89 @@ BUILDIN_FUNC(countspiritball) {
return SCRIPT_CMD_SUCCESS;
}
/** Merges separated stackable items because of guid
* mergeitem {<item_id>};
* mergeitem {"<item name>"};
* @param item Item ID/Name for merging specific item (Optional)
* @author [Cydh]
*/
BUILDIN_FUNC(mergeitem) {
struct map_session_data *sd = script_rid2sd(st);
struct item *items;
uint16 i, count = 0;
int nameid = 0;
if (!sd)
return SCRIPT_CMD_SUCCESS;
if (script_hasdata(st, 2)) {
struct script_data *data = script_getdata(st, 2);
struct item_data *id;
get_val(st, data);
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);
script_pushint(st, count);
return SCRIPT_CMD_FAILURE;
}
nameid = id->nameid;
}
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);
script_pushint(st, count);
return SCRIPT_CMD_FAILURE;
}
}
}
for (i = 0; i < MAX_INVENTORY; i++) {
struct item *it = &sd->status.inventory[i];
if (!it || !it->unique_id || it->expire_time || !itemdb_isstackable(it->nameid))
continue;
if ((!nameid || (nameid == it->nameid))) {
uint8 k;
if (!count) {
CREATE(items, struct item, 1);
memcpy(&items[count++], it, sizeof(struct item));
pc_delitem(sd, i, it->amount, 0, 0, LOG_TYPE_NPC);
continue;
}
for (k = 0; k < count; k++) {
// Find Match
if (&items[k] && items[k].nameid == it->nameid && items[k].bound == it->bound && memcmp(items[k].card, it->card, sizeof(it->card)) == 0) {
items[k].amount += it->amount;
pc_delitem(sd, i, it->amount, 0, 0, LOG_TYPE_NPC);
break;
}
}
if (k >= count) {
// New entry
RECREATE(items, struct item, count+1);
memcpy(&items[count++], it, sizeof(struct item));
pc_delitem(sd, i, it->amount, 0, 0, LOG_TYPE_NPC);
}
}
}
// Retrieve the items
for (i = 0; i < count; i++) {
uint8 flag = 0;
if (!&items[i])
continue;
items[i].id = 0;
items[i].unique_id = 0;
if ((flag = pc_additem(sd, &items[i], items[i].amount, LOG_TYPE_NPC)))
clif_additem(sd, i, items[i].amount, flag);
}
aFree(items);
script_pushint(st, count);
return SCRIPT_CMD_SUCCESS;
}
#include "../custom/script.inc"
// declarations that were supposed to be exported from npc_chat.c
@ -19653,6 +19737,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(addspiritball,"ii?"),
BUILDIN_DEF(delspiritball,"i?"),
BUILDIN_DEF(countspiritball,"?"),
BUILDIN_DEF(mergeitem,"?"),
#include "../custom/script_def.inc"

View File

@ -131,7 +131,7 @@ int storage_storageopen(struct map_session_data *sd)
}
/**
* check if 2 item a and b have same values
* Check if 2 item a and b have same values
* @param a : item 1
* @param b : item 2
* @return 1:same, 0:are different
@ -143,7 +143,12 @@ 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
#ifdef ENABLE_ITEM_GUID
&& a->unique_id == b->unique_id
#endif
)
{
int i;
for (i = 0; i < MAX_SLOTS && (a->card[i] == b->card[i]); i++);