Converted mob_boss to yaml (#6011)
* Converts the Monster summon group Database into YAML. (mob_boss.txt, mob_branch.txt, mob_classchange.txt, mob_poring.txt, mob_mission.txt, mob_pouch.txt, mob_random_db.txt) * Includes CSV2YAML converter. Thanks to @Lemongrass3110 !
This commit is contained in:
229
src/map/mob.cpp
229
src/map/mob.cpp
@@ -93,19 +93,7 @@ std::unordered_map<int32, std::shared_ptr<s_mob_skill_db>> mob_skill_db; /// Mon
|
||||
static struct eri *item_drop_ers; //For loot drops delay structures.
|
||||
static struct eri *item_drop_list_ers;
|
||||
|
||||
struct s_randomsummon_entry {
|
||||
uint16 mob_id;
|
||||
uint32 rate;
|
||||
};
|
||||
|
||||
struct s_randomsummon_group {
|
||||
uint8 random_id;
|
||||
struct s_randomsummon_entry *list;
|
||||
uint16 count;
|
||||
};
|
||||
|
||||
static DBMap *mob_summon_db; /// Random Summon DB. struct s_randomsummon_group -> group_id
|
||||
|
||||
MobSummonDatabase mob_summon_db;
|
||||
MobChatDatabase mob_chat_db;
|
||||
|
||||
/*==========================================
|
||||
@@ -507,44 +495,44 @@ struct mob_data* mob_spawn_dataset(struct spawn_data *data)
|
||||
*------------------------------------------*/
|
||||
int mob_get_random_id(int type, enum e_random_monster_flags flag, int lv)
|
||||
{
|
||||
struct s_randomsummon_group *msummon = (struct s_randomsummon_group *)idb_get(mob_summon_db, type);
|
||||
std::shared_ptr<s_randomsummon_group> summon = mob_summon_db.find(type);
|
||||
|
||||
if (type == MOBG_Bloody_Dead_Branch && flag&RMF_MOB_NOT_BOSS)
|
||||
if (type == MOBG_BLOODY_DEAD_BRANCH && flag&RMF_MOB_NOT_BOSS)
|
||||
flag = static_cast<e_random_monster_flags>(flag&~RMF_MOB_NOT_BOSS);
|
||||
|
||||
if (!msummon) {
|
||||
if (!summon) {
|
||||
ShowError("mob_get_random_id: Invalid type (%d) of random monster.\n", type);
|
||||
return 0;
|
||||
}
|
||||
if (!msummon->count) {
|
||||
if (summon->list.empty()) {
|
||||
ShowError("mob_get_random_id: Random monster type %d is not defined.\n", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<s_mob_db> mob;
|
||||
int i = 0, mob_id = 0, rand = 0;
|
||||
struct s_randomsummon_entry *entry = nullptr;
|
||||
for( size_t i = 0, max = summon->list.size() * 3; i < max; i++ ){
|
||||
std::shared_ptr<s_randomsummon_entry> entry = util::umap_random( summon->list );
|
||||
std::shared_ptr<s_mob_db> mob = mob_db.find( entry->mob_id );
|
||||
|
||||
do {
|
||||
rand = rnd()%msummon->count;
|
||||
entry = &msummon->list[rand];
|
||||
mob_id = entry->mob_id;
|
||||
mob = mob_db.find(mob_id);
|
||||
} while ((rand == 0 || // Skip default first
|
||||
mob == nullptr ||
|
||||
mob_is_clone(mob_id) ||
|
||||
(flag&RMF_DB_RATE && (entry->rate < 1000000 && entry->rate <= rnd() % 1000000)) ||
|
||||
(flag&RMF_CHECK_MOB_LV && lv < mob->lv) ||
|
||||
(flag&RMF_MOB_NOT_BOSS && status_has_mode(&mob->status,MD_STATUSIMMUNE) ) ||
|
||||
(flag&RMF_MOB_NOT_SPAWN && !mob_has_spawn(mob_id)) ||
|
||||
(flag&RMF_MOB_NOT_PLANT && status_has_mode(&mob->status,MD_IGNOREMELEE|MD_IGNOREMAGIC|MD_IGNORERANGED|MD_IGNOREMISC) )
|
||||
) && (i++) < MAX_MOB_DB && msummon->count > 1);
|
||||
if(mob == nullptr ||
|
||||
mob_is_clone( entry->mob_id ) ||
|
||||
(flag&RMF_DB_RATE && (entry->rate < 1000000 && entry->rate <= rnd() % 1000000)) ||
|
||||
(flag&RMF_CHECK_MOB_LV && lv < mob->lv) ||
|
||||
(flag&RMF_MOB_NOT_BOSS && status_has_mode(&mob->status,MD_STATUSIMMUNE) ) ||
|
||||
(flag&RMF_MOB_NOT_SPAWN && !mob_has_spawn( entry->mob_id )) ||
|
||||
(flag&RMF_MOB_NOT_PLANT && status_has_mode(&mob->status,MD_IGNOREMELEE|MD_IGNOREMAGIC|MD_IGNORERANGED|MD_IGNOREMISC) )
|
||||
){
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i >= MAX_MOB_DB && &msummon->list[0]) {
|
||||
ShowError("mob_get_random_id: no suitable monster found, use fallback for given list. Last_MobID: %d\n", mob_id);
|
||||
mob_id = msummon->list[0].mob_id;
|
||||
return entry->mob_id;
|
||||
}
|
||||
return mob_id;
|
||||
|
||||
if (mob_db.find( summon->default_mob_id ) == nullptr) {
|
||||
ShowError("mob_get_random_id: Default monster is not defined for type %d.\n", type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return summon->default_mob_id;
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
@@ -3061,7 +3049,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
|
||||
((battle_config.taekwon_mission_mobname == 1 && util::vector_exists(status_get_race2(&md->bl), RC2_GOBLIN) && util::vector_exists(mission_mdb->race2, RC2_GOBLIN)) ||
|
||||
(battle_config.taekwon_mission_mobname == 2 && mob->jname.compare(mission_mdb->jname) == 0))))
|
||||
{ //TK_MISSION [Skotlex]
|
||||
if (++(sd->mission_count) >= 100 && (temp = mob_get_random_id(MOBG_Branch_Of_Dead_Tree, static_cast<e_random_monster_flags>(RMF_CHECK_MOB_LV|RMF_MOB_NOT_BOSS|RMF_MOB_NOT_SPAWN), sd->status.base_level)))
|
||||
if (++(sd->mission_count) >= 100 && (temp = mob_get_random_id(MOBG_BRANCH_OF_DEAD_TREE, static_cast<e_random_monster_flags>(RMF_CHECK_MOB_LV|RMF_MOB_NOT_BOSS|RMF_MOB_NOT_SPAWN), sd->status.base_level)))
|
||||
{
|
||||
pc_addfame(sd, battle_config.fame_taekwon_mission);
|
||||
sd->mission_mobid = temp;
|
||||
@@ -5463,59 +5451,106 @@ uint64 MobAvailDatabase::parseBodyNode(const YAML::Node &node) {
|
||||
|
||||
MobAvailDatabase mob_avail_db;
|
||||
|
||||
/*==========================================
|
||||
* Reading of random monster data
|
||||
* MobGroup,MobID,DummyName,Rate
|
||||
*------------------------------------------*/
|
||||
static bool mob_readdb_group(char* str[], int columns, int current){
|
||||
struct s_randomsummon_group *msummon = NULL;
|
||||
int mob_id, group = 0;
|
||||
unsigned short i = 0;
|
||||
bool set_default = false;
|
||||
|
||||
if (ISDIGIT(str[0][0]) && ISDIGIT(str[0][1]))
|
||||
group = atoi(str[0]);
|
||||
else {
|
||||
int64 group_tmp;
|
||||
const std::string MobSummonDatabase::getDefaultLocation() {
|
||||
return std::string(db_path) + "/mob_summon.yml";
|
||||
}
|
||||
|
||||
if (!script_get_constant(str[0], &group_tmp)) {
|
||||
ShowError("mob_readdb_group: Invalid random monster group '%s'\n", str[0]);
|
||||
return false;
|
||||
/**
|
||||
* Reads and parses an entry from the mob_summon.
|
||||
* @param node: YAML node containing the entry.
|
||||
* @return count of successfully parsed rows
|
||||
*/
|
||||
uint64 MobSummonDatabase::parseBodyNode(const YAML::Node &node) {
|
||||
std::string group_name;
|
||||
|
||||
if (!this->asString(node, "Group", group_name))
|
||||
return 0;
|
||||
|
||||
std::string group_name_constant = "MOBG_" + group_name;
|
||||
int64 constant;
|
||||
|
||||
if (!script_get_constant(group_name_constant.c_str(), &constant) || constant < MOBG_BRANCH_OF_DEAD_TREE || constant >= MOBG_MAX) {
|
||||
this->invalidWarning(node["Group"], "Invalid monster group %s.\n", group_name.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16 id = static_cast<uint16>(constant);
|
||||
|
||||
std::shared_ptr<s_randomsummon_group> summon = this->find(id);
|
||||
bool exists = summon != nullptr;
|
||||
|
||||
if (!exists) {
|
||||
if (!this->nodesExist(node, { "Default" }))
|
||||
return 0;
|
||||
|
||||
summon = std::make_shared<s_randomsummon_group>();
|
||||
summon->random_id = id;
|
||||
}
|
||||
|
||||
if (this->nodeExists(node, "Default")) {
|
||||
std::string mob_name;
|
||||
|
||||
if (!this->asString(node, "Default", mob_name))
|
||||
return 0;
|
||||
|
||||
std::shared_ptr<s_mob_db> mob = mobdb_search_aegisname(mob_name.c_str());
|
||||
|
||||
if (mob == nullptr) {
|
||||
this->invalidWarning(node["Default"], "Unknown mob %s.\n", mob_name.c_str());
|
||||
return 0;
|
||||
}
|
||||
group = static_cast<int>(group_tmp);
|
||||
summon->default_mob_id = mob->vd.class_;
|
||||
}
|
||||
|
||||
mob_id = atoi(str[1]);
|
||||
if (mob_id != 0 && mob_db.find(mob_id) == nullptr) {
|
||||
ShowError("mob_readdb_group: Invalid random monster group '%s'\n", str[0]);
|
||||
return false;
|
||||
}
|
||||
else if (mob_id == 0){
|
||||
mob_id = atoi(str[3]);
|
||||
if (mob_db.find(mob_id) == nullptr) {
|
||||
ShowError("mob_readdb_group: Invalid random monster group '%s'\n", str[0]);
|
||||
return false;
|
||||
if (this->nodeExists(node, "Summon")) {
|
||||
const YAML::Node &MobNode = node["Summon"];
|
||||
|
||||
for (const YAML::Node &mobit : MobNode) {
|
||||
if (!this->nodesExist(mobit, { "Mob", "Rate" })) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string mob_name;
|
||||
|
||||
if (!this->asString(mobit, "Mob", mob_name))
|
||||
continue;
|
||||
|
||||
std::shared_ptr<s_mob_db> mob = mobdb_search_aegisname(mob_name.c_str());
|
||||
|
||||
if (mob == nullptr) {
|
||||
this->invalidWarning(mobit["Mob"], "Unknown mob %s.\n", mob_name.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 rate;
|
||||
|
||||
if (!this->asUInt32(mobit, "Rate", rate))
|
||||
continue;
|
||||
|
||||
uint16 mob_id = mob->vd.class_;
|
||||
|
||||
if (rate == 0) {
|
||||
if (summon->list.erase(mob_id) == 0)
|
||||
this->invalidWarning(mobit["Rate"], "Failed to remove %s, the monster doesn't exist in group %s.\n", mob_name.c_str(), group_name.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
std::shared_ptr<s_randomsummon_entry> entry = util::umap_find(summon->list, mob_id);
|
||||
|
||||
if (entry == nullptr) {
|
||||
entry = std::make_shared<s_randomsummon_entry>();
|
||||
entry->mob_id = mob->vd.class_;
|
||||
summon->list[mob_id] = entry;
|
||||
}
|
||||
entry->rate = rate;
|
||||
}
|
||||
set_default = true;
|
||||
}
|
||||
|
||||
if (!(msummon = (struct s_randomsummon_group *)idb_get(mob_summon_db, group))) {
|
||||
CREATE(msummon, struct s_randomsummon_group, 1);
|
||||
CREATE(msummon->list, struct s_randomsummon_entry, (msummon->count = 1));
|
||||
msummon->list[0].mob_id = mob_id;
|
||||
msummon->list[0].rate = atoi(str[3]);
|
||||
msummon->random_id = group;
|
||||
idb_put(mob_summon_db, group, msummon);
|
||||
}
|
||||
else {
|
||||
ARR_FIND(0, msummon->count, i, set_default || (i > 0 && msummon->list[i].mob_id == mob_id));
|
||||
if (i >= msummon->count)
|
||||
RECREATE(msummon->list, struct s_randomsummon_entry, ++msummon->count);
|
||||
msummon->list[i].mob_id = mob_id;
|
||||
msummon->list[i].rate = atoi(str[3]);
|
||||
}
|
||||
if (!exists)
|
||||
this->put(id, summon);
|
||||
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const std::string MobChatDatabase::getDefaultLocation() {
|
||||
@@ -6153,23 +6188,6 @@ static void mob_skill_db_set_single(struct s_mob_skill_db *skill) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Free random summon data
|
||||
**/
|
||||
static int mob_summon_db_free(DBKey key, DBData *data, va_list ap) {
|
||||
struct s_randomsummon_group *msummon = (struct s_randomsummon_group *)db_data2ptr(data);
|
||||
if (msummon) {
|
||||
if (msummon->list) {
|
||||
aFree(msummon->list);
|
||||
msummon->list = NULL;
|
||||
msummon->count = 0;
|
||||
}
|
||||
aFree(msummon);
|
||||
msummon = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set monster skills
|
||||
**/
|
||||
@@ -6221,19 +6239,13 @@ static void mob_load(void)
|
||||
mob_readskilldb(dbsubpath2, silent);
|
||||
|
||||
sv_readdb(dbsubpath1, "mob_item_ratio.txt", ',', 2, 2+MAX_ITEMRATIO_MOBS, -1, &mob_readdb_itemratio, silent);
|
||||
sv_readdb(dbsubpath2, "mob_random_db.txt", ',', 4, 4, -1, &mob_readdb_group, silent);
|
||||
sv_readdb(dbsubpath2, "mob_branch.txt", ',', 4, 4, -1, &mob_readdb_group, silent);
|
||||
sv_readdb(dbsubpath2, "mob_poring.txt", ',', 4, 4, -1, &mob_readdb_group, silent);
|
||||
sv_readdb(dbsubpath2, "mob_boss.txt", ',', 4, 4, -1, &mob_readdb_group, silent);
|
||||
sv_readdb(dbsubpath1, "mob_pouch.txt", ',', 4, 4, -1, &mob_readdb_group, silent);
|
||||
sv_readdb(dbsubpath1, "mob_mission.txt", ',', 4, 4, -1, &mob_readdb_group, silent);
|
||||
sv_readdb(dbsubpath1, "mob_classchange.txt", ',', 4, 4, -1, &mob_readdb_group, silent);
|
||||
|
||||
aFree(dbsubpath1);
|
||||
aFree(dbsubpath2);
|
||||
}
|
||||
|
||||
mob_avail_db.load();
|
||||
mob_summon_db.load();
|
||||
|
||||
mob_drop_ratio_adjust();
|
||||
mob_skill_db_set();
|
||||
@@ -6250,7 +6262,6 @@ void mob_db_load(bool is_reload){
|
||||
item_drop_list_ers = ers_new(sizeof(struct item_drop_list),"mob.cpp::item_drop_list_ers",ERS_OPT_NONE);
|
||||
}
|
||||
mob_item_drop_ratio = uidb_alloc(DB_OPT_BASE);
|
||||
mob_summon_db = idb_alloc(DB_OPT_BASE);
|
||||
mob_load();
|
||||
}
|
||||
|
||||
@@ -6400,7 +6411,7 @@ void do_final_mob(bool is_reload){
|
||||
mob_skill_db.clear();
|
||||
|
||||
mob_item_drop_ratio->destroy(mob_item_drop_ratio,mob_item_drop_ratio_free);
|
||||
mob_summon_db->destroy(mob_summon_db, mob_summon_db_free);
|
||||
mob_summon_db.clear();
|
||||
if( !is_reload ) {
|
||||
ers_destroy(item_drop_ers);
|
||||
ers_destroy(item_drop_list_ers);
|
||||
|
||||
Reference in New Issue
Block a user