diff options
author | Haruna <haru@dotalux.com> | 2015-07-08 03:39:36 +0200 |
---|---|---|
committer | Haruna <haru@dotalux.com> | 2015-07-08 03:39:36 +0200 |
commit | 041e0625b543215e8b319fc4ef32fa24cd199656 (patch) | |
tree | 4f36abbb84364ad48c53f1f8bc6db007b01a20f6 /src/map | |
parent | 5fd40de233d3a897284f771338cbf8e657182261 (diff) | |
parent | 856b6f1feb25ca74d716a4c22fff650e0ff065a0 (diff) | |
download | hercules-041e0625b543215e8b319fc4ef32fa24cd199656.tar.gz hercules-041e0625b543215e8b319fc4ef32fa24cd199656.tar.bz2 hercules-041e0625b543215e8b319fc4ef32fa24cd199656.tar.xz hercules-041e0625b543215e8b319fc4ef32fa24cd199656.zip |
Merge pull request #586 from hemagx/master
Update UID system to match official and Implement Merger
Diffstat (limited to 'src/map')
-rw-r--r-- | src/map/clif.c | 157 | ||||
-rw-r--r-- | src/map/clif.h | 21 | ||||
-rw-r--r-- | src/map/itemdb.c | 64 | ||||
-rw-r--r-- | src/map/itemdb.h | 3 | ||||
-rw-r--r-- | src/map/packets.h | 2 | ||||
-rw-r--r-- | src/map/pc.c | 7 | ||||
-rw-r--r-- | src/map/script.c | 12 | ||||
-rw-r--r-- | src/map/storage.c | 4 |
8 files changed, 245 insertions, 25 deletions
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; |