diff options
author | shennetsind <shennetsind@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2012-07-27 00:11:32 +0000 |
---|---|---|
committer | shennetsind <shennetsind@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2012-07-27 00:11:32 +0000 |
commit | 96cc4f2e7496202c8c278399124f9f85ce3a5ae5 (patch) | |
tree | 7455cde7f3b96c014e441b58662630910f49ed36 /src/map/pc.c | |
parent | 679b172c58b43307a8e25ba85bae0d83f8598926 (diff) | |
download | hercules-96cc4f2e7496202c8c278399124f9f85ce3a5ae5.tar.gz hercules-96cc4f2e7496202c8c278399124f9f85ce3a5ae5.tar.bz2 hercules-96cc4f2e7496202c8c278399124f9f85ce3a5ae5.tar.xz hercules-96cc4f2e7496202c8c278399124f9f85ce3a5ae5.zip |
Fixed bugreport:309 combos may now stack properly. moved all combo processing out of item bonuses and made it's own processing scheme, which is by far more efficient cpu-wise although it requires a little more memory, instead of checking for combo items whenever a status effect is turned on/off it only checks when equipping/un-equipping a item (and on login). Special Thanks to GreenBox, Kenpachi, Skotlex and Trojal
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@16508 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src/map/pc.c')
-rw-r--r-- | src/map/pc.c | 200 |
1 files changed, 193 insertions, 7 deletions
diff --git a/src/map/pc.c b/src/map/pc.c index 1a7efc260..c697fd046 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1220,6 +1220,8 @@ int pc_reg_received(struct map_session_data *sd) map_delnickdb(sd->status.char_id, sd->status.name); if (!chrif_auth_finished(sd)) ShowError("pc_reg_received: Failed to properly remove player %d:%d from logging db!\n", sd->status.account_id, sd->status.char_id); + + pc_load_combo(sd); status_calc_pc(sd,1); chrif_scdata_request(sd->status.account_id, sd->status.char_id); @@ -7859,12 +7861,158 @@ int pc_cleareventtimer(struct map_session_data *sd) } return 0; } +/* 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; -// -// ? 備物 -// + for( i = 0; i < data->combos_count; i++ ) { + + /* ensure this isn't a duplicate combo */ + if( sd->combos.bonus != NULL ) { + int x; + ARR_FIND( 0, sd->combos.count, x, sd->combos.id[x] == data->combos[i]->id ); + + /* found a match, skip this combo */ + if( x < sd->combos.count ) + continue; + } + + for( j = 0; j < data->combos[i]->count; j++ ) { + int id = data->combos[i]->nameid[j]; + bool found = false; + + for( k = 0; k < EQI_MAX; k++ ) { + index = sd->equip_index[k]; + if( index < 0 ) continue; + if( k == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index ) continue; + if( k == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index ) continue; + if( k == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index) ) continue; + + if(!sd->inventory_data[index]) + continue; + + if ( itemdb_type(id) != IT_CARD ) { + if ( sd->inventory_data[index]->nameid != id ) + continue; + + found = true; + break; + } else { //Cards + if ( sd->inventory_data[index]->slot == 0 || itemdb_isspecial(sd->status.inventory[index].card[0]) ) + continue; + + for (z = 0; z < sd->inventory_data[index]->slot; z++) { + + if (sd->status.inventory[index].card[z] != id) + continue; + + // We have found a match + found = true; + break; + } + } + + } + + if( !found ) + break;/* we haven't found all the ids for this combo, so we can return */ + } + + /* means we broke out of the count loop w/o finding all ids, we can move to the next combo */ + if( j < data->combos[i]->count ) + continue; + + /* 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; + + success++; + } + return success; +} + +/* called when a item with combo is removed */ +void pc_removecombo(struct map_session_data *sd, struct item_data *data ) { + int i; + + if( sd->combos.bonus == NULL ) + return;/* 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 ); + /* no match, skip this combo */ + if( !(x < sd->combos.count) ) + continue; + + sd->combos.bonus[x] = NULL; + sd->combos.id[x] = 0; + + for( j = 0, cursor = 0; j < sd->combos.count; j++ ) { + if( sd->combos.bonus[j] == NULL ) + continue; + + if( cursor != j ) { + sd->combos.bonus[cursor] = sd->combos.bonus[j]; + sd->combos.id[cursor] = sd->combos.id[j]; + } + + cursor++; + } + + /* 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; + return; /* we also can return at this point for we have no more combos to check */ + } + + } + +} +int pc_load_combo(struct map_session_data *sd) { + int i, ret = 0; + for( i = 0; i < EQI_MAX; i++ ) { + struct item_data *id = NULL; + int idx = sd->equip_index[i]; + if( sd->equip_index[i] < 0 || !(id = sd->inventory_data[idx] ) ) + continue; + if( id->combos_count ) + ret += pc_checkcombo(sd,id); + if(!itemdb_isspecial(sd->status.inventory[idx].card[0])) { + struct item_data *data; + int j; + for( j = 0; j < id->slot; j++ ) { + if (!sd->status.inventory[idx].card[j]) + continue; + if ( ( data = itemdb_exists(sd->status.inventory[idx].card[j]) ) != NULL ) { + if( data->combos_count ) + ret += pc_checkcombo(sd,data); + } + } + } + } + return ret; +} /*========================================== - * アイテムを?備する + * Attempt to equip item in inventory index 'n' in the EQP_ 'req_pos' *------------------------------------------*/ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) { @@ -8019,15 +8167,32 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) } pc_checkallowskill(sd); //Check if status changes should be halted. - - + + /* check for combos (MUST be before status_calc_pc) */ + if ( id ) { + struct item_data *data; + if( id->combos_count ) + pc_checkcombo(sd,id); + if(itemdb_isspecial(sd->status.inventory[n].card[0])) + ; //No cards + else { + for( i = 0; i < id->slot; i++ ) { + if (!sd->status.inventory[n].card[i]) + continue; + if ( ( data = itemdb_exists(sd->status.inventory[n].card[i]) ) != NULL ) { + if( data->combos_count ) + pc_checkcombo(sd,data); + } + } + } + } + status_calc_pc(sd,0); if (flag) //Update skill data clif_skillinfoblock(sd); //OnEquip script [Skotlex] if (id) { - int i; struct item_data *data; if (id->equip_script) run_script(id->equip_script,0,sd->bl.id,fake_nd->bl.id); @@ -8150,6 +8315,27 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) sd->status.inventory[n].equip=0; if(flag&1) { + + /* check for combos (MUST be before status_calc_pc) */ + if ( sd->inventory_data[n] ) { + struct item_data *data; + + if( sd->inventory_data[n]->combos_count ) + pc_removecombo(sd,sd->inventory_data[n]); + if(itemdb_isspecial(sd->status.inventory[n].card[0])) + ; //No cards + else { + for( i = 0; i < sd->inventory_data[n]->slot; i++ ) { + if (!sd->status.inventory[n].card[i]) + continue; + if ( ( data = itemdb_exists(sd->status.inventory[n].card[i]) ) != NULL ) { + if( data->combos_count ) + pc_removecombo(sd,data); + } + } + } + } + pc_checkallowskill(sd); status_calc_pc(sd,0); } |