summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
Diffstat (limited to 'src/map')
-rw-r--r--src/map/atcommand.c131
-rw-r--r--src/map/chrif.c13
-rw-r--r--src/map/clif.c89
-rw-r--r--src/map/clif.h2
-rw-r--r--src/map/intif.c88
-rw-r--r--src/map/intif.h4
-rw-r--r--src/map/map.c20
-rw-r--r--src/map/map.h1
-rw-r--r--src/map/pc.c34
-rw-r--r--src/map/pc.h7
-rw-r--r--src/map/script.c40
-rw-r--r--src/map/storage.c401
-rw-r--r--src/map/storage.h35
-rw-r--r--src/map/unit.c13
14 files changed, 679 insertions, 199 deletions
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 6dae53720..540cea620 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -870,6 +870,41 @@ ACMD(speed)
*------------------------------------------*/
ACMD(storage)
{
+ char storage_name[NAME_LENGTH] = "";
+ int storage_id = 0, intval = 0;
+
+ if (*message != '\0' && sscanf(message, "%12d", &intval) == 1) {
+ if (storage->get_settings(intval) == NULL) {
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 67), storage_name);
+ clif->message(fd, atcmd_output); // Invalid storage name or ID.
+ return false;
+ }
+ storage_id = intval;
+ } else if (*message != '\0' && sscanf(message, "%23s", storage_name) == 1) {
+ if ((storage_id = storage->get_id_by_name(storage_name)) == -1) {
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 67), storage_name);
+ clif->message(fd, atcmd_output); // Invalid storage name or ID.
+ return false;
+ }
+ } else {
+ clif->message(fd, msg_fd(fd, 68)); // Please specify a storage name (usage: @storage <storage name>).
+ return false;
+ }
+
+ sd->storage.access = STORAGE_ACCESS_ALL; // Default storage access for atcommands.
+
+ struct storage_data *stor = NULL;
+ if ((stor = storage->ensure(sd, storage_id)) == NULL) {
+ ShowError("atcommand_storage: Error ensuring storage for player %d, storage_id %d\n", sd->bl.id, storage_id);
+ return false;
+ }
+
+ if (!stor->received) {
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 27), storage_name);
+ clif->message(fd, atcmd_output); // -- Storage '%s' has not been loaded yet.
+ return false;
+ }
+
if (sd->npc_id || sd->state.vending || sd->state.prevend || sd->state.buyingstore || sd->state.trading || sd->state.storage_flag)
return false;
@@ -878,12 +913,14 @@ ACMD(storage)
return false;
}
- if (storage->open(sd) == 1) { //Already open.
- clif->message(fd, msg_fd(fd,250)); // You have already opened your storage. Close it first.
+ if (storage->open(sd, stor) == 1) { // Already open.
+ clif->message(fd, msg_fd(fd, 250)); // You have already opened your storage. Close it first.
return false;
}
- clif->message(fd, msg_fd(fd,919)); // Storage opened.
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 919), storage_id);
+
+ clif->message(fd, atcmd_output); // Storage #%d opened.
return true;
}
@@ -5422,16 +5459,46 @@ ACMD(dropall)
*------------------------------------------*/
ACMD(storeall)
{
+ char storage_name[NAME_LENGTH] = "";
+ int storage_id = 0, intval = 0;
+
+ if (*message != '\0' && sscanf(message, "%12d", &intval) == 1) {
+ if (storage->get_settings(intval) == NULL) {
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 67), storage_name);
+ clif->message(fd, atcmd_output); // Invalid storage name or ID.
+ return false;
+ }
+ storage_id = intval;
+ } else if (*message != '\0' && sscanf(message, "%23s", storage_name) == 1) {
+ if ((storage_id = storage->get_id_by_name(storage_name)) == -1) {
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 67), storage_name);
+ clif->message(fd, atcmd_output); // Invalid storage name or ID.
+ return false;
+ }
+ } else {
+ clif->message(fd, msg_fd(fd, 65)); // Please specify a storage name (usage: @storeall <storage name>).
+ return false;
+ }
+
+ sd->storage.access = STORAGE_ACCESS_ALL; // Default storage access for atcommands.
+
+ struct storage_data *stor = NULL;
+ if ((stor = storage->ensure(sd, storage_id)) == NULL) {
+ ShowError("atcommand_storeall: Error ensuring storage for player %d, storage_id %d\n", sd->bl.id, storage_id);
+ return false;
+ }
+
if (sd->state.storage_flag != STORAGE_FLAG_NORMAL) {
//Open storage.
- if (storage->open(sd) == 1) {
- clif->message(fd, msg_fd(fd,1161)); // You currently cannot open your storage.
+ if (storage->open(sd, stor) == 1) {
+ clif->message(fd, msg_fd(fd, 1161)); // You currently cannot open your storage.
return false;
}
}
- if (sd->storage.received == false) {
- clif->message(fd, msg_fd(fd, 27)); // "Storage has not been loaded yet"
+ if (!stor->received) {
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 27), storage_name);
+ clif->message(fd, atcmd_output); // -- Storage '%s' has not been loaded yet.
return false;
}
@@ -5439,39 +5506,70 @@ ACMD(storeall)
if (sd->status.inventory[i].amount) {
if(sd->status.inventory[i].equip != 0)
pc->unequipitem(sd, i, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
- storage->add(sd, i, sd->status.inventory[i].amount);
+ storage->add(sd, stor, i, sd->status.inventory[i].amount);
}
}
+
storage->close(sd);
clif->message(fd, msg_fd(fd,1162)); // All items stored.
+
return true;
}
ACMD(clearstorage)
{
- int i;
+ int i = 0;
+ char storage_name[NAME_LENGTH] = "";
+ int storage_id = 0, intval = 0;
+
+ if (*message != '\0' && sscanf(message, "%12d", &intval) == 1) {
+ if (storage->get_settings(intval) == NULL) {
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 67), storage_name);
+ clif->message(fd, atcmd_output); // Invalid storage name or ID.
+ return false;
+ }
+ storage_id = intval;
+ } else if (*message != '\0' && sscanf(message, "%23s", storage_name) == 1) {
+ if ((storage_id = storage->get_id_by_name(storage_name)) == -1) {
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 67), storage_name);
+ clif->message(fd, atcmd_output); // Invalid storage name or ID.
+ return false;
+ }
+ } else {
+ clif->message(fd, msg_fd(fd, 66)); // Please specify a storage name (usage: @clearstorage <skill name>).
+ return false;
+ }
if (sd->state.storage_flag == STORAGE_FLAG_NORMAL) {
- clif->message(fd, msg_fd(fd,250));
+ clif->message(fd, msg_fd(fd, 250)); // You have already opened your storage. Close it first.
+ return false;
+ }
+
+ sd->storage.access = STORAGE_ACCESS_ALL; // Default storage access for atcommands.
+
+ struct storage_data *stor = NULL;
+ if ((stor = storage->ensure(sd, storage_id)) == NULL) {
+ ShowError("atcommand_clearstorage: Error ensuring storage for player %d, storage_id %d\n", sd->bl.id, storage_id);
return false;
}
- if (sd->storage.received == false) {
+ if (!stor->received) {
clif->message(fd, msg_fd(fd, 27)); // "Storage has not been loaded yet"
return false;
}
- for (i = 0; i < VECTOR_LENGTH(sd->storage.item); ++i) {
- if (VECTOR_INDEX(sd->storage.item, i).nameid == 0)
+ for (i = 0; i < VECTOR_LENGTH(stor->item); ++i) {
+ if (VECTOR_INDEX(stor->item, i).nameid == 0)
continue; // we skip the already deleted items.
- storage->delitem(sd, i, VECTOR_INDEX(sd->storage.item, i).amount);
+ storage->delitem(sd, stor, i, VECTOR_INDEX(stor->item, i).amount);
}
storage->close(sd);
clif->message(fd, msg_fd(fd,1394)); // Your storage was cleaned.
+
return true;
}
@@ -8391,8 +8489,9 @@ ACMD(itemlist)
if( strcmpi(info->command, "storagelist") == 0 ) {
location = "storage";
- items = VECTOR_DATA(sd->storage.item);
- size = VECTOR_LENGTH(sd->storage.item);
+ struct storage_data *stor = storage->ensure(sd, 1);
+ items = VECTOR_DATA(stor->item);
+ size = VECTOR_LENGTH(stor->item);
} else if( strcmpi(info->command, "cartlist") == 0 ) {
location = "cart";
items = sd->status.cart;
diff --git a/src/map/chrif.c b/src/map/chrif.c
index ddc106d0c..0622621bb 100644
--- a/src/map/chrif.c
+++ b/src/map/chrif.c
@@ -310,8 +310,12 @@ static bool chrif_save(struct map_session_data *sd, int flag)
if (sd->state.storage_flag == STORAGE_FLAG_GUILD)
gstorage->save(sd->status.account_id, sd->status.guild_id, flag);
- if (flag)
- sd->state.storage_flag = STORAGE_FLAG_CLOSED; //Force close it.
+ if (flag != 0 && sd->state.storage_flag != STORAGE_FLAG_CLOSED) {
+ if (sd->state.storage_flag == STORAGE_FLAG_NORMAL)
+ storage->close(sd);
+ else if (sd->state.storage_flag == STORAGE_FLAG_GUILD)
+ gstorage->close(sd);
+ }
//Saving of registry values.
if (sd->vars_dirty)
@@ -339,8 +343,9 @@ static bool chrif_save(struct map_session_data *sd, int flag)
if (VECTOR_LENGTH(sd->achievement) > 0)
intif->achievements_save(sd);
- if (sd->storage.received == true && sd->storage.save == true)
- intif->send_account_storage(sd);
+ for (int i = 0; i < VECTOR_LENGTH(sd->storage.list); i++)
+ if (VECTOR_INDEX(sd->storage.list, i).received && VECTOR_INDEX(sd->storage.list, i).save)
+ intif->send_account_storage(sd, VECTOR_INDEX(sd->storage.list, i).uid);
return true;
}
diff --git a/src/map/clif.c b/src/map/clif.c
index 721f5fc37..6bffa5aa4 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -2922,17 +2922,21 @@ static void clif_equipItems(struct map_session_data *sd, enum inventory_type typ
static void clif_storageList(struct map_session_data *sd, struct item *items, int items_length)
{
nullpo_retv(sd);
-
- clif->inventoryStart(sd, INVTYPE_STORAGE, "Storage");
- if (sd->storage.aggregate > 0)
- clif->storageItems(sd, INVTYPE_STORAGE, items, items_length);
+ const struct storage_settings *stst = storage->get_settings(sd->storage.current);
+ nullpo_retv(stst);
+ struct storage_data *stor = storage->ensure(sd, sd->storage.current);
+ nullpo_retv(stor);
+
+ clif->inventoryStart(sd, INVTYPE_STORAGE, stst->name);
+ if (stor->aggregate > 0)
+ clif->storageItems(sd, INVTYPE_STORAGE, items, items_length, stst->name);
clif->inventoryEnd(sd, INVTYPE_STORAGE);
}
static void clif_guildStorageList(struct map_session_data *sd, struct item *items, int items_length)
{
clif->inventoryStart(sd, INVTYPE_GUILD_STORAGE, "Guild storage");
- clif->storageItems(sd, INVTYPE_GUILD_STORAGE, items, items_length);
+ clif->storageItems(sd, INVTYPE_GUILD_STORAGE, items, items_length, "Storage");
clif->inventoryEnd(sd, INVTYPE_GUILD_STORAGE);
}
@@ -2979,10 +2983,11 @@ static void clif_inventoryEnd(struct map_session_data *sd, enum inventory_type t
#endif
}
-static void clif_storageItems(struct map_session_data *sd, enum inventory_type type, struct item *items, int items_length)
+static void clif_storageItems(struct map_session_data *sd, enum inventory_type type, struct item *items, int items_length, const char *name)
{
nullpo_retv(sd);
nullpo_retv(items);
+ nullpo_retv(name);
int normal_count = 0, equip_count = 0;
for (int i = 0; i < items_length; ++i) {
@@ -3004,7 +3009,7 @@ static void clif_storageItems(struct map_session_data *sd, enum inventory_type t
storelist_normal.invType = type;
#endif
#if PACKETVER >= 20120925 && PACKETVER_RE_NUM < 20180829 && PACKETVER_ZERO_NUM < 20180919 && PACKETVER_MAIN_NUM < 20181002
- safestrncpy(storelist_normal.name, "Storage", NAME_LENGTH);
+ safestrncpy(storelist_normal.name, name, NAME_LENGTH);
#endif
clif->send(&storelist_normal, storelist_normal.PacketLength, &sd->bl, SELF);
@@ -3019,7 +3024,7 @@ static void clif_storageItems(struct map_session_data *sd, enum inventory_type t
storelist_equip.invType = type;
#endif
#if PACKETVER >= 20120925 && PACKETVER_RE_NUM < 20180829 && PACKETVER_ZERO_NUM < 20180919 && PACKETVER_MAIN_NUM < 20181002
- safestrncpy(storelist_equip.name, "Storage", NAME_LENGTH);
+ safestrncpy(storelist_equip.name, name, NAME_LENGTH);
#endif
clif->send(&storelist_equip, storelist_equip.PacketLength, &sd->bl, SELF);
@@ -3035,7 +3040,7 @@ static void clif_storageItems(struct map_session_data *sd, enum inventory_type t
storelist_normal.invType = type;
#endif
#if PACKETVER >= 20120925 && PACKETVER_RE_NUM < 20180829 && PACKETVER_ZERO_NUM < 20180919 && PACKETVER_MAIN_NUM < 20181002
- safestrncpy(storelist_normal.name, "Storage", NAME_LENGTH);
+ safestrncpy(storelist_normal.name, name, NAME_LENGTH);
#endif
clif->send(&storelist_normal, storelist_normal.PacketLength, &sd->bl, SELF);
@@ -3050,7 +3055,7 @@ static void clif_storageItems(struct map_session_data *sd, enum inventory_type t
storelist_equip.invType = type;
#endif
#if PACKETVER >= 20120925 && PACKETVER_RE_NUM < 20180829 && PACKETVER_ZERO_NUM < 20180919 && PACKETVER_MAIN_NUM < 20181002
- safestrncpy(storelist_equip.name, "Storage", NAME_LENGTH);
+ safestrncpy(storelist_equip.name, name, NAME_LENGTH);
#endif
clif->send(&storelist_equip, storelist_equip.PacketLength, &sd->bl, SELF);
@@ -9244,14 +9249,24 @@ static void clif_serviceMessageColor(struct map_session_data *sd, uint32 color,
static void clif_refresh_storagewindow(struct map_session_data *sd)
{
nullpo_retv(sd);
+
// Notify the client that the storage is open
if (sd->state.storage_flag == STORAGE_FLAG_NORMAL) {
- 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);
+ const struct storage_settings* stst = storage->get_settings(sd->storage.current);
+ nullpo_retv(stst);
+
+ struct storage_data* stor = NULL;
+ if ((stor = storage->ensure(sd, sd->storage.current)) == NULL)
+ return;
+
+ if (stor->aggregate > 0)
+ storage->sortitem(VECTOR_DATA(stor->item), VECTOR_LENGTH(stor->item));
+
+ clif->storageList(sd, VECTOR_DATA(stor->item), VECTOR_LENGTH(stor->item));
+
+ clif->updatestorageamount(sd, stor->aggregate, MAX_STORAGE);
}
+
// Notify the client that the gstorage is open otherwise it will
// remain locked forever and nobody will be able to access it
if (sd->state.storage_flag == STORAGE_FLAG_GUILD) {
@@ -9327,7 +9342,12 @@ static void clif_refresh(struct map_session_data *sd)
pc->disguise(sd, disguise);
}
- clif->refresh_storagewindow(sd);
+ // Close storage when refreshing the client
+ // to avoid an unnecessary complication of things.
+ if (sd->state.storage_flag == STORAGE_FLAG_NORMAL)
+ storage->close(sd);
+ else if (sd->state.storage_flag == STORAGE_FLAG_GUILD)
+ gstorage->close(sd);
}
static void clif_send_selforarea(int fd, struct block_list *bl, const void *buf, int len)
@@ -13341,10 +13361,13 @@ static void clif_parse_MoveToKafra(int fd, struct map_session_data *sd)
if (item_index < 0 || item_index >= sd->status.inventorySize || item_amount < 1)
return;
- if (sd->state.storage_flag == STORAGE_FLAG_NORMAL)
- storage->add(sd, item_index, item_amount);
- else if (sd->state.storage_flag == STORAGE_FLAG_GUILD)
+ if (sd->state.storage_flag == STORAGE_FLAG_NORMAL) {
+ struct storage_data *stor = storage->ensure(sd, sd->storage.current);
+ if (stor != NULL)
+ storage->add(sd, stor, item_index, item_amount);
+ } else if (sd->state.storage_flag == STORAGE_FLAG_GUILD) {
gstorage->add(sd, item_index, item_amount);
+ }
}
static void clif_parse_MoveFromKafra(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -13359,13 +13382,17 @@ static void clif_parse_MoveFromKafra(int fd, struct map_session_data *sd)
int item_index, item_amount;
+
item_index = RFIFOW(fd,packet_db[RFIFOW(fd,0)].pos[0])-1;
item_amount = RFIFOL(fd,packet_db[RFIFOW(fd,0)].pos[1]);
- if (sd->state.storage_flag == STORAGE_FLAG_NORMAL)
- storage->get(sd, item_index, item_amount);
- else if(sd->state.storage_flag == STORAGE_FLAG_GUILD)
+ if (sd->state.storage_flag == STORAGE_FLAG_NORMAL) {
+ struct storage_data *stor = storage->ensure(sd, sd->storage.current);
+ if (stor != NULL)
+ storage->get(sd, stor, item_index, item_amount);
+ } else if (sd->state.storage_flag == STORAGE_FLAG_GUILD) {
gstorage->get(sd, item_index, item_amount);
+ }
}
static void clif_parse_MoveToKafraFromCart(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -13378,10 +13405,13 @@ static void clif_parse_MoveToKafraFromCart(int fd, struct map_session_data *sd)
if (!pc_iscarton(sd))
return;
- if (sd->state.storage_flag == STORAGE_FLAG_NORMAL)
- storage->addfromcart(sd, RFIFOW(fd,2) - 2, RFIFOL(fd,4));
- else if (sd->state.storage_flag == STORAGE_FLAG_GUILD)
+ if (sd->state.storage_flag == STORAGE_FLAG_NORMAL) {
+ struct storage_data *stor = storage->ensure(sd, sd->storage.current);
+ if (stor != NULL)
+ storage->addfromcart(sd, stor, RFIFOW(fd, 2) - 2, RFIFOL(fd, 4));
+ } else if (sd->state.storage_flag == STORAGE_FLAG_GUILD) {
gstorage->addfromcart(sd, RFIFOW(fd,2) - 2, RFIFOL(fd,4));
+ }
}
static void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -13394,10 +13424,13 @@ static void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd)
if (!pc_iscarton(sd))
return;
- if (sd->state.storage_flag == STORAGE_FLAG_NORMAL)
- storage->gettocart(sd, RFIFOW(fd,2)-1, RFIFOL(fd,4));
- else if (sd->state.storage_flag == STORAGE_FLAG_GUILD)
+ if (sd->state.storage_flag == STORAGE_FLAG_NORMAL) {
+ struct storage_data *stor = storage->ensure(sd, sd->storage.current);
+ if (stor != NULL)
+ storage->gettocart(sd, stor, RFIFOW(fd,2) - 1, RFIFOL(fd, 4));
+ } else if (sd->state.storage_flag == STORAGE_FLAG_GUILD) {
gstorage->gettocart(sd, RFIFOW(fd,2)-1, RFIFOL(fd,4));
+ }
}
static void clif_parse_CloseKafra(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
diff --git a/src/map/clif.h b/src/map/clif.h
index 0dfc00c01..194194752 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -1091,7 +1091,7 @@ struct clif_interface {
/* storage handling */
void (*storageList) (struct map_session_data* sd, struct item* items, int items_length);
void (*guildStorageList) (struct map_session_data* sd, struct item* items, int items_length);
- void (*storageItems) (struct map_session_data* sd, enum inventory_type type, struct item* items, int items_length);
+ void (*storageItems) (struct map_session_data *sd, enum inventory_type type, struct item *items, int items_length, const char *name);
void (*inventoryStart) (struct map_session_data* sd, enum inventory_type type, const char* name);
void (*inventoryEnd) (struct map_session_data* sd, enum inventory_type type);
void (*updatestorageamount) (struct map_session_data* sd, int amount, int max_amount);
diff --git a/src/map/intif.c b/src/map/intif.c
index 5a62f9644..f211b9705 100644
--- a/src/map/intif.c
+++ b/src/map/intif.c
@@ -297,26 +297,33 @@ static int intif_request_registry(struct map_session_data *sd, int flag)
/**
* Request the inter-server for a character's storage data.
- * @packet 0x3010 [out] <account_id>.L
- * @param sd [in] pointer to session data.
+ *
+ * @packet 0x3010 [out] <account_id>.L <storage_id>.W <storage_size>.W
+ * @param sd [in] pointer to session data.
+ * @param storage_id [in] storage id to retrieve
*/
-static void intif_request_account_storage(const struct map_session_data *sd)
+static void intif_request_account_storage(const struct map_session_data *sd, int storage_id)
{
nullpo_retv(sd);
+ const struct storage_settings *stst = storage->get_settings(storage_id);
+ nullpo_retv(stst);
+
/* Check for character server availability */
if (intif->CheckForCharServer())
return;
- WFIFOHEAD(inter_fd, 6);
+ WFIFOHEAD(inter_fd, 10);
WFIFOW(inter_fd, 0) = 0x3010;
WFIFOL(inter_fd, 2) = sd->status.account_id;
- WFIFOSET(inter_fd, 6);
+ WFIFOW(inter_fd, 6) = storage_id;
+ WFIFOW(inter_fd, 8) = stst->capacity;
+ WFIFOSET(inter_fd, 10);
}
/**
* Parse the reception of account storage from the inter-server.
- * @packet 0x3805 [in] <packet_len>.W <account_id>.L <struct item[]>.P
+ * @packet 0x3805 [in] <packet_len>.W <account_id>.L <storage_id>.W <struct item[]>.P
* @param fd [in] file/socket descriptor.
*/
static void intif_parse_account_storage(int fd)
@@ -327,94 +334,113 @@ static void intif_parse_account_storage(int fd)
Assert_retv(fd > 0);
- payload_size = RFIFOW(fd, 2) - 8;
+ payload_size = RFIFOW(fd, 2) - 10;
if ((account_id = RFIFOL(fd, 4)) == 0 || (sd = map->id2sd(account_id)) == NULL) {
ShowError("intif_parse_account_storage: Session pointer was null for account id %d!\n", account_id);
return;
}
- if (sd->storage.received == true) {
+ struct storage_data *stor = NULL;
+ if ((stor = storage->ensure(sd, RFIFOW(fd, 8))) == NULL)
+ return;
+
+ if (stor->received) {
ShowError("intif_parse_account_storage: Multiple calls from the inter-server received.\n");
return;
}
storage_count = (payload_size/sizeof(struct item));
- VECTOR_ENSURE(sd->storage.item, storage_count, 1);
+ VECTOR_ENSURE(stor->item, storage_count, 1);
- sd->storage.aggregate = storage_count; // Total items in storage.
+ stor->aggregate = storage_count; // Total items in storage.
for (i = 0; i < storage_count; i++) {
- const struct item *it = RFIFOP(fd, 8 + i * sizeof(struct item));
- VECTOR_PUSH(sd->storage.item, *it);
+ const struct item *it = RFIFOP(fd, 10 + i * sizeof(struct item));
+ VECTOR_PUSH(stor->item, *it);
}
- sd->storage.received = true; // Mark the storage state as received.
- sd->storage.save = false; // Initialize the save flag as false.
+ stor->received = true; // Mark the storage state as received.
+ stor->save = false; // Initialize the save flag as false.
pc->checkitem(sd); // re-check remaining items.
}
/**
* Send account storage information for saving.
- * @packet 0x3011 [out] <packet_len>.W <account_id>.L <struct item[]>.P
- * @param sd [in] pointer to session data.
+ *
+ * @packet 0x3011 [out] <packet_len>.W <account_id>.L <storage_id>.W <struct item[]>.P
+ * @param sd [in] pointer to session data.
+ * @param storage_id [in] storage id to be saved.
*/
-static void intif_send_account_storage(struct map_session_data *sd)
+static void intif_send_account_storage(struct map_session_data *sd, int storage_id)
{
int len = 0, i = 0, c = 0;
nullpo_retv(sd);
+ struct storage_data *stor = NULL;
+ if ((stor = storage->ensure(sd, storage_id)) == NULL)
+ return;
+
// Assert that at this point in the code, both flags are true.
- Assert_retv(sd->storage.save == true);
- Assert_retv(sd->storage.received == true);
+ Assert_retv(stor->save);
+ Assert_retv(stor->received);
if (intif->CheckForCharServer())
return;
- len = 8 + sd->storage.aggregate * sizeof(struct item);
+ len = 10 + stor->aggregate * sizeof(struct item);
WFIFOHEAD(inter_fd, len);
WFIFOW(inter_fd, 0) = 0x3011;
WFIFOW(inter_fd, 2) = (uint16) len;
WFIFOL(inter_fd, 4) = sd->status.account_id;
- for (i = 0, c = 0; i < VECTOR_LENGTH(sd->storage.item); i++) {
- if (VECTOR_INDEX(sd->storage.item, i).nameid == 0)
+ WFIFOW(inter_fd, 8) = storage_id;
+
+ for (i = 0, c = 0; i < VECTOR_LENGTH(stor->item); i++) {
+ if (VECTOR_INDEX(stor->item, i).nameid == 0)
continue;
- memcpy(WFIFOP(inter_fd, 8 + c * sizeof(struct item)), &VECTOR_INDEX(sd->storage.item, i), sizeof(struct item));
+ memcpy(WFIFOP(inter_fd, 10 + c * sizeof(struct item)), &VECTOR_INDEX(stor->item, i), sizeof(struct item));
c++;
}
WFIFOSET(inter_fd, len);
- sd->storage.save = false; // Save request has been sent
+ stor->save = false; // Save request has been sent
}
/**
* Parse acknowledgement packet for the saving of an account's storage.
- * @packet 0x3808 [in] <account_id>.L <saved_flag>.B
+ * @packet 0x3808 [in] <account_id>.L <storage_id>.W <saved_flag>.B
* @param fd [in] file/socket descriptor.
*/
static void intif_parse_account_storage_save_ack(int fd)
{
int account_id = RFIFOL(fd, 2);
- uint8 saved = RFIFOB(fd, 6);
- struct map_session_data *sd = NULL;
+ int storage_id = RFIFOW(fd, 6);
+ char saved = RFIFOB(fd, 8);
Assert_retv(account_id > 0);
Assert_retv(fd > 0);
-
+ Assert_retv(storage_id >= 0);
+
+ struct map_session_data *sd = NULL;
if ((sd = map->id2sd(account_id)) == NULL)
return; // character is most probably offline.
if (saved == 0) {
- ShowError("intif_parse_account_storage_save_ack: Storage has not been saved! (AID: %d)\n", account_id);
- sd->storage.save = true; // Flag it as unsaved, to re-attempt later
+ ShowError("intif_parse_account_storage_save_ack: Storage id %d has not been saved! (AID: %d)\n", storage_id, account_id);
return;
}
+
+ struct storage_data *stor = NULL;
+ if ((stor = storage->ensure(sd, storage_id)) == NULL)
+ return;
+
+ stor->save = false; // Storage has been saved.
}
//=================================================================
@@ -2718,7 +2744,7 @@ static int intif_parse(int fd)
void intif_defaults(void)
{
const int packet_len_table [INTIF_PACKET_LEN_TABLE_SIZE] = {
- 0, 0, 0, 0, -1,-1,37,-1, 7, 0, 0, 0, 0, 0, 0, 0, //0x3800-0x380f
+ 0, 0, 0, 0, -1,-1,37,-1, 9, 0, 0, 0, 0, 0, 0, 0, //0x3800-0x380f
-1, 0, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0, //0x3810 Achievements [Smokexyz/Hercules]
39,-1,15,15, 14,19, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3820
10,-1,15, 0, 79,25, 7, 0, 0,-1,-1,-1, 14,67,186,-1, //0x3830
diff --git a/src/map/intif.h b/src/map/intif.h
index ffac4a1c9..082f87a8b 100644
--- a/src/map/intif.h
+++ b/src/map/intif.h
@@ -62,8 +62,8 @@ struct intif_interface {
int pet_equip, short intimate, short hungry, char rename_flag, char incubate, char *pet_name);
int (*saveregistry) (struct map_session_data *sd);
int (*request_registry) (struct map_session_data *sd, int flag);
- void (*request_account_storage) (const struct map_session_data *sd);
- void (*send_account_storage) (struct map_session_data *sd);
+ void (*request_account_storage) (const struct map_session_data *sd, int storage_id);
+ void (*send_account_storage) (struct map_session_data *sd, int storage_id);
int (*request_guild_storage) (int account_id, int guild_id);
int (*send_guild_storage) (int account_id, struct guild_storage *gstor);
int (*create_party) (struct party_member *member, const char *name, int item, int item2);
diff --git a/src/map/map.c b/src/map/map.c
index 2161f7023..fefcc78c2 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -6193,6 +6193,7 @@ int do_final(void)
script->final();
itemdb->final();
instance->final();
+ storage->final();
gstorage->final();
guild->final();
party->final();
@@ -6255,6 +6256,7 @@ int do_final(void)
aFree(map->GRF_PATH_FILENAME);
aFree(map->INTER_CONF_NAME);
aFree(map->LOG_CONF_NAME);
+ aFree(map->STORAGE_CONF_FILENAME);
HPM->event(HPET_POST_FINAL);
@@ -6510,6 +6512,19 @@ static CMDLINEARG(grfpath)
return true;
}
/**
+ * --storage-path handler
+ *
+ * Overrides the default grf configuration filename.
+ * @see cmdline->exec
+ */
+static CMDLINEARG(storagepath)
+{
+ aFree(map->STORAGE_CONF_FILENAME);
+ map->STORAGE_CONF_FILENAME = aStrdup(params);
+ return true;
+}
+
+/**
* --inter-config handler
*
* Overrides the default inter-server configuration filename.
@@ -6571,6 +6586,7 @@ void cmdline_args_init_local(void)
CMDLINEARG_DEF2(script-config, scriptconfig, "Alternative script configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
CMDLINEARG_DEF2(msg-config, msgconfig, "Alternative message configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
CMDLINEARG_DEF2(grf-path, grfpath, "Alternative GRF path configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
+ CMDLINEARG_DEF2(storage-path, storagepath, "Alternative Storage configuration path.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
CMDLINEARG_DEF2(inter-config, interconfig, "Alternative inter-server configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
CMDLINEARG_DEF2(log-config, logconfig, "Alternative logging configuration.", CMDLINE_OPT_NORMAL|CMDLINE_OPT_PARAM);
CMDLINEARG_DEF2(script-check, scriptcheck, "Doesn't run the server, only tests the scripts passed through --load-script.", CMDLINE_OPT_SILENT);
@@ -6596,6 +6612,7 @@ int do_init(int argc, char *argv[])
map->SCRIPT_CONF_NAME = aStrdup("conf/map/script.conf");
map->MSG_CONF_NAME = aStrdup("conf/messages.conf");
map->GRF_PATH_FILENAME = aStrdup("conf/grf-files.txt");
+ map->STORAGE_CONF_FILENAME = aStrdup("conf/map/storage.conf");
HPM_map_do_init();
cmdline->exec(argc, argv, CMDLINE_OPT_PREINIT);
@@ -6661,6 +6678,7 @@ int do_init(int argc, char *argv[])
atcommand->msg_read(map->MSG_CONF_NAME, false);
map->inter_config_read(map->INTER_CONF_NAME, false);
logs->config_read(map->LOG_CONF_NAME, false);
+ storage->config_read(map->STORAGE_CONF_FILENAME, false);
}
script->config_read(map->SCRIPT_CONF_NAME, false);
@@ -6733,6 +6751,7 @@ int do_init(int argc, char *argv[])
status->init(minimal);
party->init(minimal);
guild->init(minimal);
+ storage->init(minimal);
gstorage->init(minimal);
pet->init(minimal);
homun->init(minimal);
@@ -6834,6 +6853,7 @@ void map_defaults(void)
map->SCRIPT_CONF_NAME = "conf/map/script.conf";
map->MSG_CONF_NAME = "conf/messages.conf";
map->GRF_PATH_FILENAME = "conf/grf-files.txt";
+ map->STORAGE_CONF_FILENAME = "conf/map/storage.conf";
map->default_codepage[0] = '\0';
map->server_port = 3306;
diff --git a/src/map/map.h b/src/map/map.h
index b9199f3bb..450588fd2 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -1052,6 +1052,7 @@ struct map_interface {
char *SCRIPT_CONF_NAME;
char *MSG_CONF_NAME;
char *GRF_PATH_FILENAME;
+ char *STORAGE_CONF_FILENAME;
char autotrade_merchants_db[32];
char autotrade_data_db[32];
diff --git a/src/map/pc.c b/src/map/pc.c
index e9332ee46..e1da6f69d 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -1268,9 +1268,11 @@ static bool pc_authok(struct map_session_data *sd, int login_id2, time_t expirat
VECTOR_INIT(sd->channels);
VECTOR_INIT(sd->script_queues);
VECTOR_INIT(sd->achievement); // Achievements [Smokexyz/Hercules]
- VECTOR_INIT(sd->storage.item); // initialize storage item vector.
VECTOR_INIT(sd->hatEffectId);
+ // Storage
+ VECTOR_INIT(sd->storage.list);
+
sd->state.dialog = 0;
sd->delayed_damage = 0;
@@ -1505,7 +1507,8 @@ static int pc_reg_received(struct map_session_data *sd)
sd->status.last_login = time(NULL);
// Storage Request
- intif->request_account_storage(sd);
+ for (i = 0; i < VECTOR_LENGTH(storage->configuration); i++)
+ intif->request_account_storage(sd, VECTOR_INDEX(storage->configuration, i).uid);
intif->Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox
intif->request_questlog(sd);
@@ -10506,21 +10509,26 @@ static int pc_checkitem(struct map_session_data *sd)
sd->itemcheck &= ~PCCHECKITEM_CART;
}
- if (sd->itemcheck & PCCHECKITEM_STORAGE && sd->storage.received == true) {
- for (i = 0; i < VECTOR_LENGTH(sd->storage.item); i++) {
- struct item *it = &VECTOR_INDEX(sd->storage.item, i);
+ if ((sd->itemcheck & PCCHECKITEM_STORAGE) != 0) {
+ for (i = 0; i < VECTOR_LENGTH(sd->storage.list); i++) {
+ struct storage_data *stor = &VECTOR_INDEX(sd->storage.list, i);
- if ((id = it->nameid) == 0)
- continue;
+ for (int j = 0; j < VECTOR_LENGTH(sd->storage.list); j++) {
+ struct item *it = &VECTOR_INDEX(stor->item, j);
- if (!itemdb_available(id)) {
- ShowWarning("pc_checkitem: Removed invalid/disabled item id %d from storage (amount=%d, char_id=%d).\n", id, it->amount, sd->status.char_id);
- storage->delitem(sd, i, it->amount);
- continue;
+ if ((id = it->nameid) == 0)
+ continue;
+
+ if (itemdb_available(id) == 0) {
+ ShowWarning("pc_checkitem: Removed invalid/disabled item id %d from storage %d (amount=%d, char_id=%d).\n", id, stor->uid, it->amount, sd->status.char_id);
+ storage->delitem(sd, stor, i, it->amount);
+ continue;
+ }
+
+ if (it->unique_id == 0 && itemdb->isstackable(id) == 0)
+ it->unique_id = itemdb->unique_id(sd);
}
- if (it->unique_id == 0 && itemdb->isstackable(id) == 0)
- it->unique_id = itemdb->unique_id(sd);
}
storage->close(sd);
diff --git a/src/map/pc.h b/src/map/pc.h
index cc8d83b65..75ea3d359 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -32,6 +32,7 @@
#include "map/script.h" // struct reg_db
#include "map/searchstore.h" // struct s_search_store_info
#include "map/status.h" // enum sc_type, OPTION_*
+#include "map/storage.h"
#include "map/unit.h" // struct unit_data, struct view_data
#include "map/vending.h" // struct s_vending
#include "common/db.h"
@@ -263,7 +264,11 @@ struct map_session_data {
struct mmo_charstatus status;
struct item_data *inventory_data[MAX_INVENTORY]; // direct pointers to itemdb entries (faster than doing item_id lookups)
- struct storage_data storage; ///< Account Storage
+ struct {
+ int current; ///< Marker for the current storage ID in use.
+ enum storage_access_modes access; ///< Access level for the user.
+ VECTOR_DECL(struct storage_data) list; ///< Account Storage
+ } storage;
enum pc_checkitem_types itemcheck;
short equip_index[EQI_MAX];
unsigned int weight,max_weight;
diff --git a/src/map/script.c b/src/map/script.c
index e7c5eba0c..355735740 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -10894,10 +10894,30 @@ static BUILDIN(gettimestr)
static BUILDIN(openstorage)
{
struct map_session_data *sd = script->rid2sd(st);
- if (sd == NULL)
+ int storage_id = script_hasdata(st, 2) ? script_getnum(st, 2) : 1;
+ if (sd == NULL) {
+ script_pushint(st, 0);
+ ShowWarning("buildin_openstorage: Player not attached for Storage with ID %d!\n", storage_id);
+ return false;
+ }
+
+ int storage_access = script_hasdata(st, 3) ? script_getnum(st, 3) : STORAGE_ACCESS_ALL;
+ struct storage_data *stor = NULL;
+
+ if ((stor = storage->ensure(sd, storage_id)) == NULL) {
+ script_pushint(st, 0);
+ ShowError("buildin_openstorage: Error ensuring storage for player aid %d, storage id %d.\n", sd->bl.id, storage_id);
return false;
+ }
- if (sd->storage.received == false) {
+ const struct storage_settings *stst = NULL;
+ if ((stst = storage->get_settings(storage_id)) == NULL) {
+ script_pushint(st, 0);
+ ShowWarning("buildin_openstorage: Storage with ID %d was not found!\n", storage_id);
+ return false;
+ }
+
+ if (stor == NULL || !stor->received) {
script_pushint(st, 0);
ShowWarning("buildin_openstorage: Storage data for AID %d has not been loaded.\n", sd->bl.id);
return false;
@@ -10909,9 +10929,13 @@ static BUILDIN(openstorage)
return true;
}
- storage->open(sd);
+ sd->storage.access = storage_access; // Set storage access level. [Smokexyz/Hercules]
- script_pushint(st, 1); // success flag.
+ if (storage->open(sd, stor) == 0) {
+ script_pushint(st, 1); // success
+ } else {
+ script_pushint(st, 0);
+ }
return true;
}
@@ -26292,7 +26316,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(gettimetick,"i"),
BUILDIN_DEF(gettime,"i"),
BUILDIN_DEF(gettimestr, "si?"),
- BUILDIN_DEF(openstorage,""),
+ BUILDIN_DEF(openstorage,"??"),
BUILDIN_DEF(guildopenstorage,""),
BUILDIN_DEF(itemskill,"vi?"),
BUILDIN_DEF(produce,"i"),
@@ -27368,6 +27392,12 @@ static void script_hardcoded_constants(void)
script->set_constant("GUILDINFO_MASTER_NAME", GUILDINFO_MASTER_NAME, false, false);
script->set_constant("GUILDINFO_MASTER_CID", GUILDINFO_MASTER_CID, false, false);
+ script->constdb_comment("Storage Access Types");
+ script->set_constant("STORAGE_ACCESS_VIEW", STORAGE_ACCESS_VIEW, false, false);
+ script->set_constant("STORAGE_ACCESS_GET", STORAGE_ACCESS_GET, false, false);
+ script->set_constant("STORAGE_ACCESS_PUT", STORAGE_ACCESS_PUT, false, false);
+ script->set_constant("STORAGE_ACCESS_ALL", STORAGE_ACCESS_ALL, false, false);
+
script->constdb_comment("Renewal");
#ifdef RENEWAL
script->set_constant("RENEWAL", 1, false, false);
diff --git a/src/map/storage.c b/src/map/storage.c
index 90b620f63..5b9478d8a 100644
--- a/src/map/storage.c
+++ b/src/map/storage.c
@@ -33,9 +33,11 @@
#include "map/map.h" // struct map_session_data
#include "map/pc.h"
#include "common/cbasetypes.h"
-#include "common/db.h"
+#include "common/conf.h"
#include "common/memmgr.h"
+#include "common/mmo.h"
#include "common/nullpo.h"
+#include "common/showmsg.h"
#include <stdio.h>
#include <stdlib.h>
@@ -95,37 +97,109 @@ static void do_reconnect_storage(void)
gstorage->db->foreach(gstorage->db, storage->reconnect_sub);
}
+/**
+ * Get a storage id by its name (through @commands etc...)
+ *
+ * @param[in] storage_name pointer to the storage name char array.
+ * @return id of the storage or -1 if not found.
+ */
+int storage_get_id_by_name(const char *storage_name)
+{
+ nullpo_chk(storage_name);
+ int i = 0;
+
+ ARR_FIND(0, VECTOR_LENGTH(storage->configuration), i, strcmp(VECTOR_INDEX(storage->configuration, i).name, storage_name) == 0);
+
+ if (i == VECTOR_LENGTH(storage->configuration))
+ return -1;
+
+ return VECTOR_INDEX(storage->configuration, i).uid;
+}
+
+/**
+ * Get storage with a particular ID from a player.
+ *
+ * @param[in] sd pointer to map session data.
+ * @param[in] storage_id ID of the storage to receive.
+ * @return pointer to player's storage data structure or null if not found.
+ */
+struct storage_data *storage_ensure(struct map_session_data *sd, int storage_id)
+{
+ nullpo_retr(NULL, sd);
+
+ int i = 0;
+ struct storage_data *stor = NULL;
+
+ ARR_FIND(0, VECTOR_LENGTH(sd->storage.list), i, (stor = &VECTOR_INDEX(sd->storage.list, i)) != NULL && stor->uid == storage_id);
+
+ if (i == VECTOR_LENGTH(sd->storage.list)) {
+ struct storage_data t_stor = { 0 };
+
+ t_stor.uid = storage_id;
+ VECTOR_INIT(t_stor.item);
+ VECTOR_ENSURE(sd->storage.list, 1, 1);
+ VECTOR_PUSH(sd->storage.list, t_stor);
+ stor = &VECTOR_LAST(sd->storage.list);
+ }
+
+ return stor;
+}
+
+/**
+ * Get a storage's settings through its ID.
+ *
+ * @param[in] storage_id the ID of the storage to find.
+ * @return storage settings of the storage in question.
+ */
+const struct storage_settings *storage_get_settings(int storage_id)
+{
+ int i = 0;
+
+ ARR_FIND(0, VECTOR_LENGTH(storage->configuration), i, VECTOR_INDEX(storage->configuration, i).uid == storage_id);
+
+ struct storage_settings *tmp_stor = NULL;
+ if (i < VECTOR_LENGTH(storage->configuration))
+ tmp_stor = &VECTOR_INDEX(storage->configuration, i);
+
+ return tmp_stor;
+}
+
/*==========================================
* Opens a storage. Returns:
* 0 - success
* 1 - fail
*------------------------------------------*/
-static int storage_storageopen(struct map_session_data *sd)
+static int storage_storageopen(struct map_session_data *sd, struct storage_data *stor)
{
- nullpo_ret(sd);
+ nullpo_retr(1, sd);
+ nullpo_retr(1, stor);
+ Assert_retr(1, stor->received); // Assert the availability of data.
- if (sd->state.storage_flag != STORAGE_FLAG_CLOSED)
- return 1; //Already open?
+ const struct storage_settings *stst = NULL;
- if (sd->storage.received == false) {
- clif->message(sd->fd, msg_sd(sd, 27)); // Storage has not been loaded yet.
- return 1;
- }
+ nullpo_retr(1, stst = storage->get_settings(stor->uid));
+
+ if (sd->state.storage_flag != STORAGE_FLAG_CLOSED)
+ return 1; // Storage is already open.
- if( !pc_can_give_items(sd) ) {
- //check is this GM level is allowed to put items to storage
+ // GM Permission check.
+ if (!pc_can_give_items(sd)) {
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;
+ sd->state.storage_flag = STORAGE_FLAG_NORMAL; // Set the storage use state.
+ sd->storage.current = stor->uid; // Set current storage ID used.
- if (sd->storage.aggregate > 0) {
- storage->sortitem(VECTOR_DATA(sd->storage.item), VECTOR_LENGTH(sd->storage.item));
+ /* Send item list to client if available. */
+ if (stor->aggregate > 0) {
+ storage->sortitem(VECTOR_DATA(stor->item), VECTOR_LENGTH(stor->item));
}
- clif->storageList(sd, VECTOR_DATA(sd->storage.item), VECTOR_LENGTH(sd->storage.item));
+ clif->storageList(sd, VECTOR_DATA(stor->item), VECTOR_LENGTH(stor->item));
- clif->updatestorageamount(sd, sd->storage.aggregate, MAX_STORAGE);
+ /* Send storage total items and max amount update. */
+ clif->updatestorageamount(sd, stor->aggregate, stst->capacity);
+
return 0;
}
@@ -155,21 +229,19 @@ static int compare_item(struct item *a, struct item *b)
/*==========================================
* Internal add-item function.
*------------------------------------------*/
-static int storage_additem(struct map_session_data *sd, struct item *item_data, int amount)
+static int storage_additem(struct map_session_data *sd, struct storage_data *stor, struct item* item_data, int amount)
{
- struct item_data *data = NULL;
- struct item *it = NULL;
- int i;
-
nullpo_retr(1, sd);
- Assert_retr(1, sd->storage.received == true);
+ nullpo_retr(1, stor); // Assert Storage
+ Assert_retr(1, stor->received); // Assert the availability of the storage.
+ nullpo_retr(1, item_data); // Assert availability of item data.
+ Assert_retr(1, item_data->nameid > 0); // Assert existence of item in the database.
+ Assert_retr(1, amount > 0); // Assert quantity of item.
+
+ const struct storage_settings *stst = NULL;
+ nullpo_retr(1, (stst = storage->get_settings(stor->uid))); // Assert existence of storage configuration.
- nullpo_retr(1, item_data);
- Assert_retr(1, item_data->nameid > 0);
-
- Assert_retr(1, amount > 0);
-
- data = itemdb->search(item_data->nameid);
+ struct item_data *data = itemdb->search(item_data->nameid);
if (data->stack.storage && amount > data->stack.amount) // item stack limitation
return 1;
@@ -185,9 +257,11 @@ static int storage_additem(struct map_session_data *sd, struct item *item_data,
return 1;
}
+ int i;
+ struct item *it = NULL;
if (itemdb->isstackable2(data)) {//Stackable
- for (i = 0; i < VECTOR_LENGTH(sd->storage.item); i++) {
- it = &VECTOR_INDEX(sd->storage.item, i);
+ for (i = 0; i < VECTOR_LENGTH(stor->item); i++) {
+ it = &VECTOR_INDEX(stor->item, i);
if (it->nameid == 0)
continue;
@@ -199,38 +273,37 @@ static int storage_additem(struct map_session_data *sd, struct item *item_data,
it->amount += amount;
clif->storageitemadded(sd, it, i, amount);
-
- sd->storage.save = true; // set a save flag.
-
+ stor->save = true; // set a save flag.
+
return 0;
}
}
}
// Check if storage exceeds limit.
- if (sd->storage.aggregate >= MAX_STORAGE)
+ if (stor->aggregate >= stst->capacity)
return 1;
- ARR_FIND(0, VECTOR_LENGTH(sd->storage.item), i, VECTOR_INDEX(sd->storage.item, i).nameid == 0);
+ ARR_FIND(0, VECTOR_LENGTH(stor->item), i, VECTOR_INDEX(stor->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);
+ if (i == VECTOR_LENGTH(stor->item)) {
+ VECTOR_ENSURE(stor->item, 1, 1);
+ VECTOR_PUSH(stor->item, *item_data);
+ it = &VECTOR_LAST(stor->item);
} else {
- it = &VECTOR_INDEX(sd->storage.item, i);
+ it = &VECTOR_INDEX(stor->item, i);
*it = *item_data;
}
it->amount = amount;
- sd->storage.aggregate++;
+ stor->aggregate++;
clif->storageitemadded(sd, it, i, amount);
- clif->updatestorageamount(sd, sd->storage.aggregate, MAX_STORAGE);
+ clif->updatestorageamount(sd, stor->aggregate, stst->capacity);
- sd->storage.save = true; // set a save flag.
+ stor->save = true; // set a save flag.
return 0;
}
@@ -238,30 +311,31 @@ static int storage_additem(struct map_session_data *sd, struct item *item_data,
/*==========================================
* Internal del-item function
*------------------------------------------*/
-static int storage_delitem(struct map_session_data *sd, int n, int amount)
+static int storage_delitem(struct map_session_data *sd, struct storage_data *stor, int n, int amount)
{
- struct item *it = NULL;
nullpo_retr(1, sd);
+ nullpo_retr(1, stor);
+ Assert_retr(1, stor->received);
- Assert_retr(1, sd->storage.received == true);
-
- Assert_retr(1, n >= 0 && n < VECTOR_LENGTH(sd->storage.item));
+ const struct storage_settings* stst = NULL;
+ nullpo_retr(1, (stst = storage->get_settings(stor->uid)));
- it = &VECTOR_INDEX(sd->storage.item, n);
+ Assert_retr(1, n >= 0 && n < VECTOR_LENGTH(stor->item));
+ struct item *it = &VECTOR_INDEX(stor->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);
+ clif->updatestorageamount(sd, --stor->aggregate, stst->capacity);
}
- sd->storage.save = true;
+ stor->save = true;
if (sd->state.storage_flag == STORAGE_FLAG_NORMAL)
clif->storageitemremoved(sd, n, amount);
@@ -276,13 +350,22 @@ static int storage_delitem(struct map_session_data *sd, int n, int amount)
* 0 : fail
* 1 : success
*------------------------------------------*/
-static int storage_add_from_inventory(struct map_session_data *sd, int index, int amount)
+static int storage_add_from_inventory(struct map_session_data *sd, struct storage_data *stor, int index, int amount)
{
- nullpo_ret(sd);
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor);
+ Assert_retr(0, stor->received);
+
+ const struct storage_settings *stst = NULL;
+ nullpo_retr(0, (stst = storage->get_settings(stor->uid)));
- Assert_ret(sd->storage.received == true);
+ if ((sd->storage.access & STORAGE_ACCESS_PUT) == 0) {
+ clif->delitem(sd, index, amount, DELITEM_NORMAL);
+ clif->additem(sd, index, amount, 0);
+ return 0;
+ }
- if (sd->storage.aggregate > MAX_STORAGE)
+ if (stor->aggregate >= stst->capacity)
return 0; // storage full
if (index < 0 || index >= sd->status.inventorySize)
@@ -294,7 +377,7 @@ static int storage_add_from_inventory(struct map_session_data *sd, int index, in
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, stor, &sd->status.inventory[index], amount) == 0)
pc->delitem(sd, index, amount, 0, DELITEM_TOSTORAGE, LOG_TYPE_STORAGE);
else
clif->item_movefailed(sd, index);
@@ -309,19 +392,20 @@ static int storage_add_from_inventory(struct map_session_data *sd, int index, in
* 0 : fail
* 1 : success
*------------------------------------------*/
-static int storage_add_to_inventory(struct map_session_data *sd, int index, int amount)
+static int storage_add_to_inventory(struct map_session_data *sd, struct storage_data *stor, int index, int amount)
{
- int flag;
- struct item *it = NULL;
-
nullpo_ret(sd);
+ nullpo_ret(stor);
- Assert_ret(sd->storage.received == true);
+ Assert_ret(stor->received);
- if (index < 0 || index >= VECTOR_LENGTH(sd->storage.item))
+ if ((sd->storage.access & STORAGE_ACCESS_GET) == 0)
return 0;
- it = &VECTOR_INDEX(sd->storage.item, index);
+ if (index < 0 || index >= VECTOR_LENGTH(stor->item))
+ return 0;
+
+ struct item *it = &VECTOR_INDEX(stor->item, index);
if (it->nameid <= 0)
return 0; //Nothing there
@@ -329,8 +413,9 @@ static int storage_add_to_inventory(struct map_session_data *sd, int index, int
if (amount < 1 || amount > it->amount)
return 0;
+ int flag;
if ((flag = pc->additem(sd, it, amount, LOG_TYPE_STORAGE)) == 0)
- storage->delitem(sd, index, amount);
+ storage->delitem(sd, stor, index, amount);
else
clif->additem(sd, 0, 0, flag);
@@ -344,26 +429,36 @@ static int storage_add_to_inventory(struct map_session_data *sd, int index, int
* 0 : fail
* 1 : success
*------------------------------------------*/
-static int storage_storageaddfromcart(struct map_session_data *sd, int index, int amount)
+static int storage_storageaddfromcart(struct map_session_data *sd, struct storage_data *stor, int index, int amount)
{
nullpo_ret(sd);
+ nullpo_ret(stor);
+ Assert_ret(stor->received);
+
+ const struct storage_settings *stst = NULL;
+ nullpo_ret(stst = storage->get_settings(stor->uid));
- Assert_ret(sd->storage.received == true);
- if (sd->storage.aggregate > MAX_STORAGE)
+ if ((sd->storage.access & STORAGE_ACCESS_PUT) == 0) {
+ clif->delitem(sd, index, amount, DELITEM_NORMAL);
+ clif->additem(sd, index, amount, 0);
+ return 0;
+ }
+
+ if (stor->aggregate >= stst->capacity)
return 0; // storage full / storage closed
if (index < 0 || index >= MAX_CART)
return 0;
- if( sd->status.cart[index].nameid <= 0 )
+ if (sd->status.cart[index].nameid <= 0)
return 0; //No item there.
if (amount < 1 || amount > sd->status.cart[index].amount)
return 0;
- if (storage->additem(sd,&sd->status.cart[index],amount) == 0)
- pc->cart_delitem(sd,index,amount,0,LOG_TYPE_STORAGE);
+ if (storage->additem(sd, stor, &sd->status.cart[index], amount) == 0)
+ pc->cart_delitem(sd, index, amount, 0, LOG_TYPE_STORAGE);
return 1;
}
@@ -375,19 +470,19 @@ static int storage_storageaddfromcart(struct map_session_data *sd, int index, in
* 0 : fail
* 1 : success
*------------------------------------------*/
-static int storage_storagegettocart(struct map_session_data *sd, int index, int amount)
+static int storage_storagegettocart(struct map_session_data *sd, struct storage_data *stor, int index, int amount)
{
- int flag = 0;
- struct item *it = NULL;
+ nullpo_retr(0, sd);
+ nullpo_retr(0, stor);
+ Assert_retr(0, stor->received);
- nullpo_ret(sd);
-
- Assert_ret(sd->storage.received == true);
+ if ((sd->storage.access & STORAGE_ACCESS_GET) == 0)
+ return 0;
- if (index < 0 || index >= VECTOR_LENGTH(sd->storage.item))
+ if (index < 0 || index >= VECTOR_LENGTH(stor->item))
return 0;
- it = &VECTOR_INDEX(sd->storage.item, index);
+ struct item *it = &VECTOR_INDEX(stor->item, index);
if (it->nameid <= 0)
return 0; //Nothing there.
@@ -395,8 +490,9 @@ static int storage_storagegettocart(struct map_session_data *sd, int index, int
if (amount < 1 || amount > it->amount)
return 0;
+ int flag = 0;
if ((flag = pc->cart_additem(sd, it, amount, LOG_TYPE_STORAGE)) == 0)
- storage->delitem(sd, index, amount);
+ storage->delitem(sd, stor, index, amount);
else {
// probably this line is useless? it remove inventory lock but not storage [4144]
clif->dropitem(sd, index,0);
@@ -413,11 +509,12 @@ static int storage_storagegettocart(struct map_session_data *sd, int index, int
*------------------------------------------*/
static void storage_storageclose(struct map_session_data *sd)
{
- int i = 0;
-
nullpo_retv(sd);
- Assert_retv(sd->storage.received == true);
+ struct storage_data *curr_stor = NULL;
+ if ((curr_stor = storage->ensure(sd, sd->storage.current)) == NULL)
+ return;
+
clif->storageclose(sd);
@@ -426,15 +523,18 @@ static void storage_storageclose(struct map_session_data *sd)
/* 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);
+ int i = 0;
+ while (i < VECTOR_LENGTH(curr_stor->item)) {
+ if (VECTOR_INDEX(curr_stor->item, i).nameid == 0) {
+ VECTOR_ERASE(curr_stor->item, i);
} else {
i++;
}
}
sd->state.storage_flag = STORAGE_FLAG_CLOSED;
+ sd->storage.current = 0; // Reset current storage identifier.
+ sd->storage.access = STORAGE_ACCESS_ALL; // Reset access level to all levels.
}
/*==========================================
@@ -841,10 +941,132 @@ static int storage_guild_storage_quit(struct map_session_data *sd, int flag)
return 0;
}
+/**
+ * Read additional storage configuration fields for plugins.
+ *
+ * @param t [in] pointer to the config element being parsed.
+ * @param s_conf [in] pointer to the config struct being written to.
+ * @param filename [in] pointer to the filename string.
+ */
+static void storage_config_read_additional_fields(struct config_setting_t *t, struct storage_settings *s_conf, const char *filename)
+{
+ // plugins do their own thing.
+}
+
+/**
+ * Dynamically reads storage configuration and initializes required variables.
+ *
+ * @param filename Path to configuration file.
+ * @param imported Whether the current config is imported from another file.
+ * @retval false in case of error.
+ */
+static bool storage_config_read(const char *filename, bool imported)
+{
+ nullpo_retr(false, filename);
+
+ if (!imported)
+ VECTOR_INIT(storage->configuration);
+
+ struct config_t stor_libconf;
+ if (libconfig->load_file(&stor_libconf, filename) == CONFIG_FALSE)
+ return false; // Error message is already shown by libconfig->load_file()
+
+ const struct config_setting_t *setting = NULL;
+ if ((setting = libconfig->setting_get_member(stor_libconf.root, "storage_conf")) == NULL && !imported) {
+ ShowError("storage_config_read: Error in reading file '%s'\n", filename);
+ libconfig->destroy(&stor_libconf);
+ return false;
+ }
+
+ struct config_setting_t *t = NULL;
+ int i = 0;
+ while ((t = libconfig->setting_get_elem(setting, i++)) != NULL) {
+ struct storage_settings s_conf = { 0 };
+
+ /* Id */
+ if (libconfig->setting_lookup_int(t, "Id", &s_conf.uid) == CONFIG_FALSE) {
+ ShowError("storage_config_read: Id field not found for storage configuration in '%s'. Skipping...\n", filename);
+ continue;
+ }
+
+ // Duplicate ID search and report...
+ int d = 0;
+ ARR_FIND(0, VECTOR_LENGTH(storage->configuration), d, VECTOR_INDEX(storage->configuration, d).uid == s_conf.uid);
+ if (d < VECTOR_LENGTH(storage->configuration)) {
+ ShowError("storage_config_read: Duplicate ID %d for storage. Skipping...\n", s_conf.uid);
+ continue;
+ }
+
+ // Check for an invalid ID...
+ if (s_conf.uid <= 0) {
+ ShowError("storage_config_read: ID for storage cannot be less than or equal to zero. Skipping...\n");
+ continue;
+ }
+
+ /* Name */
+ if (libconfig->setting_lookup_mutable_string(t, "Name", s_conf.name, NAME_LENGTH) == CONFIG_FALSE) {
+ ShowError("storage_config_read: Name field not found for storage configuration (Id: %d) in '%s'. Skipping...\n", s_conf.uid, filename);
+ continue;
+ }
+
+ /* Capacity */
+ if (libconfig->setting_lookup_int(t, "Capacity", &s_conf.capacity) == CONFIG_FALSE) {
+ ShowError("storage_config_read: Capacity field not found for storage configuration (Id: %d) in '%s'. Skipping...\n", s_conf.uid, filename);
+ continue;
+ }
+
+ /* Additional Fields */
+ struct config_setting_t *tt = NULL;
+ storage->config_read_additional_fields(tt, &s_conf, filename);
+
+ if (imported) {
+ ARR_FIND(0, VECTOR_LENGTH(storage->configuration), i, VECTOR_INDEX(storage->configuration, i).uid == s_conf.uid);
+ if (i < VECTOR_LENGTH(storage->configuration))
+ VECTOR_ERASE(storage->configuration, i);
+ }
+
+ VECTOR_ENSURE(storage->configuration, 1, 1);
+ VECTOR_PUSH(storage->configuration, s_conf);
+ }
+
+ // import should overwrite any previous configuration, so it should be called last
+ const char *import = NULL;
+ if (libconfig->lookup_string(&stor_libconf, "import", &import) == CONFIG_TRUE) {
+ if (strcmp(import, filename) == 0 || strcmp(import, map->STORAGE_CONF_FILENAME) == 0) {
+ ShowWarning("battle_config_read: Loop detected! Skipping 'import'...\n");
+ libconfig->destroy(&stor_libconf);
+ return false;
+ } else if (storage->config_read(import, true) == false) {
+ libconfig->destroy(&stor_libconf);
+ return false;
+ }
+ }
+
+ libconfig->destroy(&stor_libconf);
+
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", VECTOR_LENGTH(storage->configuration), map->STORAGE_CONF_FILENAME);
+
+ return true;
+}
+
+static void do_init_storage(bool minimal)
+{
+ if (minimal)
+ return;
+}
+
+static void do_final_storage(void)
+{
+ // Clear storage configuration vector.
+ if (VECTOR_LENGTH(storage->configuration) > 0)
+ VECTOR_CLEAR(storage->configuration);
+}
+
static void do_init_gstorage(bool minimal)
{
if (minimal)
return;
+
gstorage->db = idb_alloc(DB_OPT_RELEASE_DATA);
}
@@ -857,9 +1079,16 @@ void storage_defaults(void)
{
storage = &storage_s;
+ storage->init = do_init_storage;
+ storage->final = do_final_storage;
/* */
storage->reconnect = do_reconnect_storage;
+ storage->config_read = storage_config_read;
+ storage->config_read_additional_fields = storage_config_read_additional_fields;
/* */
+ storage->get_id_by_name = storage_get_id_by_name;
+ storage->ensure = storage_ensure;
+ storage->get_settings = storage_get_settings;
storage->delitem = storage_delitem;
storage->open = storage_storageopen;
storage->add = storage_add_from_inventory;
diff --git a/src/map/storage.h b/src/map/storage.h
index 5c6152894..ec1ce4fe5 100644
--- a/src/map/storage.h
+++ b/src/map/storage.h
@@ -24,9 +24,12 @@
#include "common/hercules.h"
#include "common/db.h"
+struct config_setting_t;
struct guild_storage;
struct item;
struct map_session_data;
+struct storage_settings;
+struct storage_data;
/**
* Acceptable values for map_session_data.state.storage_flag
@@ -37,21 +40,37 @@ enum storage_flag {
STORAGE_FLAG_GUILD = 2, // Guild Storage open
};
+// Storage Access Modes [Smokexyz/Hercules]
+enum storage_access_modes {
+ STORAGE_ACCESS_VIEW = 0x0,
+ STORAGE_ACCESS_GET = 0x1,
+ STORAGE_ACCESS_PUT = 0x2,
+ STORAGE_ACCESS_ALL = STORAGE_ACCESS_VIEW | STORAGE_ACCESS_GET | STORAGE_ACCESS_PUT
+};
+
struct storage_interface {
+ VECTOR_DECL(struct storage_settings) configuration;
+ void (*init) (bool minimal);
+ void (*final) (void);
/* */
void (*reconnect) (void);
+ bool (*config_read) (const char *filename, bool imported);
+ void (*config_read_additional_fields) (struct config_setting_t *t, struct storage_settings *s_conf, const char *filename);
/* */
- int (*delitem) (struct map_session_data* sd, int n, int amount);
- int (*open) (struct map_session_data *sd);
- int (*add) (struct map_session_data *sd,int index,int amount);
- int (*get) (struct map_session_data *sd,int index,int amount);
- int (*additem) (struct map_session_data* sd, struct item* item_data, int amount);
- int (*addfromcart) (struct map_session_data *sd,int index,int amount);
- int (*gettocart) (struct map_session_data *sd,int index,int amount);
+ int (*get_id_by_name) (const char *storage_name);
+ struct storage_data *(*ensure) (struct map_session_data *sd, int storage_id);
+ const struct storage_settings *(*get_settings) (int storage_id);
+ int (*delitem) (struct map_session_data *sd, struct storage_data *stor, int n, int amount);
+ int (*open) (struct map_session_data *sd, struct storage_data *stor);
+ int (*add) (struct map_session_data *sd, struct storage_data *stor, int index, int amount);
+ int (*get) (struct map_session_data *sd, struct storage_data *stor, int index, int amount);
+ int (*additem) (struct map_session_data *sd, struct storage_data *stor, struct item* item_data, int amount);
+ int (*addfromcart) (struct map_session_data *sd, struct storage_data *stor, int index,int amount);
+ int (*gettocart) (struct map_session_data *sd, struct storage_data *stor, int index,int amount);
void (*close) (struct map_session_data *sd);
void (*pc_quit) (struct map_session_data *sd, int flag);
int (*comp_item) (const void *i1_, const void *i2_);
- void (*sortitem) (struct item* items, unsigned int size);
+ void (*sortitem) (struct item *items, unsigned int size);
int (*reconnect_sub) (union DBKey key, struct DBData *data, va_list ap);
};
diff --git a/src/map/unit.c b/src/map/unit.c
index 1e9433eaf..ba055da02 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -2750,8 +2750,7 @@ static int unit_free(struct block_list *bl, enum clr_type clrtype)
sd->combo_count = 0;
/* [Ind/Hercules] */
if( sd->sc_display_count ) {
- int i;
- for(i = 0; i < sd->sc_display_count; i++) {
+ for (int i = 0; i < sd->sc_display_count; i++) {
ers_free(pc->sc_display_ers, sd->sc_display[i]);
}
sd->sc_display_count = 0;
@@ -2767,10 +2766,16 @@ static int unit_free(struct block_list *bl, enum clr_type clrtype)
VECTOR_CLEAR(sd->channels);
VECTOR_CLEAR(sd->script_queues);
VECTOR_CLEAR(sd->achievement); // Achievement [Smokexyz/Hercules]
- VECTOR_CLEAR(sd->storage.item);
VECTOR_CLEAR(sd->hatEffectId);
VECTOR_CLEAR(sd->title_ids); // Title [Dastgir/Hercules]
- sd->storage.received = false;
+
+ /* Storages */
+ for (int i = 0; i < VECTOR_LENGTH(sd->storage.list); i++) {
+ VECTOR_CLEAR(VECTOR_INDEX(sd->storage.list, i).item);
+ VECTOR_INDEX(sd->storage.list, i).received = false;
+ }
+ VECTOR_CLEAR(sd->storage.list);
+
if( sd->quest_log != NULL ) {
aFree(sd->quest_log);
sd->quest_log = NULL;