diff options
Diffstat (limited to 'src/map')
-rw-r--r-- | src/map/atcommand.c | 27 | ||||
-rw-r--r-- | src/map/battle.c | 2 | ||||
-rw-r--r-- | src/map/chrif.c | 3 | ||||
-rw-r--r-- | src/map/clif.c | 44 | ||||
-rw-r--r-- | src/map/intif.c | 137 | ||||
-rw-r--r-- | src/map/intif.h | 4 | ||||
-rw-r--r-- | src/map/itemdb.c | 10 | ||||
-rw-r--r-- | src/map/pc.c | 119 | ||||
-rw-r--r-- | src/map/pc.h | 13 | ||||
-rw-r--r-- | src/map/script.c | 10 | ||||
-rw-r--r-- | src/map/storage.c | 207 | ||||
-rw-r--r-- | src/map/unit.c | 2 |
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; |