Large diffs are not rendered by default.

@@ -28,9 +28,6 @@ struct guardian_data;
#define MAX_MVP_DROP_ADD 2
#define MAX_MOB_DROP_TOTAL (MAX_MOB_DROP+MAX_MOB_DROP_ADD)
#define MAX_MVP_DROP_TOTAL (MAX_MVP_DROP+MAX_MVP_DROP_ADD)
#define MAX_STEAL_DROP 7

#define MAX_RACE2_MOBS 100

//Min time between AI executions
const t_tick MIN_MOBTHINKTIME = 100;
@@ -136,7 +133,50 @@ enum e_mob_bosstype : uint8{
BOSSTYPE_MVP
};

struct mob_skill {
/// Monster Aegis AI types
enum e_aegis_monstertype : uint16 {
MONSTER_TYPE_01 = 0x81,
MONSTER_TYPE_02 = 0x83,
MONSTER_TYPE_03 = 0x1089,
MONSTER_TYPE_04 = 0x3885,
MONSTER_TYPE_05 = 0x2085,
MONSTER_TYPE_06 = 0,
MONSTER_TYPE_07 = 0x108B,
MONSTER_TYPE_08 = 0x7085,
MONSTER_TYPE_09 = 0x3095,
MONSTER_TYPE_10 = 0x84,
MONSTER_TYPE_11 = 0x84,
MONSTER_TYPE_12 = 0x2085,
MONSTER_TYPE_13 = 0x308D,
//MONSTER_TYPE_14
//MONSTER_TYPE_15
//MONSTER_TYPE_16
MONSTER_TYPE_17 = 0x91,
//MONSTER_TYPE_18
MONSTER_TYPE_19 = 0x3095,
MONSTER_TYPE_20 = 0x3295,
MONSTER_TYPE_21 = 0x3695,
//MONSTER_TYPE_22
//MONSTER_TYPE_23
MONSTER_TYPE_24 = 0xA1,
MONSTER_TYPE_25 = 0x1,
MONSTER_TYPE_26 = 0xB695,
MONSTER_TYPE_27 = 0x8084,
};

/// Aegis monster class types
enum e_aegis_monsterclass : int8 {
CLASS_NONE = -1,
CLASS_NORMAL = 0,
CLASS_BOSS,
CLASS_GUARDIAN,
CLASS_BATTLEFIELD = 4,
CLASS_EVENT,
CLASS_ALL,
CLASS_MAX,
};

struct s_mob_skill {
enum MobSkillState state;
uint16 skill_id,skill_lv;
short permillage;
@@ -174,32 +214,47 @@ struct s_mob_drop {
bool steal_protected;
};

struct mob_db {
char sprite[NAME_LENGTH],name[NAME_LENGTH],jname[NAME_LENGTH];
struct s_mob_db {
std::string sprite, name, jname;
t_exp base_exp;
t_exp job_exp;
t_exp mexp;
short range2,range3;
enum e_race2 race2; // celest
unsigned short lv;
struct s_mob_drop dropitem[MAX_MOB_DROP_TOTAL], mvpitem[MAX_MVP_DROP_TOTAL];
struct status_data status;
struct view_data vd;
unsigned int option;
int maxskill;
struct mob_skill skill[MAX_MOBSKILL];
uint16 range2, range3;
std::vector<e_race2> race2; // celest
uint16 lv;
s_mob_drop dropitem[MAX_MOB_DROP_TOTAL], mvpitem[MAX_MVP_DROP_TOTAL];
status_data status;
view_data vd;
uint32 option;
std::vector<std::shared_ptr<s_mob_skill>> skill;

e_mob_bosstype get_bosstype();
};

class MobDatabase : public TypesafeCachedYamlDatabase <uint32, s_mob_db> {
private:
bool parseDropNode(std::string nodeName, YAML::Node node, uint8 max, s_mob_drop *drops);

public:
MobDatabase() : TypesafeCachedYamlDatabase("MOB_DB", 1) {

}

const std::string getDefaultLocation();
uint64 parseBodyNode(const YAML::Node &node);
void loadingFinished();
};

extern MobDatabase mob_db;

struct mob_data {
struct block_list bl;
struct unit_data ud;
struct view_data *vd;
bool vd_changed;
struct status_data status, *base_status; //Second one is in case of leveling up mobs, or tiny/large mobs.
struct status_change sc;
struct mob_db *db; //For quick data access (saves doing mob_db(md->mob_id) all the time) [Skotlex]
std::shared_ptr<s_mob_db> db; //For quick data access (saves doing mob_db(md->mob_id) all the time) [Skotlex]
char name[NAME_LENGTH];
struct s_specialState {
unsigned int size : 2; //Small/Big monsters.
@@ -329,9 +384,8 @@ struct item_drop_list {
struct item_drop* item; // linked list of drops
};

struct mob_db *mob_db(int mob_id);
uint16 mobdb_searchname(const char * const str);
struct mob_db* mobdb_search_aegisname( const char* str );
std::shared_ptr<s_mob_db> mobdb_search_aegisname( const char* str );
int mobdb_searchname_array(const char *str, uint16 * out, int size);
int mobdb_checkid(const int id);
struct view_data* mob_get_viewdata(int mob_id);
@@ -1401,7 +1401,7 @@ void run_tomb(struct map_session_data* sd, struct npc_data* nd)
strftime(time, sizeof(time), "%H:%M", localtime(&nd->u.tomb.kill_time));

// TODO: Find exact color?
snprintf(buffer, sizeof(buffer), msg_txt(sd,657), nd->u.tomb.md->db->name);
snprintf(buffer, sizeof(buffer), msg_txt(sd,657), nd->u.tomb.md->db->name.c_str());
clif_scriptmes(sd, nd->bl.id, buffer);

clif_scriptmes(sd, nd->bl.id, msg_txt(sd,658));
@@ -5909,7 +5909,7 @@ bool pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 ski
sd_status= status_get_status_data(&sd->bl);
md_status= status_get_status_data(bl);

if (md->master_id || status_has_mode(md_status, MD_STATUS_IMMUNE) || status_get_race2(&md->bl) == RC2_TREASURE ||
if (md->master_id || status_has_mode(md_status, MD_STATUSIMMUNE) || util::vector_exists(status_get_race2(&md->bl), RC2_TREASURE) ||
map_getmapflag(bl->m, MF_NOMOBLOOT) || // check noloot map flag [Lorky]
(battle_config.skill_steal_max_tries && //Reached limit of steal attempts. [Lupus]
md->state.steal_flag++ >= battle_config.skill_steal_max_tries)
@@ -5931,14 +5931,14 @@ bool pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 ski

// Try dropping one item, in the order from first to last possible slot.
// Droprate is affected by the skill success rate.
for( i = 0; i < MAX_STEAL_DROP; i++ )
for( i = 0; i < MAX_MOB_DROP; i++ )
if( md->db->dropitem[i].nameid > 0 && !md->db->dropitem[i].steal_protected && itemdb_exists(md->db->dropitem[i].nameid) && rnd() % 10000 < md->db->dropitem[i].rate
#ifndef RENEWAL
* rate/100.
#endif
)
break;
if( i == MAX_STEAL_DROP )
if( i == MAX_MOB_DROP )
return false;

itemid = md->db->dropitem[i].nameid;
@@ -5968,7 +5968,7 @@ bool pc_steal_item(struct map_session_data *sd,struct block_list *bl, uint16 ski
struct item_data *i_data;
char message[128];
i_data = itemdb_search(itemid);
sprintf (message, msg_txt(sd,542), (sd->status.name[0])?sd->status.name :"GM", md->db->jname, i_data->ename.c_str(), (float)md->db->dropitem[i].rate / 100);
sprintf (message, msg_txt(sd,542), (sd->status.name[0])?sd->status.name :"GM", md->db->jname.c_str(), i_data->ename.c_str(), (float)md->db->dropitem[i].rate / 100);
//MSG: "'%s' stole %s's %s (chance: %0.02f%%)"
intif_broadcast(message, strlen(message) + 1, BC_DEFAULT);
}
@@ -5992,7 +5992,7 @@ int pc_steal_coin(struct map_session_data *sd,struct block_list *target)
md = (TBL_MOB*)target;
target_lv = status_get_lv(target);

if (md->state.steal_coin_flag || md->sc.data[SC_STONE] || md->sc.data[SC_FREEZE] || status_bl_has_mode(target,MD_STATUS_IMMUNE) || status_get_race2(&md->bl) == RC2_TREASURE)
if (md->state.steal_coin_flag || md->sc.data[SC_STONE] || md->sc.data[SC_FREEZE] || status_bl_has_mode(target,MD_STATUSIMMUNE) || util::vector_exists(status_get_race2(&md->bl), RC2_TREASURE))
return 0;

rate = sd->battle_status.dex / 2 + 2 * (sd->status.base_level - target_lv) + (10 * pc_checkskill(sd, RG_STEALCOIN)) + sd->battle_status.luk / 2;
@@ -11804,7 +11804,7 @@ void pc_delspiritcharm(struct map_session_data *sd, int count, int type)
* @param type: 1 - EXP, 2 - Item Drop
* @return Penalty rate
*/
uint16 pc_level_penalty_mod( struct map_session_data* sd, e_penalty_type type, struct mob_db* mob, mob_data* md ){
uint16 pc_level_penalty_mod( struct map_session_data* sd, e_penalty_type type, std::shared_ptr<s_mob_db> mob, mob_data* md ){
// No player was attached, we don't use any modifier (100 = rates are not touched)
if( sd == nullptr ){
return 100;
@@ -11821,7 +11821,7 @@ uint16 pc_level_penalty_mod( struct map_session_data* sd, e_penalty_type type, s
return 100;
}

if( ( type == PENALTY_DROP || type == PENALTY_MVP_DROP ) && status_has_mode( &mob->status, MD_FIXED_ITEMDROP ) ){
if( ( type == PENALTY_DROP || type == PENALTY_MVP_DROP ) && status_has_mode( &mob->status, MD_FIXEDITEMDROP ) ){
return 100;
}

@@ -1459,7 +1459,7 @@ void pc_show_questinfo_reinit(struct map_session_data *sd);
bool pc_job_can_entermap(enum e_job jobid, int m, int group_lv);

#if defined(RENEWAL_DROP) || defined(RENEWAL_EXP)
uint16 pc_level_penalty_mod( struct map_session_data* sd, e_penalty_type type, struct mob_db* mob, mob_data* md = nullptr );
uint16 pc_level_penalty_mod( struct map_session_data* sd, e_penalty_type type, std::shared_ptr<s_mob_db> mob, mob_data* md = nullptr );
#endif

bool pc_attendance_enabled();
@@ -46,7 +46,7 @@ uint64 PetDatabase::parseBodyNode( const YAML::Node &node ){
return 0;
}

struct mob_db* mob = mobdb_search_aegisname( mob_name.c_str() );
std::shared_ptr<s_mob_db> mob = mobdb_search_aegisname( mob_name.c_str() );

if( mob == nullptr ){
this->invalidWarning( node["Target"], "Mob %s does not exist and cannot be used as a pet.\n", mob_name.c_str() );
@@ -412,7 +412,7 @@ uint64 PetDatabase::parseBodyNode( const YAML::Node &node ){
return 0;
}

struct mob_db* mob = mobdb_search_aegisname( target_name.c_str() );
std::shared_ptr<s_mob_db> mob = mobdb_search_aegisname( target_name.c_str() );

if( mob == nullptr ){
this->invalidWarning( evolutionNode["Target"], "Evolution target %s does not exist.\n", target_name.c_str() );
@@ -553,7 +553,7 @@ static int pet_reload_sub( struct map_session_data *sd, va_list args ){
pet_clear_support_bonuses(sd);

// Relink the pet to the new database entry
pd->db = mob_db( pet_db_ptr->class_ );
pd->db = mob_db.find( pet_db_ptr->class_ );

if( battle_config.pet_status_support ){
run_script( pet_db_ptr->pet_support_script, 0, sd->bl.id, 0 );
@@ -666,7 +666,7 @@ bool pet_create_egg(struct map_session_data *sd, t_itemid item_id)
if (!pet)
return false; //No pet egg here.

struct mob_db* mdb = mob_db(pet->class_);
std::shared_ptr<s_mob_db> mdb = mob_db.find(pet->class_);

if( mdb == nullptr ){
return false;
@@ -676,7 +676,7 @@ bool pet_create_egg(struct map_session_data *sd, t_itemid item_id)
return false; // Inventory full

sd->catch_target_class = pet->class_;
intif_create_pet(sd->status.account_id, sd->status.char_id, pet->class_, mdb->lv, pet->EggID, 0, pet->intimate, 100, 0, 1, mdb->jname);
intif_create_pet(sd->status.account_id, sd->status.char_id, pet->class_, mdb->lv, pet->EggID, 0, pet->intimate, 100, 0, 1, mdb->jname.c_str());

return true;
}
@@ -1026,7 +1026,7 @@ bool pet_data_init(struct map_session_data *sd, struct s_pet *pet)
pd->bl.id = npc_get_new_npc_id();

pd->master = sd;
pd->db = mob_db(pet->class_);
pd->db = mob_db.find(pet->class_);
memcpy(&pd->pet, pet, sizeof(struct s_pet));
status_set_viewdata(&pd->bl, pet->class_);
unit_dataset(&pd->bl);
@@ -1066,7 +1066,7 @@ bool pet_data_init(struct map_session_data *sd, struct s_pet *pet)
pd->masterteleport_timer = INVALID_TIMER;

if( !pet->rename_flag ){
safestrncpy( sd->pd->pet.name, pd->db->jname, NAME_LENGTH );
safestrncpy( sd->pd->pet.name, pd->db->jname.c_str(), NAME_LENGTH );
}

return true;
@@ -1254,7 +1254,7 @@ int pet_catch_process2(struct map_session_data* sd, int target_id)
// If the target is a valid pet, we have a few exceptions
if( pet ){
//catch_target_class == PET_CATCH_UNIVERSAL is used for universal lures (except bosses for now). [Skotlex]
if (sd->catch_target_class == PET_CATCH_UNIVERSAL && !status_has_mode(&md->status,MD_STATUS_IMMUNE)){
if (sd->catch_target_class == PET_CATCH_UNIVERSAL && !status_has_mode(&md->status,MD_STATUSIMMUNE)){
sd->catch_target_class = md->mob_id;
//catch_target_class == PET_CATCH_UNIVERSAL_ITEM is used for catching any monster required the lure item used
}else if (sd->catch_target_class == PET_CATCH_UNIVERSAL_ITEM && sd->itemid == pet->itemID){
@@ -1284,9 +1284,9 @@ int pet_catch_process2(struct map_session_data* sd, int target_id)
status_kill(&md->bl);
clif_pet_roulette(sd,1);

struct mob_db *mdb = mob_db(pet->class_);
std::shared_ptr<s_mob_db> mdb = mob_db.find(pet->class_);

intif_create_pet(sd->status.account_id, sd->status.char_id, pet->class_, mdb->lv, pet->EggID, 0, pet->intimate, 100, 0, 1, mdb->jname);
intif_create_pet(sd->status.account_id, sd->status.char_id, pet->class_, mdb->lv, pet->EggID, 0, pet->intimate, 100, 0, 1, mdb->jname.c_str());
} else {
clif_pet_roulette(sd,0);
sd->catch_target_class = PET_CATCH_FAIL;
@@ -2270,9 +2270,9 @@ void pet_evolution(struct map_session_data *sd, int16 pet_id) {
sd->pd->pet.egg_id = new_data->EggID;
pet_set_intimate(sd->pd, new_data->intimate);
if( !sd->pd->pet.rename_flag ){
struct mob_db* mdb = mob_db( pet_id );
std::shared_ptr<s_mob_db> mdb = mob_db.find( pet_id );

safestrncpy(sd->pd->pet.name, mdb->jname, NAME_LENGTH);
safestrncpy(sd->pd->pet.name, mdb->jname.c_str(), NAME_LENGTH);
}
status_set_viewdata(&sd->pd->bl, pet_id);

@@ -148,7 +148,7 @@ struct pet_data {
struct view_data vd;
struct s_pet pet;
struct status_data status;
struct mob_db *db;
std::shared_ptr<s_mob_db> db;
int pet_hungry_timer;
int target_id;
struct {
@@ -121,7 +121,7 @@ uint64 QuestDatabase::parseBodyNode(const YAML::Node &node) {
if (!this->asString(targetNode, "Mob", mob_name))
return 0;

struct mob_db *mob = mobdb_search_aegisname(mob_name.c_str());
std::shared_ptr<s_mob_db> mob = mobdb_search_aegisname(mob_name.c_str());

if (!mob) {
this->invalidWarning(targetNode["Mob"], "Mob %s does not exist, skipping.\n", mob_name.c_str());
@@ -331,7 +331,7 @@ uint64 QuestDatabase::parseBodyNode(const YAML::Node &node) {
if (!this->asString(dropNode, "Mob", mob_name))
return 0;

struct mob_db *mob = mobdb_search_aegisname(mob_name.c_str());
std::shared_ptr<s_mob_db> mob = mobdb_search_aegisname(mob_name.c_str());

if (!mob) {
this->invalidWarning(dropNode["Mob"], "Mob %s does not exist, skipping.\n", mob_name.c_str());
@@ -10467,9 +10467,9 @@ BUILDIN_FUNC(makepet)

sd->catch_target_class = mob_id;

struct mob_db* mdb = mob_db(pet->class_);
std::shared_ptr<s_mob_db> mdb = mob_db.find(pet->class_);

intif_create_pet( sd->status.account_id, sd->status.char_id, pet->class_, mdb->lv, pet->EggID, 0, pet->intimate, 100, 0, 1, mdb->jname );
intif_create_pet( sd->status.account_id, sd->status.char_id, pet->class_, mdb->lv, pet->EggID, 0, pet->intimate, 100, 0, 1, mdb->jname.c_str() );

return SCRIPT_CMD_SUCCESS;
}
@@ -10619,15 +10619,14 @@ BUILDIN_FUNC(getmobdrops)
{
int class_ = script_getnum(st,2);
int i, j = 0;
struct mob_db *mob;

if( !mobdb_checkid(class_) )
{
script_pushint(st, 0);
return SCRIPT_CMD_SUCCESS;
}

mob = mob_db(class_);
std::shared_ptr<s_mob_db> mob = mob_db.find(class_);

for( i = 0; i < MAX_MOB_DROP_TOTAL; i++ )
{
@@ -13774,14 +13773,16 @@ BUILDIN_FUNC(strmobinfo)
return SCRIPT_CMD_SUCCESS;
}

std::shared_ptr<s_mob_db> mob = mob_db.find(class_);

switch (num) {
case 1: script_pushstrcopy(st,mob_db(class_)->name); break;
case 2: script_pushstrcopy(st,mob_db(class_)->jname); break;
case 3: script_pushint(st,mob_db(class_)->lv); break;
case 4: script_pushint(st,mob_db(class_)->status.max_hp); break;
case 5: script_pushint(st,mob_db(class_)->status.max_sp); break;
case 6: script_pushint(st,mob_db(class_)->base_exp); break;
case 7: script_pushint(st,mob_db(class_)->job_exp); break;
case 1: script_pushstrcopy(st,mob->name.c_str()); break;
case 2: script_pushstrcopy(st, mob->jname.c_str()); break;
case 3: script_pushint(st,mob->lv); break;
case 4: script_pushint(st,mob->status.max_hp); break;
case 5: script_pushint(st,mob->status.max_sp); break;
case 6: script_pushint(st,mob->base_exp); break;
case 7: script_pushint(st,mob->job_exp); break;
default:
script_pushint(st,0);
break;
@@ -17443,13 +17444,13 @@ BUILDIN_FUNC(setitemscript)
*-------------------------------------------------------*/
BUILDIN_FUNC(addmonsterdrop)
{
struct mob_db *mob;
std::shared_ptr<s_mob_db> mob;
int rate;

if(script_isstring(st, 2))
mob = mob_db(mobdb_searchname(script_getstr(st,2)));
mob = mob_db.find(mobdb_searchname(script_getstr(st,2)));
else
mob = mob_db(script_getnum(st,2));
mob = mob_db.find(script_getnum(st,2));

t_itemid item_id=script_getnum(st,3);
rate=script_getnum(st,4);
@@ -17497,12 +17498,12 @@ BUILDIN_FUNC(addmonsterdrop)
*-------------------------------------------------------*/
BUILDIN_FUNC(delmonsterdrop)
{
struct mob_db *mob;
std::shared_ptr<s_mob_db> mob;

if(script_isstring(st, 2))
mob = mob_db(mobdb_searchname(script_getstr(st,2)));
mob = mob_db.find(mobdb_searchname(script_getstr(st,2)));
else
mob = mob_db(script_getnum(st,2));
mob = mob_db.find(script_getnum(st,2));

t_itemid item_id=script_getnum(st,3);

@@ -17539,7 +17540,6 @@ BUILDIN_FUNC(delmonsterdrop)
*------------------------------------------*/
BUILDIN_FUNC(getmonsterinfo)
{
struct mob_db *mob;
int mob_id;

mob_id = script_getnum(st,2);
@@ -17551,9 +17551,11 @@ BUILDIN_FUNC(getmonsterinfo)
script_pushint(st,-1);
return SCRIPT_CMD_SUCCESS;
}
mob = mob_db(mob_id);

std::shared_ptr<s_mob_db> mob = mob_db.find(mob_id);

switch ( script_getnum(st,3) ) {
case MOB_NAME: script_pushstrcopy(st,mob->jname); break;
case MOB_NAME: script_pushstrcopy(st,mob->jname.c_str()); break;
case MOB_LV: script_pushint(st,mob->lv); break;
case MOB_MAXHP: script_pushint(st,mob->status.max_hp); break;
case MOB_BASEEXP: script_pushint(st,mob->base_exp); break;
@@ -3743,10 +3743,10 @@
export_constant(RC2_KOBOLD);
export_constant(RC2_ORC);
export_constant(RC2_GOLEM);
export_constant(RC2_GUARDIAN);
export_deprecated_constant(RC2_GUARDIAN);
export_constant(RC2_NINJA);
export_constant(RC2_GVG);
export_constant(RC2_BATTLEFIELD);
export_deprecated_constant(RC2_BATTLEFIELD);
export_constant(RC2_TREASURE);
export_constant(RC2_BIOLAB);
export_constant(RC2_MANUK);
@@ -3768,12 +3768,38 @@
export_constant(RC2_ILLUSION_VAMPIRE);
export_constant(RC2_MAX);

/* monster ai */
export_constant(MONSTER_TYPE_01);
export_constant(MONSTER_TYPE_02);
export_constant(MONSTER_TYPE_03);
export_constant(MONSTER_TYPE_04);
export_constant(MONSTER_TYPE_05);
export_constant(MONSTER_TYPE_06);
export_constant(MONSTER_TYPE_07);
export_constant(MONSTER_TYPE_08);
export_constant(MONSTER_TYPE_09);
export_constant(MONSTER_TYPE_10);
export_constant(MONSTER_TYPE_11);
export_constant(MONSTER_TYPE_12);
export_constant(MONSTER_TYPE_13);
export_constant(MONSTER_TYPE_17);
export_constant(MONSTER_TYPE_19);
export_constant(MONSTER_TYPE_20);
export_constant(MONSTER_TYPE_21);
export_constant(MONSTER_TYPE_24);
export_constant(MONSTER_TYPE_25);
export_constant(MONSTER_TYPE_26);
export_constant(MONSTER_TYPE_27);

/* classes */
export_constant(CLASS_NONE);
export_constant(CLASS_NORMAL);
export_constant(CLASS_BOSS);
export_constant(CLASS_GUARDIAN);
export_constant(CLASS_BATTLEFIELD);
export_constant(CLASS_EVENT);
export_constant(CLASS_ALL);
export_constant(CLASS_MAX);

/* sizes */
export_constant2("Size_Small",SZ_SMALL);
@@ -7607,28 +7633,40 @@
export_constant(MD_LOOTER);
export_constant(MD_AGGRESSIVE);
export_constant(MD_ASSIST);
export_constant(MD_CASTSENSOR_IDLE);
export_constant(MD_NORANDOM_WALK);
export_constant(MD_NOCAST_SKILL);
export_constant(MD_CASTSENSORIDLE);
export_constant(MD_NORANDOMWALK);
export_constant(MD_NOCAST);
export_constant(MD_CANATTACK);
export_constant(MD_CASTSENSOR_CHASE);
export_constant(MD_CASTSENSORCHASE);
export_constant(MD_CHANGECHASE);
export_constant(MD_ANGRY);
export_constant(MD_CHANGETARGET_MELEE);
export_constant(MD_CHANGETARGET_CHASE);
export_constant(MD_CHANGETARGETMELEE);
export_constant(MD_CHANGETARGETCHASE);
export_constant(MD_TARGETWEAK);
export_constant(MD_RANDOMTARGET);
export_constant(MD_IGNOREMELEE);
export_constant(MD_IGNOREMAGIC);
export_constant(MD_IGNORERANGED);
export_constant(MD_MVP);
export_constant(MD_IGNOREMISC);
export_constant(MD_KNOCKBACK_IMMUNE);
export_constant(MD_TELEPORT_BLOCK);
export_constant(MD_FIXED_ITEMDROP);
export_constant(MD_KNOCKBACKIMMUNE);
export_constant(MD_TELEPORTBLOCK);
export_constant(MD_FIXEDITEMDROP);
export_constant(MD_DETECTOR);
export_constant(MD_STATUS_IMMUNE);
export_constant(MD_SKILL_IMMUNE);
export_constant(MD_STATUSIMMUNE);
export_constant(MD_SKILLIMMUNE);

export_deprecated_constant3("MD_CASTSENSOR_IDLE", MD_CASTSENSORIDLE, "MD_CASTSENSORIDLE");
export_deprecated_constant3("MD_NORANDOM_WALK", MD_NORANDOMWALK, "MD_NORANDOMWALK");
export_deprecated_constant3("MD_NOCAST_SKILL", MD_NOCAST, "MD_NOCAST");
export_deprecated_constant3("MD_CASTSENSOR_CHASE", MD_CASTSENSORCHASE, "MD_CASTSENSORCHASE");
export_deprecated_constant3("MD_CHANGETARGET_MELEE", MD_CHANGETARGETMELEE, "MD_CHANGETARGETMELEE");
export_deprecated_constant3("MD_CHANGETARGET_CHASE", MD_CHANGETARGETCHASE, "MD_CHANGETARGETCHASE");
export_deprecated_constant3("MD_KNOCKBACK_IMMUNE", MD_KNOCKBACKIMMUNE, "MD_KNOCKBACKIMMUNE");
export_deprecated_constant3("MD_TELEPORT_BLOCK", MD_TELEPORTBLOCK, "MD_TELEPORTBLOCK");
export_deprecated_constant3("MD_FIXED_ITEMDROP", MD_FIXEDITEMDROP, "MD_FIXEDITEMDROP");
export_deprecated_constant3("MD_STATUS_IMMUNE", MD_STATUSIMMUNE, "MD_STATUSIMMUNE");
export_deprecated_constant3("MD_SKILL_IMMUNE", MD_SKILLIMMUNE, "MD_SKILLIMMUNE");

/* guild storage flags */
export_constant(GSTORAGE_OPEN);
@@ -1602,7 +1602,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1

case LK_SPIRALPIERCE:
case ML_SPIRALPIERCE:
if( dstsd || ( dstmd && status_bl_has_mode(bl,MD_STATUS_IMMUNE) ) ) //Does not work on status immune
if( dstsd || ( dstmd && status_bl_has_mode(bl,MD_STATUSIMMUNE) ) ) //Does not work on status immune
sc_start(src,bl,SC_STOP,100,0,skill_get_time2(skill_id,skill_lv));
break;

@@ -2099,7 +2099,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1
}

// Coma
if (sd && sd->special_state.bonus_coma && (!md || status_get_race2(&md->bl) != RC2_GVG || status_get_class(&md->bl) != CLASS_BATTLEFIELD)) {
if (sd && sd->special_state.bonus_coma && (!md || util::vector_exists(status_get_race2(&md->bl), RC2_GVG) || status_get_class(&md->bl) != CLASS_BATTLEFIELD)) {
rate = 0;
//! TODO: Filter the skills that shouldn't inflict coma bonus, to avoid some non-damage skills inflict coma. [Cydh]
if (!skill_id || !skill_get_nk(skill_id, NK_NODAMAGE)) {
@@ -2284,7 +2284,7 @@ int skill_additional_effect(struct block_list* src, struct block_list *bl, uint1

//Polymorph
if(sd && sd->bonus.classchange && attack_type&BF_WEAPON &&
dstmd && !status_has_mode(tstatus,MD_STATUS_IMMUNE) &&
dstmd && !status_has_mode(tstatus,MD_STATUSIMMUNE) &&
(rnd()%10000 < sd->bonus.classchange))
{
int class_ = mob_get_random_id(MOBG_Branch_Of_Dead_Tree, RMF_DB_RATE, 0);
@@ -3305,7 +3305,7 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
nullpo_ret(dsrc); //dsrc is the actual originator of the damage, can be the same as src, or a skill casted by src.
nullpo_ret(bl); //Target to be attacked.

if (status_bl_has_mode(bl,MD_SKILL_IMMUNE) || (status_get_class(bl) == MOBID_EMPERIUM && !skill_get_inf2(skill_id, INF2_TARGETEMPERIUM)))
if (status_bl_has_mode(bl,MD_SKILLIMMUNE) || (status_get_class(bl) == MOBID_EMPERIUM && !skill_get_inf2(skill_id, INF2_TARGETEMPERIUM)))
return 0;

if (src != dsrc) {
@@ -3765,7 +3765,7 @@ int64 skill_attack (int attack_type, struct block_list* src, struct block_list *
}
}

if(damage > 0 && !status_has_mode(tstatus,MD_STATUS_IMMUNE)) {
if(damage > 0 && !status_has_mode(tstatus,MD_STATUSIMMUNE)) {
if( skill_id == RG_INTIMIDATE ) {
int rate = 50 + skill_lv * 5;
rate = rate + (status_get_lv(src) - status_get_lv(bl));
@@ -6561,7 +6561,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
heal = 0;

if( tsc && tsc->count ) {
if( tsc->data[SC_KAITE] && !status_has_mode(sstatus,MD_STATUS_IMMUNE) ) { //Bounce back heal
if( tsc->data[SC_KAITE] && !status_has_mode(sstatus,MD_STATUSIMMUNE) ) { //Bounce back heal
if (--tsc->data[SC_KAITE]->val2 <= 0)
status_change_end(bl, SC_KAITE, INVALID_TIMER);
if (src == bl)
@@ -6809,14 +6809,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
{
int class_;

if ( sd && status_has_mode(&dstmd->status,MD_STATUS_IMMUNE) ) {
if ( sd && status_has_mode(&dstmd->status,MD_STATUSIMMUNE) ) {
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
break;
}
class_ = (skill_id == SA_MONOCELL ? MOBID_PORING : mob_get_random_id(MOBG_ClassChange, RMF_DB_RATE, 0));
clif_skill_nodamage(src,bl,skill_id,skill_lv,1);
mob_class_change(dstmd,class_);
if( tsc && status_has_mode(&dstmd->status,MD_STATUS_IMMUNE) ) {
if( tsc && status_has_mode(&dstmd->status,MD_STATUSIMMUNE) ) {
const enum sc_type scs[] = { SC_QUAGMIRE, SC_PROVOKE, SC_ROKISWEIL, SC_GRAVITATION, SC_SUITON, SC_STRIPWEAPON, SC_STRIPSHIELD, SC_STRIPARMOR, SC_STRIPHELM, SC_BLADESTOP };
for (i = SC_COMMON_MIN; i <= SC_COMMON_MAX; i++)
if (tsc->data[i]) status_change_end(bl, (sc_type)i, INVALID_TIMER);
@@ -6826,7 +6826,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
}
break;
case SA_DEATH:
if ( sd && dstmd && status_has_mode(&dstmd->status,MD_STATUS_IMMUNE) ) {
if ( sd && dstmd && status_has_mode(&dstmd->status,MD_STATUSIMMUNE) ) {
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
break;
}
@@ -7265,7 +7265,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case SM_PROVOKE:
case SM_SELFPROVOKE:
case MER_PROVOKE:
if( status_has_mode(tstatus,MD_STATUS_IMMUNE) || battle_check_undead(tstatus->race,tstatus->def_ele) ) {
if( status_has_mode(tstatus,MD_STATUSIMMUNE) || battle_check_undead(tstatus->race,tstatus->def_ele) ) {
map_freeblock_unlock();
return 1;
}
@@ -7444,7 +7444,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
i += dstsd->spiritcharm * 7;
pc_delspiritcharm(dstsd,dstsd->spiritcharm,dstsd->spiritcharm_type);
}
} else if (dstmd && !status_has_mode(tstatus,MD_STATUS_IMMUNE) && rnd() % 100 < 20) { // check if target is a monster and not status immune, for the 20% chance to absorb 2 SP per monster's level [Reddozen]
} else if (dstmd && !status_has_mode(tstatus,MD_STATUSIMMUNE) && rnd() % 100 < 20) { // check if target is a monster and not status immune, for the 20% chance to absorb 2 SP per monster's level [Reddozen]
i = 2 * dstmd->level;
mob_target(dstmd,src,0);
} else {
@@ -7855,7 +7855,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
{
if( status_get_lv(src) > status_get_lv(bl)
&& (tstatus->race == RC_DEMON || tstatus->race == RC_DEMIHUMAN || tstatus->race == RC_PLAYER_HUMAN || tstatus->race == RC_PLAYER_DORAM || tstatus->race == RC_ANGEL)
&& !status_has_mode(tstatus,MD_STATUS_IMMUNE) )
&& !status_has_mode(tstatus,MD_STATUSIMMUNE) )
clif_skill_nodamage(src,bl,skill_id,skill_lv, sc_start2(src,bl,type,70,skill_lv,src->id,skill_get_time(skill_id,skill_lv)));
else
{
@@ -7914,7 +7914,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case MG_STONECURSE:
{
int brate = 0;
if (status_has_mode(tstatus,MD_STATUS_IMMUNE)) {
if (status_has_mode(tstatus,MD_STATUSIMMUNE)) {
if (sd) clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
break;
}
@@ -8597,7 +8597,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
break; //Nothing to cancel.
bl_skill_id = ud->skill_id;
bl_skill_lv = ud->skill_lv;
if (status_has_mode(tstatus,MD_STATUS_IMMUNE)) { //Only 10% success chance against status immune. [Skotlex]
if (status_has_mode(tstatus,MD_STATUSIMMUNE)) { //Only 10% success chance against status immune. [Skotlex]
if (rnd()%100 < 90)
{
if (sd) clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
@@ -8682,7 +8682,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case SA_ELEMENTFIRE:
case SA_ELEMENTGROUND:
case SA_ELEMENTWIND:
if (sd && (!dstmd || status_has_mode(tstatus,MD_STATUS_IMMUNE))) // Only works on monsters (Except status immune monsters).
if (sd && (!dstmd || status_has_mode(tstatus,MD_STATUSIMMUNE))) // Only works on monsters (Except status immune monsters).
break;
case NPC_ATTRICHANGE:
case NPC_CHANGEWATER:
@@ -8737,7 +8737,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case NPC_SUMMONMONSTER:
case NPC_DEATHSUMMON:
if(md && md->skill_idx >= 0)
mob_summonslave(md,md->db->skill[md->skill_idx].val,skill_lv,skill_id);
mob_summonslave(md,md->db->skill[md->skill_idx]->val,skill_lv,skill_id);
break;

case NPC_CALLSLAVE:
@@ -8788,9 +8788,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case NPC_TRANSFORMATION:
case NPC_METAMORPHOSIS:
if(md && md->skill_idx >= 0) {
int class_ = mob_random_class (md->db->skill[md->skill_idx].val,0);
int class_ = mob_random_class (md->db->skill[md->skill_idx]->val,0);
if (skill_lv > 1) //Multiply the rest of mobs. [Skotlex]
mob_summonslave(md,md->db->skill[md->skill_idx].val,skill_lv-1,skill_id);
mob_summonslave(md,md->db->skill[md->skill_idx]->val,skill_lv-1,skill_id);
if (class_) mob_class_change(md, class_);
}
break;
@@ -8805,19 +8805,19 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
//val[4] if set, asks to delete the previous mode change.
if(md && md->skill_idx >= 0 && tsc)
{
clif_emotion(bl, md->db->skill[md->skill_idx].val[0]);
if(md->db->skill[md->skill_idx].val[4] && tsce)
clif_emotion(bl, md->db->skill[md->skill_idx]->val[0]);
if(md->db->skill[md->skill_idx]->val[4] && tsce)
status_change_end(bl, type, INVALID_TIMER);

//If mode gets set by NPC_EMOTION then the target should be reset [Playtester]
if(!battle_config.npc_emotion_behavior && skill_id == NPC_EMOTION && md->db->skill[md->skill_idx].val[1])
if(!battle_config.npc_emotion_behavior && skill_id == NPC_EMOTION && md->db->skill[md->skill_idx]->val[1])
mob_unlocktarget(md,tick);

if(md->db->skill[md->skill_idx].val[1] || md->db->skill[md->skill_idx].val[2])
if(md->db->skill[md->skill_idx]->val[1] || md->db->skill[md->skill_idx]->val[2])
sc_start4(src,src, type, 100, skill_lv,
md->db->skill[md->skill_idx].val[1],
md->db->skill[md->skill_idx].val[2],
md->db->skill[md->skill_idx].val[3],
md->db->skill[md->skill_idx]->val[1],
md->db->skill[md->skill_idx]->val[2],
md->db->skill[md->skill_idx]->val[3],
skill_get_time(skill_id, skill_lv));

//Reset aggressive state depending on resulting mode
@@ -9067,7 +9067,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
break;

case AS_SPLASHER:
if( status_has_mode(tstatus,MD_STATUS_IMMUNE)
if( status_has_mode(tstatus,MD_STATUSIMMUNE)
// Renewal dropped the 3/4 hp requirement
#ifndef RENEWAL
|| tstatus-> hp > tstatus->max_hp*3/4
@@ -9086,7 +9086,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui

case PF_MINDBREAKER:
{
if(status_has_mode(tstatus,MD_STATUS_IMMUNE) || battle_check_undead(tstatus->race,tstatus->def_ele)) {
if(status_has_mode(tstatus,MD_STATUSIMMUNE) || battle_check_undead(tstatus->race,tstatus->def_ele)) {
map_freeblock_unlock();
return 1;
}
@@ -11250,7 +11250,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
case OB_AKAITSUKI:
case OB_OBOROGENSOU:
if( sd && ( (skill_id == OB_OBOROGENSOU && bl->type == BL_MOB) // This skill does not work on monsters.
|| status_bl_has_mode(bl,MD_STATUS_IMMUNE) ) ){ // Does not work on status immune monsters.
|| status_bl_has_mode(bl,MD_STATUSIMMUNE) ) ){ // Does not work on status immune monsters.
clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0);
break;
}
@@ -11674,7 +11674,7 @@ static int8 skill_castend_id_check(struct block_list *src, struct block_list *ta
int inf = skill->inf;
struct status_change *tsc = status_get_sc(target);

if (src != target && (status_bl_has_mode(target,MD_SKILL_IMMUNE) || (status_get_class(target) == MOBID_EMPERIUM && !skill->inf2[INF2_TARGETEMPERIUM])) && skill_get_casttype(skill_id) == CAST_NODAMAGE)
if (src != target && (status_bl_has_mode(target,MD_SKILLIMMUNE) || (status_get_class(target) == MOBID_EMPERIUM && !skill->inf2[INF2_TARGETEMPERIUM])) && skill_get_casttype(skill_id) == CAST_NODAMAGE)
return USESKILL_FAIL_MAX; // Don't show a skill fail message (NoDamage type doesn't consume requirements)

switch (skill_id) {
@@ -11922,8 +11922,8 @@ TIMER_FUNC(skill_castend_id){

if(md) {
md->last_thinktime=tick +MIN_MOBTHINKTIME;
if(md->skill_idx >= 0 && md->db->skill[md->skill_idx].emotion >= 0)
clif_emotion(src, md->db->skill[md->skill_idx].emotion);
if(md->skill_idx >= 0 && md->db->skill[md->skill_idx]->emotion >= 0)
clif_emotion(src, md->db->skill[md->skill_idx]->emotion);
}

if (src != target && battle_config.skill_add_range &&
@@ -11952,7 +11952,7 @@ TIMER_FUNC(skill_castend_id){
break;
else {
skill_consume_requirement(sd,ud->skill_id,ud->skill_lv,1);
if (src != target && (status_bl_has_mode(target,MD_SKILL_IMMUNE) || (status_get_class(target) == MOBID_EMPERIUM && !skill_get_inf2(ud->skill_id, INF2_TARGETEMPERIUM))) && skill_get_casttype(ud->skill_id) == CAST_DAMAGE) {
if (src != target && (status_bl_has_mode(target,MD_SKILLIMMUNE) || (status_get_class(target) == MOBID_EMPERIUM && !skill_get_inf2(ud->skill_id, INF2_TARGETEMPERIUM))) && skill_get_casttype(ud->skill_id) == CAST_DAMAGE) {
clif_skill_fail(sd, ud->skill_id, USESKILL_FAIL_LEVEL, 0);
break; // Show a skill fail message (Damage type consumes requirements)
}
@@ -12180,8 +12180,8 @@ TIMER_FUNC(skill_castend_pos){

if(md) {
md->last_thinktime=tick +MIN_MOBTHINKTIME;
if(md->skill_idx >= 0 && md->db->skill[md->skill_idx].emotion >= 0)
clif_emotion(src, md->db->skill[md->skill_idx].emotion);
if(md->skill_idx >= 0 && md->db->skill[md->skill_idx]->emotion >= 0)
clif_emotion(src, md->db->skill[md->skill_idx]->emotion);
}

if(battle_config.skill_log && battle_config.skill_log&src->type)
@@ -14794,7 +14794,7 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, t_t
}
break;
case UNT_NETHERWORLD:
if (!status_bl_has_mode(bl,MD_STATUS_IMMUNE) || (!map_flag_gvg2(ss->m) && battle_check_target(&unit->bl,bl,BCT_PARTY) < 0)) {
if (!status_bl_has_mode(bl,MD_STATUSIMMUNE) || (!map_flag_gvg2(ss->m) && battle_check_target(&unit->bl,bl,BCT_PARTY) < 0)) {
if (!(tsc && tsc->data[type])) {
sc_start(ss, bl, type, 100, sg->skill_lv, skill_get_time2(sg->skill_id,sg->skill_lv));
sg->limit = DIFF_TICK(tick,sg->tick);
@@ -14824,7 +14824,7 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, t_t
case UNT_WALLOFTHORN:
if (unit->val2-- <= 0) // Max hit reached
break;
if (status_bl_has_mode(bl,MD_STATUS_IMMUNE))
if (status_bl_has_mode(bl,MD_STATUSIMMUNE))
break; // This skill doesn't affect to Boss monsters. [iRO Wiki]
skill_blown(&unit->bl, bl, skill_get_blewcount(sg->skill_id, sg->skill_lv), unit_getdir(bl), BLOWN_IGNORE_NO_KNOCKBACK);
skill_addtimerskill(ss, tick + 100, bl->id, unit->bl.x, unit->bl.y, sg->skill_id, sg->skill_lv, skill_get_type(sg->skill_id), 4|SD_LEVEL);
@@ -18409,7 +18409,7 @@ static int skill_trap_splash(struct block_list *bl, va_list ap)
break;
case UNT_ELECTRICSHOCKER:
if (bl->id != ss->id) {
if (status_bl_has_mode(bl,MD_STATUS_IMMUNE))
if (status_bl_has_mode(bl,MD_STATUSIMMUNE))
break;
if (status_change_start(ss, bl, SC_ELECTRICSHOCKER, 10000, sg->skill_lv, sg->group_id, 0, 0, skill_get_time2(sg->skill_id, sg->skill_lv), SCSTART_NORATEDEF)) {
map_moveblock(bl, unit->bl.x, unit->bl.y, tick);
@@ -2396,13 +2396,13 @@ bool status_check_skilluse(struct block_list *src, struct block_list *target, ui
case ALL_ODINS_POWER:
// Should fail when used on top of Land Protector [Skotlex]
if (src && map_getcell(src->m, src->x, src->y, CELL_CHKLANDPROTECTOR)
&& !status_has_mode(status,MD_STATUS_IMMUNE)
&& !status_has_mode(status,MD_STATUSIMMUNE)
&& (src->type != BL_PC || ((TBL_PC*)src)->skillitem != skill_id))
return false;
break;
case SC_MANHOLE:
// Skill is disabled against special racial grouped monsters(GvG and Battleground)
if (target && ( status_get_race2(target) == RC2_GVG || status_get_race2(target) == RC2_BATTLEFIELD ) )
if (target && ( util::vector_exists(status_get_race2(target), RC2_GVG) || util::vector_exists(status_get_race2(target), RC2_BATTLEFIELD) ) )
return false;
default:
break;
@@ -2415,7 +2415,7 @@ bool status_check_skilluse(struct block_list *src, struct block_list *target, ui
if (sc->data[SC_ALL_RIDING])
return false; //You can't use skills while in the new mounts (The client doesn't let you, this is to make cheat-safe)

if (flag == 1 && !status_has_mode(status,MD_STATUS_IMMUNE) && ( // Applies to after cast completion only and doesn't apply to Boss monsters.
if (flag == 1 && !status_has_mode(status,MD_STATUSIMMUNE) && ( // Applies to after cast completion only and doesn't apply to Boss monsters.
(sc->data[SC_ASH] && rnd()%2) || // Volcanic Ash has a 50% chance of causing skills to fail.
(sc->data[SC_KYOMU] && rnd()%100 < 25) // Kyomu has a 25% chance of causing skills fail.
)) {
@@ -3848,7 +3848,7 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt)

// !FIXME: Most of these stuff should be calculated once, but how do I fix the memset above to do that? [Skotlex]
// Give them all modes except these (useful for clones)
base_status->mode = static_cast<e_mode>(MD_MASK&~(MD_STATUS_IMMUNE|MD_IGNOREMELEE|MD_IGNOREMAGIC|MD_IGNORERANGED|MD_IGNOREMISC|MD_DETECTOR|MD_ANGRY|MD_TARGETWEAK));
base_status->mode = static_cast<e_mode>(MD_MASK&~(MD_STATUSIMMUNE|MD_IGNOREMELEE|MD_IGNOREMAGIC|MD_IGNORERANGED|MD_IGNOREMISC|MD_DETECTOR|MD_ANGRY|MD_TARGETWEAK));

base_status->size = (sd->class_&JOBL_BABY) ? SZ_SMALL : (((sd->class_&MAPID_BASEMASK) == MAPID_SUMMONER) ? battle_config.summoner_size : SZ_MEDIUM);
if (battle_config.character_size && pc_isriding(sd)) { // [Lupus]
@@ -5529,10 +5529,13 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag)
if(flag&SCB_MODE) {
status->mode = status_calc_mode(bl, sc, b_status->mode);

// Only switch between Normal and Boss classes as the others are determined by the race value
if (status->class_ == CLASS_NORMAL && status_has_mode(status, MD_STATUS_IMMUNE|MD_KNOCKBACK_IMMUNE|MD_DETECTOR))
if (status->class_ != CLASS_BATTLEFIELD && status_has_mode(status, MD_STATUSIMMUNE|MD_SKILLIMMUNE))
status->class_ = CLASS_BATTLEFIELD;
else if (status->class_ != CLASS_BOSS && status_has_mode(status, MD_STATUSIMMUNE|MD_KNOCKBACKIMMUNE|MD_DETECTOR))
status->class_ = CLASS_BOSS;
else if (status->class_ == CLASS_BOSS && !status_has_mode(status, MD_STATUS_IMMUNE|MD_KNOCKBACK_IMMUNE|MD_DETECTOR))
else if (status->class_ != CLASS_GUARDIAN && status_has_mode(status, MD_STATUSIMMUNE))
status->class_ = CLASS_GUARDIAN;
else if (status->class_ != CLASS_NORMAL)
status->class_ = CLASS_NORMAL;

// Since mode changed, reset their state.
@@ -8000,7 +8003,7 @@ void status_calc_slave_mode(struct mob_data *md, struct mob_data *mmd)
sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, 0, MD_AGGRESSIVE, 0);
break;
case 4: // Overwrite with slave mode
sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, MD_CANMOVE|MD_NORANDOM_WALK|MD_CANATTACK, 0, 0, 0);
sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, MD_CANMOVE|MD_NORANDOMWALK|MD_CANATTACK, 0, 0, 0);
break;
default: //Copy master
if (status_has_mode(&mmd->status,MD_AGGRESSIVE))
@@ -8308,15 +8311,15 @@ int status_get_emblem_id(struct block_list *bl)
* @param bl: Object whose race2 to get [MOB|PET]
* @return race2
*/
enum e_race2 status_get_race2(struct block_list *bl)
std::vector<e_race2> status_get_race2(struct block_list *bl)
{
nullpo_retr(RC2_NONE,bl);
nullpo_retr(std::vector<e_race2>(),bl);

if (bl->type == BL_MOB)
return ((struct mob_data *)bl)->db->race2;
if (bl->type == BL_PET)
return ((struct pet_data *)bl)->db->race2;
return RC2_NONE;
return std::vector<e_race2>();
}

/**
@@ -8723,7 +8726,7 @@ t_tick status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_
sc_def2 = status->mdef*100;
break;
case SC_ANKLE:
if(status_has_mode(status,MD_STATUS_IMMUNE)) // Lasts 5 times less on bosses
if(status_has_mode(status,MD_STATUSIMMUNE)) // Lasts 5 times less on bosses
tick /= 5;
sc_def = status->agi*50;
break;
@@ -9106,7 +9109,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty

// Uncomment to prevent status adding hp to gvg mob (like bloodylust=hp*3 etc...
// if (bl->type == BL_MOB)
// if (status_get_race2(bl) == RC2_GVG && status_sc2scb_flag(type)&SCB_MAXHP) return 0;
// if (util::vector_exists(status_get_race2(bl), RC2_GVG) && status_sc2scb_flag(type)&SCB_MAXHP) return 0;

if( sc->data[SC_REFRESH] ) {
if( type >= SC_COMMON_MIN && type <= SC_COMMON_MAX) // Confirmed.
@@ -9563,7 +9566,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
}

// Check for resistances
if(status_has_mode(status,MD_STATUS_IMMUNE) && !(flag&SCSTART_NOAVOID)) {
if(status_has_mode(status,MD_STATUSIMMUNE) && !(flag&SCSTART_NOAVOID)) {
if (type>=SC_COMMON_MIN && type <= SC_COMMON_MAX)
return 0;
switch (type) {
@@ -11079,7 +11082,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
val3= 20*val1; // Int increase
break;
case SC_SWOO:
if(status_has_mode(status,MD_STATUS_IMMUNE))
if(status_has_mode(status,MD_STATUSIMMUNE))
tick /= 5; // !TODO: Reduce skill's duration. But for how long?
break;
case SC_ARMOR:
@@ -11792,7 +11795,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
val2 = 0; // hit % reduc
val3 = 0; // def % reduc
val4 = 0; // atk flee & reduc
if (!status_bl_has_mode(bl,MD_STATUS_IMMUNE)) {
if (!status_bl_has_mode(bl,MD_STATUSIMMUNE)) {
val2 = 50;
if (status_get_race(bl) == RC_PLANT) // plant type
val3 = 50;
@@ -15191,7 +15194,7 @@ int status_change_spread(struct block_list *src, struct block_list *bl, bool typ
tick = gettick();

// Status Immunity resistance
if (status_bl_has_mode(src,MD_STATUS_IMMUNE) || status_bl_has_mode(bl,MD_STATUS_IMMUNE))
if (status_bl_has_mode(src,MD_STATUSIMMUNE) || status_bl_has_mode(bl,MD_STATUSIMMUNE))
return 0;

for( i = SC_COMMON_MIN; i < SC_MAX; i++ ) {
@@ -2732,7 +2732,7 @@ unsigned char status_calc_attack_element(struct block_list *bl, struct status_ch
int status_get_party_id(struct block_list *bl);
int status_get_guild_id(struct block_list *bl);
int status_get_emblem_id(struct block_list *bl);
enum e_race2 status_get_race2(struct block_list *bl);
std::vector<e_race2> status_get_race2(struct block_list *bl);

struct view_data *status_get_viewdata(struct block_list *bl);
void status_set_viewdata(struct block_list *bl, int class_);
@@ -412,7 +412,7 @@ static TIMER_FUNC(unit_walktoxy_timer)
case BL_MOB:
md = BL_CAST(BL_MOB, bl);

if (status_has_mode(&md->status,MD_STATUS_IMMUNE))
if (status_has_mode(&md->status,MD_STATUSIMMUNE))
icewall_walk_block = battle_config.boss_icewall_walk_block;
else
icewall_walk_block = battle_config.mob_icewall_walk_block;
@@ -1216,7 +1216,7 @@ enum e_unit_blown unit_blown_immune(struct block_list* bl, uint8 flag)
switch (bl->type) {
case BL_MOB:
// Immune can't be knocked back
if (((flag&0x1) && status_bl_has_mode(bl,MD_KNOCKBACK_IMMUNE))
if (((flag&0x1) && status_bl_has_mode(bl,MD_KNOCKBACKIMMUNE))
&& ((flag&0x2) || !(battle_config.skill_trap_type&0x2)))
return UB_MD_KNOCKBACK_IMMUNE;
break;
@@ -1488,8 +1488,8 @@ int unit_can_move(struct block_list *bl) {
// Icewall walk block special trapped monster mode
if(bl->type == BL_MOB) {
struct mob_data *md = BL_CAST(BL_MOB, bl);
if(md && ((status_has_mode(&md->status,MD_STATUS_IMMUNE) && battle_config.boss_icewall_walk_block == 1 && map_getcell(bl->m,bl->x,bl->y,CELL_CHKICEWALL))
|| (!status_has_mode(&md->status,MD_STATUS_IMMUNE) && battle_config.mob_icewall_walk_block == 1 && map_getcell(bl->m,bl->x,bl->y,CELL_CHKICEWALL)))) {
if(md && ((status_has_mode(&md->status,MD_STATUSIMMUNE) && battle_config.boss_icewall_walk_block == 1 && map_getcell(bl->m,bl->x,bl->y,CELL_CHKICEWALL))
|| (!status_has_mode(&md->status,MD_STATUSIMMUNE) && battle_config.mob_icewall_walk_block == 1 && map_getcell(bl->m,bl->x,bl->y,CELL_CHKICEWALL)))) {
md->walktoxy_fail_count = 1; //Make sure rudeattacked skills are invoked
return 0;
}
@@ -1541,7 +1541,7 @@ int unit_set_walkdelay(struct block_list *bl, t_tick tick, t_tick delay, int typ

if (type) {
//Bosses can ignore skill induced walkdelay (but not damage induced)
if(bl->type == BL_MOB && status_has_mode(status_get_status_data(bl),MD_STATUS_IMMUNE))
if(bl->type == BL_MOB && status_has_mode(status_get_status_data(bl),MD_STATUSIMMUNE))
return 0;
//Make sure walk delay is not decreased
if (DIFF_TICK(ud->canmove_tick, tick+delay) > 0)
@@ -1965,11 +1965,11 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui

mobskill_event(md, src, tick, -1); // Cast targetted skill event.

if ((status_has_mode(tstatus,MD_CASTSENSOR_IDLE) || status_has_mode(tstatus,MD_CASTSENSOR_CHASE)) && battle_check_target(target, src, BCT_ENEMY) > 0) {
if ((status_has_mode(tstatus,MD_CASTSENSORIDLE) || status_has_mode(tstatus,MD_CASTSENSORCHASE)) && battle_check_target(target, src, BCT_ENEMY) > 0) {
switch (md->state.skillstate) {
case MSS_RUSH:
case MSS_FOLLOW:
if (!status_has_mode(tstatus,MD_CASTSENSOR_CHASE))
if (!status_has_mode(tstatus,MD_CASTSENSORCHASE))
break;

md->target_id = src->id;
@@ -1978,7 +1978,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, ui
break;
case MSS_IDLE:
case MSS_WALK:
if (!status_has_mode(tstatus,MD_CASTSENSOR_IDLE))
if (!status_has_mode(tstatus,MD_CASTSENSORIDLE))
break;

md->target_id = src->id;

Large diffs are not rendered by default.

@@ -31,6 +31,24 @@
#include "../common/winapi.hpp"
#endif

// Only for constants - do not use functions of it or linking will fail
#include "../map/achievement.hpp"
#include "../map/battle.hpp"
#include "../map/battleground.hpp"
#include "../map/channel.hpp"
#include "../map/chat.hpp"
#include "../map/date.hpp"
#include "../map/instance.hpp"
#include "../map/mercenary.hpp"
#include "../map/mob.hpp"
#include "../map/npc.hpp"
#include "../map/pc.hpp"
#include "../map/pet.hpp"
#include "../map/quest.hpp"
#include "../map/script.hpp"
#include "../map/skill.hpp"
#include "../map/storage.hpp"

using namespace rathena;

#ifndef WIN32
@@ -47,15 +65,51 @@ int getch( void ){
}
#endif

// Constants for conversion
std::unordered_map<const char *, int64> constants;

// Forward declaration of conversion functions
static bool item_db_yaml2sql(const std::string &file, const std::string &table);
static bool mob_db_yaml2sql(const std::string &file, const std::string &table);

bool fileExists( const std::string& path );
bool askConfirmation( const char* fmt, ... );

YAML::Node inNode;
std::ofstream out;

// Implement the function instead of including the original version by linking
void script_set_constant_(const char *name, int64 value, const char *constant_name, bool isparameter, bool deprecated) {
constants[name] = value;
}

const char *constant_lookup(int32 value, const char *prefix) {
if (prefix == nullptr)
return nullptr;

for (auto const &pair : constants) {
// Same prefix group and same value
if (strncasecmp(pair.first, prefix, strlen(prefix)) == 0 && pair.second == value) {
return pair.first;
}
}

return nullptr;
}

int64 constant_lookup_int(const char *constant) {
if (constant == nullptr)
return -100;

for (auto const &pair : constants) {
if (strlen(pair.first) == strlen(constant) && strncasecmp(pair.first, constant, strlen(constant)) == 0) {
return pair.second;
}
}

return -100;
}

void copyFileIfExists( std::ofstream& file,const std::string& name ){
std::string path = "doc/yaml/sql/" + name + ".sql";

@@ -136,16 +190,23 @@ int do_init( int argc, char** argv ){
#ifdef RENEWAL
const std::string item_table_name = "item_db_re";
const std::string item_import_table_name = "item_db2_re";
const std::string mob_table_name = "mob_db_re";
const std::string mob_import_table_name = "mob_db2_re";
#else
const std::string item_table_name = "item_db";
const std::string item_import_table_name = "item_db2";
const std::string mob_table_name = "mob_db";
const std::string mob_import_table_name = "mob_db2";
#endif
std::vector<std::string> item_table_suffixes = {
"usable",
"equip",
"etc"
};

// Load constants
#include "../map/script_constants.hpp"

for( const std::string& suffix : item_table_suffixes ){
if (!process("ITEM_DB", 1, { path_db_mode }, "item_db_" + suffix, item_table_name + "_" + suffix, item_table_name, [](const std::string& path, const std::string& name_ext, const std::string& table) -> bool {
return item_db_yaml2sql(path + name_ext, table);
@@ -160,6 +221,18 @@ int do_init( int argc, char** argv ){
return 0;
}

if (!process("MOB_DB", 1, { path_db_mode }, "mob_db", mob_table_name, mob_table_name, [](const std::string &path, const std::string &name_ext, const std::string &table) -> bool {
return mob_db_yaml2sql(path + name_ext, table);
})) {
return 0;
}

if (!process("MOB_DB", 1, { path_db_import }, "mob_db", mob_import_table_name, mob_import_table_name, [](const std::string &path, const std::string &name_ext, const std::string &table) -> bool {
return mob_db_yaml2sql(path + name_ext, table);
})) {
return 0;
}

// TODO: add implementations ;-)

return 0;
@@ -638,3 +711,200 @@ static bool item_db_yaml2sql(const std::string &file, const std::string &table)

return true;
}

// Copied and adjusted from mob.cpp
static bool mob_db_yaml2sql(const std::string &file, const std::string &table) {
size_t entries = 0;

for (const YAML::Node &input : inNode["Body"]) {
std::string column = "", value = "";

if (appendEntry(input["Id"], value))
column.append("`id`,");
if (appendEntry(input["AegisName"], value, true))
column.append("`name_aegis`,");
if (appendEntry(input["Name"], value, true))
column.append("`name_english`,");
if (appendEntry(input["Name"], value, true))
column.append("`name_japanese`,");
if (appendEntry(input["Level"], value))
column.append("`level`,");
if (appendEntry(input["Hp"], value))
column.append("`hp`,");
if (appendEntry(input["Sp"], value))
column.append("`sp`,");
if (appendEntry(input["BaseExp"], value))
column.append("`base_exp`,");
if (appendEntry(input["JobExp"], value))
column.append("`job_exp`,");
if (appendEntry(input["MvpExp"], value))
column.append("`mvp_exp`,");
if (appendEntry(input["Attack"], value))
column.append("`attack`,");
if (appendEntry(input["Attack2"], value))
column.append("`attack2`,");
if (appendEntry(input["Defense"], value))
column.append("`defense`,");
if (appendEntry(input["MagicDefense"], value))
column.append("`magic_defense`,");
if (appendEntry(input["Str"], value))
column.append("`str`,");
if (appendEntry(input["Agi"], value))
column.append("`agi`,");
if (appendEntry(input["Vit"], value))
column.append("`vit`,");
if (appendEntry(input["Int"], value))
column.append("`int`,");
if (appendEntry(input["Dex"], value))
column.append("`dex`,");
if (appendEntry(input["Luk"], value))
column.append("`luk`,");
if (appendEntry(input["AttackRange"], value))
column.append("`attack_range`,");
if (appendEntry(input["SkillRange"], value))
column.append("`skill_range`,");
if (appendEntry(input["ChaseRange"], value))
column.append("`chase_range`,");
if (appendEntry(input["Size"], value, true))
column.append("`size`,");
if (appendEntry(input["Race"], value, true))
column.append("`race`,");

const YAML::Node &racegroups = input["RaceGroups"];

if (racegroups) {
for (uint16 i = 1; i < RC2_MAX; i++) {
std::string constant = constant_lookup(i, "RC2_");

constant.erase(0, 4);

if (appendEntry(racegroups[name2Upper(constant)], value)) {
std::transform(constant.begin(), constant.end(), constant.begin(), ::tolower);
column.append("`racegroup_" + constant + "`,");
}
}
}

if (appendEntry(input["Element"], value, true))
column.append("`element`,");
if (appendEntry(input["ElementLevel"], value))
column.append("`element_level`,");
if (appendEntry(input["WalkSpeed"], value))
column.append("`walk_speed`,");
if (appendEntry(input["AttackDelay"], value))
column.append("`attack_delay`,");
if (appendEntry(input["AttackMotion"], value))
column.append("`attack_motion`,");
if (appendEntry(input["DamageMotion"], value))
column.append("`damage_motion`,");
if (appendEntry(input["Ai"], value, true))
column.append("`ai`,");
if (appendEntry(input["Class"], value, true))
column.append("`class`,");

const YAML::Node &modes = input["Modes"];

if (modes) {
if (appendEntry(modes["CanMove"], value))
column.append("`mode_canmove`,");
if (appendEntry(modes["Looter"], value))
column.append("`mode_looter`,");
if (appendEntry(modes["Aggressive"], value))
column.append("`mode_aggressive`,");
if (appendEntry(modes["Assist"], value))
column.append("`mode_assist`,");
if (appendEntry(modes["CastSensorIdle"], value))
column.append("`mode_castsensoridle`,");
if (appendEntry(modes["NoRandomWalk"], value))
column.append("`mode_norandomwalk`,");
if (appendEntry(modes["NoCast"], value))
column.append("`mode_nocast`,");
if (appendEntry(modes["CanAttack"], value))
column.append("`mode_canattack`,");
if (appendEntry(modes["CastSensorChase"], value))
column.append("`mode_castsensorchase`,");
if (appendEntry(modes["ChangeChase"], value))
column.append("`mode_changechase`,");
if (appendEntry(modes["Angry"], value))
column.append("`mode_angry`,");
if (appendEntry(modes["ChangeTargetMelee"], value))
column.append("`mode_changetargetmelee`,");
if (appendEntry(modes["ChangeTargetChase"], value))
column.append("`mode_changetargetchase`,");
if (appendEntry(modes["TargetWeak"], value))
column.append("`mode_targetweak`,");
if (appendEntry(modes["RandomTarget"], value))
column.append("`mode_randomtarget`,");
if (appendEntry(modes["IgnoreMelee"], value))
column.append("`mode_ignoremelee`,");
if (appendEntry(modes["IgnoreMagic"], value))
column.append("`mode_ignoremagic`,");
if (appendEntry(modes["IgnoreRanged"], value))
column.append("`mode_ignoreranged`,");
if (appendEntry(modes["Mvp"], value))
column.append("`mode_mvp`,");
if (appendEntry(modes["IgnoreMisc"], value))
column.append("`mode_ignoremisc`,");
if (appendEntry(modes["KnockBackImmune"], value))
column.append("`mode_knockbackimmune`,");
if (appendEntry(modes["TeleportBlock"], value))
column.append("`mode_teleportblock`,");
if (appendEntry(modes["FixedItemDrop"], value))
column.append("`mode_fixeditemdrop`,");
if (appendEntry(modes["Detector"], value))
column.append("`mode_detector`,");
if (appendEntry(modes["StatusImmune"], value))
column.append("`mode_statusimmune`,");
if (appendEntry(modes["SkillImmune"], value))
column.append("`mode_skillimmune`,");
}

for (uint16 i = 0; i < MAX_MVP_DROP; i++) {
if (!input["MvpDrops"].IsDefined())
continue;

const YAML::Node &mvpdrops = input["MvpDrops"][i];

if (mvpdrops) {
if (appendEntry(mvpdrops["Item"], value, true))
column.append("`mvpdrop" + std::to_string(i + 1) + "_item`,");
if (appendEntry(mvpdrops["Rate"], value))
column.append("`mvpdrop" + std::to_string(i + 1) + "_rate`,");
if (appendEntry(mvpdrops["RandomOptionGroup"], value, true))
column.append("`mvpdrop" + std::to_string(i + 1) + "_option`,");
if (appendEntry(mvpdrops["Index"], value))
column.append("`mvpdrop" + std::to_string(i + 1) + "_index`,");
}
}

for (uint16 i = 0; i < MAX_MOB_DROP; i++) {
if (!input["Drops"].IsDefined())
continue;

const YAML::Node &drops = input["Drops"][i];

if (drops) {
if (appendEntry(drops["Item"], value, true))
column.append("`drop" + std::to_string(i + 1) + "_item`,");
if (appendEntry(drops["Rate"], value))
column.append("`drop" + std::to_string(i + 1) + "_rate`,");
if (appendEntry(drops["StealProtected"], value))
column.append("`drop" + std::to_string(i + 1) + "_nosteal`,");
if (appendEntry(drops["RandomOptionGroup"], value, true))
column.append("`drop" + std::to_string(i + 1) + "_option`,");
if (appendEntry(drops["Index"], value))
column.append("`drop" + std::to_string(i + 1) + "_index`,");
}
}

column.pop_back(); // Remove last ','
value.pop_back(); // Remove last ','

out << "REPLACE INTO `" + table + "` (" + column + ") VALUES (" + value + ");\n";
entries++;
}

ShowStatus("Done converting '" CL_WHITE "%d" CL_RESET "' mobs in '" CL_WHITE "%s" CL_RESET "'.\n", entries, file.c_str());

return true;
}