parent
c5031982d2
commit
c06492def6
44
db/import-tmpl/map_drops.yml
Normal file
44
db/import-tmpl/map_drops.yml
Normal file
@ -0,0 +1,44 @@
|
||||
# This file is a part of rAthena.
|
||||
# Copyright(C) 2022 rAthena Development Team
|
||||
# https://rathena.org - https://github.com/rathena
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
###########################################################################
|
||||
# Map Drop Database
|
||||
###########################################################################
|
||||
#
|
||||
# Map Drop Settings
|
||||
#
|
||||
###########################################################################
|
||||
# - Map Name of the map.
|
||||
# GlobalDrops Drops for all monsters on this map. (Default: empty)
|
||||
# These drops are unaffected by server drop rate and cannot be stolen.
|
||||
# - Index Unique index of the drop.
|
||||
# Item Item name.
|
||||
# Rate Drop rate of item.
|
||||
# RandomOptionGroup Random Option Group applied to item on drop. (Default: None)
|
||||
# SpecificDrops Drops for specific monsters on this map. (Default: empty)
|
||||
# - Monster Monster name.
|
||||
# Drops Drops for this specific monster. (Default: empty)
|
||||
# These drops are unaffected by server drop rate and cannot be stolen.
|
||||
# - Index Unique index of the drop.
|
||||
# Item Item name.
|
||||
# Rate Drop rate of item.
|
||||
# RandomOptionGroup Random Option Group applied to item on drop. (Default: None)
|
||||
###########################################################################
|
||||
|
||||
Header:
|
||||
Type: MAP_DROP_DB
|
||||
Version: 1
|
50
db/map_drops.yml
Normal file
50
db/map_drops.yml
Normal file
@ -0,0 +1,50 @@
|
||||
# This file is a part of rAthena.
|
||||
# Copyright(C) 2022 rAthena Development Team
|
||||
# https://rathena.org - https://github.com/rathena
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
###########################################################################
|
||||
# Map Drop Database
|
||||
###########################################################################
|
||||
#
|
||||
# Map Drop Settings
|
||||
#
|
||||
###########################################################################
|
||||
# - Map Name of the map.
|
||||
# GlobalDrops Drops for all monsters on this map. (Default: empty)
|
||||
# These drops are unaffected by server drop rate and cannot be stolen.
|
||||
# - Index Unique index of the drop.
|
||||
# Item Item name.
|
||||
# Rate Drop rate of item.
|
||||
# RandomOptionGroup Random Option Group applied to item on drop. (Default: None)
|
||||
# SpecificDrops Drops for specific monsters on this map. (Default: empty)
|
||||
# - Monster Monster name.
|
||||
# Drops Drops for this specific monster. (Default: empty)
|
||||
# These drops are unaffected by server drop rate and cannot be stolen.
|
||||
# - Index Unique index of the drop.
|
||||
# Item Item name.
|
||||
# Rate Drop rate of item.
|
||||
# RandomOptionGroup Random Option Group applied to item on drop. (Default: None)
|
||||
###########################################################################
|
||||
|
||||
Header:
|
||||
Type: MAP_DROP_DB
|
||||
Version: 1
|
||||
|
||||
Footer:
|
||||
Imports:
|
||||
- Path: db/re/map_drops.yml
|
||||
Mode: Renewal
|
||||
- Path: db/import/map_drops.yml
|
44
db/re/map_drops.yml
Normal file
44
db/re/map_drops.yml
Normal file
@ -0,0 +1,44 @@
|
||||
# This file is a part of rAthena.
|
||||
# Copyright(C) 2022 rAthena Development Team
|
||||
# https://rathena.org - https://github.com/rathena
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
###########################################################################
|
||||
# Map Drop Database
|
||||
###########################################################################
|
||||
#
|
||||
# Map Drop Settings
|
||||
#
|
||||
###########################################################################
|
||||
# - Map Name of the map.
|
||||
# GlobalDrops Drops for all monsters on this map. (Default: empty)
|
||||
# These drops are unaffected by server drop rate and cannot be stolen.
|
||||
# - Index Unique index of the drop.
|
||||
# Item Item name.
|
||||
# Rate Drop rate of item.
|
||||
# RandomOptionGroup Random Option Group applied to item on drop. (Default: None)
|
||||
# SpecificDrops Drops for specific monsters on this map. (Default: empty)
|
||||
# - Monster Monster name.
|
||||
# Drops Drops for this specific monster. (Default: empty)
|
||||
# These drops are unaffected by server drop rate and cannot be stolen.
|
||||
# - Index Unique index of the drop.
|
||||
# Item Item name.
|
||||
# Rate Drop rate of item.
|
||||
# RandomOptionGroup Random Option Group applied to item on drop. (Default: None)
|
||||
###########################################################################
|
||||
|
||||
Header:
|
||||
Type: MAP_DROP_DB
|
||||
Version: 1
|
@ -343,6 +343,7 @@
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\level_penalty.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\level_penalty.yml')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\magicmushroom_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\magicmushroom_db.yml')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\map_cache.dat" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\map_cache.dat')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\map_drops.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\map_drops.yml')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\map_index.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\map_index.txt')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\mercenary_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\mercenary_db.yml')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\mob_avail.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\mob_avail.yml')" />
|
||||
|
205
src/map/mob.cpp
205
src/map/mob.cpp
@ -87,6 +87,7 @@ static struct eri *item_drop_list_ers;
|
||||
|
||||
MobSummonDatabase mob_summon_db;
|
||||
MobChatDatabase mob_chat_db;
|
||||
MapDropDatabase map_drop_db;
|
||||
|
||||
/*==========================================
|
||||
* Local prototype declaration (only required thing)
|
||||
@ -2836,8 +2837,7 @@ 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;
|
||||
memset(&mobdrop, 0, sizeof(struct s_mob_drop));
|
||||
struct s_mob_drop mobdrop = {};
|
||||
mobdrop.nameid = itemdb_group.get_random_item_id(IG_FINDINGORE,1);
|
||||
ditem = mob_setdropitem(&mobdrop, 1, md->mob_id);
|
||||
mob_item_drop(md, dlist, ditem, 0, battle_config.finding_ore_rate/10, homkillonly || merckillonly);
|
||||
@ -2848,7 +2848,6 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
|
||||
t_itemid dropid = 0;
|
||||
|
||||
for (const auto &it : sd->add_drop) {
|
||||
struct s_mob_drop mobdrop;
|
||||
if (!&it || (!it.nameid && !it.group))
|
||||
continue;
|
||||
if ((it.race < RC_NONE_ && it.race == -md->mob_id) || //Race < RC_NONE_, use mob_id
|
||||
@ -2869,7 +2868,7 @@ 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);
|
||||
memset(&mobdrop, 0, sizeof(struct s_mob_drop));
|
||||
struct s_mob_drop mobdrop = {};
|
||||
mobdrop.nameid = dropid;
|
||||
|
||||
mob_item_drop(md, dlist, mob_setdropitem(&mobdrop,1,md->mob_id), 0, drop_rate, homkillonly || merckillonly);
|
||||
@ -2889,6 +2888,37 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
|
||||
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);
|
||||
}
|
||||
|
||||
// Process map specific drops
|
||||
std::shared_ptr<s_map_drops> mapdrops;
|
||||
|
||||
// If it is an instance map, we check for map specific drops of the original map
|
||||
if( map[md->bl.m].instance_id > 0 ){
|
||||
mapdrops = map_drop_db.find( map[md->bl.m].instance_src_map );
|
||||
}else{
|
||||
mapdrops = map_drop_db.find( md->bl.m );
|
||||
}
|
||||
|
||||
if( mapdrops != nullptr ){
|
||||
// Process map wide drops
|
||||
for( const auto& it : mapdrops->globals ){
|
||||
if( rnd_chance( it.second->rate, 10000 ) ){
|
||||
mob_item_drop( md, dlist, mob_setdropitem( it.second.get(), 1, md->mob_id ), 0, it.second->rate, homkillonly || merckillonly );
|
||||
}
|
||||
}
|
||||
|
||||
// Process map drops for this specific mob
|
||||
const auto& specific = mapdrops->specific.find( md->mob_id );
|
||||
|
||||
if( specific != mapdrops->specific.end() ){
|
||||
for( const auto& it : specific->second ){
|
||||
if( rnd_chance( it.second->rate, 10000 ) ){
|
||||
mob_item_drop( md, dlist, mob_setdropitem( it.second.get(), 1, md->mob_id ), 0, it.second->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
|
||||
@ -6320,6 +6350,170 @@ static void mob_drop_ratio_adjust(void){
|
||||
mob_item_drop_ratio.clear();
|
||||
}
|
||||
|
||||
const std::string MapDropDatabase::getDefaultLocation(){
|
||||
return std::string( db_path ) + "/map_drops.yml";
|
||||
}
|
||||
|
||||
uint64 MapDropDatabase::parseBodyNode( const ryml::NodeRef& node ){
|
||||
std::string mapname;
|
||||
|
||||
if( !this->asString( node, "Map", mapname ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16 mapindex = mapindex_name2idx( mapname.c_str(), nullptr );
|
||||
|
||||
if( mapindex == 0 ){
|
||||
this->invalidWarning( node["Map"], "Unknown map \"%s\".\n", mapname.c_str() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int16 mapid = map_mapindex2mapid( mapindex );
|
||||
|
||||
if( mapid < 0 ){
|
||||
// Silently ignore. Map might be on a different map-server
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<s_map_drops> mapdrops = this->find( mapid );
|
||||
bool exists = mapdrops != nullptr;
|
||||
|
||||
if( !exists ){
|
||||
mapdrops = std::make_shared<s_map_drops>();
|
||||
mapdrops->mapid = mapid;
|
||||
}
|
||||
|
||||
if( this->nodeExists( node, "GlobalDrops" ) ){
|
||||
const ryml::NodeRef& globalNode = node["GlobalDrops"];
|
||||
|
||||
for( const auto& it : globalNode ){
|
||||
if( !this->parseDrop( it, mapdrops->globals ) ){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( this->nodeExists( node, "SpecificDrops" ) ){
|
||||
const ryml::NodeRef& specificNode = node["SpecificDrops"];
|
||||
|
||||
for( const auto& monsterNode : specificNode ){
|
||||
if( !this->nodesExist( monsterNode, { "Monster", "Drops" } ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string mobname;
|
||||
|
||||
if( !this->asString( monsterNode, "Monster", mobname ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<s_mob_db> mob = mobdb_search_aegisname( mobname.c_str() );
|
||||
|
||||
if( mob == nullptr ){
|
||||
this->invalidWarning( monsterNode["Monster"], "Unknown monster \"%s\".\n", mobname.c_str() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::unordered_map<uint16, std::shared_ptr<s_mob_drop>>& specificDrops = mapdrops->specific[mob->id];
|
||||
|
||||
for( const auto& it : monsterNode["Drops"] ){
|
||||
if( !this->parseDrop( it, specificDrops ) ){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !exists ){
|
||||
this->put( mapid, mapdrops );
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool MapDropDatabase::parseDrop( const ryml::NodeRef& node, std::unordered_map<uint16, std::shared_ptr<s_mob_drop>>& drops ){
|
||||
uint16 index;
|
||||
|
||||
if( !this->asUInt16( node, "Index", index ) ){
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<s_mob_drop> drop = util::umap_find( drops, index );
|
||||
bool exists = drop != nullptr;
|
||||
|
||||
if( !exists ){
|
||||
if( !this->nodesExist( node, { "Item", "Rate" } ) ){
|
||||
return false;
|
||||
}
|
||||
|
||||
drop = std::make_shared<s_mob_drop>();
|
||||
drop->steal_protected = true;
|
||||
}
|
||||
|
||||
if( this->nodeExists( node, "Item" ) ){
|
||||
std::string itemname;
|
||||
|
||||
if( !this->asString( node, "Item", itemname ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<item_data> item = item_db.search_aegisname( itemname.c_str() );
|
||||
|
||||
if( item == nullptr ){
|
||||
this->invalidWarning( node["Item"], "Item %s does not exist.\n", itemname.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
drop->nameid = item->nameid;
|
||||
}
|
||||
|
||||
if( this->nodeExists( node, "Rate" ) ){
|
||||
uint16 rate;
|
||||
|
||||
if( !this->asUInt16Rate( node, "Rate", rate ) ){
|
||||
return false;
|
||||
}
|
||||
|
||||
if( rate == 0 ){
|
||||
if( exists ){
|
||||
drops.erase( index );
|
||||
return true;
|
||||
}else{
|
||||
this->invalidWarning( node["Rate"], "Rate %" PRIu16 " is below minimum of 1.\n", rate );
|
||||
return false;
|
||||
}
|
||||
}else if( rate > 10000 ){
|
||||
this->invalidWarning( node["Rate"], "Rate %" PRIu16 " exceeds maximum of 10000.\n", rate );
|
||||
return false;
|
||||
}
|
||||
|
||||
drop->rate = rate;
|
||||
}
|
||||
|
||||
if( this->nodeExists( node, "RandomOptionGroup" ) ){
|
||||
std::string name;
|
||||
|
||||
if( !this->asString( node, "RandomOptionGroup", name ) ){
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !random_option_group.option_get_id( name, drop->randomopt_group ) ){
|
||||
this->invalidWarning( node["RandomOptionGroup"], "Unknown random option group \"%s\".\n", name.c_str() );
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
if( !exists ){
|
||||
drop->randomopt_group = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( !exists ){
|
||||
drops[drop->nameid] = drop;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy skill from DB to monster
|
||||
* @param mob Monster DB entry
|
||||
@ -6431,6 +6625,7 @@ static void mob_load(void)
|
||||
mob_item_drop_ratio.load();
|
||||
mob_avail_db.load();
|
||||
mob_summon_db.load();
|
||||
map_drop_db.load();
|
||||
|
||||
mob_drop_ratio_adjust();
|
||||
mob_skill_db_set();
|
||||
@ -6593,9 +6788,9 @@ void do_final_mob(bool is_reload){
|
||||
mob_db.clear();
|
||||
mob_chat_db.clear();
|
||||
mob_skill_db.clear();
|
||||
|
||||
mob_item_drop_ratio.clear();
|
||||
mob_summon_db.clear();
|
||||
map_drop_db.clear();
|
||||
if( !is_reload ) {
|
||||
ers_destroy(item_drop_ers);
|
||||
ers_destroy(item_drop_list_ers);
|
||||
|
@ -286,6 +286,32 @@ public:
|
||||
|
||||
extern MobDatabase mob_db;
|
||||
|
||||
struct s_map_mob_drop{
|
||||
uint16 mob_id;
|
||||
std::shared_ptr<s_mob_drop> drop;
|
||||
};
|
||||
|
||||
struct s_map_drops{
|
||||
uint16 mapid;
|
||||
std::unordered_map<uint16, std::shared_ptr<s_mob_drop>> globals;
|
||||
std::unordered_map<uint16, std::unordered_map<uint16, std::shared_ptr<s_mob_drop>>> specific;
|
||||
};
|
||||
|
||||
class MapDropDatabase : public TypesafeYamlDatabase<uint16, s_map_drops>{
|
||||
public:
|
||||
MapDropDatabase() : TypesafeYamlDatabase( "MAP_DROP_DB", 1 ){
|
||||
|
||||
}
|
||||
|
||||
const std::string getDefaultLocation() override;
|
||||
uint64 parseBodyNode( const ryml::NodeRef& node ) override;
|
||||
|
||||
private:
|
||||
bool parseDrop( const ryml::NodeRef& node, std::unordered_map<uint16, std::shared_ptr<s_mob_drop>>& drops );
|
||||
};
|
||||
|
||||
extern MapDropDatabase map_drop_db;
|
||||
|
||||
struct mob_data {
|
||||
struct block_list bl;
|
||||
struct unit_data ud;
|
||||
|
Loading…
x
Reference in New Issue
Block a user