Implemented new monster range (#2604)
With this the internal static array was changed to a std::map which manages it's memory dynamically when needed. Dropped mob_dummy since it was useless to have it in the first place. Replaced a lot of direct accesses to the mob db by the "get" function. With this you can now use 20021-31998 for monsters and also 4000-20020 will be used for player clones whenever needed. Dropped mobdb_exists Replaced almost all references to MAX_MOB_DB Moved MAX_MOB_DB from the header directly into the source file to make it only visible to the .cpp file itself and not to any other. Moved the mob drop calculation function from itemdb.cpp into mob.cpp, because it needs to iterate over the whole mob db. Added a few missing clone checks. Thanks to @lighta, @Jeybla and @aleos89.
This commit is contained in:
parent
34817c9715
commit
b2ab9724fe
@ -1027,7 +1027,7 @@ struct achievement_db *achievement_read_db_sub(yamlwrapper *wrapper, int n, cons
|
||||
for (tt = yaml_iterator_first(it); yaml_iterator_has_next(it) && entry->target_count < MAX_ACHIEVEMENT_OBJECTIVES; tt = yaml_iterator_next(it)) {
|
||||
int mobid = 0, count = 0;
|
||||
|
||||
if (yaml_node_is_defined(tt, "MobID") && (mobid = yaml_get_int(tt, "MobID")) && !mobdb_exists(mobid)) { // The mob ID field is not required
|
||||
if (yaml_node_is_defined(tt, "MobID") && (mobid = yaml_get_int(tt, "MobID")) && mob_db(mobid) == NULL) { // The mob ID field is not required
|
||||
ShowError("achievement_read_db_sub: Invalid mob ID %d for achievement %d in \"%s\", skipping.\n", mobid, achievement_id, source);
|
||||
continue;
|
||||
}
|
||||
|
@ -1913,40 +1913,6 @@ static int itemdb_randomopt_free(DBKey key, DBData *data, va_list ap) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-link monster drop data with item data
|
||||
* Fixes the need of a @reloadmobdb after a @reloaditemdb
|
||||
* @author Epoque
|
||||
*/
|
||||
void itemdb_reload_itemmob_data(void) {
|
||||
int i;
|
||||
|
||||
for( i = 0; i < MAX_MOB_DB; i++ ) {
|
||||
struct mob_db *entry = mob_db(i);
|
||||
int d, k;
|
||||
|
||||
for(d = 0; d < MAX_MOB_DROP_TOTAL; d++) {
|
||||
struct item_data *id;
|
||||
if( !entry->dropitem[d].nameid )
|
||||
continue;
|
||||
id = itemdb_search(entry->dropitem[d].nameid);
|
||||
|
||||
for (k = 0; k < MAX_SEARCH; k++) {
|
||||
if (id->mob[k].chance <= entry->dropitem[d].p)
|
||||
break;
|
||||
}
|
||||
|
||||
if (k == MAX_SEARCH)
|
||||
continue;
|
||||
|
||||
if (id->mob[k].id != i)
|
||||
memmove(&id->mob[k+1], &id->mob[k], (MAX_SEARCH-k-1)*sizeof(id->mob[0]));
|
||||
id->mob[k].chance = entry->dropitem[d].p;
|
||||
id->mob[k].id = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload Item DB
|
||||
*/
|
||||
@ -1969,7 +1935,7 @@ void itemdb_reload(void) {
|
||||
if (battle_config.feature_roulette)
|
||||
itemdb_parse_roulette_db();
|
||||
|
||||
itemdb_reload_itemmob_data();
|
||||
mob_reload_itemmob_data();
|
||||
|
||||
// readjust itemdb pointer cache for each player
|
||||
iter = mapit_geteachpc();
|
||||
|
@ -954,7 +954,6 @@ bool itemdb_parse_roulette_db(void);
|
||||
struct s_random_opt_data *itemdb_randomopt_exists(short id);
|
||||
struct s_random_opt_group *itemdb_randomopt_group_exists(int id);
|
||||
|
||||
void itemdb_reload_itemmob_data(void);
|
||||
void itemdb_reload(void);
|
||||
|
||||
void do_final_itemdb(void);
|
||||
|
419
src/map/mob.cpp
419
src/map/mob.cpp
@ -4,6 +4,7 @@
|
||||
#include "mob.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <map>
|
||||
#include <math.h>
|
||||
|
||||
#include "../common/cbasetypes.h"
|
||||
@ -52,7 +53,6 @@
|
||||
#define MOB_MAX_DELAY (24*3600*1000)
|
||||
#define MAX_MINCHASE 30 //Max minimum chase value to use for mobs.
|
||||
#define RUDE_ATTACKED_COUNT 1 //After how many rude-attacks should the skill be used?
|
||||
#define MAX_MOB_CHAT 50 //Max Skill's messages
|
||||
|
||||
// On official servers, monsters will only seek targets that are closer to walk to than their
|
||||
// search range. The search range is affected depending on if the monster is walking or not.
|
||||
@ -63,19 +63,39 @@
|
||||
// Disable this to make monsters not do any path search when looking for a target (old behavior).
|
||||
#define ACTIVEPATHSEARCH
|
||||
|
||||
//Dynamic mob database, allows saving of memory when there's big gaps in the mob_db [Skotlex]
|
||||
//!NOTE: Mob ID is used also as index in mob db
|
||||
struct mob_db *mob_db_data[MAX_MOB_DB+1];
|
||||
struct mob_db *mob_dummy = NULL; //Dummy mob to be returned when a non-existant one is requested.
|
||||
// Limits for the monster database
|
||||
#define MIN_MOB_DB 1000
|
||||
#define MAX_MOB_DB 3999
|
||||
#define MIN_MOB_DB2 20020
|
||||
#define MAX_MOB_DB2 31999
|
||||
|
||||
struct mob_db *mob_db(int mob_id) { if (mob_id < 0 || mob_id > MAX_MOB_DB || mob_db_data[mob_id] == NULL) return mob_dummy; return mob_db_data[mob_id]; }
|
||||
// These define the range of available IDs for clones. [Valaris]
|
||||
#define MOB_CLONE_START MAX_MOB_DB
|
||||
#define MOB_CLONE_END MIN_MOB_DB2
|
||||
|
||||
//Dynamic mob database
|
||||
std::map<uint16, struct mob_db> mob_db_data;
|
||||
|
||||
struct mob_db *mob_db( int mob_id ){
|
||||
try{
|
||||
return &mob_db_data.at(mob_id);
|
||||
}catch( std::out_of_range ){
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// holds Monster Spawn informations
|
||||
std::unordered_map<uint16, std::vector<spawn_info>> mob_spawn_data;
|
||||
|
||||
//Dynamic mob chat database
|
||||
struct mob_chat *mob_chat_db[MAX_MOB_CHAT+1];
|
||||
struct mob_chat *mob_chat(short id) { if(id<=0 || id>MAX_MOB_CHAT || mob_chat_db[id]==NULL) return (struct mob_chat*)NULL; return mob_chat_db[id]; }
|
||||
std::map<short,struct mob_chat> mob_chat_db;
|
||||
struct mob_chat *mob_chat(short id) {
|
||||
try{
|
||||
return &mob_chat_db.at(id);
|
||||
}catch( std::out_of_range ){
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//Dynamic item drop ratio database for per-item drop ratio modifiers overriding global drop ratios.
|
||||
#define MAX_ITEMRATIO_MOBS 10
|
||||
@ -94,14 +114,6 @@ struct s_mob_skill {
|
||||
};
|
||||
static DBMap *mob_skill_db; /// Monster skill temporary db. s_mob_skill -> mobid
|
||||
|
||||
struct mob_db *mobdb_exists(uint16 mob_id) {
|
||||
struct mob_db *db = mob_db(mob_id);
|
||||
|
||||
if (db == mob_dummy)
|
||||
return NULL;
|
||||
return db;
|
||||
}
|
||||
|
||||
static struct eri *item_drop_ers; //For loot drops delay structures.
|
||||
static struct eri *item_drop_list_ers;
|
||||
|
||||
@ -121,7 +133,6 @@ static DBMap *mob_summon_db; /// Random Summon DB. struct s_randomsummon_group -
|
||||
/*==========================================
|
||||
* Local prototype declaration (only required thing)
|
||||
*------------------------------------------*/
|
||||
static int mob_makedummymobdb(int);
|
||||
static int mob_spawn_guardian_sub(int tid, unsigned int tick, int id, intptr_t data);
|
||||
int mob_skill_id2skill_idx(int mob_id,uint16 skill_id);
|
||||
|
||||
@ -315,7 +326,8 @@ static bool mobdb_searchname_sub(uint16 mob_id, const char * const str, bool ful
|
||||
*/
|
||||
uint16 mobdb_searchname_(const char * const str, bool full_cmp)
|
||||
{
|
||||
for(uint16 mob_id = 0; mob_id <= MAX_MOB_DB; mob_id++) {
|
||||
for( auto const &mobdb_pair : mob_db_data ) {
|
||||
const uint16 mob_id = mobdb_pair.first;
|
||||
if( mobdb_searchname_sub(mob_id, str, full_cmp) )
|
||||
return mob_id;
|
||||
}
|
||||
@ -332,12 +344,15 @@ uint16 mobdb_searchname(const char * const str)
|
||||
int mobdb_searchname_array_(const char *str, uint16 * out, int size, bool full_cmp)
|
||||
{
|
||||
unsigned short count = 0;
|
||||
for(uint16 mob_id = 0; mob_id <= MAX_MOB_DB && count < size; mob_id++) {
|
||||
for( auto const &mobdb_pair : mob_db_data ) {
|
||||
const uint16 mob_id = mobdb_pair.first;
|
||||
if( mobdb_searchname_sub(mob_id, str, full_cmp) ) {
|
||||
if( count < size )
|
||||
out[count] = mob_id;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -351,7 +366,7 @@ int mobdb_searchname_array(const char *str, uint16 * out, int size)
|
||||
*------------------------------------------*/
|
||||
int mobdb_checkid(const int id)
|
||||
{
|
||||
if (mob_db(id) == mob_dummy)
|
||||
if (mob_db(id) == NULL)
|
||||
return 0;
|
||||
if (mob_is_clone(id)) //checkid is used mostly for random ID based code, therefore clone mobs are out of the question.
|
||||
return 0;
|
||||
@ -363,9 +378,13 @@ int mobdb_checkid(const int id)
|
||||
*------------------------------------------*/
|
||||
struct view_data * mob_get_viewdata(int mob_id)
|
||||
{
|
||||
if (mob_db(mob_id) == mob_dummy)
|
||||
struct mob_db* db = mob_db(mob_id);
|
||||
|
||||
if( db == NULL ){
|
||||
return NULL;
|
||||
return &mob_db(mob_id)->vd;
|
||||
}
|
||||
|
||||
return &db->vd;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -507,7 +526,7 @@ int mob_get_random_id(int type, int flag, int lv)
|
||||
mob_id = entry->mob_id;
|
||||
mob = mob_db(mob_id);
|
||||
} while ((rand == 0 || // Skip default first
|
||||
mob == mob_dummy ||
|
||||
mob == NULL ||
|
||||
mob_is_clone(mob_id) ||
|
||||
(flag&0x01 && (entry->rate < 1000000 && entry->rate <= rnd() % 1000000)) ||
|
||||
(flag&0x02 && lv < mob->lv) ||
|
||||
@ -2954,7 +2973,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
|
||||
}
|
||||
|
||||
if (sd) {
|
||||
struct mob_db *mission_mdb = mobdb_exists(sd->mission_mobid);
|
||||
struct mob_db *mission_mdb = mob_db(sd->mission_mobid);
|
||||
|
||||
if ((sd->mission_mobid == md->mob_id) ||
|
||||
(battle_config.taekwon_mission_mobname == 1 && mission_mdb && status_get_race2(&md->bl) == RC2_GOBLIN && mission_mdb->race2 == RC2_GOBLIN) ||
|
||||
@ -3789,7 +3808,7 @@ int mob_is_clone(int mob_id)
|
||||
{
|
||||
if(mob_id < MOB_CLONE_START || mob_id > MOB_CLONE_END)
|
||||
return 0;
|
||||
if (mob_db(mob_id) == mob_dummy)
|
||||
if (mob_db(mob_id) == NULL)
|
||||
return 0;
|
||||
return mob_id;
|
||||
}
|
||||
@ -3828,11 +3847,17 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons
|
||||
if(pc_isdead(sd) && master_id && flag&1)
|
||||
return 0;
|
||||
|
||||
ARR_FIND( MOB_CLONE_START, MOB_CLONE_END, mob_id, mob_db_data[mob_id] == NULL );
|
||||
ARR_FIND( MOB_CLONE_START, MOB_CLONE_END, mob_id, mob_db(mob_id) == NULL );
|
||||
if(mob_id >= MOB_CLONE_END)
|
||||
return 0;
|
||||
|
||||
db = mob_db_data[mob_id]=(struct mob_db*)aCalloc(1, sizeof(struct mob_db));
|
||||
try{
|
||||
db = &mob_db_data[mob_id];
|
||||
}catch( std::bad_alloc ){
|
||||
ShowError( "mob_clone_spawn: Memory allocation for clone %hu failed.\n", mob_id );
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = &db->status;
|
||||
strcpy(db->sprite,sd->status.name);
|
||||
strcpy(db->name,sd->status.name);
|
||||
@ -4012,69 +4037,19 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons
|
||||
return md->bl.id;
|
||||
}
|
||||
|
||||
int mob_clone_delete(struct mob_data *md)
|
||||
{
|
||||
int mob_clone_delete(struct mob_data *md){
|
||||
const int mob_id = md->mob_id;
|
||||
if (mob_id >= MOB_CLONE_START && mob_id < MOB_CLONE_END
|
||||
&& mob_db_data[mob_id]!=NULL) {
|
||||
aFree(mob_db_data[mob_id]);
|
||||
mob_db_data[mob_id]=NULL;
|
||||
&& mob_db(mob_id)!=NULL) {
|
||||
mob_db_data.erase(mob_id);
|
||||
//Clear references to the db
|
||||
md->db = mob_dummy;
|
||||
md->db = NULL;
|
||||
md->vd = NULL;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialization
|
||||
//
|
||||
/*==========================================
|
||||
* Since un-setting [ mob ] up was used, it is an initial provisional value setup.
|
||||
*------------------------------------------*/
|
||||
static int mob_makedummymobdb(int mob_id)
|
||||
{
|
||||
if (mob_dummy != NULL)
|
||||
{
|
||||
if (mob_db(mob_id) == mob_dummy)
|
||||
return 1; //Using the mob_dummy data already. [Skotlex]
|
||||
if (mob_id > 0 && mob_id <= MAX_MOB_DB)
|
||||
{ //Remove the mob data so that it uses the dummy data instead.
|
||||
aFree(mob_db_data[mob_id]);
|
||||
mob_db_data[mob_id] = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//Initialize dummy data.
|
||||
mob_dummy = (struct mob_db*)aCalloc(1, sizeof(struct mob_db)); //Initializing the dummy mob.
|
||||
sprintf(mob_dummy->sprite,"DUMMY");
|
||||
sprintf(mob_dummy->name,"Dummy");
|
||||
sprintf(mob_dummy->jname,"Dummy");
|
||||
mob_dummy->lv=1;
|
||||
mob_dummy->status.max_hp=1000;
|
||||
mob_dummy->status.max_sp=1;
|
||||
mob_dummy->status.rhw.range=1;
|
||||
mob_dummy->status.rhw.atk=7;
|
||||
mob_dummy->status.rhw.atk2=10;
|
||||
mob_dummy->status.str=1;
|
||||
mob_dummy->status.agi=1;
|
||||
mob_dummy->status.vit=1;
|
||||
mob_dummy->status.int_=1;
|
||||
mob_dummy->status.dex=6;
|
||||
mob_dummy->status.luk=2;
|
||||
mob_dummy->status.speed=300;
|
||||
mob_dummy->status.adelay=1000;
|
||||
mob_dummy->status.amotion=500;
|
||||
mob_dummy->status.dmotion=500;
|
||||
mob_dummy->base_exp=2;
|
||||
mob_dummy->job_exp=1;
|
||||
mob_dummy->range2=10;
|
||||
mob_dummy->range3=10;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Adjusts the drop rate of item according to the criteria given. [Skotlex]
|
||||
static unsigned int mob_drop_adjust(int baserate, int rate_adjust, unsigned short rate_min, unsigned short rate_max)
|
||||
{
|
||||
@ -4126,39 +4101,29 @@ static bool mob_parse_dbrow(char** str)
|
||||
|
||||
mob_id = atoi(str[0]);
|
||||
|
||||
if (mob_id <= 1000 || mob_id > MAX_MOB_DB) {
|
||||
ShowError("mob_parse_dbrow: Invalid monster ID %d, must be in range %d-%d.\n", mob_id, 1000, MAX_MOB_DB);
|
||||
return false;
|
||||
}
|
||||
if (pcdb_checkid(mob_id)) {
|
||||
ShowError("mob_parse_dbrow: Invalid monster ID %d, reserved for player classes.\n", mob_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mob_id >= MOB_CLONE_START && mob_id < MOB_CLONE_END) {
|
||||
ShowError("mob_parse_dbrow: Invalid monster ID %d. Range %d-%d is reserved for player clones. Please increase MAX_MOB_DB (%d).\n", mob_id, MOB_CLONE_START, MOB_CLONE_END-1, MAX_MOB_DB);
|
||||
if (!((mob_id > MIN_MOB_DB && mob_id < MAX_MOB_DB) || (mob_id > MIN_MOB_DB2 && mob_id < MAX_MOB_DB2))) {
|
||||
ShowError("mob_parse_dbrow: Invalid monster ID %d, must be in range %d-%d or %d-%d.\n", mob_id, MIN_MOB_DB, MAX_MOB_DB);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
|
||||
db = &entry;
|
||||
status = &db->status;
|
||||
status = &entry.status;
|
||||
|
||||
db->vd.class_ = mob_id;
|
||||
safestrncpy(db->sprite, str[1], sizeof(db->sprite));
|
||||
safestrncpy(db->jname, str[2], sizeof(db->jname));
|
||||
safestrncpy(db->name, str[3], sizeof(db->name));
|
||||
db->lv = atoi(str[4]);
|
||||
db->lv = cap_value(db->lv, 1, USHRT_MAX);
|
||||
entry.vd.class_ = mob_id;
|
||||
safestrncpy(entry.sprite, str[1], sizeof(entry.sprite));
|
||||
safestrncpy(entry.jname, str[2], sizeof(entry.jname));
|
||||
safestrncpy(entry.name, str[3], sizeof(entry.name));
|
||||
entry.lv = atoi(str[4]);
|
||||
entry.lv = cap_value(entry.lv, 1, USHRT_MAX);
|
||||
status->max_hp = atoi(str[5]);
|
||||
status->max_sp = atoi(str[6]);
|
||||
|
||||
exp = (double)atoi(str[7]) * (double)battle_config.base_exp_rate / 100.;
|
||||
db->base_exp = (unsigned int)cap_value(exp, 0, UINT_MAX);
|
||||
entry.base_exp = (unsigned int)cap_value(exp, 0, UINT_MAX);
|
||||
|
||||
exp = (double)atoi(str[8]) * (double)battle_config.job_exp_rate / 100.;
|
||||
db->job_exp = (unsigned int)cap_value(exp, 0, UINT_MAX);
|
||||
entry.job_exp = (unsigned int)cap_value(exp, 0, UINT_MAX);
|
||||
|
||||
status->rhw.range = atoi(str[9]);
|
||||
status->rhw.atk = atoi(str[10]);
|
||||
@ -4179,20 +4144,20 @@ static bool mob_parse_dbrow(char** str)
|
||||
if (status->dex < 1) status->dex = 1;
|
||||
if (status->luk < 1) status->luk = 1;
|
||||
|
||||
db->range2 = atoi(str[20]);
|
||||
db->range3 = atoi(str[21]);
|
||||
entry.range2 = atoi(str[20]);
|
||||
entry.range3 = atoi(str[21]);
|
||||
if (battle_config.view_range_rate != 100) {
|
||||
db->range2 = db->range2 * battle_config.view_range_rate / 100;
|
||||
if (db->range2 < 1)
|
||||
db->range2 = 1;
|
||||
entry.range2 = entry.range2 * battle_config.view_range_rate / 100;
|
||||
if (entry.range2 < 1)
|
||||
entry.range2 = 1;
|
||||
}
|
||||
if (battle_config.chase_range_rate != 100) {
|
||||
db->range3 = db->range3 * battle_config.chase_range_rate / 100;
|
||||
if (db->range3 < db->range2)
|
||||
db->range3 = db->range2;
|
||||
entry.range3 = entry.range3 * battle_config.chase_range_rate / 100;
|
||||
if (entry.range3 < entry.range2)
|
||||
entry.range3 = entry.range2;
|
||||
}
|
||||
//Tests showed that chase range is effectively 2 cells larger than expected [Playtester]
|
||||
db->range3 += 2;
|
||||
entry.range3 += 2;
|
||||
|
||||
status->size = atoi(str[22]);
|
||||
status->race = atoi(str[23]);
|
||||
@ -4234,18 +4199,18 @@ static bool mob_parse_dbrow(char** str)
|
||||
|
||||
// Fill in remaining status data by using a dummy monster.
|
||||
data.bl.type = BL_MOB;
|
||||
data.level = db->lv;
|
||||
data.level = entry.lv;
|
||||
memcpy(&data.status, status, sizeof(struct status_data));
|
||||
status_calc_misc(&data.bl, status, db->lv);
|
||||
status_calc_misc(&data.bl, status, entry.lv);
|
||||
|
||||
// MVP EXP Bonus: MEXP
|
||||
// Some new MVP's MEXP multipled by high exp-rate cause overflow. [LuzZza]
|
||||
exp = (double)atoi(str[30]) * (double)battle_config.mvp_exp_rate / 100.;
|
||||
db->mexp = (unsigned int)cap_value(exp, 0, UINT_MAX);
|
||||
entry.mexp = (unsigned int)cap_value(exp, 0, UINT_MAX);
|
||||
|
||||
//Now that we know if it is an mvp or not, apply battle_config modifiers [Skotlex]
|
||||
maxhp = (double)status->max_hp;
|
||||
if (db->mexp > 0) { //Mvp
|
||||
if (entry.mexp > 0) { //Mvp
|
||||
if (battle_config.mvp_hp_rate != 100)
|
||||
maxhp = maxhp * (double)battle_config.mvp_hp_rate / 100.;
|
||||
} else //Normal mob
|
||||
@ -4261,46 +4226,54 @@ static bool mob_parse_dbrow(char** str)
|
||||
|
||||
// MVP Drops: MVP1id,MVP1per,MVP2id,MVP2per,MVP3id,MVP3per
|
||||
for(i = 0; i < MAX_MVP_DROP; i++) {
|
||||
db->mvpitem[i].nameid = atoi(str[31+i*2]);
|
||||
entry.mvpitem[i].nameid = atoi(str[31+i*2]);
|
||||
|
||||
if( db->mvpitem[i].nameid ){
|
||||
if( itemdb_search(db->mvpitem[i].nameid) ){
|
||||
db->mvpitem[i].p = atoi(str[32+i*2]);
|
||||
if( entry.mvpitem[i].nameid ){
|
||||
if( itemdb_search(entry.mvpitem[i].nameid) ){
|
||||
entry.mvpitem[i].p = atoi(str[32+i*2]);
|
||||
continue;
|
||||
}else{
|
||||
ShowWarning( "Monster \"%s\"(id: %d) is dropping an unknown item \"%s\"(MVP-Drop %d)\n", db->name, mob_id, str[31+i*2], ( i / 2 ) + 1 );
|
||||
ShowWarning( "Monster \"%s\"(id: %d) is dropping an unknown item \"%s\"(MVP-Drop %d)\n", entry.name, mob_id, str[31+i*2], ( i / 2 ) + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the item
|
||||
db->mvpitem[i].nameid = 0;
|
||||
db->mvpitem[i].p = 0;
|
||||
entry.mvpitem[i].nameid = 0;
|
||||
entry.mvpitem[i].p = 0;
|
||||
}
|
||||
|
||||
for(i = 0; i < MAX_MOB_DROP; i++) {
|
||||
int k = 31 + MAX_MVP_DROP*2 + i*2;
|
||||
|
||||
db->dropitem[i].nameid = atoi(str[k]);
|
||||
entry.dropitem[i].nameid = atoi(str[k]);
|
||||
|
||||
if( db->dropitem[i].nameid ){
|
||||
if( itemdb_search( db->dropitem[i].nameid ) ){
|
||||
db->dropitem[i].p = atoi(str[k+1]);
|
||||
if( entry.dropitem[i].nameid ){
|
||||
if( itemdb_search( entry.dropitem[i].nameid ) ){
|
||||
entry.dropitem[i].p = atoi(str[k+1]);
|
||||
continue;
|
||||
}else{
|
||||
ShowWarning( "Monster \"%s\"(id: %d) is dropping an unknown item \"%s\"(Drop %d)\n", db->name, mob_id, str[k], ( i / 2 ) + 1 );
|
||||
ShowWarning( "Monster \"%s\"(id: %d) is dropping an unknown item \"%s\"(Drop %d)\n", entry.name, mob_id, str[k], ( i / 2 ) + 1 );
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the item
|
||||
db->dropitem[i].nameid = 0;
|
||||
db->dropitem[i].p = 0;
|
||||
entry.dropitem[i].nameid = 0;
|
||||
entry.dropitem[i].p = 0;
|
||||
}
|
||||
|
||||
// Finally insert monster's data into the database.
|
||||
if (mob_db_data[mob_id] == NULL)
|
||||
mob_db_data[mob_id] = (struct mob_db*)aCalloc(1, sizeof(struct mob_db));
|
||||
db = mob_db(mob_id);
|
||||
|
||||
memcpy(mob_db_data[mob_id], db, sizeof(struct mob_db));
|
||||
// Finally insert monster's data into the database.
|
||||
if (db == NULL) {
|
||||
try{
|
||||
db = &mob_db_data[mob_id];
|
||||
}catch( std::bad_alloc ){
|
||||
ShowError( "Memory allocation for monster %hu failed.\n", mob_id );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(db, &entry, sizeof(struct mob_db));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -4371,10 +4344,11 @@ static int mob_read_sqldb(void)
|
||||
static bool mob_readdb_mobavail(char* str[], int columns, int current)
|
||||
{
|
||||
int mob_id, sprite_id;
|
||||
struct mob_db *db;
|
||||
|
||||
mob_id = atoi(str[0]);
|
||||
|
||||
if(mob_db(mob_id) == mob_dummy) // invalid class (probably undefined in db)
|
||||
if( (db=mob_db(mob_id)) == NULL) // invalid class (probably undefined in db)
|
||||
{
|
||||
ShowWarning("mob_readdb_mobavail: Unknown mob id %d.\n", mob_id);
|
||||
return false;
|
||||
@ -4382,31 +4356,31 @@ static bool mob_readdb_mobavail(char* str[], int columns, int current)
|
||||
|
||||
sprite_id = atoi(str[1]);
|
||||
|
||||
memset(&mob_db_data[mob_id]->vd, 0, sizeof(struct view_data));
|
||||
mob_db_data[mob_id]->vd.class_ = sprite_id;
|
||||
memset(&db->vd, 0, sizeof(struct view_data));
|
||||
db->vd.class_ = sprite_id;
|
||||
|
||||
//Player sprites
|
||||
if(pcdb_checkid(sprite_id) && columns==12) {
|
||||
mob_db_data[mob_id]->vd.sex=atoi(str[2]);
|
||||
mob_db_data[mob_id]->vd.hair_style=atoi(str[3]);
|
||||
mob_db_data[mob_id]->vd.hair_color=atoi(str[4]);
|
||||
mob_db_data[mob_id]->vd.weapon=atoi(str[5]);
|
||||
mob_db_data[mob_id]->vd.shield=atoi(str[6]);
|
||||
mob_db_data[mob_id]->vd.head_top=atoi(str[7]);
|
||||
mob_db_data[mob_id]->vd.head_mid=atoi(str[8]);
|
||||
mob_db_data[mob_id]->vd.head_bottom=atoi(str[9]);
|
||||
mob_db_data[mob_id]->option=atoi(str[10])&~(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE);
|
||||
mob_db_data[mob_id]->vd.cloth_color=atoi(str[11]); // Monster player dye option - Valaris
|
||||
db->vd.sex=atoi(str[2]);
|
||||
db->vd.hair_style=atoi(str[3]);
|
||||
db->vd.hair_color=atoi(str[4]);
|
||||
db->vd.weapon=atoi(str[5]);
|
||||
db->vd.shield=atoi(str[6]);
|
||||
db->vd.head_top=atoi(str[7]);
|
||||
db->vd.head_mid=atoi(str[8]);
|
||||
db->vd.head_bottom=atoi(str[9]);
|
||||
db->option=atoi(str[10])&~(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE);
|
||||
db->vd.cloth_color=atoi(str[11]); // Monster player dye option - Valaris
|
||||
|
||||
#ifdef NEW_CARTS
|
||||
if( mob_db_data[mob_id]->option & OPTION_CART ){
|
||||
if( db->option & OPTION_CART ){
|
||||
ShowWarning("mob_readdb_mobavail: You tried to use a cart for mob id %d. This does not work with setting an option anymore.\n", mob_id );
|
||||
mob_db_data[mob_id]->option &= ~OPTION_CART;
|
||||
db->option &= ~OPTION_CART;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if(columns==3)
|
||||
mob_db_data[mob_id]->vd.head_bottom=atoi(str[2]); // mob equipment [Valaris]
|
||||
db->vd.head_bottom=atoi(str[2]); // mob equipment [Valaris]
|
||||
else if( columns != 2 )
|
||||
return false;
|
||||
|
||||
@ -4431,13 +4405,13 @@ static bool mob_readdb_group(char* str[], int columns, int current){
|
||||
}
|
||||
|
||||
mob_id = atoi(str[1]);
|
||||
if (mob_id != 0 && mob_db(mob_id) == mob_dummy) {
|
||||
if (mob_id != 0 && mob_db(mob_id) == NULL) {
|
||||
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(mob_id) == mob_dummy) {
|
||||
if (mob_db(mob_id) == NULL) {
|
||||
ShowError("mob_readdb_group: Invalid random monster group '%s'\n", str[0]);
|
||||
return false;
|
||||
}
|
||||
@ -4474,15 +4448,22 @@ static bool mob_parse_row_chatdb(char* fields[], int columns, int current)
|
||||
|
||||
msg_id = atoi(fields[0]);
|
||||
|
||||
if (msg_id <= 0 || msg_id > MAX_MOB_CHAT){
|
||||
if (msg_id <= 0){
|
||||
ShowError("mob_parse_row_chatdb: Invalid chat ID '%d' in line %d\n", msg_id, current);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mob_chat_db[msg_id] == NULL)
|
||||
mob_chat_db[msg_id] = (struct mob_chat*)aCalloc(1, sizeof (struct mob_chat));
|
||||
ms = mob_chat(msg_id);
|
||||
|
||||
if( ms == NULL ){
|
||||
try{
|
||||
ms = &mob_chat_db[msg_id];
|
||||
}catch( std::bad_alloc ){
|
||||
ShowError( "mob_parse_row_chatdb: Memory allocation for chat ID '%d' failed.\n", msg_id );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ms = mob_chat_db[msg_id];
|
||||
//MSG ID
|
||||
ms->msg_id=msg_id;
|
||||
//Color
|
||||
@ -4595,10 +4576,11 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current)
|
||||
struct mob_skill *ms = NULL;
|
||||
int mob_id;
|
||||
int i = 0, j, tmp;
|
||||
struct mob_db *mob;
|
||||
|
||||
mob_id = atoi(str[0]);
|
||||
|
||||
if (mob_id > 0 && mob_db(mob_id) == mob_dummy)
|
||||
if (mob_id > 0 && (mob = mob_db(mob_id)) == NULL)
|
||||
{
|
||||
if (mob_id != last_mob_id) {
|
||||
ShowError("mob_parse_row_mobskilldb: Non existant Mob id %d\n", mob_id);
|
||||
@ -4624,7 +4606,7 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current)
|
||||
if( i == MAX_MOBSKILL )
|
||||
{
|
||||
if (mob_id != last_mob_id) {
|
||||
ShowError("mob_parse_row_mobskilldb: Too many skills for monster %d[%s]\n", mob_id, mob_db_data[mob_id]->sprite);
|
||||
ShowError("mob_parse_row_mobskilldb: Too many skills for monster %d[%s]\n", mob_id, mob->sprite);
|
||||
last_mob_id = mob_id;
|
||||
}
|
||||
return false;
|
||||
@ -4648,7 +4630,7 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current)
|
||||
if (mob_id < 0)
|
||||
ShowError("mob_parse_row_mobskilldb: Invalid Skill ID (%d) for all mobs\n", j);
|
||||
else
|
||||
ShowError("mob_parse_row_mobskilldb: Invalid Skill ID (%d) for mob %d (%s)\n", j, mob_id, mob_db_data[mob_id]->sprite);
|
||||
ShowError("mob_parse_row_mobskilldb: Invalid Skill ID (%d) for mob %d (%s)\n", j, mob_id, mob->sprite);
|
||||
return false;
|
||||
}
|
||||
ms->skill_id = j;
|
||||
@ -4693,13 +4675,13 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current)
|
||||
{
|
||||
ShowWarning("mob_parse_row_mobskilldb: Wrong mob skill target for ground skill %d (%s) for %s.\n",
|
||||
ms->skill_id, skill_get_name(ms->skill_id),
|
||||
mob_id < 0 ? "all mobs" : mob_db_data[mob_id]->sprite);
|
||||
mob_id < 0 ? "all mobs" : mob->sprite);
|
||||
ms->target = MST_TARGET;
|
||||
}
|
||||
} else if (ms->target > MST_MASTER) {
|
||||
ShowWarning("mob_parse_row_mobskilldb: Wrong mob skill target 'around' for non-ground skill %d (%s) for %s.\n",
|
||||
ms->skill_id, skill_get_name(ms->skill_id),
|
||||
mob_id < 0 ? "all mobs" : mob_db_data[mob_id]->sprite);
|
||||
mob_id < 0 ? "all mobs" : mob->sprite);
|
||||
ms->target = MST_TARGET;
|
||||
}
|
||||
|
||||
@ -4746,7 +4728,7 @@ static bool mob_parse_row_mobskilldb(char** str, int columns, int current)
|
||||
else
|
||||
ms->emotion = -1;
|
||||
|
||||
if(str[18] != NULL && mob_chat_db[atoi(str[18])]!=NULL)
|
||||
if(str[18] != NULL && mob_chat(atoi(str[18]))!=NULL)
|
||||
ms->msg_id = atoi(str[18]);
|
||||
else
|
||||
ms->msg_id = 0;
|
||||
@ -4845,18 +4827,19 @@ static bool mob_readdb_race2(char* fields[], int columns, int current)
|
||||
|
||||
for(i = 1; i < columns; i++) {
|
||||
int mob_id = atoi(fields[i]);
|
||||
struct mob_db* db = mob_db(mob_id);
|
||||
|
||||
if (mob_db(mob_id) == mob_dummy) {
|
||||
if (db == NULL) {
|
||||
ShowWarning("mob_readdb_race2: Unknown mob id %d for race2 %d.\n", mob_id, race);
|
||||
continue;
|
||||
}
|
||||
mob_db_data[mob_id]->race2 = (enum e_race2)race;
|
||||
db->race2 = (enum e_race2)race;
|
||||
|
||||
// Apply Aegis Class
|
||||
if (race == RC2_GUARDIAN)
|
||||
mob_db_data[mob_id]->status.class_ = CLASS_GUARDIAN;
|
||||
db->status.class_ = CLASS_GUARDIAN;
|
||||
else if (race == RC2_BATTLEFIELD)
|
||||
mob_db_data[mob_id]->status.class_ = CLASS_BATTLEFIELD;
|
||||
db->status.class_ = CLASS_BATTLEFIELD;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -4885,7 +4868,7 @@ static bool mob_readdb_itemratio(char* str[], int columns, int current)
|
||||
memset(item_ratio->mob_id, 0, sizeof(item_ratio->mob_id));
|
||||
for (i = 0; i < columns-2; i++) {
|
||||
uint16 mob_id = atoi(str[i+2]);
|
||||
if (mob_db(mob_id) == mob_dummy)
|
||||
if (mob_db(mob_id) == NULL)
|
||||
ShowError("mob_readdb_itemratio: Invalid monster with ID %hu (Item:%hu Col:%d).\n", mob_id, nameid, columns);
|
||||
else
|
||||
item_ratio->mob_id[i] = atoi(str[i+2]);
|
||||
@ -4910,7 +4893,7 @@ static bool mob_readdb_drop(char* str[], int columns, int current) {
|
||||
struct s_mob_drop *drop;
|
||||
|
||||
mobid = atoi(str[0]);
|
||||
if ((mob = mob_db(mobid)) == mob_dummy) {
|
||||
if ((mob = mob_db(mobid)) == NULL) {
|
||||
ShowError("mob_readdb_drop: Invalid monster with ID %s.\n", str[0]);
|
||||
return false;
|
||||
}
|
||||
@ -4987,23 +4970,19 @@ static int mob_item_drop_ratio_free(DBKey key, DBData *data, va_list ap) {
|
||||
* Adjust drop ratio for each monster
|
||||
**/
|
||||
static void mob_drop_ratio_adjust(void){
|
||||
unsigned short i;
|
||||
|
||||
for( i = 0; i <= MAX_MOB_DB; i++ ){
|
||||
for( auto &pair : mob_db_data ){
|
||||
struct mob_db *mob;
|
||||
struct item_data *id;
|
||||
unsigned short nameid;
|
||||
int j, rate, rate_adjust = 0, mob_id;
|
||||
|
||||
mob = mob_db(i);
|
||||
mob_id = pair.first;
|
||||
mob = &pair.second;
|
||||
|
||||
// Skip dummy mobs.
|
||||
if( mob == mob_dummy ){
|
||||
if( mob_is_clone( mob_id ) ){
|
||||
continue;
|
||||
}
|
||||
|
||||
mob_id = i;
|
||||
|
||||
for( j = 0; j < MAX_MVP_DROP_TOTAL; j++ ){
|
||||
nameid = mob->mvpitem[j].nameid;
|
||||
rate = mob->mvpitem[j].p;
|
||||
@ -5026,7 +5005,7 @@ static void mob_drop_ratio_adjust(void){
|
||||
|
||||
// Item is not known anymore(should never happen)
|
||||
if( !id ){
|
||||
ShowWarning( "Monster \"%s\"(id:%d) is dropping an unknown item(id: %d)\n", mob->name, mob_id, nameid );
|
||||
ShowWarning( "Monster \"%s\"(id:%hu) is dropping an unknown item(id: %d)\n", mob->name, mob_id, nameid );
|
||||
mob->mvpitem[j].nameid = 0;
|
||||
mob->mvpitem[j].p = 0;
|
||||
continue;
|
||||
@ -5056,7 +5035,7 @@ static void mob_drop_ratio_adjust(void){
|
||||
|
||||
// Item is not known anymore(should never happen)
|
||||
if( !id ){
|
||||
ShowWarning( "Monster \"%s\"(id:%d) is dropping an unknown item(id: %d)\n", mob->name, mob_id, nameid );
|
||||
ShowWarning( "Monster \"%s\"(id:%hu) is dropping an unknown item(id: %d)\n", mob->name, mob_id, nameid );
|
||||
mob->dropitem[j].nameid = 0;
|
||||
mob->dropitem[j].p = 0;
|
||||
continue;
|
||||
@ -5172,30 +5151,27 @@ static void mob_skill_db_set_single_sub(struct mob_db *mob, struct s_mob_skill *
|
||||
* @param skill
|
||||
**/
|
||||
static void mob_skill_db_set_single(struct s_mob_skill *skill) {
|
||||
struct mob_db *mob = NULL;
|
||||
|
||||
nullpo_retv(skill);
|
||||
|
||||
// Specific monster
|
||||
if (skill->mob_id >= 0) {
|
||||
mob = mob_db(skill->mob_id);
|
||||
if (mob != mob_dummy)
|
||||
//memcpy(&mob->skill, skill, sizeof(skill));
|
||||
struct mob_db *mob = mob_db(skill->mob_id);
|
||||
if (mob != NULL)
|
||||
mob_skill_db_set_single_sub(mob, skill);
|
||||
}
|
||||
// Global skill
|
||||
else {
|
||||
uint16 i, id = skill->mob_id;
|
||||
uint16 id = skill->mob_id;
|
||||
id *= -1;
|
||||
for (i = 0; i < MAX_MOB_DB; i++) {
|
||||
mob = mob_db(i);
|
||||
if (mob == mob_dummy)
|
||||
for( auto &pair : mob_db_data ){
|
||||
if ( mob_is_clone(pair.first) ){
|
||||
continue;
|
||||
if ( (!(id&1) && status_has_mode(&mob->status,MD_STATUS_IMMUNE)) // Bosses
|
||||
|| (!(id&2) && !status_has_mode(&mob->status,MD_STATUS_IMMUNE)) // Normal monsters
|
||||
}
|
||||
if ( (!(id&1) && status_has_mode(&pair.second.status,MD_STATUS_IMMUNE)) // Bosses
|
||||
|| (!(id&2) && !status_has_mode(&pair.second.status,MD_STATUS_IMMUNE)) // Normal monsters
|
||||
)
|
||||
continue;
|
||||
mob_skill_db_set_single_sub(mob, skill);
|
||||
mob_skill_db_set_single_sub(&pair.second, skill);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5299,7 +5275,7 @@ static void mob_load(void)
|
||||
sv_readdb(dbsubpath1, "mob_avail.txt", ',', 2, 12, -1, &mob_readdb_mobavail,silent);
|
||||
sv_readdb(dbsubpath2, "mob_race2_db.txt", ',', 2, MAX_RACE2_MOBS, -1, &mob_readdb_race2, silent);
|
||||
sv_readdb(dbsubpath1, "mob_item_ratio.txt", ',', 2, 2+MAX_ITEMRATIO_MOBS, -1, &mob_readdb_itemratio, silent);
|
||||
sv_readdb(dbsubpath1, "mob_chat_db.txt", '#', 3, 3, MAX_MOB_CHAT, &mob_parse_row_chatdb, silent);
|
||||
sv_readdb(dbsubpath1, "mob_chat_db.txt", '#', 3, 3, -1, &mob_parse_row_chatdb, 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);
|
||||
@ -5320,9 +5296,6 @@ static void mob_load(void)
|
||||
* Initialize monster data
|
||||
*/
|
||||
void mob_db_load(bool is_reload){
|
||||
memset(mob_db_data,0,sizeof(mob_db_data)); //Clear the array
|
||||
mob_db_data[0] = (struct mob_db*)aCalloc(1, sizeof (struct mob_db)); //This mob is used for random spawns
|
||||
mob_makedummymobdb(0); //The first time this is invoked, it creates the dummy mob
|
||||
if( !is_reload ) {
|
||||
// on mobdbreload it's not neccessary to execute this
|
||||
// item ers needs to be allocated only once
|
||||
@ -5335,6 +5308,41 @@ void mob_db_load(bool is_reload){
|
||||
mob_load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-link monster drop data with item data
|
||||
* Fixes the need of a @reloadmobdb after a @reloaditemdb
|
||||
* @author Epoque
|
||||
*/
|
||||
void mob_reload_itemmob_data(void) {
|
||||
for( auto const &pair : mob_db_data ){
|
||||
int d, k;
|
||||
|
||||
if( mob_is_clone( pair.first ) ){
|
||||
continue;
|
||||
}
|
||||
|
||||
for(d = 0; d < MAX_MOB_DROP_TOTAL; d++) {
|
||||
struct item_data *id;
|
||||
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].p)
|
||||
break;
|
||||
}
|
||||
|
||||
if (k == MAX_SEARCH)
|
||||
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].p;
|
||||
id->mob[k].id = pair.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the proper view data on monsters during mob_db reload.
|
||||
* @param md: Mob to adjust
|
||||
@ -5424,28 +5432,9 @@ void do_init_mob(void){
|
||||
* Clean memory usage.
|
||||
*------------------------------------------*/
|
||||
void do_final_mob(bool is_reload){
|
||||
int i;
|
||||
if (mob_dummy)
|
||||
{
|
||||
aFree(mob_dummy);
|
||||
mob_dummy = NULL;
|
||||
}
|
||||
for (i = 0; i <= MAX_MOB_DB; i++)
|
||||
{
|
||||
if (mob_db_data[i] != NULL)
|
||||
{
|
||||
aFree(mob_db_data[i]);
|
||||
mob_db_data[i] = NULL;
|
||||
}
|
||||
}
|
||||
for (i = 0; i <= MAX_MOB_CHAT; i++)
|
||||
{
|
||||
if (mob_chat_db[i] != NULL)
|
||||
{
|
||||
aFree(mob_chat_db[i]);
|
||||
mob_chat_db[i] = NULL;
|
||||
}
|
||||
}
|
||||
mob_db_data.clear();
|
||||
mob_chat_db.clear();
|
||||
|
||||
mob_item_drop_ratio->destroy(mob_item_drop_ratio,mob_item_drop_ratio_free);
|
||||
mob_skill_db->destroy(mob_skill_db, mob_skill_db_free);
|
||||
mob_summon_db->destroy(mob_summon_db, mob_summon_db_free);
|
||||
|
@ -13,11 +13,6 @@
|
||||
|
||||
struct guardian_data;
|
||||
|
||||
// Change this to increase the table size in your mob_db to accomodate a larger mob database.
|
||||
// Be sure to note that IDs 4001 to 4048 are reserved for advanced/baby/expanded classes.
|
||||
// Notice that the last 1000 entries are used for player clones, so always set this to desired value +1000
|
||||
#define MAX_MOB_DB 5000
|
||||
|
||||
//The number of drops all mobs have and the max drop-slot that the steal skill will attempt to steal from.
|
||||
#define MAX_MOB_DROP 10
|
||||
#define MAX_MVP_DROP 3
|
||||
@ -39,10 +34,6 @@ struct guardian_data;
|
||||
//Distance that slaves should keep from their master.
|
||||
#define MOB_SLAVEDISTANCE 2
|
||||
|
||||
// These define the range of available IDs for clones. [Valaris]
|
||||
#define MOB_CLONE_START (MAX_MOB_DB-999)
|
||||
#define MOB_CLONE_END MAX_MOB_DB
|
||||
|
||||
//Used to determine default enemy type of mobs (for use in eachinrange calls)
|
||||
#define DEFAULT_ENEMY_TYPE(md) (md->special_state.ai?BL_CHAR:BL_MOB|BL_PC|BL_HOM|BL_MER)
|
||||
|
||||
@ -294,7 +285,6 @@ struct item_drop_list {
|
||||
};
|
||||
|
||||
struct mob_db *mob_db(int mob_id);
|
||||
struct mob_db *mobdb_exists(uint16 mob_id);
|
||||
uint16 mobdb_searchname(const char * const str);
|
||||
int mobdb_searchname_array(const char *str, uint16 * out, int size);
|
||||
int mobdb_checkid(const int id);
|
||||
@ -359,6 +349,7 @@ int mob_is_clone(int mob_id);
|
||||
int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, const char *event, int master_id, enum e_mode mode, int flag, unsigned int duration);
|
||||
int mob_clone_delete(struct mob_data *md);
|
||||
|
||||
void mob_reload_itemmob_data(void);
|
||||
void mob_reload(void);
|
||||
void mob_add_spawn(uint16 mob_id, const struct spawn_info& new_spawn);
|
||||
|
||||
|
@ -514,7 +514,7 @@ void quest_read_txtdb(void)
|
||||
|
||||
if (!mob_id)
|
||||
continue;
|
||||
if (mobdb_exists(mob_id) == NULL) {
|
||||
if (mob_db(mob_id) == NULL) {
|
||||
ShowWarning("quest_read_txtdb: Invalid monster as objective '%d' in line %d.\n", mob_id, ln);
|
||||
continue;
|
||||
}
|
||||
@ -529,7 +529,7 @@ void quest_read_txtdb(void)
|
||||
|
||||
if (!nameid)
|
||||
continue;
|
||||
if (!itemdb_exists(nameid) || (mob_id && mobdb_exists(mob_id) == NULL)) {
|
||||
if (!itemdb_exists(nameid) || (mob_id && mob_db(mob_id) == NULL)) {
|
||||
ShowWarning("quest_read_txtdb: Invalid item reward '%d' (mob %d, optional) in line %d.\n", nameid, mob_id, ln);
|
||||
continue;
|
||||
}
|
||||
|
@ -17069,7 +17069,7 @@ BUILDIN_FUNC(addmonsterdrop)
|
||||
if(c) { //Fill in the slot with the item and rate
|
||||
mob->dropitem[c].nameid = item_id;
|
||||
mob->dropitem[c].p = (rate > 10000)?10000:rate;
|
||||
itemdb_reload_itemmob_data(); // Reload the mob search data stored in the item_data
|
||||
mob_reload_itemmob_data(); // Reload the mob search data stored in the item_data
|
||||
script_pushint(st,1);
|
||||
} else //No place to put the new drop
|
||||
script_pushint(st,0);
|
||||
@ -17115,7 +17115,7 @@ BUILDIN_FUNC(delmonsterdrop)
|
||||
if(mob->dropitem[i].nameid == item_id) {
|
||||
mob->dropitem[i].nameid = 0;
|
||||
mob->dropitem[i].p = 0;
|
||||
itemdb_reload_itemmob_data(); // Reload the mob search data stored in the item_data
|
||||
mob_reload_itemmob_data(); // Reload the mob search data stored in the item_data
|
||||
script_pushint(st,1);
|
||||
return SCRIPT_CMD_SUCCESS;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user