-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Keep track of all mobs that drop an item #8049
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8368,31 +8368,34 @@ ACMD_FUNC(whodrops) | |
sprintf(atcmd_output, msg_txt(sd,1285), item_db.create_item_link( id ).c_str(), id->nameid); // Item: '%s' (ID:%u) | ||
clif_displaymessage(fd, atcmd_output); | ||
|
||
if (id->mob[0].chance == 0) { | ||
if (id->mobs.empty()) { | ||
strcpy(atcmd_output, msg_txt(sd,1286)); // - Item is not dropped by mobs. | ||
clif_displaymessage(fd, atcmd_output); | ||
} else { | ||
sprintf(atcmd_output, msg_txt(sd,1287), MAX_SEARCH); // - Common mobs with highest drop chance (only max %d are listed): | ||
clif_displaymessage(fd, atcmd_output); | ||
return 0; | ||
} | ||
sprintf(atcmd_output, msg_txt(sd,1287), MAX_SEARCH); // - Common mobs with highest drop chance (only max %d are listed): | ||
clif_displaymessage(fd, atcmd_output); | ||
|
||
for (uint16 j=0; j < MAX_SEARCH && id->mob[j].chance > 0; j++) | ||
{ | ||
int dropchance = id->mob[j].chance; | ||
std::shared_ptr<s_mob_db> mob = mob_db.find(id->mob[j].id); | ||
if(!mob) continue; | ||
// NB: We don't const-ref this because we modify dropchance, so let's just make a copy | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldnt it be more performant to const-ref this and just have a separate variable for the "real" droprate calculation? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ehh, two 32bit copy or a 64bit address with a 32bit copy, not sure which is better |
||
int count = MAX_SEARCH; | ||
for (auto [dropchance, mob_id] : id->mobs) { | ||
std::shared_ptr<s_mob_db> mob = mob_db.find(mob_id); | ||
if (!mob) | ||
continue; | ||
|
||
#ifdef RENEWAL_DROP | ||
if( battle_config.atcommand_mobinfo_type ) { | ||
dropchance = dropchance * pc_level_penalty_mod( sd, PENALTY_DROP, mob ) / 100; | ||
if (dropchance <= 0 && !battle_config.drop_rate0item) | ||
dropchance = 1; | ||
} | ||
#endif | ||
if (pc_isvip(sd)) // Display item rate increase for VIP | ||
dropchance += (dropchance * battle_config.vip_drop_increase) / 100; | ||
sprintf(atcmd_output, "- %s (%d): %02.02f%%", mob->jname.c_str(), id->mob[j].id, dropchance/100.); | ||
clif_displaymessage(fd, atcmd_output); | ||
if (battle_config.atcommand_mobinfo_type) { | ||
dropchance = dropchance * pc_level_penalty_mod(sd, PENALTY_DROP, mob) / 100; | ||
if (dropchance <= 0 && !battle_config.drop_rate0item) | ||
dropchance = 1; | ||
} | ||
#endif | ||
if (pc_isvip(sd)) // Display item rate increase for VIP | ||
dropchance += (dropchance * battle_config.vip_drop_increase) / 100; | ||
sprintf(atcmd_output, "- %s (%d): %02.02f%%", mob->jname.c_str(), mob_id, dropchance/100.); | ||
clif_displaymessage(fd, atcmd_output); | ||
if (--count <= 0) | ||
break; | ||
} | ||
} | ||
return 0; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2259,10 +2259,11 @@ struct item_data | |
// some script commands should be revised as well... | ||
uint64 class_base[3]; //Specifies if the base can wear this item (split in 3 indexes per type: 1-1, 2-1, 2-2) | ||
uint16 class_upper; //Specifies if the class-type can equip it (See e_item_job) | ||
struct { | ||
int chance; | ||
int id; | ||
} mob[MAX_SEARCH]; //Holds the mobs that have the highest drop rate for this item. [Skotlex] | ||
struct drop_chance { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be nice to move this outside and follow the naming standards. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the naming standards? |
||
uint32 chance; | ||
uint32 mob_id; | ||
}; | ||
std::vector<drop_chance> mobs; // Sorted vector that holds the mobs that have the highest drop rate for this item. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This vector has no limit now anymore. |
||
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. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6284,20 +6284,11 @@ static void mob_drop_ratio_adjust(void){ | |
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]) ); | ||
} | ||
item_data::drop_chance drop{static_cast<uint32>(rate), pair.second->id}; | ||
|
||
id->mob[k].chance = rate; | ||
id->mob[k].id = mob_id; | ||
} | ||
id->mobs.insert(std::lower_bound(id->mobs.begin(), id->mobs.end(), drop, [](const auto &drop, const auto &it) { | ||
return drop.chance > it.chance; | ||
}), drop); | ||
} | ||
|
||
mob->dropitem[j].rate = rate; | ||
|
@@ -6609,30 +6600,29 @@ void mob_db_load(bool is_reload){ | |
*/ | ||
void mob_reload_itemmob_data(void) { | ||
for( auto const &pair : mob_db ){ | ||
int d, k; | ||
|
||
if( mob_is_clone( pair.first ) ){ | ||
continue; | ||
} | ||
|
||
for(d = 0; d < MAX_MOB_DROP_TOTAL; d++) { | ||
struct item_data *id; | ||
for(int d = 0; d < MAX_MOB_DROP_TOTAL; d++) { | ||
if( !pair.second->dropitem[d].nameid ) | ||
continue; | ||
id = itemdb_search(pair.second->dropitem[d].nameid); | ||
|
||
for (k = 0; k < MAX_SEARCH; k++) { | ||
if (id->mob[k].chance <= pair.second->dropitem[d].rate) | ||
break; | ||
} | ||
|
||
if (k == MAX_SEARCH) | ||
struct item_data *id = itemdb_search(pair.second->dropitem[d].nameid); | ||
if (!id) | ||
continue; | ||
|
||
if (id->mob[k].id != pair.first) | ||
memmove(&id->mob[k+1], &id->mob[k], (MAX_SEARCH-k-1)*sizeof(id->mob[0])); | ||
id->mob[k].chance = pair.second->dropitem[d].rate; | ||
id->mob[k].id = pair.first; | ||
item_data::drop_chance drop{pair.second->dropitem[d].rate, pair.second->id}; | ||
|
||
id->mobs.insert( | ||
std::lower_bound( | ||
id->mobs.begin(), | ||
id->mobs.end(), | ||
drop, | ||
[](const auto &drop, const auto &it) { | ||
return drop.chance < it.chance; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this the only place where we use |
||
}), | ||
drop); | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18239,7 +18239,16 @@ BUILDIN_FUNC(addmonsterdrop) | |
mob->dropitem[c].rate = rate; | ||
mob->dropitem[c].steal_protected = steal_protected > 0; | ||
mob->dropitem[c].randomopt_group = group; | ||
mob_reload_itemmob_data(); // Reload the mob search data stored in the item_data | ||
item_data::drop_chance drop{static_cast<uint32>(rate), mob->id}; | ||
itm->mobs.insert( | ||
std::lower_bound( | ||
itm->mobs.begin(), | ||
itm->mobs.end(), | ||
drop, | ||
[](const auto &drop, const auto &it) { | ||
return drop.chance > it.chance; | ||
}), | ||
drop); | ||
|
||
script_pushint(st, true); | ||
return SCRIPT_CMD_SUCCESS; | ||
|
@@ -18270,25 +18279,38 @@ BUILDIN_FUNC(delmonsterdrop) | |
return SCRIPT_CMD_FAILURE; | ||
} | ||
|
||
if(mob) { //We got a valid monster, check for item drop on monster | ||
unsigned char i; | ||
for(i = 0; i < MAX_MOB_DROP_TOTAL; i++) { | ||
if(mob->dropitem[i].nameid == item_id) { | ||
mob->dropitem[i].nameid = 0; | ||
mob->dropitem[i].rate = 0; | ||
mob->dropitem[i].steal_protected = false; | ||
mob->dropitem[i].randomopt_group = 0; | ||
mob_reload_itemmob_data(); // Reload the mob search data stored in the item_data | ||
script_pushint(st,1); | ||
return SCRIPT_CMD_SUCCESS; | ||
} | ||
} | ||
//No drop on that monster | ||
script_pushint(st,0); | ||
} else { | ||
ShowWarning("delmonsterdrop: bad mob id given %d\n",script_getnum(st,2)); | ||
if (!mob) { | ||
if (script_isstring(st, 2)) | ||
ShowWarning("delmonsterdrop: bad mob name given %s\n", script_getstr(st, 2)); | ||
else | ||
ShowWarning("delmonsterdrop: bad mob id given %d\n", script_getnum(st, 2)); | ||
return SCRIPT_CMD_FAILURE; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we combine that with the if/else right at the start? |
||
|
||
unsigned char i; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please change this to be the loop variable. |
||
for(i = 0; i < MAX_MOB_DROP_TOTAL; i++) { | ||
if(mob->dropitem[i].nameid != item_id) { | ||
continue; | ||
} | ||
mob->dropitem[i].nameid = 0; | ||
mob->dropitem[i].rate = 0; | ||
mob->dropitem[i].steal_protected = false; | ||
mob->dropitem[i].randomopt_group = 0; | ||
|
||
std::shared_ptr<item_data> itm = item_db.find(item_id); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is already the following call at the start: Please rewrite it and only look it up once at the start of the function. |
||
if (itm) { | ||
auto it = std::find_if(itm->mobs.begin(), itm->mobs.end(), [&mob](const auto &drop) { | ||
return drop.mob_id == mob->id; | ||
}); | ||
if (it != itm->mobs.end()) | ||
itm->mobs.erase(it); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why dont we std::remove_if here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we only want to remove one drop, remove_if moves all to the end, so i went with find |
||
} | ||
|
||
script_pushint(st,1); | ||
return SCRIPT_CMD_SUCCESS; | ||
Comment on lines
+18299
to
+18300
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this was broken sometime in the past, since we support monsters dropping the same item id multiple times now. |
||
} | ||
//No drop on that monster | ||
script_pushint(st,0); | ||
return SCRIPT_CMD_SUCCESS; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can be more than one item, so sadly we cannot cancel early.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, you're right