summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2017-05-27 19:24:42 +0200
committerGitHub <noreply@github.com>2017-05-27 19:24:42 +0200
commitcb3e2f5f3b91d0a1f7711eff9c10ae9a655a74f2 (patch)
tree1b1df55f4143bae6bed85093f3424b6af11e4a01 /src/map
parentbe118c7fad6df29dc691452ef511ac12fea37a06 (diff)
parentd966a8e6860d418bb3a235e57928436127eba555 (diff)
downloadhercules-cb3e2f5f3b91d0a1f7711eff9c10ae9a655a74f2.tar.gz
hercules-cb3e2f5f3b91d0a1f7711eff9c10ae9a655a74f2.tar.bz2
hercules-cb3e2f5f3b91d0a1f7711eff9c10ae9a655a74f2.tar.xz
hercules-cb3e2f5f3b91d0a1f7711eff9c10ae9a655a74f2.zip
Merge pull request #1722 from Smokexyz/mmo_charstatus-fix
Dismemberment of `storage_data` from `mmo_charstatus`.
Diffstat (limited to 'src/map')
-rw-r--r--src/map/atcommand.c27
-rw-r--r--src/map/battle.c2
-rw-r--r--src/map/chrif.c3
-rw-r--r--src/map/clif.c44
-rw-r--r--src/map/intif.c137
-rw-r--r--src/map/intif.h4
-rw-r--r--src/map/itemdb.c10
-rw-r--r--src/map/pc.c119
-rw-r--r--src/map/pc.h13
-rw-r--r--src/map/script.c10
-rw-r--r--src/map/storage.c207
-rw-r--r--src/map/unit.c2
12 files changed, 421 insertions, 157 deletions
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 9f37a754f..4d3a82ee2 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -5159,6 +5159,11 @@ ACMD(storeall)
}
}
+ if (sd->storage.received == false) {
+ clif->message(fd, msg_fd(fd, 27)); // "Storage has not been loaded yet"
+ return false;
+ }
+
for (i = 0; i < MAX_INVENTORY; i++) {
if (sd->status.inventory[i].amount) {
if(sd->status.inventory[i].equip != 0)
@@ -5174,17 +5179,25 @@ ACMD(storeall)
ACMD(clearstorage)
{
- int i, j;
+ int i;
if (sd->state.storage_flag == STORAGE_FLAG_NORMAL) {
clif->message(fd, msg_fd(fd,250));
return false;
}
- j = sd->status.storage.storage_amount;
- for (i = 0; i < j; ++i) {
- storage->delitem(sd, i, sd->status.storage.items[i].amount);
+ if (sd->storage.received == false) {
+ 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)
+ continue; // we skip the already deleted items.
+
+ storage->delitem(sd, i, VECTOR_INDEX(sd->storage.item, i).amount);
+ }
+
storage->close(sd);
clif->message(fd, msg_fd(fd,1394)); // Your storage was cleaned.
@@ -8041,8 +8054,8 @@ ACMD(itemlist)
if( strcmpi(info->command, "storagelist") == 0 ) {
location = "storage";
- items = sd->status.storage.items;
- size = MAX_STORAGE;
+ items = VECTOR_DATA(sd->storage.item);
+ size = VECTOR_LENGTH(sd->storage.item);
} else if( strcmpi(info->command, "cartlist") == 0 ) {
location = "cart";
items = sd->status.cart;
@@ -8063,7 +8076,7 @@ ACMD(itemlist)
const struct item* it = &items[i];
struct item_data* itd;
- if( it->nameid == 0 || (itd = itemdb->exists(it->nameid)) == NULL )
+ if (it->nameid == 0 || (itd = itemdb->exists(it->nameid)) == NULL)
continue;
counter += it->amount;
diff --git a/src/map/battle.c b/src/map/battle.c
index 11425d4a9..57a74bba4 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -7034,7 +7034,7 @@ static const struct battle_data {
{ "max_heal_lv", &battle_config.max_heal_lv, 11, 1, INT_MAX, },
{ "max_heal", &battle_config.max_heal, 9999, 0, INT_MAX, },
{ "combo_delay_rate", &battle_config.combo_delay_rate, 100, 0, INT_MAX, },
- { "item_check", &battle_config.item_check, 0, 0, 1, },
+ { "item_check", &battle_config.item_check, 0, 0, 0xF, },
{ "item_use_interval", &battle_config.item_use_interval, 100, 0, INT_MAX, },
{ "wedding_modifydisplay", &battle_config.wedding_modifydisplay, 0, 0, 1, },
{ "wedding_ignorepalette", &battle_config.wedding_ignorepalette, 0, 0, 1, },
diff --git a/src/map/chrif.c b/src/map/chrif.c
index bf613b029..39aa046d7 100644
--- a/src/map/chrif.c
+++ b/src/map/chrif.c
@@ -324,6 +324,9 @@ bool chrif_save(struct map_session_data *sd, int flag) {
if( sd->save_quest )
intif->quest_save(sd);
+ if (sd->storage.received == true && sd->storage.save == true)
+ intif->send_account_storage(sd);
+
return true;
}
diff --git a/src/map/clif.c b/src/map/clif.c
index e70857ab6..524378439 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -4189,12 +4189,13 @@ void clif_storageitemremoved(struct map_session_data* sd, int index, int amount)
nullpo_retv(sd);
- fd=sd->fd;
- WFIFOHEAD(fd,packet_len(0xf6));
- WFIFOW(fd,0)=0xf6; // Storage item removed
- WFIFOW(fd,2)=index+1;
- WFIFOL(fd,4)=amount;
- WFIFOSET(fd,packet_len(0xf6));
+ fd = sd->fd;
+
+ WFIFOHEAD(fd, packet_len(0xf6));
+ WFIFOW(fd, 0) = 0xf6; // Storage item removed
+ WFIFOW(fd, 2) = index + 1;
+ WFIFOL(fd, 4) = amount;
+ WFIFOSET(fd, packet_len(0xf6));
}
/// Closes storage (ZC_CLOSE_STORE).
@@ -8431,9 +8432,11 @@ 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) {
- 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);
}
// Notify the client that the gstorage is open otherwise it will
// remain locked forever and nobody will be able to access it
@@ -9340,7 +9343,7 @@ void clif_parse_LoadEndAck(int fd, struct map_session_data *sd) {
sd->state.warping = 0;
sd->state.dialog = 0;/* reset when warping, client dialog will go missing */
- // look
+ // Character Looks
#if PACKETVER < 4
clif->changelook(&sd->bl,LOOK_WEAPON,sd->status.weapon);
clif->changelook(&sd->bl,LOOK_SHIELD,sd->status.shield);
@@ -9350,21 +9353,26 @@ void clif_parse_LoadEndAck(int fd, struct map_session_data *sd) {
if(sd->vd.cloth_color)
clif->refreshlook(&sd->bl,sd->bl.id,LOOK_CLOTHES_COLOR,sd->vd.cloth_color,SELF);
+
if (sd->vd.body_style)
clif->refreshlook(&sd->bl,sd->bl.id,LOOK_BODY2,sd->vd.body_style,SELF);
- // item
- clif->inventorylist(sd); // inventory list first, otherwise deleted items in pc->checkitem show up as 'unknown item'
- pc->checkitem(sd);
- // cart
+ // Send character inventory to the client.
+ // call this before pc->checkitem() so that the client isn't called to delete a non-existent item.
+ clif->inventorylist(sd);
+
+ // Send the cart inventory, counts & weight to the client.
if(pc_iscarton(sd)) {
clif->cartlist(sd);
- clif->updatestatus(sd,SP_CARTINFO);
+ clif->updatestatus(sd, SP_CARTINFO);
}
- // weight
- clif->updatestatus(sd,SP_WEIGHT);
- clif->updatestatus(sd,SP_MAXWEIGHT);
+ // Check for and delete unavailable/disabled items.
+ pc->checkitem(sd);
+
+ // Send the character's weight to the client.
+ clif->updatestatus(sd, SP_WEIGHT);
+ clif->updatestatus(sd, SP_MAXWEIGHT);
// guild
// (needs to go before clif_spawn() to show guild emblems correctly)
diff --git a/src/map/intif.c b/src/map/intif.c
index 10a9ea8a9..61d2e3633 100644
--- a/src/map/intif.c
+++ b/src/map/intif.c
@@ -439,6 +439,135 @@ int intif_request_registry(struct map_session_data *sd, int flag)
return 0;
}
+//=================================================================
+// Account Storage
+//-----------------------------------------------------------------
+
+/**
+ * Request the inter-server for a character's storage data.
+ * @packet 0x3010 [out] <account_id>.L
+ * @param sd [in] pointer to session data.
+ */
+void intif_request_account_storage(const struct map_session_data *sd)
+{
+ nullpo_retv(sd);
+
+ /* Check for character server availability */
+ if (intif->CheckForCharServer())
+ return;
+
+ WFIFOHEAD(inter_fd, 6);
+ WFIFOW(inter_fd, 0) = 0x3010;
+ WFIFOL(inter_fd, 2) = sd->status.account_id;
+ WFIFOSET(inter_fd, 6);
+}
+
+/**
+ * Parse the reception of account storage from the inter-server.
+ * @packet 0x3805 [in] <packet_len>.W <account_id>.L <struct item[]>.P
+ * @param fd [in] file/socket descriptor.
+ */
+void intif_parse_account_storage(int fd)
+{
+ int account_id = 0, payload_size = 0, storage_count = 0;
+ int i = 0;
+ struct map_session_data *sd = NULL;
+
+ Assert_retv(fd > 0);
+
+ payload_size = RFIFOW(fd, 2) - 8;
+
+ 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) {
+ 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);
+
+ sd->storage.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);
+ }
+
+ sd->storage.received = true; // Mark the storage state as received.
+ sd->storage.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.
+ */
+void intif_send_account_storage(const struct map_session_data *sd)
+{
+ int len = 0, i = 0, c = 0;
+
+ nullpo_retv(sd);
+
+ // Assert that at this point in the code, both flags are true.
+ Assert_retv(sd->storage.save == true);
+ Assert_retv(sd->storage.received == true);
+
+ if (intif->CheckForCharServer())
+ return;
+
+ len = 8 + sd->storage.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)
+ continue;
+ memcpy(WFIFOP(inter_fd, 8 + c * sizeof(struct item)), &VECTOR_INDEX(sd->storage.item, i), sizeof(struct item));
+ c++;
+ }
+
+ WFIFOSET(inter_fd, len);
+}
+
+/**
+ * Parse acknowledgement packet for the saving of an account's storage.
+ * @packet 0x3808 [in] <account_id>.L <saved_flag>.B
+ * @param fd [in] file/socket descriptor.
+ */
+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;
+
+ Assert_retv(account_id > 0);
+ Assert_retv(fd > 0);
+
+ 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);
+ return;
+ }
+
+ sd->storage.save = false; // Storage has been saved.
+}
+
+//=================================================================
+// Guild Storage
+//-----------------------------------------------------------------
+
int intif_request_guild_storage(int account_id,int guild_id)
{
if (intif->CheckForCharServer())
@@ -2306,8 +2435,10 @@ int intif_parse(int fd)
case 0x3802: intif->pWisEnd(fd); break;
case 0x3803: intif->pWisToGM(fd); break;
case 0x3804: intif->pRegisters(fd); break;
+ case 0x3805: intif->pAccountStorage(fd); break;
case 0x3806: intif->pChangeNameOk(fd); break;
case 0x3807: intif->pMessageToFD(fd); break;
+ case 0x3808: intif->pAccountStorageSaveAck(fd); break;
case 0x3818: intif->pLoadGuildStorage(fd); break;
case 0x3819: intif->pSaveGuildStorage(fd); break;
case 0x3820: intif->pPartyCreated(fd); break;
@@ -2394,7 +2525,7 @@ int intif_parse(int fd)
*-------------------------------------*/
void intif_defaults(void) {
const int packet_len_table [INTIF_PACKET_LEN_TABLE_SIZE] = {
- -1,-1,27,-1, -1, 0,37,-1, 0, 0, 0, 0, 0, 0, 0, 0, //0x3800-0x380f
+ -1,-1,27,-1, -1,-1,37,-1, 7, 0, 0, 0, 0, 0, 0, 0, //0x3800-0x380f
0, 0, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0, //0x3810
39,-1,15,15, 14,19, 7,-1, 0, 0, 0, 0, 0, 0, 0, 0, //0x3820
10,-1,15, 0, 79,19, 7,-1, 0,-1,-1,-1, 14,67,186,-1, //0x3830
@@ -2421,6 +2552,8 @@ void intif_defaults(void) {
intif->wis_message_to_gm = intif_wis_message_to_gm;
intif->saveregistry = intif_saveregistry;
intif->request_registry = intif_request_registry;
+ intif->request_account_storage = intif_request_account_storage;
+ intif->send_account_storage = intif_send_account_storage;
intif->request_guild_storage = intif_request_guild_storage;
intif->send_guild_storage = intif_send_guild_storage;
intif->create_party = intif_create_party;
@@ -2497,6 +2630,8 @@ void intif_defaults(void) {
intif->pRegisters = intif_parse_Registers;
intif->pChangeNameOk = intif_parse_ChangeNameOk;
intif->pMessageToFD = intif_parse_MessageToFD;
+ intif->pAccountStorage = intif_parse_account_storage;
+ intif->pAccountStorageSaveAck = intif_parse_account_storage_save_ack;
intif->pLoadGuildStorage = intif_parse_LoadGuildStorage;
intif->pSaveGuildStorage = intif_parse_SaveGuildStorage;
intif->pPartyCreated = intif_parse_PartyCreated;
diff --git a/src/map/intif.h b/src/map/intif.h
index b20acf029..3d6a52440 100644
--- a/src/map/intif.h
+++ b/src/map/intif.h
@@ -66,6 +66,8 @@ struct intif_interface {
int (*wis_message_to_gm) (char *Wisp_name, int permission, char *mes);
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) (const struct map_session_data *sd);
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);
@@ -139,8 +141,10 @@ struct intif_interface {
int (*pWisToGM_sub) (struct map_session_data* sd,va_list va);
void (*pWisToGM) (int fd);
void (*pRegisters) (int fd);
+ void (*pAccountStorage) (int fd);
void (*pChangeNameOk) (int fd);
void (*pMessageToFD) (int fd);
+ void (*pAccountStorageSaveAck) (int fd);
void (*pLoadGuildStorage) (int fd);
void (*pSaveGuildStorage) (int fd);
void (*pPartyCreated) (int fd);
diff --git a/src/map/itemdb.c b/src/map/itemdb.c
index 4076e295c..9a43bae14 100644
--- a/src/map/itemdb.c
+++ b/src/map/itemdb.c
@@ -2490,16 +2490,20 @@ void itemdb_reload(void) {
for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) {
memset(sd->item_delay, 0, sizeof(sd->item_delay)); // reset item delays
pc->setinventorydata(sd);
- if( battle_config.item_check )
- sd->state.itemcheck = 1;
+
+ if (battle->bc->item_check != PCCHECKITEM_NONE) // Check and flag items for inspection.
+ sd->itemcheck = (enum pc_checkitem_types) battle->bc->item_check;
+
/* clear combo bonuses */
- if( sd->combo_count ) {
+ if (sd->combo_count) {
aFree(sd->combos);
sd->combos = NULL;
sd->combo_count = 0;
if( pc->load_combo(sd) > 0 )
status_calc_pc(sd,SCO_FORCE);
}
+
+ // Check for and delete unavailable/disabled items.
pc->checkitem(sd);
}
mapit->free(iter);
diff --git a/src/map/pc.c b/src/map/pc.c
index f40fba8ae..2303a83ca 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -1251,13 +1251,14 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
sd->bg_queue.type = 0;
VECTOR_INIT(sd->script_queues);
+ VECTOR_INIT(sd->storage.item); // initialize storage item vector.
sd->state.dialog = 0;
sd->delayed_damage = 0;
- if( battle_config.item_check )
- sd->state.itemcheck = 1;
+ if (battle->bc->item_check != PCCHECKITEM_NONE) // Check and flag items for inspection.
+ sd->itemcheck = (enum pc_checkitem_types) battle->bc->item_check;
// Event Timers
for( i = 0; i < MAX_EVENTTIMER; i++ )
@@ -1483,6 +1484,9 @@ int pc_reg_received(struct map_session_data *sd)
status_calc_pc(sd,SCO_FIRST|SCO_FORCE);
chrif->scdata_request(sd->status.account_id, sd->status.char_id);
+ // Storage Request
+ intif->request_account_storage(sd);
+
intif->Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox
intif->request_questlog(sd);
@@ -10166,99 +10170,108 @@ int pc_checkitem(struct map_session_data *sd)
nullpo_ret(sd);
- if (sd->state.vending) //Avoid reorganizing items when we are vending, as that leads to exploits (pointed out by End of Exam)
+ if (sd->state.vending == 1) // Avoid reorganizing items when we are vending, as that leads to exploits (pointed out by End of Exam)
return 0;
- if (sd->state.itemcheck) { // check for invalid(ated) items
- int id;
- for (i = 0; i < MAX_INVENTORY; i++) {
- id = sd->status.inventory[i].nameid;
+ if (sd->itemcheck != PCCHECKITEM_NONE) { // check for invalid(ated) items
+ int id = 0;
- if (!id)
- continue;
+ if (sd->itemcheck & PCCHECKITEM_INVENTORY) {
+ for (i = 0; i < MAX_INVENTORY; i++) {
+ if ((id = sd->status.inventory[i].nameid) == 0)
+ continue;
- if (!itemdb_available(id)) {
- ShowWarning("Removed invalid/disabled item id %d from inventory (amount=%d, char_id=%d).\n", id, sd->status.inventory[i].amount, sd->status.char_id);
- pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_INV_INVALID);
- continue;
+ if (!itemdb_available(id)) {
+ ShowWarning("pc_checkitem: Removed invalid/disabled item id %d from inventory (amount=%d, char_id=%d).\n", id, sd->status.inventory[i].amount, sd->status.char_id);
+ pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_INV_INVALID);
+ continue;
+ }
+
+ if (sd->status.inventory[i].unique_id == 0 && !itemdb->isstackable(id))
+ sd->status.inventory[i].unique_id = itemdb->unique_id(sd);
}
- if (!sd->status.inventory[i].unique_id && !itemdb->isstackable(id))
- sd->status.inventory[i].unique_id = itemdb->unique_id(sd);
+ sd->itemcheck &= ~PCCHECKITEM_INVENTORY;
}
- for( i = 0; i < MAX_CART; i++ ) {
- id = sd->status.cart[i].nameid;
+ if (sd->itemcheck & PCCHECKITEM_CART) {
+ for (i = 0; i < MAX_CART; i++) {
+ if ((id = sd->status.cart[i].nameid) == 0)
+ continue;
- if (!id)
- continue;
+ if( !itemdb_available(id) ) {
+ ShowWarning("pc_checkitem: Removed invalid/disabled item id %d from cart (amount=%d, char_id=%d).\n", id, sd->status.cart[i].amount, sd->status.char_id);
+ pc->cart_delitem(sd, i, sd->status.cart[i].amount, 0, LOG_TYPE_CART_INVALID);
+ continue;
+ }
- if( !itemdb_available(id) ) {
- ShowWarning("Removed invalid/disabled item id %d from cart (amount=%d, char_id=%d).\n", id, sd->status.cart[i].amount, sd->status.char_id);
- pc->cart_delitem(sd, i, sd->status.cart[i].amount, 0, LOG_TYPE_CART_INVALID);
- continue;
+ if (sd->status.cart[i].unique_id == 0 && !itemdb->isstackable(id))
+ sd->status.cart[i].unique_id = itemdb->unique_id(sd);
}
- if ( !sd->status.cart[i].unique_id && !itemdb->isstackable(id) )
- sd->status.cart[i].unique_id = itemdb->unique_id(sd);
+ sd->itemcheck &= ~PCCHECKITEM_CART;
}
- for( i = 0; i < MAX_STORAGE; i++ ) {
- id = sd->status.storage.items[i].nameid;
+ 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 (!id)
- continue;
+ if ((id = it->nameid) == 0)
+ continue;
- if( id && !itemdb_available(id) ) {
- ShowWarning("Removed invalid/disabled item id %d from storage (amount=%d, char_id=%d).\n", id, sd->status.storage.items[i].amount, sd->status.char_id);
- storage->delitem(sd, i, sd->status.storage.items[i].amount);
- storage->close(sd);
- continue;
+ 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 (it->unique_id == 0 && itemdb->isstackable(id) == 0)
+ it->unique_id = itemdb->unique_id(sd);
}
- if ( !sd->status.storage.items[i].unique_id && !itemdb->isstackable(id) )
- sd->status.storage.items[i].unique_id = itemdb->unique_id(sd);
+ storage->close(sd);
+
+ sd->itemcheck &= ~PCCHECKITEM_STORAGE;
}
- if (sd->guild) {
+ if (sd->guild && sd->itemcheck & PCCHECKITEM_GSTORAGE) {
struct guild_storage *guild_storage = idb_get(gstorage->db,sd->guild->guild_id);
if (guild_storage) {
- for( i = 0; i < MAX_GUILD_STORAGE; i++ ) {
- id = guild_storage->items[i].nameid;
-
- if (!id)
+ for (i = 0; i < MAX_GUILD_STORAGE; i++) {
+ if ((id = guild_storage->items[i].nameid) == 0)
continue;
- if( !itemdb_available(id) ) {
- ShowWarning("Removed invalid/disabled item id %d from guild storage (amount=%d, char_id=%d, guild_id=%d).\n", id, guild_storage->items[i].amount, sd->status.char_id, sd->guild->guild_id);
+ if (!itemdb_available(id)) {
+ ShowWarning("pc_checkitem: Removed invalid/disabled item id %d from guild storage (amount=%d, char_id=%d, guild_id=%d).\n", id, guild_storage->items[i].amount, sd->status.char_id, sd->guild->guild_id);
gstorage->delitem(sd, guild_storage, i, guild_storage->items[i].amount);
gstorage->close(sd); // force closing
continue;
}
- if (!guild_storage->items[i].unique_id && !itemdb->isstackable(id))
+ if (guild_storage->items[i].unique_id == 0 && !itemdb->isstackable(id))
guild_storage->items[i].unique_id = itemdb->unique_id(sd);
}
}
+
+ sd->itemcheck &= ~PCCHECKITEM_GSTORAGE;
}
- sd->state.itemcheck = 0;
}
- for( i = 0; i < MAX_INVENTORY; i++) {
+ for (i = 0; i < MAX_INVENTORY; i++) {
- if( sd->status.inventory[i].nameid == 0 )
+ if (sd->status.inventory[i].nameid == 0)
continue;
- if( !sd->status.inventory[i].equip )
+ if (sd->status.inventory[i].equip == 0)
continue;
- if( sd->status.inventory[i].equip&~pc->equippoint(sd,i) ) {
+ if (sd->status.inventory[i].equip & ~pc->equippoint(sd,i)) {
pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE);
calc_flag = 1;
continue;
}
- if (battle_config.unequip_restricted_equipment&1) {
+ if (battle_config.unequip_restricted_equipment & 1) {
int j;
for (j = 0; j < map->list[sd->bl.m].zone->disabled_items_count; j++) {
if (map->list[sd->bl.m].zone->disabled_items[j] == sd->status.inventory[i].nameid) {
@@ -10268,7 +10281,7 @@ int pc_checkitem(struct map_session_data *sd)
}
}
- if (battle_config.unequip_restricted_equipment&2) {
+ if (battle_config.unequip_restricted_equipment & 2) {
if (!itemdb_isspecial(sd->status.inventory[i].card[0])) {
int j, slot;
for (slot = 0; slot < MAX_SLOTS; slot++) {
@@ -10284,9 +10297,9 @@ int pc_checkitem(struct map_session_data *sd)
}
- if( calc_flag && sd->state.active ) {
+ if (calc_flag != 0 && sd->state.active == 1) {
pc->checkallowskill(sd);
- status_calc_pc(sd,SCO_NONE);
+ status_calc_pc(sd, SCO_NONE);
}
return 0;
diff --git a/src/map/pc.h b/src/map/pc.h
index 482e30c41..af52f8946 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -94,6 +94,14 @@ enum pc_resetskill_flag {
PCRESETSKILL_CHSEX = 0x4, // just reset the skills if the player class is a bard/dancer type (for changesex.)
};
+enum pc_checkitem_types {
+ PCCHECKITEM_NONE = 0x0,
+ PCCHECKITEM_INVENTORY = 0x1,
+ PCCHECKITEM_CART = 0x2,
+ PCCHECKITEM_STORAGE = 0x4,
+ PCCHECKITEM_GSTORAGE = 0x8
+};
+
struct weapon_data {
int atkmods[3];
BEGIN_ZEROED_BLOCK; // all the variables within this block get zero'ed in each call of status_calc_pc
@@ -225,7 +233,6 @@ struct map_session_data {
unsigned int hold_recalc : 1;
unsigned int snovice_call_flag : 3; //Summon Angel (stage 1~3)
unsigned int hpmeter_visible : 1;
- unsigned int itemcheck : 1;
unsigned int standalone : 1;/* [Ind/Hercules <3] */
unsigned int loggingout : 1;
unsigned int warp_clean : 1;
@@ -251,7 +258,9 @@ struct map_session_data {
unsigned int extra_temp_permissions; /* permissions from @addperm */
struct mmo_charstatus status;
- struct item_data* inventory_data[MAX_INVENTORY]; // direct pointers to itemdb entries (faster than doing item_id lookups)
+ struct item_data *inventory_data[MAX_INVENTORY]; // direct pointers to itemdb entries (faster than doing item_id lookups)
+ struct storage_data storage; ///< Account Storage
+ enum pc_checkitem_types itemcheck;
short equip_index[EQI_MAX];
unsigned int weight,max_weight;
int cart_weight,cart_num,cart_weight_max;
diff --git a/src/map/script.c b/src/map/script.c
index 599285e1e..75f747fb6 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -10424,9 +10424,17 @@ BUILDIN(openstorage)
{
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
- return true;
+ return false;
+
+ if (sd->storage.received == false) {
+ script_pushint(st, 0);
+ ShowWarning("buildin_openstorage: Storage data for AID %d has not been loaded.\n", sd->bl.id);
+ return false;
+ }
storage->open(sd);
+
+ script_pushint(st, 1); // success flag.
return true;
}
diff --git a/src/map/storage.c b/src/map/storage.c
index aacc7c053..4aefaae96 100644
--- a/src/map/storage.c
+++ b/src/map/storage.c
@@ -107,6 +107,11 @@ 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)); // Your GM level doesn't authorize you to perform this action.
@@ -114,9 +119,13 @@ int storage_storageopen(struct map_session_data *sd)
}
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;
}
@@ -148,61 +157,76 @@ int compare_item(struct item *a, struct item *b)
*------------------------------------------*/
int storage_additem(struct map_session_data* sd, struct item* item_data, int amount)
{
- struct storage_data* stor;
- struct item_data *data;
+ 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, item_data);
- stor = &sd->status.storage;
- if( item_data->nameid <= 0 || amount <= 0 )
- return 1;
+ 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)); // This item cannot be stored.
+ 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)); // This bound item cannot be stored there.
+ 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);
+
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;
+ }
+
+ 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;
}
@@ -212,21 +236,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)
{
+ struct item *it = NULL;
+
nullpo_retr(1, sd);
- Assert_retr(1, n >= 0 && n < MAX_STORAGE);
- if( sd->status.storage.items[n].nameid == 0 || sd->status.storage.items[n].amount < amount )
- return 1;
- 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);
+ 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;
}
@@ -237,23 +272,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);
@@ -268,24 +305,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);
- 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->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;
}
@@ -301,19 +344,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;
@@ -329,22 +374,28 @@ int storage_storageaddfromcart(struct map_session_data* sd, int index, int amoun
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;
@@ -356,12 +407,26 @@ int storage_storagegettocart(struct map_session_data* sd, int index, int amount)
*------------------------------------------*/
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;
}
@@ -791,8 +856,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;
diff --git a/src/map/unit.c b/src/map/unit.c
index 79abb8c6a..00c78054b 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -2757,6 +2757,8 @@ int unit_free(struct block_list *bl, clr_type clrtype)
sd->instance = NULL;
}
VECTOR_CLEAR(sd->script_queues);
+ VECTOR_CLEAR(sd->storage.item);
+ sd->storage.received = false;
if( sd->quest_log != NULL ) {
aFree(sd->quest_log);
sd->quest_log = NULL;