From 54031eda9dcea4a0c5958276a7786cbcdcdc55c5 Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Sat, 3 Jan 2015 03:14:26 +0100 Subject: [PATCH 1/3] Seperated monster drop ratio adjustment into it's own function. Fixes #146 --- src/map/mob.c | 258 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 175 insertions(+), 83 deletions(-) diff --git a/src/map/mob.c b/src/map/mob.c index 4b55a4fcc2..d500dfb656 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -3875,99 +3875,39 @@ static bool mob_parse_dbrow(char** str) // MVP Drops: MVP1id,MVP1per,MVP2id,MVP2per,MVP3id,MVP3per for(i = 0; i < MAX_MVP_DROP; i++) { - int rate_adjust = battle_config.item_rate_mvp;; db->mvpitem[i].nameid = atoi(str[31+i*2]); - if (!db->mvpitem[i].nameid) { - db->mvpitem[i].p = 0; //No item.... - continue; - } - item_dropratio_adjust(db->mvpitem[i].nameid, mob_id, &rate_adjust); - db->mvpitem[i].p = mob_drop_adjust(atoi(str[32+i*2]), rate_adjust, battle_config.item_drop_mvp_min, battle_config.item_drop_mvp_max); - //calculate and store Max available drop chance of the MVP item - if (db->mvpitem[i].p) { - struct item_data *id; - id = itemdb_search(db->mvpitem[i].nameid); - if (id->maxchance == -1 || (id->maxchance < db->mvpitem[i].p/10 + 1) ) { - //item has bigger drop chance or sold in shops - id->maxchance = db->mvpitem[i].p/10 + 1; //reduce MVP drop info to not spoil common drop rate + if( db->mvpitem[i].nameid ){ + if( itemdb_search(db->mvpitem[i].nameid) ){ + db->mvpitem[i].p = atoi(str[32+i*2]); + continue; + }else{ + ShowWarning( "Monster \"%s\"(id: %d) is dropping an unknown item \"%s\"(MVP-Drop %d)\n", db->name, mob_id, str[31+i*2], ( i / 2 ) + 1 ); } } + + // Delete the item + db->mvpitem[i].nameid = 0; + db->mvpitem[i].p = 0; } for(i = 0; i < MAX_MOB_DROP; i++) { - int rate = 0, rate_adjust, type; - unsigned short ratemin, ratemax; - struct item_data *id; int k = 31 + MAX_MVP_DROP*2 + i*2; + db->dropitem[i].nameid = atoi(str[k]); - if (!db->dropitem[i].nameid) { - db->dropitem[i].p = 0; //No drop. - continue; - } - id = itemdb_search(db->dropitem[i].nameid); - type = id->type; - rate = atoi(str[k+1]); - if (battle_config.drop_rateincrease) - if (rate < 5000) rate++; - if( (mob_id >= 1324 && mob_id <= 1363) || (mob_id >= 1938 && mob_id <= 1946) ) - { //Treasure box drop rates [Skotlex] - rate_adjust = battle_config.item_rate_treasure; - ratemin = battle_config.item_drop_treasure_min; - ratemax = battle_config.item_drop_treasure_max; - } - else switch (type) - { // Added suport to restrict normal drops of MVP's [Reddozen] - case IT_HEALING: - rate_adjust = (status->mode&MD_BOSS) ? battle_config.item_rate_heal_boss : battle_config.item_rate_heal; - ratemin = battle_config.item_drop_heal_min; - ratemax = battle_config.item_drop_heal_max; - break; - case IT_USABLE: - case IT_CASH: - rate_adjust = (status->mode&MD_BOSS) ? battle_config.item_rate_use_boss : battle_config.item_rate_use; - ratemin = battle_config.item_drop_use_min; - ratemax = battle_config.item_drop_use_max; - break; - case IT_WEAPON: - case IT_ARMOR: - case IT_PETARMOR: - rate_adjust = (status->mode&MD_BOSS) ? battle_config.item_rate_equip_boss : battle_config.item_rate_equip; - ratemin = battle_config.item_drop_equip_min; - ratemax = battle_config.item_drop_equip_max; - break; - case IT_CARD: - rate_adjust = (status->mode&MD_BOSS) ? battle_config.item_rate_card_boss : battle_config.item_rate_card; - ratemin = battle_config.item_drop_card_min; - ratemax = battle_config.item_drop_card_max; - break; - default: - rate_adjust = (status->mode&MD_BOSS) ? battle_config.item_rate_common_boss : battle_config.item_rate_common; - ratemin = battle_config.item_drop_common_min; - ratemax = battle_config.item_drop_common_max; - break; - } - item_dropratio_adjust(id->nameid, mob_id, &rate_adjust); - db->dropitem[i].p = mob_drop_adjust(rate, rate_adjust, ratemin, ratemax); - //calculate and store Max available drop chance of the item - if( db->dropitem[i].p && (mob_id < 1324 || mob_id > 1363) && (mob_id < 1938 || mob_id > 1946) ) - { //Skip treasure chests. - if (id->maxchance == -1 || (id->maxchance < db->dropitem[i].p) ) { - id->maxchance = db->dropitem[i].p; //item has bigger drop chance or sold in shops - } - for (k = 0; k< MAX_SEARCH; k++) { - if (id->mob[k].chance <= db->dropitem[i].p) - break; - } - if (k == MAX_SEARCH) + if( db->dropitem[i].nameid ){ + if( itemdb_search( db->dropitem[i].nameid ) ){ + db->dropitem[i].p = atoi(str[k+1]); continue; - - if (id->mob[k].id != mob_id) - memmove(&id->mob[k+1], &id->mob[k], (MAX_SEARCH-k-1)*sizeof(id->mob[0])); - id->mob[k].chance = db->dropitem[i].p; - id->mob[k].id = mob_id; + }else{ + ShowWarning( "Monster \"%s\"(id: %d) is dropping an unknown item \"%s\"(Drop %d)\n", db->name, mob_id, str[k], ( i / 2 ) + 1 ); + } } + + // Delete the item + db->dropitem[i].nameid = 0; + db->dropitem[i].p = 0; } // Finally insert monster's data into the database. @@ -4606,6 +4546,154 @@ static int mob_item_drop_ratio_free(DBKey key, DBData *data, va_list ap) { return 0; } +static void mob_drop_ratio_adjust(){ + struct mob_db *mob; + struct item_data *id; + unsigned short nameid, ratemin, ratemax; + int i, j, k, rate, rate_adjust, type, mob_id; + bool is_treasurechest; + + for( i = 0; i <= MAX_MOB_DB; i++ ){ + mob = mob_db(i); + + // Skip dummy mobs. + if( mob == mob_dummy ){ + continue; + } + + mob_id = i; + + for( j = 0; j < MAX_MVP_DROP; j++ ){ + nameid = mob->mvpitem[j].nameid; + rate = mob->mvpitem[j].p; + + if( nameid == 0 || rate == 0 ){ + continue; + } + + rate_adjust = battle_config.item_rate_mvp; + + // Adjust the rate if there is an entry in mob_item_ratio + item_dropratio_adjust( nameid, mob_id, &rate_adjust ); + + // Adjust rate with given algorithms + rate = mob_drop_adjust( rate, rate_adjust, battle_config.item_drop_mvp_min, battle_config.item_drop_mvp_max ); + + // calculate and store Max available drop chance of the MVP item + if( rate ){ + id = itemdb_search( nameid ); + + if( id->maxchance == -1 || ( id->maxchance < rate/10 + 1 ) ){ + // item has bigger drop chance or sold in shops + id->maxchance = rate/10 + 1; // reduce MVP drop info to not spoil common drop rate + } + } + + mob->mvpitem[j].p = rate; + } + + for( j = 0; j < MAX_MOB_DROP; j++ ){ + nameid = mob->dropitem[j].nameid; + rate = mob->dropitem[j].p; + + if( nameid == 0 || rate == 0 ){ + continue; + } + + id = itemdb_search( nameid ); + + // Item is not known anymore(should never happen) + if( !id ){ + ShowWarning( "Monster \"%s\"(id:%d) is dropping an unknown item(id: %d)\n", mob->name, mob_id, nameid ); + mob->dropitem[j].nameid = 0; + mob->dropitem[j].p = 0; + continue; + } + + type = id->type; + + if( battle_config.drop_rateincrease && rate < 5000 ){ + rate++; + } + + // Treasure box drop rates [Skotlex] + if( ( mob_id >= 1324 && mob_id <= 1363 ) || ( mob_id >= 1938 && mob_id <= 1946 ) ){ + is_treasurechest = true; + + rate_adjust = battle_config.item_rate_treasure; + ratemin = battle_config.item_drop_treasure_min; + ratemax = battle_config.item_drop_treasure_max; + }else{ + is_treasurechest = false; + + // Added suport to restrict normal drops of MVP's [Reddozen] + switch( type ){ + case IT_HEALING: + rate_adjust = (mob->status.mode&MD_BOSS) ? battle_config.item_rate_heal_boss : battle_config.item_rate_heal; + ratemin = battle_config.item_drop_heal_min; + ratemax = battle_config.item_drop_heal_max; + break; + case IT_USABLE: + case IT_CASH: + rate_adjust = (mob->status.mode&MD_BOSS) ? battle_config.item_rate_use_boss : battle_config.item_rate_use; + ratemin = battle_config.item_drop_use_min; + ratemax = battle_config.item_drop_use_max; + break; + case IT_WEAPON: + case IT_ARMOR: + case IT_PETARMOR: + rate_adjust = (mob->status.mode&MD_BOSS) ? battle_config.item_rate_equip_boss : battle_config.item_rate_equip; + ratemin = battle_config.item_drop_equip_min; + ratemax = battle_config.item_drop_equip_max; + break; + case IT_CARD: + rate_adjust = (mob->status.mode&MD_BOSS) ? battle_config.item_rate_card_boss : battle_config.item_rate_card; + ratemin = battle_config.item_drop_card_min; + ratemax = battle_config.item_drop_card_max; + break; + default: + rate_adjust = (mob->status.mode&MD_BOSS) ? battle_config.item_rate_common_boss : battle_config.item_rate_common; + ratemin = battle_config.item_drop_common_min; + ratemax = battle_config.item_drop_common_max; + break; + } + } + + item_dropratio_adjust( nameid, mob_id, &rate_adjust ); + + rate = mob_drop_adjust( rate, rate_adjust, ratemin, ratemax ); + + // calculate and store Max available drop chance of the item + // but skip treasure chests. + if( rate && !is_treasurechest ){ + if( id->maxchance == -1 || ( id->maxchance < rate ) ){ + id->maxchance = rate; // item has bigger drop chance or sold in shops + } + + for( k = 0; k < MAX_SEARCH; k++ ){ + if( id->mob[k].chance <= rate ){ + break; + } + } + + if( k != MAX_SEARCH ){ + if( id->mob[k].id != mob_id ){ + memmove( &id->mob[k+1], &id->mob[k], (MAX_SEARCH-k-1)*sizeof(id->mob[0]) ); + } + + id->mob[k].chance = rate; + id->mob[k].id = mob_id; + } + } + + mob->dropitem[j].p = rate; + } + } + + // Now that we are done we can delete the stored item ratios + mob_item_drop_ratio->clear( mob_item_drop_ratio, mob_item_drop_ratio_free ); +} + /** * read all mob-related databases */ @@ -4633,8 +4721,6 @@ static void mob_load(void) safesnprintf(dbsubpath2,n1,"%s%s",db_path,dbsubpath[i]); } - sv_readdb(dbsubpath1, "mob_item_ratio.txt", ',', 2, 2+MAX_ITEMRATIO_MOBS, -1, &mob_readdb_itemratio, i); // must be read before mobdb - sv_readdb(dbsubpath1, "mob_chat_db.txt", '#', 3, 3, MAX_MOB_CHAT, &mob_parse_row_chatdb, i); if (db_use_sqldbs && i==0) //only read once for sql { mob_read_sqldb(); @@ -4643,12 +4729,18 @@ static void mob_load(void) sv_readdb(dbsubpath2, "mob_db.txt", ',', 31+2*MAX_MVP_DROP+2*MAX_MOB_DROP, 31+2*MAX_MVP_DROP+2*MAX_MOB_DROP, -1, &mob_readdb_sub, i); mob_readskilldb(dbsubpath2,i); } + sv_readdb(dbsubpath1, "mob_avail.txt", ',', 2, 12, -1, &mob_readdb_mobavail, i); sv_readdb(dbsubpath2, "mob_race2_db.txt", ',', 2, 20, -1, &mob_readdb_race2, i); + sv_readdb(dbsubpath1, "mob_item_ratio.txt", ',', 2, 2+MAX_ITEMRATIO_MOBS, -1, &mob_readdb_itemratio, i); // must be read before mobdb + sv_readdb(dbsubpath1, "mob_chat_db.txt", '#', 3, 3, MAX_MOB_CHAT, &mob_parse_row_chatdb, i); aFree(dbsubpath1); aFree(dbsubpath2); } + + mob_drop_ratio_adjust(); + mob_read_randommonster(); } From d555cac992dcdc73e3cb588feafd40bf73f47791 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Sat, 3 Jan 2015 19:23:35 +0700 Subject: [PATCH 2/3] Follow up 54031eda9dcea4a0c5958276a7786cbcdcdc55c5 Signed-off-by: Cydh Ramdh --- src/map/itemdb.h | 2 +- src/map/mob.c | 32 ++++++++++++++++++++++---------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 795c5660e6..09916c2d9f 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -399,7 +399,7 @@ struct item_data 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 : 6; //Specifies if the class-type can equip it (0x01: normal, 0x02: trans, 0x04: baby, 0x08:third, 0x10:trans-third, 0x20-third-baby) struct { - unsigned short chance; + int 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. diff --git a/src/map/mob.c b/src/map/mob.c index d500dfb656..828d45e9fa 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -4546,14 +4546,15 @@ static int mob_item_drop_ratio_free(DBKey key, DBData *data, va_list ap) { return 0; } -static void mob_drop_ratio_adjust(){ - struct mob_db *mob; - struct item_data *id; - unsigned short nameid, ratemin, ratemax; - int i, j, k, rate, rate_adjust, type, mob_id; - bool is_treasurechest; +static void mob_drop_ratio_adjust(void){ + unsigned short i; for( i = 0; i <= MAX_MOB_DB; i++ ){ + struct mob_db *mob; + struct item_data *id; + unsigned short nameid; + int j, rate, rate_adjust = 0, mob_id; + mob = mob_db(i); // Skip dummy mobs. @@ -4583,6 +4584,14 @@ static void mob_drop_ratio_adjust(){ if( rate ){ id = itemdb_search( nameid ); + // Item is not known anymore(should never happen) + if( !id ){ + ShowWarning( "Monster \"%s\"(id:%d) is dropping an unknown item(id: %d)\n", mob->name, mob_id, nameid ); + mob->mvpitem[j].nameid = 0; + mob->mvpitem[j].p = 0; + continue; + } + if( id->maxchance == -1 || ( id->maxchance < rate/10 + 1 ) ){ // item has bigger drop chance or sold in shops id->maxchance = rate/10 + 1; // reduce MVP drop info to not spoil common drop rate @@ -4593,6 +4602,9 @@ static void mob_drop_ratio_adjust(){ } for( j = 0; j < MAX_MOB_DROP; j++ ){ + unsigned short ratemin, ratemax; + bool is_treasurechest; + nameid = mob->dropitem[j].nameid; rate = mob->dropitem[j].p; @@ -4610,14 +4622,12 @@ static void mob_drop_ratio_adjust(){ continue; } - type = id->type; - if( battle_config.drop_rateincrease && rate < 5000 ){ rate++; } // Treasure box drop rates [Skotlex] - if( ( mob_id >= 1324 && mob_id <= 1363 ) || ( mob_id >= 1938 && mob_id <= 1946 ) ){ + if( ( mob_id >= MOBID_TREAS01 && mob_id <= MOBID_TREAS40 ) || ( mob_id >= MOBID_TREAS41 && mob_id <= MOBID_TREAS49 ) ){ is_treasurechest = true; rate_adjust = battle_config.item_rate_treasure; @@ -4627,7 +4637,7 @@ static void mob_drop_ratio_adjust(){ is_treasurechest = false; // Added suport to restrict normal drops of MVP's [Reddozen] - switch( type ){ + switch( id->type ){ case IT_HEALING: rate_adjust = (mob->status.mode&MD_BOSS) ? battle_config.item_rate_heal_boss : battle_config.item_rate_heal; ratemin = battle_config.item_drop_heal_min; @@ -4666,6 +4676,8 @@ static void mob_drop_ratio_adjust(){ // calculate and store Max available drop chance of the item // but skip treasure chests. if( rate && !is_treasurechest ){ + unsigned short k; + if( id->maxchance == -1 || ( id->maxchance < rate ) ){ id->maxchance = rate; // item has bigger drop chance or sold in shops } From 5feff01ddd621fd49985e0374bf3fe169ded02f3 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Thu, 8 Jan 2015 12:51:52 +0700 Subject: [PATCH 3/3] Follow up 54031eda9dcea4a0c5958276a7786cbcdcdc55c5 * Missing `item_ratio->nameid = nameid;` assignment when item_ratio isn't exist in db yet * Modified @whodrops result for monster list to: "- (): %" Signed-off-by: Cydh Ramdh --- src/map/atcommand.c | 2 +- src/map/itemdb.c | 2 +- src/map/mob.c | 25 ++++++++++++++++++------- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 62d2368ae7..a3b86eb4b5 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -7584,7 +7584,7 @@ ACMD_FUNC(whodrops) if (pc_isvip(sd) && battle_config.vip_drop_increase) dropchance += battle_config.vip_drop_increase; #endif - sprintf(atcmd_output, "- %s (%02.02f%%)", mob_db(item_data->mob[j].id)->jname, dropchance/100.); + sprintf(atcmd_output, "- %s (%d): %02.02f%%", mob_db(item_data->mob[j].id)->jname, item_data->mob[j].id, dropchance/100.); clif_displaymessage(fd, atcmd_output); } } diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 1c10975fb6..6a267ef324 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -1604,7 +1604,7 @@ void itemdb_reload(void) { //- Fixes the need of a @reloadmobdb after a @reloaditemdb to re-link monster drop data for( i = 0; i < MAX_MOB_DB; i++ ) { struct mob_db *entry; - if( !((i < 1324 || i > 1363) && (i < 1938 || i > 1946)) ) + if( !((i < MOBID_TREAS01 || i > MOBID_TREAS40) && (i < MOBID_TREAS41 || i > MOBID_TREAS49)) ) continue; entry = mob_db(i); for(d = 0; d < MAX_MOB_DROP; d++) { diff --git a/src/map/mob.c b/src/map/mob.c index 828d45e9fa..37c1cf5b37 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -3880,7 +3880,7 @@ static bool mob_parse_dbrow(char** str) if( db->mvpitem[i].nameid ){ if( itemdb_search(db->mvpitem[i].nameid) ){ db->mvpitem[i].p = atoi(str[32+i*2]); - continue; + continue; }else{ ShowWarning( "Monster \"%s\"(id: %d) is dropping an unknown item \"%s\"(MVP-Drop %d)\n", db->name, mob_id, str[31+i*2], ( i / 2 ) + 1 ); } @@ -4531,21 +4531,34 @@ static bool mob_readdb_itemratio(char* str[], int columns, int current) item_ratio->drop_ratio = ratio; memset(item_ratio->mob_id, 0, sizeof(item_ratio->mob_id)); - for (i = 0; i < columns-2; i++) - item_ratio->mob_id[i] = atoi(str[i+2]); + for (i = 0; i < columns-2; i++) { + uint16 mob_id = atoi(str[i+2]); + if (mob_db(mob_id) == mob_dummy) + ShowError("itemdb_read_itemratio: Invalid monster with ID %hu (Item:%hu Col:%d).\n", mob_id, nameid, columns); + else + item_ratio->mob_id[i] = atoi(str[i+2]); + } - if (!item_ratio->nameid) + if (!item_ratio->nameid) { + item_ratio->nameid = nameid; idb_put(mob_item_drop_ratio, nameid, item_ratio); + } return true; } +/** + * Free drop ratio data + **/ static int mob_item_drop_ratio_free(DBKey key, DBData *data, va_list ap) { struct s_mob_item_drop_ratio *item_ratio = db_data2ptr(data); aFree(item_ratio); return 0; } +/** + * Adjust drop ratio for each monster + **/ static void mob_drop_ratio_adjust(void){ unsigned short i; @@ -4670,7 +4683,6 @@ static void mob_drop_ratio_adjust(void){ } item_dropratio_adjust( nameid, mob_id, &rate_adjust ); - rate = mob_drop_adjust( rate, rate_adjust, ratemin, ratemax ); // calculate and store Max available drop chance of the item @@ -4744,7 +4756,7 @@ static void mob_load(void) sv_readdb(dbsubpath1, "mob_avail.txt", ',', 2, 12, -1, &mob_readdb_mobavail, i); sv_readdb(dbsubpath2, "mob_race2_db.txt", ',', 2, 20, -1, &mob_readdb_race2, i); - sv_readdb(dbsubpath1, "mob_item_ratio.txt", ',', 2, 2+MAX_ITEMRATIO_MOBS, -1, &mob_readdb_itemratio, i); // must be read before mobdb + sv_readdb(dbsubpath1, "mob_item_ratio.txt", ',', 2, 2+MAX_ITEMRATIO_MOBS, -1, &mob_readdb_itemratio, i); sv_readdb(dbsubpath1, "mob_chat_db.txt", '#', 3, 3, MAX_MOB_CHAT, &mob_parse_row_chatdb, i); aFree(dbsubpath1); @@ -4752,7 +4764,6 @@ static void mob_load(void) } mob_drop_ratio_adjust(); - mob_read_randommonster(); }