From 00ef66fb9261a50e6761cf77c11e7f468494c95f Mon Sep 17 00:00:00 2001 From: shennetsind Date: Sun, 2 Feb 2014 16:50:03 -0200 Subject: Fixed item combo bypassing disabled item restrictions Special Thanks to Mhalicot! Also improves the overall memory usage of the item combo feature Signed-off-by: shennetsind --- src/map/itemdb.c | 94 +++++++++++++++++++++++++------------------------------- src/map/itemdb.h | 7 +++-- src/map/pc.c | 70 ++++++++++++++++++++--------------------- src/map/pc.h | 15 +++++---- src/map/status.c | 27 +++++++++++++--- src/map/unit.c | 8 ++--- 6 files changed, 115 insertions(+), 106 deletions(-) (limited to 'src/map') diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 6db503214..527972516 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -1449,8 +1449,7 @@ void itemdb_read_combos() { } else { int items[MAX_ITEMS_PER_COMBO]; int v = 0, retcount = 0; - struct item_data * id = NULL; - int idx = 0; + struct item_combo *combo = NULL; if((retcount = itemdb->combo_split_atoi(str[0], items)) < 2) { ShowError("itemdb_read_combos: line %d of \"%s\" doesn't have enough items to make for a combo (min:2), skipping.\n", lines, filepath); @@ -1467,33 +1466,23 @@ void itemdb_read_combos() { /* failed at some item */ if( v < retcount ) continue; - - id = itemdb->exists(items[0]); - - idx = id->combos_count; - /* first entry, create */ - if( id->combos == NULL ) { - CREATE(id->combos, struct item_combo*, 1); - id->combos_count = 1; - } else { - RECREATE(id->combos, struct item_combo*, ++id->combos_count); - } + RECREATE(itemdb->combos, struct item_combo*, ++itemdb->combo_count); - CREATE(id->combos[idx],struct item_combo,1); + CREATE(combo, struct item_combo, 1); - id->combos[idx]->nameid = aMalloc( retcount * sizeof(unsigned short) ); - id->combos[idx]->count = retcount; - id->combos[idx]->script = script->parse(str[1], filepath, lines, 0); - id->combos[idx]->id = count; - id->combos[idx]->isRef = false; + combo->count = retcount; + combo->script = script->parse(str[1], filepath, lines, 0); + combo->id = itemdb->combo_count - 1; /* populate ->nameid field */ for( v = 0; v < retcount; v++ ) { - id->combos[idx]->nameid[v] = items[v]; + combo->nameid[v] = items[v]; } - /* populate the children to refer to this combo */ - for( v = 1; v < retcount; v++ ) { + itemdb->combos[itemdb->combo_count - 1] = combo; + + /* populate the items to refer to this combo */ + for( v = 0; v < retcount; v++ ) { struct item_data * it; int index; @@ -1501,19 +1490,9 @@ void itemdb_read_combos() { index = it->combos_count; - if( it->combos == NULL ) { - CREATE(it->combos, struct item_combo*, 1); - it->combos_count = 1; - } else { - RECREATE(it->combos, struct item_combo*, ++it->combos_count); - } - - CREATE(it->combos[index],struct item_combo,1); + RECREATE(it->combos, struct item_combo*, ++it->combos_count); - /* we copy previously alloc'd pointers and just set it to reference */ - memcpy(it->combos[index],id->combos[idx],sizeof(struct item_combo)); - /* we flag this way to ensure we don't double-dealloc same data */ - it->combos[index]->isRef = true; + it->combos[index] = combo; } } @@ -2076,6 +2055,15 @@ void itemdb_read(bool minimal) { itemdb->uid_load(); } +/** + * retrieves item_combo data by combo id + **/ +struct item_combo * itemdb_id2combo( unsigned short id ) { + if( id > itemdb->combo_count ) + return NULL; + return itemdb->combos[id]; +} + /*========================================== * Initialize / Finalize *------------------------------------------*/ @@ -2092,17 +2080,8 @@ void destroy_item_data(struct item_data* self, int free_self) script->free_code(self->equip_script); if( self->unequip_script ) script->free_code(self->unequip_script); - if( self->combos_count ) { - int i; - for( i = 0; i < self->combos_count; i++ ) { - if( !self->combos[i]->isRef ) { - aFree(self->combos[i]->nameid); - script->free_code(self->combos[i]->script); - } - aFree(self->combos[i]); - } + if( self->combos ) aFree(self->combos); - } #if defined(DEBUG) // trash item memset(self, 0xDD, sizeof(struct item_data)); @@ -2169,6 +2148,16 @@ void itemdb_clear(bool total) { itemdb->packages = NULL; itemdb->package_count = 0; + for(i = 0; i < itemdb->combo_count; i++) { + script->free_code(itemdb->combos[i]->script); + aFree(itemdb->combos[i]); + } + if( itemdb->combos ) + aFree(itemdb->combos); + + itemdb->combos = NULL; + itemdb->combo_count = 0; + if( total ) return; @@ -2225,18 +2214,15 @@ void itemdb_reload(void) { pc->setinventorydata(sd); if( battle_config.item_check ) sd->state.itemcheck = 1; - pc->checkitem(sd); /* clear combo bonuses */ - if( sd->combos.count ) { - aFree(sd->combos.bonus); - aFree(sd->combos.id); - sd->combos.bonus = NULL; - sd->combos.id = NULL; - sd->combos.count = 0; + 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); } - + pc->checkitem(sd); } mapit->free(iter); } @@ -2286,6 +2272,9 @@ void itemdb_defaults(void) { itemdb->packages = NULL; itemdb->package_count = 0; /* */ + itemdb->combos = NULL; + itemdb->combo_count = 0; + /* */ itemdb->names = NULL; /* */ /* itemdb->array is cleared on itemdb->init() */ @@ -2352,4 +2341,5 @@ void itemdb_defaults(void) { itemdb->destroy_item_data = destroy_item_data; itemdb->final_sub = itemdb_final_sub; itemdb->clear = itemdb_clear; + itemdb->id2combo = itemdb_id2combo; } diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 74ced13e0..c399a0442 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -400,10 +400,9 @@ struct item_data { struct item_combo { struct script_code *script; - unsigned short *nameid;/* nameid array */ + unsigned short nameid[MAX_ITEMS_PER_COMBO];/* nameid array */ unsigned char count; unsigned short id;/* id of this combo */ - bool isRef;/* whether this struct is a reference or the master */ }; struct item_group { @@ -509,6 +508,9 @@ struct itemdb_interface { /* */ struct item_package *packages; unsigned short package_count; + /* list of item combos loaded */ + struct item_combo **combos; + unsigned short combo_count; /* */ DBMap *names; /* */ @@ -576,6 +578,7 @@ struct itemdb_interface { void (*destroy_item_data) (struct item_data *self, int free_self); int (*final_sub) (DBKey key, DBData *data, va_list ap); void (*clear) (bool total); + struct item_combo * (*id2combo) (unsigned short id); }; struct itemdb_interface *itemdb; diff --git a/src/map/pc.c b/src/map/pc.c index b6c354189..12a49faa8 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -8410,17 +8410,19 @@ int pc_cleareventtimer(struct map_session_data *sd) /* called when a item with combo is worn */ int pc_checkcombo(struct map_session_data *sd, struct item_data *data ) { int i, j, k, z; - int index, idx, success = 0; + int index, success = 0; + struct pc_combos *combo; for( i = 0; i < data->combos_count; i++ ) { /* ensure this isn't a duplicate combo */ - if( sd->combos.bonus != NULL ) { + if( sd->combos != NULL ) { int x; - ARR_FIND( 0, sd->combos.count, x, sd->combos.id[x] == data->combos[i]->id ); + + ARR_FIND( 0, sd->combo_count, x, sd->combos[x].id == data->combos[i]->id ); /* found a match, skip this combo */ - if( x < sd->combos.count ) + if( x < sd->combo_count ) continue; } @@ -8437,7 +8439,7 @@ int pc_checkcombo(struct map_session_data *sd, struct item_data *data ) { if(!sd->inventory_data[index]) continue; - + if ( itemdb_type(id) != IT_CARD ) { if ( sd->inventory_data[index]->nameid != id ) continue; @@ -8471,22 +8473,13 @@ int pc_checkcombo(struct map_session_data *sd, struct item_data *data ) { /* we got here, means all items in the combo are matching */ - idx = sd->combos.count; - - if( sd->combos.bonus == NULL ) { - CREATE(sd->combos.bonus, struct script_code *, 1); - CREATE(sd->combos.id, unsigned short, 1); - sd->combos.count = 1; - } else { - RECREATE(sd->combos.bonus, struct script_code *, ++sd->combos.count); - RECREATE(sd->combos.id, unsigned short, sd->combos.count); - } - - /* we simply copy the pointer */ - sd->combos.bonus[idx] = data->combos[i]->script; - /* save this combo's id */ - sd->combos.id[idx] = data->combos[i]->id; - + RECREATE(sd->combos, struct pc_combos, ++sd->combo_count); + + combo = &sd->combos[sd->combo_count - 1]; + + combo->bonus = data->combos[i]->script; + combo->id = data->combos[i]->id; + success++; } return success; @@ -8496,26 +8489,30 @@ int pc_checkcombo(struct map_session_data *sd, struct item_data *data ) { int pc_removecombo(struct map_session_data *sd, struct item_data *data ) { int i, retval = 0; - if( sd->combos.bonus == NULL ) + if( !sd->combos ) return 0;/* nothing to do here, player has no combos */ + for( i = 0; i < data->combos_count; i++ ) { /* check if this combo exists in this user */ int x = 0, cursor = 0, j; - ARR_FIND( 0, sd->combos.count, x, sd->combos.id[x] == data->combos[i]->id ); + + ARR_FIND( 0, sd->combo_count, x, sd->combos[x].id == data->combos[i]->id ); /* no match, skip this combo */ - if( !(x < sd->combos.count) ) + if( !(x < sd->combo_count) ) continue; - sd->combos.bonus[x] = NULL; - sd->combos.id[x] = 0; + sd->combos[x].bonus = NULL; + sd->combos[x].id = 0; + retval++; - for( j = 0, cursor = 0; j < sd->combos.count; j++ ) { - if( sd->combos.bonus[j] == NULL ) + + for( j = 0, cursor = 0; j < sd->combo_count; j++ ) { + if( sd->combos[j].bonus == NULL ) continue; if( cursor != j ) { - sd->combos.bonus[cursor] = sd->combos.bonus[j]; - sd->combos.id[cursor] = sd->combos.id[j]; + sd->combos[cursor].bonus = sd->combos[j].bonus; + sd->combos[cursor].id = sd->combos[j].id; } cursor++; @@ -8526,11 +8523,10 @@ int pc_removecombo(struct map_session_data *sd, struct item_data *data ) { continue; /* it's empty, we can clear all the memory */ - if( (sd->combos.count = cursor) == 0 ) { - aFree(sd->combos.bonus); - aFree(sd->combos.id); - sd->combos.bonus = NULL; - sd->combos.id = NULL; + if( (sd->combo_count = cursor) == 0 ) { + aFree(sd->combos); + sd->combos = NULL; + return retval; /* we also can return at this point for we have no more combos to check */ } @@ -8953,7 +8949,7 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) { *------------------------------------------*/ int pc_checkitem(struct map_session_data *sd) { - int i,id,calc_flag = 0; + int i, id, calc_flag = 0; nullpo_ret(sd); @@ -9019,7 +9015,7 @@ int pc_checkitem(struct map_session_data *sd) } } - + if( calc_flag && sd->state.active ) { pc->checkallowskill(sd); status_calc_pc(sd,SCO_NONE); diff --git a/src/map/pc.h b/src/map/pc.h index 03b3ddca0..f106631e7 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -116,6 +116,12 @@ enum npc_timeout_type { NPCT_MENU = 1, NPCT_WAIT = 2, }; + +struct pc_combos { + struct script_code *bonus;/* the script of the combo */ + unsigned short id;/* this combo id */ +}; + struct map_session_data { struct block_list bl; struct unit_data ud; @@ -468,12 +474,9 @@ struct map_session_data { enum npc_timeout_type npc_idle_type; #endif - struct { - struct script_code **bonus;/* the script */ - unsigned short *id;/* array of combo ids */ - unsigned char count; - } combos; - + struct pc_combos *combos; + unsigned char combo_count; + /** * Guarantees your friend request is legit (for bugreport:4629) **/ diff --git a/src/map/status.c b/src/map/status.c index 6cc3269e5..2b0aee97b 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -2598,12 +2598,29 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) { } /* we've got combos to process */ - if( sd->combos.count ) { - for( i = 0; i < sd->combos.count; i++ ) { - script->run(sd->combos.bonus[i],0,sd->bl.id,0); - if (!calculating) //Abort, script->run retriggered this. - return 1; + for( i = 0; i < sd->combo_count; i++ ) { + struct item_combo *combo = itemdb->id2combo(sd->combos[i].id); + unsigned char j; + + /** + * ensure combo usage is allowed at this location + **/ + for(j = 0; j < combo->count; j++) { + for(k = 0; k < map->list[sd->bl.m].zone->disabled_items_count; k++) { + if( map->list[sd->bl.m].zone->disabled_items[k] == combo->nameid[j] ) { + break; + } + } + if( k != map->list[sd->bl.m].zone->disabled_items_count ) + break; } + + if( j != combo->count ) + continue; + + script->run(sd->combos[i].bonus,0,sd->bl.id,0); + if (!calculating) //Abort, script->run retriggered this. + return 1; } //Store equipment script bonuses diff --git a/src/map/unit.c b/src/map/unit.c index 7b37be266..320649a6c 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -2363,11 +2363,11 @@ int unit_free(struct block_list *bl, clr_type clrtype) { sd->st = NULL; sd->npc_id = 0; } - if( sd->combos.count ) { - aFree(sd->combos.bonus); - aFree(sd->combos.id); - sd->combos.count = 0; + if( sd->combos ) { + aFree(sd->combos); + sd->combos = NULL; } + sd->combo_count = 0; /* [Ind/Hercules] */ if( sd->sc_display_count ) { for(i = 0; i < sd->sc_display_count; i++) { -- cgit v1.2.3-70-g09d2