diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 867cf5cbe4..34c32e21e3 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -5,6 +5,9 @@ IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. EV GOES INTO TRUNK AND WILL BE MERGED INTO STABLE BY VALARIS AND WIZPUTER. -- VALARIS 2006/03/08 + * Added atcommand @whodrops which lists mobs with the top drop-rates for a + given item. List of stored mobs and their dropchances is also defined by + MAX_SEARCH on map.h [Skotlex] * Modified atcommands @mobinfo and @iteminfo to display multiple matches instead of just one. Max number of matches to display is set in map.h (MAX_SEARCH) which is currently 5. [Skotlex] diff --git a/conf-tmpl/atcommand_athena.conf b/conf-tmpl/atcommand_athena.conf index 549d237857..4cb096fff0 100644 --- a/conf-tmpl/atcommand_athena.conf +++ b/conf-tmpl/atcommand_athena.conf @@ -71,6 +71,9 @@ mi: 1 iteminfo: 1 ii: 1 +// Show who drops an item (mobs with highest drop rate) +whodrops: 1 + // Syncs the position of the player on the client with the one stored in the server. refresh: 1 diff --git a/src/map/atcommand.c b/src/map/atcommand.c index f02f974c1b..97682fc5d7 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -266,6 +266,7 @@ ACMD_FUNC(shuffle); // by MouseJstr ACMD_FUNC(rates); // by MouseJstr ACMD_FUNC(iteminfo); // Lupus +ACMD_FUNC(whodrops); //Skotlex ACMD_FUNC(mapflag); // Lupus ACMD_FUNC(me); //added by massdriller, code by lordalfa ACMD_FUNC(monsterignore); // [Valaris] @@ -577,6 +578,7 @@ static AtCommandInfo atcommand_info[] = { { AtCommand_ItemInfo, "@iteminfo", 1, atcommand_iteminfo }, // [Lupus] { AtCommand_ItemInfo, "@ii", 1, atcommand_iteminfo }, // [Lupus] + { AtCommand_WhoDrops, "@whodrops", 1, atcommand_whodrops }, // [Skotlex] { AtCommand_MapFlag, "@mapflag", 99, atcommand_mapflag }, // [Lupus] { AtCommand_Me, "@me", 20, atcommand_me }, //added by massdriller, code by lordalfa @@ -9412,6 +9414,57 @@ int atcommand_iteminfo( return -1; } +/*========================================== + * Show who drops the item. + *------------------------------------------ + */ +int atcommand_whodrops( + const int fd, struct map_session_data* sd, + const char* command, const char* message) +{ + struct item_data *item_data, *item_array[MAX_SEARCH]; + int i, count = 1; + + if (!message || !*message) { + clif_displaymessage(fd, "Please, enter Item name or its ID (usage: @whodrops )."); + return -1; + } + if ((item_array[0] = itemdb_exists(atoi(message))) == NULL) + count = itemdb_searchname_array(item_array, MAX_SEARCH, message); + + if (!count) { + clif_displaymessage(fd, "Item not found."); + return -1; + } + + if (count > MAX_SEARCH) { + sprintf(atcmd_output, msg_table[269], MAX_SEARCH, count); + clif_displaymessage(fd, atcmd_output); + count = MAX_SEARCH; + } + for (i = 0; i < MAX_SEARCH; i++) { + item_data = item_array[i]; + sprintf(atcmd_output, "Item: '%s'[%d]", + item_data->jname,item_data->slot); + clif_displaymessage(fd, atcmd_output); + + if (item_data->mob[0].chance == 0) { + strcpy(atcmd_output, " - Item is not dropped by mobs."); + clif_displaymessage(fd, atcmd_output); + } else { + sprintf(atcmd_output, "- Common mobs with highest drop chance (only max %d are listed):", MAX_SEARCH); + clif_displaymessage(fd, atcmd_output); + + for (i=0; i < MAX_SEARCH && item_data->mob[i].chance > 0; i++) + { + sprintf(atcmd_output, "- %s (%02.02f%%)", mob_db(item_data->mob[i].id)->jname, item_data->mob[i].chance/100.); + clif_displaymessage(fd, atcmd_output); + } + } + } + return 0; +} + /*========================================== * @adopt by [Veider] * diff --git a/src/map/atcommand.h b/src/map/atcommand.h index a84b8ba8c0..cd90468aa6 100644 --- a/src/map/atcommand.h +++ b/src/map/atcommand.h @@ -245,6 +245,7 @@ enum AtCommandType { AtCommand_Rates, // MouseJstr AtCommand_ItemInfo, // Lupus + AtCommand_WhoDrops, // Skotlex AtCommand_MapFlag, // Lupus AtCommand_MonsterIgnore, // [Valaris] AtCommand_FakeName, // [Valaris] diff --git a/src/map/itemdb.h b/src/map/itemdb.h index c438631551..d95d64a43e 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -15,6 +15,11 @@ struct item_data { int value_sell; int type; int maxchance; //For logs, for external game info, for scripts: Max drop chance of this item (e.g. 0.01% , etc.. if it = 0, then monsters don't drop it) [Lupus] + struct { + unsigned short chance; + int id; + } mob[MAX_SEARCH]; //Holds the mobs that have the highest drop rate for this item. [Skotlex] + int sex; int equip; int weight; diff --git a/src/map/mob.c b/src/map/mob.c index c17079add8..3995eba310 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -4296,7 +4296,7 @@ static int mob_readdb(void) FILE *fp; char line[1024]; char *filename[]={ "mob_db.txt","mob_db2.txt" }; - int class_, i, fi; + int class_, i, fi, k; for(fi=0;fi<2;fi++){ sprintf(line, "%s/%s", db_path, filename[fi]); @@ -4433,12 +4433,22 @@ static int mob_readdb(void) mob_db_data[class_]->dropitem[i].p = mob_drop_adjust(rate, rate_adjust, ratemin, ratemax); //calculate and store Max available drop chance of the item - id = itemdb_search(mob_db_data[class_]->dropitem[i].nameid); if (mob_db_data[class_]->dropitem[i].p) { + id = itemdb_search(mob_db_data[class_]->dropitem[i].nameid); if (id->maxchance==10000 || (id->maxchance < mob_db_data[class_]->dropitem[i].p) ) { //item has bigger drop chance or sold in shops id->maxchance = mob_db_data[class_]->dropitem[i].p; - } + } + for (k = 0; k< MAX_SEARCH; k++) { + if (id->mob[k].chance < mob_db_data[class_]->dropitem[i].p && id->mob[k].id != class_) + break; + } + if (k == MAX_SEARCH) + continue; + + memmove(&id->mob[k+1], &id->mob[k], (MAX_SEARCH-k-1)*sizeof(id->mob[0])); + id->mob[k].chance = mob_db_data[class_]->dropitem[i].p; + id->mob[k].id = class_; } } // MVP EXP Bonus, Chance: MEXP,ExpPer @@ -4470,8 +4480,8 @@ static int mob_readdb(void) battle_config.item_drop_mvp_min, battle_config.item_drop_mvp_max); //calculate and store Max available drop chance of the MVP item - id = itemdb_search(mob_db_data[class_]->mvpitem[i].nameid); if (mob_db_data[class_]->mvpitem[i].p) { + id = itemdb_search(mob_db_data[class_]->mvpitem[i].nameid); if (id->maxchance==10000 || (id->maxchance < mob_db_data[class_]->mvpitem[i].p/10+1) ) { //item has bigger drop chance or sold in shops id->maxchance = mob_db_data[class_]->mvpitem[i].p/10+1; //reduce MVP drop info to not spoil common drop rate @@ -4910,7 +4920,7 @@ static int mob_readdb_race(void) static int mob_read_sqldb(void) { const char unknown_str[NAME_LENGTH] ="unknown"; - int i, fi, class_; + int i, fi, class_, k; double exp, maxhp; long unsigned int ln = 0; char *mob_db_name[] = { mob_db_db, mob_db2_db }; @@ -5039,12 +5049,22 @@ static int mob_read_sqldb(void) mob_db_data[class_]->dropitem[i].p = mob_drop_adjust(rate, rate_adjust, ratemin, ratemax); //calculate and store Max available drop chance of the item - id = itemdb_search(mob_db_data[class_]->dropitem[i].nameid); if (mob_db_data[class_]->dropitem[i].p) { + id = itemdb_search(mob_db_data[class_]->dropitem[i].nameid); if (id->maxchance==10000 || (id->maxchance < mob_db_data[class_]->dropitem[i].p) ) { //item has bigger drop chance or sold in shops id->maxchance = mob_db_data[class_]->dropitem[i].p; } + for (k = 0; k< MAX_SEARCH; k++) { + if (id->mob[k].chance < mob_db_data[class_]->dropitem[i].p && id->mob[k].id != class_) + break; + } + if (k == MAX_SEARCH) + continue; + + memmove(&id->mob[k+1], &id->mob[k], (MAX_SEARCH-k-1)*sizeof(id->mob[0])); + id->mob[k].chance = mob_db_data[class_]->dropitem[i].p; + id->mob[k].id = class_; } } // MVP EXP Bonus, Chance: MEXP,ExpPer