From af99be9bd11d716e0b8ef8eab4a36c9b9925e4c8 Mon Sep 17 00:00:00 2001 From: ultramage Date: Sun, 27 Apr 2008 11:06:55 +0000 Subject: Cleaning up the itemdb reload mess (see r12635, r12643, r12650, r12661, r12662, r12663) * the player data inventory-itemdb index is now refreshed using pc_setinventorydata() * mobdb will no longer initialize with nonexistent items, and mobs will no longer drop them in case of a reload * the clif_buylist() function once again hides invalid npc shop items * it is no longer possible to purchase nonexistent items from a npc shop * npc shop loading will not abort if there is a nonexistent item entry, it will just skip over it git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12665 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 10 --- conf/atcommand_athena.conf | 3 - src/map/atcommand.c | 16 +---- src/map/clif.c | 23 +++--- src/map/itemdb.c | 172 ++++++--------------------------------------- src/map/itemdb.h | 17 ++--- src/map/mob.c | 5 ++ src/map/mob.h | 5 -- src/map/npc.c | 20 ++---- src/map/npc.h | 2 - src/map/pc.c | 7 +- src/map/pc.h | 1 + src/map/storage.c | 2 +- src/map/storage.h | 1 - 14 files changed, 57 insertions(+), 227 deletions(-) diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index bc21c8015..2dfd49ea9 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -3,16 +3,6 @@ Date Added AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. -2008/04/27 - * Fixed "suggest parentheses around assignment ..." gcc warning [Toms] - * Some major changes to @reloaditemdb to allow unloading of any item - while map server is running. - - Delete any item from inventory/cart/open storages that went missing - during the reload. - - Delete item from any shop that has this item. - - Refresh item screen for anyone who has a shop open. - - Delete mob db drop table references. - - Delete item from storage during load if it isn't in the item db. [Kevin] 2008/04/26 * Added script function hasquest. [Kevin] * Fixed OnGuildBreak. [Kevin] diff --git a/conf/atcommand_athena.conf b/conf/atcommand_athena.conf index adc41db04..d2deb9777 100644 --- a/conf/atcommand_athena.conf +++ b/conf/atcommand_athena.conf @@ -700,9 +700,6 @@ mapflag: 99 // Re-load item database (admin command) reloaditemdb: 99 -// Re-load item database and delete all references to it (admin command) -reloaditemdb2: 99 - // Re-load monsters database (admin command) reloadmobdb: 99 diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 628666df3..691035c61 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -4049,25 +4049,12 @@ int atcommand_partyrecall(const int fd, struct map_session_data* sd, const char* int atcommand_reloaditemdb(const int fd, struct map_session_data* sd, const char* command, const char* message) { nullpo_retr(-1, sd); - itemdb_reload(0); + itemdb_reload(); clif_displaymessage(fd, msg_txt(97)); // Item database reloaded. return 0; } -/*========================================== - * - *------------------------------------------*/ -int atcommand_reloaditemdb2(const int fd, struct map_session_data* sd, const char* command, const char* message) -{ - nullpo_retr(-1, sd); - itemdb_reload(1); - clif_displaymessage(fd, msg_txt(97)); // Item database reloaded. - - return 0; -} - - /*========================================== * *------------------------------------------*/ @@ -8386,7 +8373,6 @@ AtCommandInfo atcommand_info[] = { { "localbroadcast", 40, atcommand_localbroadcast }, // + /lb and /nlb { "recallall", 80, atcommand_recallall }, { "reloaditemdb", 99, atcommand_reloaditemdb }, - { "reloaditemdb2", 99, atcommand_reloaditemdb2 }, { "reloadmobdb", 99, atcommand_reloadmobdb }, { "reloadskilldb", 99, atcommand_reloadskilldb }, { "reloadscript", 99, atcommand_reloadscript }, diff --git a/src/map/clif.c b/src/map/clif.c index 55e9b1776..4e6637a5e 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -1389,26 +1389,32 @@ int clif_npcbuysell(struct map_session_data* sd, int id) *------------------------------------------*/ int clif_buylist(struct map_session_data *sd, struct npc_data *nd) { - int fd,i; + int fd,i,c; nullpo_retr(0, sd); nullpo_retr(0, nd); fd = sd->fd; - WFIFOHEAD(fd, 200 * 11 + 4); + WFIFOHEAD(fd, 4 + nd->u.shop.count * 11); WFIFOW(fd,0) = 0xc6; - WFIFOW(fd,2) = 4 + nd->u.shop.count*11; + + c = 0; for( i = 0; i < nd->u.shop.count; i++ ) { - struct item_data* id = itemdb_search(nd->u.shop.shop_item[i].nameid); + struct item_data* id = itemdb_exists(nd->u.shop.shop_item[i].nameid); int val = nd->u.shop.shop_item[i].value; - WFIFOL(fd,4+i*11) = val; + if( id == NULL ) + continue; + WFIFOL(fd, 4+c*11) = val; if (!id->flag.value_notdc) val = pc_modifybuyvalue(sd,val); - WFIFOL(fd,8+i*11) = val; - WFIFOB(fd,12+i*11) = itemtype(id->type); - WFIFOW(fd,13+i*11) = ( id->view_id > 0 ) ? id->view_id : id->nameid; + WFIFOL(fd, 8+c*11) = val; + WFIFOB(fd,12+c*11) = itemtype(id->type); + WFIFOW(fd,13+c*11) = ( id->view_id > 0 ) ? id->view_id : id->nameid; + c++; } + + WFIFOW(fd,2) = 4 + c*11; WFIFOSET(fd,WFIFOW(fd,2)); return 0; @@ -8838,6 +8844,7 @@ void clif_parse_NpcBuyListSend(int fd,struct map_session_data *sd) fail = npc_buylist(sd,n,item_list); sd->npc_shopid = 0; //Clear shop data. + WFIFOHEAD(fd,packet_len(0xca)); WFIFOW(fd,0)=0xca; WFIFOB(fd,2)=fail; diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 979ba4a39..3bcd07cf1 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -10,10 +10,6 @@ #include "battle.h" // struct battle_config #include "script.h" // item script processing #include "pc.h" // W_MUSICAL, W_WHIP -#include "storage.h" -#include "npc.h" -#include "clif.h" -#include "mob.h" #include #include @@ -693,7 +689,7 @@ static int itemdb_gendercheck(struct item_data *id) /*========================================== * processes one itemdb entry *------------------------------------------*/ -static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scriptopt, int db) +static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scriptopt) { /* +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+ @@ -717,9 +713,6 @@ static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scr safestrncpy(id->name, str[1], sizeof(id->name)); safestrncpy(id->jname, str[2], sizeof(id->jname)); - if(db == 1) - id->flag.db2 = 1; - id->type = atoi(str[3]); if (id->type == IT_DELAYCONSUME) { //Items that are consumed only after target confirmation @@ -907,7 +900,8 @@ static int itemdb_readdb(void) } str[21] = p; - if (!itemdb_parse_dbrow(str, path, lines, 0, fi)) + + if (!itemdb_parse_dbrow(str, path, lines, 0)) continue; count++; @@ -954,7 +948,7 @@ static int itemdb_read_sqldb(void) if( str[i] == NULL ) str[i] = dummy; // get rid of NULL columns } - if (!itemdb_parse_dbrow(str, item_db_name[fi], lines, SCRIPT_IGNORE_EXTERNAL_BRACKETS, fi)) + if (!itemdb_parse_dbrow(str, item_db_name[fi], lines, SCRIPT_IGNORE_EXTERNAL_BRACKETS)) continue; ++count; } @@ -1012,13 +1006,6 @@ static void destroy_item_data(struct item_data* self, int free_self) aFree(self); } -/*========================================== - * This comment shall be a monument to cake. - * The cake is NOT a lie in eAthena. - * We are so awesome we have our own cake. - * Please spam Cyxult with endless PMs to get your cake. - *------------------------------------------*/ - static int itemdb_final_sub(DBKey key,void *data,va_list ap) { struct item_data *id = (struct item_data *)data; @@ -1029,149 +1016,30 @@ static int itemdb_final_sub(DBKey key,void *data,va_list ap) return 0; } -//Uncomment this if you're an elitist jerk who thinks this code is unecessary -//#define I_HATE_KEVIN -#ifndef I_HATE_KEVIN -int itemdb_reload_check_npc(DBKey key,void * data,va_list ap) +void itemdb_reload(void) { - struct npc_data * nd = (struct npc_data *)data; - int offset = 0, i = 0; - - if(nd->subtype != SHOP && nd->subtype != CASHSHOP) - return 0; - - while(i < nd->u.shop.count) - { - - if(itemdb_exists(nd->u.shop.shop_item[i].nameid) == NULL) - { - - nd->u.shop.count--; - - //Shift array to left, overwriting old data - for(offset = i; offset+1 < nd->u.shop.count; offset++); - { - nd->u.shop.shop_item[offset].nameid = nd->u.shop.shop_item[offset+1].nameid; - nd->u.shop.shop_item[offset].value = nd->u.shop.shop_item[offset+1].value; - } - - } - //increment counter if we didn't delete something - else - i++; - - } - - //Resize array - RECREATE(nd->u.shop.shop_item, struct npc_item_list, nd->u.shop.count); - - return 0; -} + struct s_mapiterator* iter; + struct map_session_data* sd; -static int itemdb_reload_check(DBKey key,void *data,va_list ap) -{ int i; - struct map_session_data *sd = (struct map_session_data *)data; - struct storage * stor; - struct item_data * id; - struct npc_data * nd; - - if(sd->npc_shopid) - { - nd = (struct npc_data*)map_id2bl(sd->npc_shopid); - clif_buylist(sd, nd); - } - - //First, handle all items in inventories/equiped, cart, and storage - for(i = 0; i < MAX_INVENTORY; i++) - { - if(!sd->status.inventory[i].nameid) - continue; - - id = itemdb_exists(sd->status.inventory[i].nameid); - if(id == NULL) - { - sd->inventory_data[i] = NULL; - pc_delitem(sd, i, sd->status.inventory[i].amount, 4); - } - else - { - sd->inventory_data[i] = id; - } - } - //Delete nonexistant items from cart - for(i = 0; i < MAX_CART; i++) - { - if(!sd->status.cart[i].nameid) - continue; - - id = itemdb_exists(sd->status.cart[i].nameid); - if(id == NULL) - { - sd->inventory_data[i] = NULL; - pc_cart_delitem(sd, i, sd->status.cart[i].amount, 0); - } - } - - //Delete storage - if((stor = account2storage2(sd->status.account_id))) - { - //If storage isn't found, it will be deleted whenever storage is loaded again - if(stor) - { - for(i = 0; i < MAX_STORAGE; i++) - { - if(!sd->status.inventory[i].nameid) - continue; - - if(itemdb_exists(sd->status.inventory[i].nameid) == NULL) - storage_delitem(sd, stor, i, stor->storage_[i].amount); - } - } - } - - return 0; -} - -//Cleanup mob db drop tables -void itemdb_foreach_mobdb(void) -{ - int i = 0, j = 0; - struct item_data * id; - s_mob_db * mdb; + // clear the previous itemdb data + for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i ) + if( itemdb_array[i] ) + destroy_item_data(itemdb_array[i], 1); - for(i=0; i < MAX_MOB_DB; i++) - { - mdb = mob_db(i); - if(mdb == mob_dummy) - continue; - for(j=0; j < MAX_MOB_DROP; j++) - { - id = itemdb_exists(mdb->dropitem[j].nameid); - if(id == NULL) - { - mdb->dropitem[j].nameid = 0; - mdb->dropitem[j].p = 0; - } - } - } -} -#endif + itemdb_other->clear(itemdb_other, itemdb_final_sub); -void itemdb_reload(int flag) -{ + memset(itemdb_array, 0, sizeof(itemdb_array)); - do_final_itemdb(); - do_init_itemdb(); + // read new data + itemdb_read(); - if(flag) - { - //Update ALL items on the server - map_foreachpc(itemdb_reload_check); - npc_foreach(itemdb_reload_check_npc); - itemdb_foreach_mobdb(); - } + // readjust itemdb pointer cache for each player + iter = mapit_geteachpc(); + for( sd = (struct map_session_data*)mapit_first(iter); mapit_exists(iter); sd = (struct map_session_data*)mapit_next(iter) ) + pc_setinventorydata(sd); + mapit_free(iter); } void do_final_itemdb(void) diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 0ea53748d..6be49f3e9 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -34,8 +34,8 @@ #define UNKNOWN_ITEM_ID 512 struct item_data { - char name[ITEM_NAME_LENGTH],jname[ITEM_NAME_LENGTH]; int nameid; + char name[ITEM_NAME_LENGTH],jname[ITEM_NAME_LENGTH]; //Do not add stuff between value_buy and wlv (see how getiteminfo works) int value_buy; int value_sell; @@ -56,27 +56,24 @@ struct item_data { // some script commands should be revised as well... unsigned int class_base[3]; //Specifies if the base can wear this item (split in 3 indexes per type: 1-1, 2-1, 2-2) unsigned class_upper : 3; //Specifies if the upper-type can equip it (bitfield, 1: normal, 2: upper, 3: baby) - unsigned unused : 5; struct { unsigned short chance; int id; } mob[MAX_SEARCH]; //Holds the mobs that have the highest drop rate for this item. [Skotlex] + struct script_code *script; //Default script for everything. + struct script_code *equip_script; //Script executed once when equipping. + struct script_code *unequip_script;//Script executed once when unequipping. struct { unsigned available : 1; unsigned value_notdc : 1; unsigned value_notoc : 1; + short no_equip; unsigned no_refine : 1; // [celest] unsigned delay_consume : 1; // Signifies items that are not consumed immediately upon double-click [Skotlex] - unsigned autoequip: 1; - unsigned unused:2; - unsigned db2: 1; //Items from the custom item database (item_db2) unsigned trade_restriction : 7; //Item restrictions mask [Skotlex] - short no_equip; + unsigned autoequip: 1; } flag; short gm_lv_trade_override; //GM-level to override trade_restriction - struct script_code *script; //Default script for everything. - struct script_code *equip_script; //Script executed once when equipping. - struct script_code *unequip_script;//Script executed once when unequipping. }; struct item_group { @@ -137,7 +134,7 @@ int itemdb_isidentified(int); int itemdb_isstackable(int); int itemdb_isstackable2(struct item_data *); -void itemdb_reload(int flag); +void itemdb_reload(void); void do_final_itemdb(void); int do_init_itemdb(void); diff --git a/src/map/mob.c b/src/map/mob.c index 2288227b4..a7fc4a783 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -2310,12 +2310,15 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) { if (md->db->dropitem[i].nameid <= 0) continue; + if (!itemdb_exists(md->db->dropitem[i].nameid)) + continue; drop_rate = md->db->dropitem[i].p; if (drop_rate <= 0) { if (battle_config.drop_rate0item) continue; drop_rate = 1; } + // change drops depending on monsters size [Valaris] if(md->special_state.size==1 && drop_rate >= 2) drop_rate/=2; @@ -2456,6 +2459,8 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) if(md->db->mvpitem[i].nameid <= 0) continue; + if(!itemdb_exists(md->db->mvpitem[i].nameid)) + continue; temp = md->db->mvpitem[i].p; if(temp <= 0 && !battle_config.drop_rate0item) diff --git a/src/map/mob.h b/src/map/mob.h index 44fae102e..f01b4fff1 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -83,11 +83,6 @@ struct mob_db { struct spawn_info spawn[10]; }; -typedef struct mob_db s_mob_db; -extern struct mob_db *mob_db_data[MAX_MOB_DB+1]; -struct mob_db *mob_db(int index); -extern struct mob_db *mob_dummy; - struct mob_data { struct block_list bl; struct unit_data ud; diff --git a/src/map/npc.c b/src/map/npc.c index f1ff119da..683be8620 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -150,19 +150,6 @@ struct npc_data* npc_name2id(const char* name) return (struct npc_data *) strdb_get(npcname_db, name); } - -/*========================================== - * Run function for each npc - *------------------------------------------*/ - -void npc_foreach(int (*func)(DBKey, void*, va_list), ...) -{ - va_list ap; - va_start(ap, func); - npcname_db->vforeach(npcname_db, func, ap); - va_end(ap); -} - /*========================================== * イベントキューのイベント処理 *------------------------------------------*/ @@ -1128,7 +1115,7 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list) itemdb_viewid(nd->u.shop.shop_item[j].nameid)==item_list[i*2+1]) //item_avail replacement break; } - if (nd->u.shop.shop_item[j].nameid == 0) + if (nd->u.shop.shop_item[j].nameid == 0 || !itemdb_exists(nd->u.shop.shop_item[j].nameid)) return 3; if (!itemdb_isstackable(nd->u.shop.shop_item[j].nameid) && item_list[i*2] > 1) @@ -1687,8 +1674,9 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const if( (id = itemdb_exists(nameid)) == NULL ) { - ShowError("npc_parse_shop: Invalid sell item in file '%s', line '%d'. Ignoring the rest of the line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4); - break; + ShowWarning("npc_parse_shop: Invalid sell item in file '%s', line '%d' (id '%d').\n", filepath, strline(buffer,start-buffer), nameid); + p = strchr(p+1,','); + continue; } if( value < 0 ) diff --git a/src/map/npc.h b/src/map/npc.h index 93fb3fa60..f75ede9c5 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -146,8 +146,6 @@ int npc_script_event(struct map_session_data* sd, enum npce_event type); int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount, int points); -void npc_foreach(int (*func)(DBKey,void*,va_list), ...); - extern struct npc_data* fake_nd; #endif /* _NPC_H_ */ diff --git a/src/map/pc.c b/src/map/pc.c index 7d268a0f5..0557708cb 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -2965,12 +2965,11 @@ int pc_delitem(struct map_session_data *sd,int n,int amount,int type) { nullpo_retr(1, sd); - if(sd->status.inventory[n].nameid==0 || amount <= 0 || sd->status.inventory[n].amountinventory_data[n] == NULL && ~type&4)) + if(sd->status.inventory[n].nameid==0 || amount <= 0 || sd->status.inventory[n].amountinventory_data[n] == NULL) return 1; sd->status.inventory[n].amount -= amount; - if(~type&4) - sd->weight -= sd->inventory_data[n]->weight*amount ; + sd->weight -= sd->inventory_data[n]->weight*amount ; if(sd->status.inventory[n].amount<=0){ if(sd->status.inventory[n].equip) pc_unequipitem(sd,n,3); @@ -3458,7 +3457,7 @@ int pc_steal_item(struct map_session_data *sd,struct block_list *bl, int lv) // Try dropping one item, in the order from first to last possible slot. // Droprate is affected by the skill success rate. for( i = 0; i < MAX_STEAL_DROP; i++ ) - if( md->db->dropitem[i].nameid > 0 && rand() % 10000 < md->db->dropitem[i].p * rate/100. ) + if( md->db->dropitem[i].nameid > 0 && itemdb_exists(md->db->dropitem[i].nameid) && rand() % 10000 < md->db->dropitem[i].p * rate/100. ) break; if( i == MAX_STEAL_DROP ) return 0; diff --git a/src/map/pc.h b/src/map/pc.h index 24a882431..a8f0b57df 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -502,6 +502,7 @@ int pc_reg_received(struct map_session_data *sd); int pc_isequip(struct map_session_data *sd,int n); int pc_equippoint(struct map_session_data *sd,int n); +int pc_setinventorydata(struct map_session_data *sd); int pc_checkskill(struct map_session_data *sd,int skill_id); int pc_checkallowskill(struct map_session_data *sd); diff --git a/src/map/storage.c b/src/map/storage.c index f43ee7f04..c2e4bf5f7 100644 --- a/src/map/storage.c +++ b/src/map/storage.c @@ -224,7 +224,7 @@ static int storage_additem(struct map_session_data *sd,struct storage *stor,stru /*========================================== * Internal del-item function *------------------------------------------*/ -int storage_delitem(struct map_session_data *sd,struct storage *stor,int n,int amount) +static int storage_delitem(struct map_session_data *sd,struct storage *stor,int n,int amount) { if(stor->storage_[n].nameid==0 || stor->storage_[n].amount