summaryrefslogtreecommitdiff
path: root/src/map/storage.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/storage.c')
-rw-r--r--src/map/storage.c283
1 files changed, 190 insertions, 93 deletions
diff --git a/src/map/storage.c b/src/map/storage.c
index f938a41ad..01e7c7c27 100644
--- a/src/map/storage.c
+++ b/src/map/storage.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -52,8 +52,8 @@ struct guild_storage_interface *gstorage;
*------------------------------------------*/
int storage_comp_item(const void *i1_, const void *i2_)
{
- struct item *i1 = (struct item *)i1_;
- struct item *i2 = (struct item *)i2_;
+ const struct item *i1 = i1_;
+ const struct item *i2 = i2_;
if (i1->nameid == i2->nameid)
return 0;
@@ -79,9 +79,10 @@ void storage_sortitem(struct item* items, unsigned int size)
* Parses storage and saves 'dirty' ones upon reconnect. [Skotlex]
* @see DBApply
*/
-int storage_reconnect_sub(DBKey key, DBData *data, va_list ap)
+int storage_reconnect_sub(union DBKey key, struct DBData *data, va_list ap)
{
struct guild_storage *stor = DB->data2ptr(data);
+ nullpo_ret(stor);
if (stor->dirty && stor->storage_status == 0) //Save closed storages.
gstorage->save(0, stor->guild_id,0);
@@ -89,7 +90,8 @@ int storage_reconnect_sub(DBKey key, DBData *data, va_list ap)
}
//Function to be invoked upon server reconnection to char. To save all 'dirty' storages [Skotlex]
-void do_reconnect_storage(void) {
+void do_reconnect_storage(void)
+{
gstorage->db->foreach(gstorage->db, storage->reconnect_sub);
}
@@ -105,16 +107,25 @@ int storage_storageopen(struct map_session_data *sd)
if (sd->state.storage_flag != STORAGE_FLAG_CLOSED)
return 1; //Already open?
+ if (sd->storage.received == false) {
+ clif->message(sd->fd, msg_sd(sd, 27)); // Storage has not been loaded yet.
+ return 1;
+ }
+
if( !pc_can_give_items(sd) ) {
//check is this GM level is allowed to put items to storage
- clif->message(sd->fd, msg_sd(sd,246));
+ clif->message(sd->fd, msg_sd(sd,246)); // Your GM level doesn't authorize you to perform this action.
return 1;
}
sd->state.storage_flag = STORAGE_FLAG_NORMAL;
- storage->sortitem(sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
- clif->storagelist(sd, sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
- clif->updatestorageamount(sd, sd->status.storage.storage_amount, MAX_STORAGE);
+
+ if (sd->storage.aggregate > 0) {
+ storage->sortitem(VECTOR_DATA(sd->storage.item), VECTOR_LENGTH(sd->storage.item));
+ clif->storagelist(sd, VECTOR_DATA(sd->storage.item), VECTOR_LENGTH(sd->storage.item));
+ }
+
+ clif->updatestorageamount(sd, sd->storage.aggregate, MAX_STORAGE);
return 0;
}
@@ -131,9 +142,12 @@ int compare_item(struct item *a, struct item *b)
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++);
- return (i == MAX_SLOTS);
+ int i = 0, k = 0;
+ ARR_FIND(0, MAX_SLOTS, i, a->card[i] != b->card[i]);
+ ARR_FIND(0, MAX_ITEM_OPTIONS, k, a->option[k].index != b->option[k].index || a->option[k].value != b->option[k].value);
+
+ if (i == MAX_SLOTS && k == MAX_ITEM_OPTIONS)
+ return 1;
}
return 0;
}
@@ -141,59 +155,82 @@ int compare_item(struct item *a, struct item *b)
/*==========================================
* Internal add-item function.
*------------------------------------------*/
-int storage_additem(struct map_session_data* sd, struct item* item_data, int amount) {
- struct storage_data* stor = &sd->status.storage;
- struct item_data *data;
+int storage_additem(struct map_session_data* sd, struct item* item_data, int amount)
+{
+ struct item_data *data = NULL;
+ struct item *it = NULL;
int i;
- if( item_data->nameid <= 0 || amount <= 0 )
- return 1;
+ nullpo_retr(1, sd);
+ Assert_retr(1, sd->storage.received == true);
+
+ nullpo_retr(1, item_data);
+ Assert_retr(1, item_data->nameid > 0);
+
+ Assert_retr(1, amount > 0);
data = itemdb->search(item_data->nameid);
- if( data->stack.storage && amount > data->stack.amount )
- {// item stack limitation
+ if (data->stack.storage && amount > data->stack.amount) // item stack limitation
return 1;
- }
if (!itemdb_canstore(item_data, pc_get_group_level(sd))) {
//Check if item is storable. [Skotlex]
- clif->message (sd->fd, msg_sd(sd,264));
+ clif->message (sd->fd, msg_sd(sd, 264)); // This item cannot be stored.
return 1;
}
- if( item_data->bound > IBT_ACCOUNT && !pc_can_give_bound_items(sd) ) {
- clif->message(sd->fd, msg_sd(sd,294));
+ if (item_data->bound > IBT_ACCOUNT && !pc_can_give_bound_items(sd)) {
+ clif->message(sd->fd, msg_sd(sd, 294)); // This bound item cannot be stored there.
return 1;
}
- if( itemdb->isstackable2(data) )
- {//Stackable
- for( i = 0; i < MAX_STORAGE; i++ )
- {
- if( compare_item(&stor->items[i], item_data) )
- {// existing items found, stack them
- if( amount > MAX_AMOUNT - stor->items[i].amount || ( data->stack.storage && amount > data->stack.amount - stor->items[i].amount ) )
+ if (itemdb->isstackable2(data)) {//Stackable
+ for (i = 0; i < VECTOR_LENGTH(sd->storage.item); i++) {
+ it = &VECTOR_INDEX(sd->storage.item, i);
+
+ if (it->nameid == 0)
+ continue;
+
+ if (compare_item(it, item_data)) { // existing items found, stack them
+ if (amount > MAX_AMOUNT - it->amount || (data->stack.storage && amount > data->stack.amount - it->amount))
return 1;
- stor->items[i].amount += amount;
- clif->storageitemadded(sd,&stor->items[i],i,amount);
+ it->amount += amount;
+
+ clif->storageitemadded(sd, it, i, amount);
+
+ sd->storage.save = true; // set a save flag.
+
return 0;
}
}
}
- // find free slot
- ARR_FIND( 0, MAX_STORAGE, i, stor->items[i].nameid == 0 );
- if( i >= MAX_STORAGE )
+ // Check if storage exceeds limit.
+ if (sd->storage.aggregate >= MAX_STORAGE)
return 1;
- // add item to slot
- memcpy(&stor->items[i],item_data,sizeof(stor->items[0]));
- stor->storage_amount++;
- stor->items[i].amount = amount;
- clif->storageitemadded(sd,&stor->items[i],i,amount);
- clif->updatestorageamount(sd, stor->storage_amount, MAX_STORAGE);
+ ARR_FIND(0, VECTOR_LENGTH(sd->storage.item), i, VECTOR_INDEX(sd->storage.item, i).nameid == 0);
+
+ if (i == VECTOR_LENGTH(sd->storage.item)) {
+ VECTOR_ENSURE(sd->storage.item, 1, 1);
+ VECTOR_PUSH(sd->storage.item, *item_data);
+ it = &VECTOR_LAST(sd->storage.item);
+ } else {
+ it = &VECTOR_INDEX(sd->storage.item, i);
+ *it = *item_data;
+ }
+
+ it->amount = amount;
+
+ sd->storage.aggregate++;
+
+ clif->storageitemadded(sd, it, i, amount);
+
+ clif->updatestorageamount(sd, sd->storage.aggregate, MAX_STORAGE);
+
+ sd->storage.save = true; // set a save flag.
return 0;
}
@@ -203,19 +240,32 @@ int storage_additem(struct map_session_data* sd, struct item* item_data, int amo
*------------------------------------------*/
int storage_delitem(struct map_session_data* sd, int n, int amount)
{
- if( sd->status.storage.items[n].nameid == 0 || sd->status.storage.items[n].amount < amount )
- return 1;
+ struct item *it = NULL;
- sd->status.storage.items[n].amount -= amount;
- if( sd->status.storage.items[n].amount == 0 )
- {
- memset(&sd->status.storage.items[n],0,sizeof(sd->status.storage.items[0]));
- sd->status.storage.storage_amount--;
- if( sd->state.storage_flag == STORAGE_FLAG_NORMAL )
- clif->updatestorageamount(sd, sd->status.storage.storage_amount, MAX_STORAGE);
+ nullpo_retr(1, sd);
+
+ Assert_retr(1, sd->storage.received == true);
+
+ Assert_retr(1, n >= 0 && n < VECTOR_LENGTH(sd->storage.item));
+
+ it = &VECTOR_INDEX(sd->storage.item, n);
+
+ Assert_retr(1, amount <= it->amount);
+
+ Assert_retr(1, it->nameid > 0);
+
+ it->amount -= amount;
+
+ if (it->amount == 0) {
+ memset(it, 0, sizeof(struct item));
+ clif->updatestorageamount(sd, --sd->storage.aggregate, MAX_STORAGE);
}
- if( sd->state.storage_flag == STORAGE_FLAG_NORMAL )
- clif->storageitemremoved(sd,n,amount);
+
+ sd->storage.save = true;
+
+ if (sd->state.storage_flag == STORAGE_FLAG_NORMAL)
+ clif->storageitemremoved(sd, n, amount);
+
return 0;
}
@@ -226,22 +276,25 @@ int storage_delitem(struct map_session_data* sd, int n, int amount)
* 0 : fail
* 1 : success
*------------------------------------------*/
-int storage_storageadd(struct map_session_data* sd, int index, int amount) {
+int storage_add_from_inventory(struct map_session_data* sd, int index, int amount)
+{
nullpo_ret(sd);
- if( sd->status.storage.storage_amount > MAX_STORAGE )
+ Assert_ret(sd->storage.received == true);
+
+ if (sd->storage.aggregate > MAX_STORAGE)
return 0; // storage full
- if( index < 0 || index >= MAX_INVENTORY )
+ if (index < 0 || index >= MAX_INVENTORY)
return 0;
- if( sd->status.inventory[index].nameid <= 0 )
+ if (sd->status.inventory[index].nameid <= 0)
return 0; // No item on that spot
- if( amount < 1 || amount > sd->status.inventory[index].amount )
+ if (amount < 1 || amount > sd->status.inventory[index].amount)
return 0;
- if( storage->additem(sd,&sd->status.inventory[index],amount) == 0 )
+ if (storage->additem(sd, &sd->status.inventory[index], amount) == 0)
pc->delitem(sd, index, amount, 0, DELITEM_TOSTORAGE, LOG_TYPE_STORAGE);
else
clif->dropitem(sd, index, 0);
@@ -256,23 +309,30 @@ int storage_storageadd(struct map_session_data* sd, int index, int amount) {
* 0 : fail
* 1 : success
*------------------------------------------*/
-int storage_storageget(struct map_session_data* sd, int index, int amount)
+int storage_add_to_inventory(struct map_session_data* sd, int index, int amount)
{
int flag;
+ struct item *it = NULL;
+
+ nullpo_ret(sd);
+
+ Assert_ret(sd->storage.received == true);
- if( index < 0 || index >= MAX_STORAGE )
+ if (index < 0 || index >= VECTOR_LENGTH(sd->storage.item))
return 0;
- if( sd->status.storage.items[index].nameid <= 0 )
+ it = &VECTOR_INDEX(sd->storage.item, index);
+
+ if (it->nameid <= 0)
return 0; //Nothing there
- if( amount < 1 || amount > sd->status.storage.items[index].amount )
+ if (amount < 1 || amount > it->amount)
return 0;
- if( (flag = pc->additem(sd,&sd->status.storage.items[index],amount,LOG_TYPE_STORAGE)) == 0 )
- storage->delitem(sd,index,amount);
+ if ((flag = pc->additem(sd, it, amount, LOG_TYPE_STORAGE)) == 0)
+ storage->delitem(sd, index, amount);
else
- clif->additem(sd,0,0,flag);
+ clif->additem(sd, 0, 0, flag);
return 1;
}
@@ -288,19 +348,21 @@ int storage_storageaddfromcart(struct map_session_data* sd, int index, int amoun
{
nullpo_ret(sd);
- if( sd->status.storage.storage_amount > MAX_STORAGE )
+ Assert_ret(sd->storage.received == true);
+
+ if (sd->storage.aggregate > MAX_STORAGE)
return 0; // storage full / storage closed
- if( index < 0 || index >= MAX_CART )
+ if (index < 0 || index >= MAX_CART)
return 0;
if( sd->status.cart[index].nameid <= 0 )
return 0; //No item there.
- if( amount < 1 || amount > sd->status.cart[index].amount )
+ if (amount < 1 || amount > sd->status.cart[index].amount)
return 0;
- if( storage->additem(sd,&sd->status.cart[index],amount) == 0 )
+ if (storage->additem(sd,&sd->status.cart[index],amount) == 0)
pc->cart_delitem(sd,index,amount,0,LOG_TYPE_STORAGE);
return 1;
@@ -313,24 +375,31 @@ int storage_storageaddfromcart(struct map_session_data* sd, int index, int amoun
* 0 : fail
* 1 : success
*------------------------------------------*/
-int storage_storagegettocart(struct map_session_data* sd, int index, int amount) {
+int storage_storagegettocart(struct map_session_data* sd, int index, int amount)
+{
int flag = 0;
+ struct item *it = NULL;
+
nullpo_ret(sd);
- if( index < 0 || index >= MAX_STORAGE )
+ Assert_ret(sd->storage.received == true);
+
+ if (index < 0 || index >= VECTOR_LENGTH(sd->storage.item))
return 0;
- if( sd->status.storage.items[index].nameid <= 0 )
+ it = &VECTOR_INDEX(sd->storage.item, index);
+
+ if (it->nameid <= 0)
return 0; //Nothing there.
- if( amount < 1 || amount > sd->status.storage.items[index].amount )
+ if (amount < 1 || amount > it->amount)
return 0;
- if( (flag = pc->cart_additem(sd,&sd->status.storage.items[index],amount,LOG_TYPE_STORAGE)) == 0 )
- storage->delitem(sd,index,amount);
+ if ((flag = pc->cart_additem(sd, it, amount, LOG_TYPE_STORAGE)) == 0)
+ storage->delitem(sd, index, amount);
else {
clif->dropitem(sd, index,0);
- clif->cart_additem_ack(sd,flag == 1?0x0:0x1);
+ clif->cart_additem_ack(sd, flag == 1?0x0:0x1);
}
return 1;
@@ -340,13 +409,28 @@ int storage_storagegettocart(struct map_session_data* sd, int index, int amount)
/*==========================================
* Modified By Valaris to save upon closing [massdriller]
*------------------------------------------*/
-void storage_storageclose(struct map_session_data* sd) {
+void storage_storageclose(struct map_session_data* sd)
+{
+ int i = 0;
+
nullpo_retv(sd);
+ Assert_retv(sd->storage.received == true);
+
clif->storageclose(sd);
- if( map->save_settings&4 )
- chrif->save(sd,0); //Invokes the storage saving as well.
+ if (map->save_settings & 4)
+ chrif->save(sd, 0); //Invokes the storage saving as well.
+
+ /* Erase deleted account storage items from memory
+ * and resize the vector. */
+ while (i < VECTOR_LENGTH(sd->storage.item)) {
+ if (VECTOR_INDEX(sd->storage.item, i).nameid == 0) {
+ VECTOR_ERASE(sd->storage.item, i);
+ } else {
+ i++;
+ }
+ }
sd->state.storage_flag = STORAGE_FLAG_CLOSED;
}
@@ -354,7 +438,8 @@ void storage_storageclose(struct map_session_data* sd) {
/*==========================================
* When quitting the game.
*------------------------------------------*/
-void storage_storage_quit(struct map_session_data* sd, int flag) {
+void storage_storage_quit(struct map_session_data* sd, int flag)
+{
nullpo_retv(sd);
if (map->save_settings&4)
@@ -366,7 +451,7 @@ void storage_storage_quit(struct map_session_data* sd, int flag) {
/**
* @see DBCreateData
*/
-DBData create_guildstorage(DBKey key, va_list args)
+struct DBData create_guildstorage(union DBKey key, va_list args)
{
struct guild_storage *gs = NULL;
gs = (struct guild_storage *) aCalloc(sizeof(struct guild_storage), 1);
@@ -382,7 +467,8 @@ struct guild_storage *guild2storage_ensure(int guild_id)
return gs;
}
-int guild_storage_delete(int guild_id) {
+int guild_storage_delete(int guild_id)
+{
idb_remove(gstorage->db,guild_id);
return 0;
}
@@ -407,7 +493,7 @@ int storage_guild_storageopen(struct map_session_data* sd)
return 1; //Can't open both storages at a time.
if( !pc_can_give_items(sd) ) { //check is this GM level can open guild storage and store items [Lupus]
- clif->message(sd->fd, msg_sd(sd,246));
+ clif->message(sd->fd, msg_sd(sd,246)); // Your GM level doesn't authorize you to perform this action.
return 1;
}
@@ -456,12 +542,12 @@ int guild_storage_additem(struct map_session_data* sd, struct guild_storage* sto
if (!itemdb_canguildstore(item_data, pc_get_group_level(sd)) || item_data->expire_time) {
//Check if item is storable. [Skotlex]
- clif->message (sd->fd, msg_sd(sd,264));
+ clif->message (sd->fd, msg_sd(sd,264)); // This item cannot be stored.
return 1;
}
if( item_data->bound && item_data->bound != IBT_GUILD && !pc_can_give_bound_items(sd) ) {
- clif->message(sd->fd, msg_sd(sd,294));
+ clif->message(sd->fd, msg_sd(sd,294)); // This bound item cannot be stored there.
return 1;
}
@@ -503,6 +589,7 @@ int guild_storage_delitem(struct map_session_data* sd, struct guild_storage* sto
nullpo_retr(1, sd);
nullpo_retr(1, stor);
+ Assert_retr(1, n >= 0 && n < MAX_GUILD_STORAGE);
if(stor->items[n].nameid==0 || stor->items[n].amount<amount)
return 1;
@@ -703,7 +790,8 @@ int storage_guild_storagesaved(int guild_id)
}
//Close storage for sd and save it
-int storage_guild_storageclose(struct map_session_data* sd) {
+int storage_guild_storageclose(struct map_session_data* sd)
+{
struct guild_storage *stor;
nullpo_ret(sd);
@@ -722,7 +810,8 @@ int storage_guild_storageclose(struct map_session_data* sd) {
return 0;
}
-int storage_guild_storage_quit(struct map_session_data* sd, int flag) {
+int storage_guild_storage_quit(struct map_session_data* sd, int flag)
+{
struct guild_storage *stor;
nullpo_ret(sd);
@@ -749,15 +838,21 @@ int storage_guild_storage_quit(struct map_session_data* sd, int flag) {
return 0;
}
-void do_init_gstorage(bool minimal) {
+
+void do_init_gstorage(bool minimal)
+{
if (minimal)
return;
gstorage->db = idb_alloc(DB_OPT_RELEASE_DATA);
}
-void do_final_gstorage(void) {
+
+void do_final_gstorage(void)
+{
db_destroy(gstorage->db);
}
-void storage_defaults(void) {
+
+void storage_defaults(void)
+{
storage = &storage_s;
/* */
@@ -765,8 +860,8 @@ void storage_defaults(void) {
/* */
storage->delitem = storage_delitem;
storage->open = storage_storageopen;
- storage->add = storage_storageadd;
- storage->get = storage_storageget;
+ storage->add = storage_add_from_inventory;
+ storage->get = storage_add_to_inventory;
storage->additem = storage_additem;
storage->addfromcart = storage_storageaddfromcart;
storage->gettocart = storage_storagegettocart;
@@ -776,7 +871,9 @@ void storage_defaults(void) {
storage->sortitem = storage_sortitem;
storage->reconnect_sub = storage_reconnect_sub;
}
-void gstorage_defaults(void) {
+
+void gstorage_defaults(void)
+{
gstorage = &gstorage_s;
/* */