|
@@ -80,9 +80,7 @@ struct s_mob_skill_db {
|
|
|
|
|
|
std::unordered_map<int32, std::shared_ptr<s_mob_skill_db>> mob_skill_db; /// Monster skill temporary db. s_mob_skill_db -> mobid
|
|
|
|
|
|
-static struct eri *item_drop_ers; //For loot drops delay structures.
|
|
|
-static struct eri *item_drop_list_ers;
|
|
|
-
|
|
|
+std::unordered_map<uint32, std::shared_ptr<s_item_drop_list>> mob_delayed_drops;
|
|
|
MobSummonDatabase mob_summon_db;
|
|
|
MobChatDatabase mob_chat_db;
|
|
|
MapDropDatabase map_drop_db;
|
|
@@ -2176,49 +2174,45 @@ static TIMER_FUNC(mob_ai_hard){
|
|
|
* @param mobdrop: Drop data
|
|
|
* @author [Cydh]
|
|
|
**/
|
|
|
-void mob_setdropitem_option(item *item, s_mob_drop *mobdrop) {
|
|
|
- if (!item || !mobdrop)
|
|
|
- return;
|
|
|
-
|
|
|
- std::shared_ptr<s_random_opt_group> group = random_option_group.find(mobdrop->randomopt_group);
|
|
|
+void mob_setdropitem_option( item& item, s_mob_drop& mobdrop ){
|
|
|
+ std::shared_ptr<s_random_opt_group> group = random_option_group.find( mobdrop.randomopt_group );
|
|
|
|
|
|
if (group != nullptr) {
|
|
|
- group->apply( *item );
|
|
|
+ group->apply( item );
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/*==========================================
|
|
|
* Initializes the delay drop structure for mob-dropped items.
|
|
|
*------------------------------------------*/
|
|
|
-static struct item_drop* mob_setdropitem(struct s_mob_drop *mobdrop, int qty, unsigned short mob_id)
|
|
|
-{
|
|
|
- struct item_drop *drop = ers_alloc(item_drop_ers, struct item_drop);
|
|
|
- memset(&drop->item_data, 0, sizeof(struct item));
|
|
|
- drop->item_data.nameid = mobdrop->nameid;
|
|
|
+static std::shared_ptr<s_item_drop> mob_setdropitem( s_mob_drop& mobdrop, int qty, unsigned short mob_id ){
|
|
|
+ std::shared_ptr<s_item_drop> drop = std::make_shared<s_item_drop>();
|
|
|
+
|
|
|
+ drop->item_data = { 0 };
|
|
|
+ drop->item_data.nameid = mobdrop.nameid;
|
|
|
drop->item_data.amount = qty;
|
|
|
- drop->item_data.identify = itemdb_isidentified(mobdrop->nameid);
|
|
|
- mob_setdropitem_option(&drop->item_data, mobdrop);
|
|
|
+ drop->item_data.identify = itemdb_isidentified( mobdrop.nameid );
|
|
|
+ mob_setdropitem_option( drop->item_data, mobdrop );
|
|
|
drop->mob_id = mob_id;
|
|
|
- drop->next = nullptr;
|
|
|
+
|
|
|
return drop;
|
|
|
}
|
|
|
|
|
|
/*==========================================
|
|
|
* Initializes the delay drop structure for mob-looted items.
|
|
|
*------------------------------------------*/
|
|
|
-static struct item_drop* mob_setlootitem(struct s_mob_lootitem *item, unsigned short mob_id)
|
|
|
-{
|
|
|
- struct item_drop *drop = ers_alloc(item_drop_ers, struct item_drop);
|
|
|
- memcpy(&drop->item_data, item, sizeof(struct item));
|
|
|
+static std::shared_ptr<s_item_drop> mob_setlootitem( s_mob_lootitem& item, unsigned short mob_id ){
|
|
|
+ std::shared_ptr<s_item_drop> drop = std::make_shared<s_item_drop>();
|
|
|
+
|
|
|
+ memcpy( &drop->item_data, &item, sizeof( struct item ) );
|
|
|
|
|
|
/**
|
|
|
- * Conditions for lotted item, so it can be announced when player pick it up
|
|
|
+ * Conditions for looted item, so it can be announced when player pick it up
|
|
|
* 1. Not-dropped other than monster. (This will be done later on pc_takeitem/party_share_loot)
|
|
|
- * 2. The mob_id is become the last lootter, instead of the real monster who drop it.
|
|
|
+ * 2. The mob_id becomes the last looter, instead of the real monster who drop it.
|
|
|
**/
|
|
|
- drop->mob_id = item->mob_id;
|
|
|
+ drop->mob_id = item.mob_id;
|
|
|
|
|
|
- drop->next = nullptr;
|
|
|
return drop;
|
|
|
}
|
|
|
|
|
@@ -2226,23 +2220,21 @@ static struct item_drop* mob_setlootitem(struct s_mob_lootitem *item, unsigned s
|
|
|
* item drop with delay (timer function)
|
|
|
*------------------------------------------*/
|
|
|
static TIMER_FUNC(mob_delay_item_drop){
|
|
|
- struct item_drop_list *list;
|
|
|
- struct item_drop *ditem;
|
|
|
+ uint32 bl_id = static_cast<uint32>( id );
|
|
|
+ std::shared_ptr<s_item_drop_list> list = util::umap_find( mob_delayed_drops, bl_id );
|
|
|
|
|
|
- list = (struct item_drop_list *)data;
|
|
|
- ditem = list->item;
|
|
|
+ if( list == nullptr ){
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
- while (ditem) {
|
|
|
- struct item_drop *ditem_prev;
|
|
|
+ for( std::shared_ptr<s_item_drop>& ditem : list->items ){
|
|
|
map_addflooritem(&ditem->item_data,ditem->item_data.amount,
|
|
|
list->m,list->x,list->y,
|
|
|
list->first_charid,list->second_charid,list->third_charid,4,ditem->mob_id,true);
|
|
|
- ditem_prev = ditem;
|
|
|
- ditem = ditem->next;
|
|
|
- ers_free(item_drop_ers, ditem_prev);
|
|
|
}
|
|
|
|
|
|
- ers_free(item_drop_list_ers, list);
|
|
|
+ mob_delayed_drops.erase( bl_id );
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -2252,7 +2244,7 @@ static TIMER_FUNC(mob_delay_item_drop){
|
|
|
* rate is the drop-rate of the item, required for autoloot.
|
|
|
* flag : Killed only by homunculus/mercenary?
|
|
|
*------------------------------------------*/
|
|
|
-static void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, struct item_drop *ditem, int loot, int drop_rate, bool flag)
|
|
|
+static void mob_item_drop(struct mob_data *md, std::shared_ptr<s_item_drop_list>& dlist, std::shared_ptr<s_item_drop>& ditem, int loot, int drop_rate, bool flag)
|
|
|
{
|
|
|
TBL_PC* sd;
|
|
|
bool test_autoloot;
|
|
@@ -2281,12 +2273,11 @@ static void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, str
|
|
|
if (party_share_loot(party_search(sd->status.party_id),
|
|
|
sd, &ditem->item_data, sd->status.char_id) == 0
|
|
|
) {
|
|
|
- ers_free(item_drop_ers, ditem);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
- ditem->next = dlist->item;
|
|
|
- dlist->item = ditem;
|
|
|
+
|
|
|
+ dlist->items.push_back( ditem );
|
|
|
}
|
|
|
|
|
|
TIMER_FUNC(mob_timer_delete){
|
|
@@ -2848,20 +2839,20 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
|
|
|
(md->special_state.ai==AI_SPHERE && battle_config.alchemist_summon_reward == 1) //Marine Sphere Drops items.
|
|
|
) )
|
|
|
{ // Item Drop
|
|
|
- struct item_drop_list *dlist = ers_alloc(item_drop_list_ers, struct item_drop_list);
|
|
|
- struct item_drop *ditem;
|
|
|
int drop_rate, drop_modifier = 100;
|
|
|
|
|
|
#ifdef RENEWAL_DROP
|
|
|
drop_modifier = pc_level_penalty_mod( mvp_sd != nullptr ? mvp_sd : second_sd != nullptr ? second_sd : third_sd, PENALTY_DROP, nullptr, md );
|
|
|
#endif
|
|
|
+
|
|
|
+ std::shared_ptr<s_item_drop_list> dlist = std::make_shared<s_item_drop_list>();
|
|
|
+
|
|
|
dlist->m = md->bl.m;
|
|
|
dlist->x = md->bl.x;
|
|
|
dlist->y = md->bl.y;
|
|
|
dlist->first_charid = (mvp_sd ? mvp_sd->status.char_id : 0);
|
|
|
dlist->second_charid = (second_sd ? second_sd->status.char_id : 0);
|
|
|
dlist->third_charid = (third_sd ? third_sd->status.char_id : 0);
|
|
|
- dlist->item = nullptr;
|
|
|
|
|
|
for (i = 0; i < MAX_MOB_DROP_TOTAL; i++) {
|
|
|
if (md->db->dropitem[i].nameid == 0)
|
|
@@ -2883,7 +2874,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- ditem = mob_setdropitem(&md->db->dropitem[i], 1, md->mob_id);
|
|
|
+ std::shared_ptr<s_item_drop> ditem = mob_setdropitem( md->db->dropitem[i], 1, md->mob_id );
|
|
|
|
|
|
//A Rare Drop Global Announce by Lupus
|
|
|
if( mvp_sd && md->db->dropitem[i].rate <= battle_config.rare_drop_announce ) {
|
|
@@ -2899,9 +2890,12 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
|
|
|
|
|
|
// Ore Discovery [Celest]
|
|
|
if (sd == mvp_sd && pc_checkskill(sd,BS_FINDINGORE)>0 && battle_config.finding_ore_rate/10 >= rnd()%10000) {
|
|
|
- struct s_mob_drop mobdrop = {};
|
|
|
+ s_mob_drop mobdrop = {};
|
|
|
+
|
|
|
mobdrop.nameid = itemdb_group.get_random_item_id(IG_FINDINGORE,1);
|
|
|
- ditem = mob_setdropitem(&mobdrop, 1, md->mob_id);
|
|
|
+
|
|
|
+ std::shared_ptr<s_item_drop> ditem = mob_setdropitem( mobdrop, 1, md->mob_id );
|
|
|
+
|
|
|
mob_item_drop(md, dlist, ditem, 0, battle_config.finding_ore_rate/10, homkillonly || merckillonly);
|
|
|
}
|
|
|
|
|
@@ -2930,10 +2924,14 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
|
|
|
if (rnd()%10000 >= drop_rate)
|
|
|
continue;
|
|
|
dropid = (it.nameid > 0) ? it.nameid : itemdb_group.get_random_item_id(it.group,1);
|
|
|
- struct s_mob_drop mobdrop = {};
|
|
|
+
|
|
|
+ s_mob_drop mobdrop = {};
|
|
|
+
|
|
|
mobdrop.nameid = dropid;
|
|
|
|
|
|
- mob_item_drop(md, dlist, mob_setdropitem(&mobdrop,1,md->mob_id), 0, drop_rate, homkillonly || merckillonly);
|
|
|
+ std::shared_ptr<s_item_drop> ditem = mob_setdropitem(mobdrop, 1, md->mob_id);
|
|
|
+
|
|
|
+ mob_item_drop( md, dlist, ditem, 0, drop_rate, homkillonly || merckillonly );
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2947,8 +2945,11 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
|
|
|
|
|
|
// process items looted by the mob
|
|
|
if (md->lootitems) {
|
|
|
- for (i = 0; i < md->lootitem_count; i++)
|
|
|
- mob_item_drop(md, dlist, mob_setlootitem(&md->lootitems[i], md->mob_id), 1, 10000, homkillonly || merckillonly);
|
|
|
+ for (i = 0; i < md->lootitem_count; i++) {
|
|
|
+ std::shared_ptr<s_item_drop> ditem = mob_setlootitem(md->lootitems[i], md->mob_id);
|
|
|
+
|
|
|
+ mob_item_drop( md, dlist, ditem, 1, 10000, homkillonly || merckillonly );
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// Process map specific drops
|
|
@@ -2967,7 +2968,8 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
|
|
|
if( rnd_chance( it.second->rate, 100000u ) ){
|
|
|
// 'Cheat' for autoloot command: rate is changed from n/100000 to n/10000
|
|
|
int32 map_drops_rate = max(1, (it.second->rate / 10));
|
|
|
- mob_item_drop( md, dlist, mob_setdropitem( it.second.get(), 1, md->mob_id ), 0, map_drops_rate, (homkillonly || merckillonly) );
|
|
|
+ std::shared_ptr<s_item_drop> ditem = mob_setdropitem(*it.second, 1, md->mob_id);
|
|
|
+ mob_item_drop( md, dlist, ditem, 0, map_drops_rate, homkillonly || merckillonly );
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2979,28 +2981,37 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
|
|
|
if( rnd_chance( it.second->rate, 100000u ) ){
|
|
|
// 'Cheat' for autoloot command: rate is changed from n/100000 to n/10000
|
|
|
int32 map_drops_rate = max(1, (it.second->rate / 10));
|
|
|
- mob_item_drop( md, dlist, mob_setdropitem( it.second.get(), 1, md->mob_id ), 0, map_drops_rate, (homkillonly || merckillonly) );
|
|
|
+ std::shared_ptr<s_item_drop> ditem = mob_setdropitem(*it.second, 1, md->mob_id);
|
|
|
+ mob_item_drop( md, dlist, ditem, 0, map_drops_rate, homkillonly || merckillonly );
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (dlist->item) //There are drop items.
|
|
|
- add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr_t)dlist);
|
|
|
- else //No drops
|
|
|
- ers_free(item_drop_list_ers, dlist);
|
|
|
+ // There are drop items.
|
|
|
+ if( !dlist->items.empty() ){
|
|
|
+ mob_delayed_drops[md->bl.id] = dlist;
|
|
|
+
|
|
|
+ add_timer( tick + ( !battle_config.delay_battle_damage ? 500 : 0 ), mob_delay_item_drop, md->bl.id, 0 );
|
|
|
+ }
|
|
|
} else if (md->lootitems && md->lootitem_count) { //Loot MUST drop!
|
|
|
- struct item_drop_list *dlist = ers_alloc(item_drop_list_ers, struct item_drop_list);
|
|
|
+ std::shared_ptr<s_item_drop_list> dlist = std::make_shared<s_item_drop_list>();
|
|
|
+
|
|
|
dlist->m = md->bl.m;
|
|
|
dlist->x = md->bl.x;
|
|
|
dlist->y = md->bl.y;
|
|
|
dlist->first_charid = (mvp_sd ? mvp_sd->status.char_id : 0);
|
|
|
dlist->second_charid = (second_sd ? second_sd->status.char_id : 0);
|
|
|
dlist->third_charid = (third_sd ? third_sd->status.char_id : 0);
|
|
|
- dlist->item = nullptr;
|
|
|
- for (i = 0; i < md->lootitem_count; i++)
|
|
|
- mob_item_drop(md, dlist, mob_setlootitem(&md->lootitems[i], md->mob_id), 1, 10000, homkillonly || merckillonly);
|
|
|
- add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr_t)dlist);
|
|
|
+
|
|
|
+ for (i = 0; i < md->lootitem_count; i++) {
|
|
|
+ std::shared_ptr<s_item_drop> ditem = mob_setlootitem(md->lootitems[i], md->mob_id);
|
|
|
+
|
|
|
+ mob_item_drop( md, dlist, ditem, 1, 10000, homkillonly || merckillonly );
|
|
|
+ }
|
|
|
+
|
|
|
+ mob_delayed_drops[md->bl.id] = dlist;
|
|
|
+ add_timer( tick + ( !battle_config.delay_battle_damage ? 500 : 0 ), mob_delay_item_drop, md->bl.id, 0 );
|
|
|
}
|
|
|
|
|
|
if( mvp_sd && md->get_bosstype() == BOSSTYPE_MVP ){
|
|
@@ -3099,7 +3110,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
|
|
|
intif_broadcast(message,strlen(message)+1,BC_DEFAULT);
|
|
|
}
|
|
|
|
|
|
- mob_setdropitem_option(&item, &mdrop[i]);
|
|
|
+ mob_setdropitem_option( item, mdrop[i] );
|
|
|
|
|
|
if((temp = pc_additem(mvp_sd,&item,1,LOG_TYPE_PICKDROP_PLAYER)) != 0) {
|
|
|
clif_additem(mvp_sd,0,0,temp);
|
|
@@ -6692,12 +6703,6 @@ static void mob_load(void)
|
|
|
* Initialize monster data
|
|
|
*/
|
|
|
void mob_db_load(bool is_reload){
|
|
|
- if( !is_reload ) {
|
|
|
- // on mobdbreload it's not neccessary to execute this
|
|
|
- // item ers needs to be allocated only once
|
|
|
- item_drop_ers = ers_new(sizeof(struct item_drop),"mob.cpp::item_drop_ers",ERS_OPT_CLEAN);
|
|
|
- item_drop_list_ers = ers_new(sizeof(struct item_drop_list),"mob.cpp::item_drop_list_ers",ERS_OPT_NONE);
|
|
|
- }
|
|
|
mob_load();
|
|
|
}
|
|
|
|
|
@@ -6849,7 +6854,6 @@ void do_final_mob(bool is_reload){
|
|
|
mob_summon_db.clear();
|
|
|
map_drop_db.clear();
|
|
|
if( !is_reload ) {
|
|
|
- ers_destroy(item_drop_ers);
|
|
|
- ers_destroy(item_drop_list_ers);
|
|
|
+ mob_delayed_drops.clear();
|
|
|
}
|
|
|
}
|