summaryrefslogtreecommitdiff
path: root/src/map/mob.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/mob.c')
-rw-r--r--src/map/mob.c394
1 files changed, 242 insertions, 152 deletions
diff --git a/src/map/mob.c b/src/map/mob.c
index bc78c6098..52705cf4d 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2015 Hercules Dev Team
+ * Copyright (C) 2012-2016 Hercules Dev Team
* Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
@@ -46,6 +46,7 @@
#include "map/status.h"
#include "common/HPM.h"
#include "common/cbasetypes.h"
+#include "common/conf.h"
#include "common/db.h"
#include "common/ers.h"
#include "common/memmgr.h"
@@ -113,6 +114,8 @@ struct mob_chat *mob_chat(short id) {
int mobdb_searchname(const char *str)
{
int i;
+
+ nullpo_ret(str);
for(i=0;i<=MAX_MOB_DB;i++){
struct mob_db *monster = mob->db(i);
if(monster == mob->dummy) //Skip dummy mobs.
@@ -128,10 +131,13 @@ int mobdb_searchname(const char *str)
return 0;
}
int mobdb_searchname_array_sub(struct mob_db* monster, const char *str, int flag) {
+
+ nullpo_ret(monster);
if (monster == mob->dummy)
return 1;
if(!monster->base_exp && !monster->job_exp && monster->spawn[0].qty < 1)
return 1; // Monsters with no base/job exp and no spawn point are, by this criteria, considered "slave mobs" and excluded from search results
+ nullpo_ret(str);
if( !flag ) {
if(stristr(monster->jname,str))
return 0;
@@ -155,6 +161,7 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time)
{
struct npc_data *nd;
+ nullpo_retv(md);
if ( md->tomb_nid )
mob->mvptomb_destroy(md);
@@ -180,6 +187,7 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time)
void mvptomb_destroy(struct mob_data *md) {
struct npc_data *nd;
+ nullpo_retv(md);
if ( (nd = map->id2nd(md->tomb_nid)) ) {
int16 m, i;
@@ -211,6 +219,7 @@ int mobdb_searchname_array(struct mob_db** data, int size, const char *str, int
{
int count = 0, i;
struct mob_db* monster;
+ nullpo_ret(data);
for(i=0;i<=MAX_MOB_DB;i++){
monster = mob->db(i);
if (monster == mob->dummy || mob->is_clone(i) ) //keep clones out (or you leak player stats)
@@ -252,6 +261,7 @@ int mob_parse_dataset(struct spawn_data *data)
{
size_t len;
+ nullpo_ret(data);
if ((!mob->db_checkid(data->class_) && !mob->is_clone(data->class_)) || !data->num)
return 0;
@@ -275,6 +285,7 @@ int mob_parse_dataset(struct spawn_data *data)
*------------------------------------------*/
struct mob_data* mob_spawn_dataset(struct spawn_data *data) {
struct mob_data *md = NULL;
+ nullpo_retr(NULL, data);
CREATE(md, struct mob_data, 1);
md->bl.id= npc->get_new_npc_id();
md->bl.type = BL_MOB;
@@ -327,6 +338,7 @@ int mob_get_random_id(int type, int flag, int lv)
ShowError("mob_get_random_id: Invalid type (%d) of random monster.\n", type);
return 0;
}
+ Assert_ret(type >= 0 && type < MAX_RANDOMMONSTER);
do {
if (type)
class_ = summon[type].class_[rnd()%summon[type].qty];
@@ -409,7 +421,7 @@ bool mob_ksprotected(struct block_list *src, struct block_list *target) {
if( DIFF_TICK(sd->ks_floodprotect_tick, tick) <= 0 )
{
sprintf(output, "[KS Warning!! - Owner : %s]", pl_sd->status.name);
- clif_disp_onlyself(sd, output, strlen(output));
+ clif_disp_onlyself(sd, output);
sd->ks_floodprotect_tick = tick + 2000;
}
@@ -418,7 +430,7 @@ bool mob_ksprotected(struct block_list *src, struct block_list *target) {
if( DIFF_TICK(pl_sd->ks_floodprotect_tick, tick) <= 0 )
{
sprintf(output, "[Watch out! %s is trying to KS you!]", sd->status.name);
- clif_disp_onlyself(pl_sd, output, strlen(output));
+ clif_disp_onlyself(pl_sd, output);
pl_sd->ks_floodprotect_tick = tick + 2000;
}
@@ -633,6 +645,11 @@ int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobnam
struct guild *g=NULL;
struct guild_castle *gc;
int16 m;
+
+ nullpo_ret(mapname);
+ nullpo_ret(mobname);
+ nullpo_ret(event);
+
memset(&data, 0, sizeof(struct spawn_data));
data.num = 1;
@@ -727,6 +744,10 @@ int mob_spawn_bg(const char* mapname, short x, short y, const char* mobname, int
struct spawn_data data;
int16 m;
+ nullpo_ret(mapname);
+ nullpo_ret(mobname);
+ nullpo_ret(event);
+
if( (m = map->mapname2mapid(mapname)) < 0 ) {
ShowWarning("mob_spawn_bg: Map [%s] not found.\n", mapname);
return 0;
@@ -743,7 +764,7 @@ int mob_spawn_bg(const char* mapname, short x, short y, const char* mobname, int
data.class_ = class_;
if( (x <= 0 || y <= 0) && !map->search_freecell(NULL, m, &x, &y, -1,-1, 1) ) {
- ShowWarning("mob_spawn_bg: Couldn't locate a spawn cell for guardian class %d (bg_id %d) at map %s\n",class_, bg_id, map->list[m].name);
+ ShowWarning("mob_spawn_bg: Couldn't locate a spawn cell for guardian class %d (bg_id %u) at map %s\n", class_, bg_id, map->list[m].name);
return 0;
}
@@ -841,9 +862,12 @@ int mob_delayspawn(int tid, int64 tick, int id, intptr_t data) {
*------------------------------------------*/
int mob_setdelayspawn(struct mob_data *md)
{
- unsigned int spawntime, mode;
+ unsigned int spawntime;
+ uint32 mode;
struct mob_db *db;
+ nullpo_ret(md);
+
if (!md->spawn) //Doesn't has respawn data!
return unit->free(&md->bl,CLR_DEAD);
@@ -901,6 +925,7 @@ int mob_spawn (struct mob_data *md)
int64 tick = timer->gettick();
int64 c = 0;
+ nullpo_retr(1, md);
md->last_thinktime = tick;
if (md->bl.prev != NULL)
unit->remove_map(&md->bl,CLR_RESPAWN,ALC_MARK);
@@ -988,8 +1013,10 @@ int mob_spawn (struct mob_data *md)
/*==========================================
* Determines if the mob can change target. [Skotlex]
*------------------------------------------*/
-int mob_can_changetarget(struct mob_data* md, struct block_list* target, int mode)
+int mob_can_changetarget(const struct mob_data *md, const struct block_list *target, uint32 mode)
{
+ nullpo_ret(md);
+ nullpo_ret(target);
// if the monster was provoked ignore the above rule [celest]
if(md->state.provoke_flag)
{
@@ -1005,7 +1032,7 @@ int mob_can_changetarget(struct mob_data* md, struct block_list* target, int mod
return 0;
return (battle_config.mob_ai&0x4 || check_distance_bl(&md->bl, target, 3));
case MSS_RUSH:
- return (mode&MD_CHANGETARGET_CHASE);
+ return (mode&MD_CHANGETARGET_CHASE) ? 1 : 0;
case MSS_FOLLOW:
case MSS_ANGRY:
case MSS_IDLE:
@@ -1044,17 +1071,19 @@ int mob_target(struct mob_data *md,struct block_list *bl,int dist)
/*==========================================
* The ?? routine of an active monster
*------------------------------------------*/
-int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap)
+int mob_ai_sub_hard_activesearch(struct block_list *bl, va_list ap)
{
struct mob_data *md;
struct block_list **target;
- int mode;
+ uint32 mode;
int dist;
nullpo_ret(bl);
md=va_arg(ap,struct mob_data *);
target= va_arg(ap,struct block_list**);
- mode= va_arg(ap,int);
+ mode = va_arg(ap, uint32);
+ nullpo_ret(md);
+ nullpo_ret(target);
//If can't seek yet, not an enemy, or you can't attack it, skip.
if (md->bl.id == bl->id || (*target) == bl || !status->check_skilluse(&md->bl, bl, 0, 0))
@@ -1070,6 +1099,7 @@ int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap)
case BL_PC:
if (BL_UCCAST(BL_PC, bl)->state.gangsterparadise && !(status_get_mode(&md->bl)&MD_BOSS))
return 0; //Gangster paradise protection.
+ FALLTHROUGH
default:
if (battle_config.hom_setting&0x4 &&
(*target) && (*target)->type == BL_HOM && bl->type != BL_HOM)
@@ -1109,8 +1139,10 @@ int mob_ai_sub_hard_changechase(struct block_list *bl,va_list ap) {
struct block_list **target;
nullpo_ret(bl);
- md=va_arg(ap,struct mob_data *);
- target= va_arg(ap,struct block_list**);
+ md = va_arg(ap,struct mob_data *);
+ target = va_arg(ap,struct block_list**);
+ nullpo_ret(md);
+ nullpo_ret(target);
//If can't seek yet, not an enemy, or you can't attack it, skip.
if( md->bl.id == bl->id || *target == bl
@@ -1137,6 +1169,8 @@ int mob_ai_sub_hard_bg_ally(struct block_list *bl,va_list ap) {
nullpo_ret(bl);
md=va_arg(ap,struct mob_data *);
target= va_arg(ap,struct block_list**);
+ nullpo_retr(1, md);
+ nullpo_retr(1, target);
if( status->check_skilluse(&md->bl, bl, 0, 0) && battle->check_target(&md->bl,bl,BCT_ENEMY)<=0 ) {
(*target) = bl;
@@ -1155,6 +1189,8 @@ int mob_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap)
md=va_arg(ap,struct mob_data *);
target= va_arg(ap,struct block_list**);
+ nullpo_ret(md);
+ nullpo_ret(target);
dist=distance_bl(&md->bl, bl);
if(mob->can_reach(md,bl,dist+1, MSS_LOOT) &&
@@ -1175,6 +1211,9 @@ int mob_warpchase_sub(struct block_list *bl,va_list ap) {
struct npc_data *nd = NULL;
nullpo_ret(bl);
+ nullpo_ret(target);
+ nullpo_ret(target_nd);
+ nullpo_ret(min_distance);
Assert_ret(bl->type == BL_NPC);
nd = BL_UCAST(BL_NPC, bl);
@@ -1199,6 +1238,7 @@ int mob_warpchase_sub(struct block_list *bl,va_list ap) {
int mob_ai_sub_hard_slavemob(struct mob_data *md, int64 tick) {
struct block_list *bl;
+ nullpo_ret(md);
bl=map->id2bl(md->master_id);
if (!bl || status->isdead(bl)) {
@@ -1287,6 +1327,7 @@ int mob_unlocktarget(struct mob_data *md, int64 tick) {
break;
//Because it is not unset when the mob finishes walking.
md->state.skillstate = MSS_IDLE;
+ FALLTHROUGH
case MSS_IDLE:
// Idle skill.
if (!(++md->ud.walk_count%IDLE_SKILL_INTERVAL) && mob->skill_use(md, tick, -1))
@@ -1376,6 +1417,7 @@ int mob_warpchase(struct mob_data *md, struct block_list *target)
{
struct npc_data *warp = NULL;
int distance = AREA_SIZE;
+ nullpo_ret(md);
if (!(target && battle_config.mob_ai&0x40 && battle_config.mob_warp&1))
return 0; //Can't warp chase.
@@ -1400,9 +1442,10 @@ int mob_warpchase(struct mob_data *md, struct block_list *target)
*------------------------------------------*/
bool mob_ai_sub_hard(struct mob_data *md, int64 tick) {
struct block_list *tbl = NULL, *abl = NULL;
- int mode;
+ uint32 mode;
int view_range, can_move;
+ nullpo_retr(false, md);
if(md->bl.prev == NULL || md->status.hp <= 0)
return false;
@@ -1541,7 +1584,7 @@ bool mob_ai_sub_hard(struct mob_data *md, int64 tick) {
}
if ((!tbl && mode&MD_AGGRESSIVE) || md->state.skillstate == MSS_FOLLOW) {
- map->foreachinrange (mob->ai_sub_hard_activesearch, &md->bl, view_range, DEFAULT_ENEMY_TYPE(md), md, &tbl, mode);
+ map->foreachinrange(mob->ai_sub_hard_activesearch, &md->bl, view_range, DEFAULT_ENEMY_TYPE(md), md, &tbl, mode);
} else if ((mode&MD_CHANGECHASE && (md->state.skillstate == MSS_RUSH || md->state.skillstate == MSS_FOLLOW)) || (md->sc.count && md->sc.data[SC__CHAOS])) {
int search_size;
search_size = view_range<md->status.rhw.range ? view_range:md->status.rhw.range;
@@ -1609,7 +1652,7 @@ bool mob_ai_sub_hard(struct mob_data *md, int64 tick) {
memmove(&md->lootitem[0], &md->lootitem[1], (LOOTITEM_SIZE-1)*sizeof(md->lootitem[0]));
memcpy (&md->lootitem[LOOTITEM_SIZE-1], &fitem->item_data, sizeof(md->lootitem[0]));
}
- if (pc->db_checkid(md->vd->class_)) {
+ if (pc->db_checkid(md->vd->class)) {
//Give them walk act/delay to properly mimic players. [Skotlex]
clif->takeitem(&md->bl,tbl);
md->ud.canact_tick = tick + md->status.amotion;
@@ -1700,6 +1743,7 @@ int mob_ai_sub_hard_timer(struct block_list *bl, va_list ap)
*------------------------------------------*/
int mob_ai_sub_foreachclient(struct map_session_data *sd, va_list ap) {
int64 tick;
+ nullpo_ret(sd);
tick=va_arg(ap, int64);
map->foreachinrange(mob->ai_sub_hard_timer,&sd->bl, AREA_SIZE+ACTIVE_AI_RANGE, BL_MOB,tick);
@@ -1808,7 +1852,10 @@ struct item_drop* mob_setdropitem(int nameid, int qty, struct item_data *data) {
*------------------------------------------*/
struct item_drop* mob_setlootitem(struct item* item)
{
- struct item_drop *drop = ers_alloc(item_drop_ers, struct item_drop);
+ struct item_drop *drop ;
+
+ nullpo_retr(NULL, item);
+ drop = ers_alloc(item_drop_ers, struct item_drop);
memcpy(&drop->item_data, item, sizeof(struct item));
drop->next = NULL;
return drop;
@@ -1845,6 +1892,9 @@ void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, struct ite
{
struct map_session_data *sd = NULL;
+ nullpo_retv(md);
+ nullpo_retv(dlist);
+ nullpo_retv(ditem);
//Logs items, dropped by mobs [Lupus]
logs->pick_mob(md, loot?LOG_TYPE_LOOT:LOG_TYPE_PICKDROP_MONSTER, -ditem->item_data.amount, &ditem->item_data, NULL);
@@ -1930,6 +1980,9 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
{
int char_id = 0, flag = MDLF_NORMAL;
+ nullpo_retv(md);
+ nullpo_retv(src);
+
if( damage < 0 )
return; //Do nothing for absorbed damage.
if( !damage && !(src->type&DEFAULT_ENEMY_TYPE(md)) )
@@ -2040,6 +2093,7 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
}
//Call when a mob has received damage.
void mob_damage(struct mob_data *md, struct block_list *src, int damage) {
+ nullpo_retv(md);
if (damage > 0) { //Store total damage...
if (UINT_MAX - (unsigned int)damage > md->tdmg)
md->tdmg+=damage;
@@ -2097,18 +2151,21 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) {
struct map_session_data *sd = BL_CAST(BL_PC, src);
struct map_session_data *tmpsd[DAMAGELOG_SIZE] = { NULL };
struct map_session_data *mvp_sd = sd, *second_sd = NULL, *third_sd = NULL;
+ struct item_data *id = NULL;
struct {
struct party_data *p;
int id,zeny;
unsigned int base_exp,job_exp;
} pt[DAMAGELOG_SIZE] = { { 0 } };
- int i, temp, count, m = md->bl.m;
+ int i, temp, count, m;
int dmgbltypes = 0; // bitfield of all bl types, that caused damage to the mob and are eligible for exp distribution
unsigned int mvp_damage;
int64 tick = timer->gettick();
bool rebirth, homkillonly;
+ nullpo_retr(3, md);
+ m = md->bl.m;
mstatus = &md->status;
if( md->guardian_data && md->guardian_data->number >= 0 && md->guardian_data->number < MAX_GUARDIANS )
@@ -2283,11 +2340,6 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) {
if(flag) {
if(base_exp || job_exp) {
if( md->dmglog[i].flag != MDLF_PET || battle_config.pet_attack_exp_to_master ) {
-#ifdef RENEWAL_EXP
- int rate = pc->level_penalty_mod(md->level - (tmpsd[i])->status.base_level, md->status.race, md->status.mode, 1);
- base_exp = (unsigned int)cap_value(base_exp * rate / 100, 1, UINT_MAX);
- job_exp = (unsigned int)cap_value(job_exp * rate / 100, 1, UINT_MAX);
-#endif
pc->gainexp(tmpsd[i], &md->bl, base_exp, job_exp, false);
}
}
@@ -2356,7 +2408,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) {
drop_rate += (int)(0.5+drop_rate*status_get_luk(src)*battle_config.drops_by_luk2/10000.);
}
if (sd && battle_config.pk_mode &&
- (int)(md->level - sd->status.base_level) >= 20)
+ md->level - sd->status.base_level >= 20)
drop_rate = (int)(drop_rate*1.25); // pk_mode increase drops if 20 level difference [Valaris]
// Increase drop rate if user has SC_CASH_RECEIVEITEM
@@ -2388,21 +2440,13 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) {
ditem = mob->setdropitem(md->db->dropitem[i].nameid, 1, it);
- //A Rare Drop Global Announce by Lupus
- if( mvp_sd && drop_rate <= battle_config.rare_drop_announce ) {
- char message[128];
- sprintf (message, msg_txt(541), mvp_sd->status.name, md->name, it->jname, (float)drop_rate/100);
- //MSG: "'%s' won %s's %s (chance: %0.02f%%)"
- intif->broadcast(message, strlen(message)+1, BC_DEFAULT);
+ // Official Drop Announce [Jedzkie]
+ if (mvp_sd != NULL) {
+ if ((id = itemdb->search(it->nameid)) != NULL && id->flag.drop_announce) {
+ clif->item_drop_announce(mvp_sd, it->nameid, md->name);
+ }
}
- /* heres the thing we got the feature set up however we're still discussing how to best define the ids,
- * so while we discuss, for a small period of time, the list is hardcoded (yes officially only those 2 use it,
- * thus why we're unsure on how to best place the setting) */
- /* temp, will not be hardcoded for long thudu. */
- if (it->nameid == ITEMID_GOLD_KEY77 || it->nameid == ITEMID_SILVER_KEY77) /* for when not hardcoded: add a check on mvp bonus drop as well */
- clif->item_drop_announce(mvp_sd, it->nameid, md->name);
-
// Announce first, or else ditem will be freed. [Lance]
// By popular demand, use base drop rate for autoloot code. [Skotlex]
mob->item_drop(md, dlist, ditem, 0, md->db->dropitem[i].p, homkillonly);
@@ -2500,60 +2544,54 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) {
pc->gainexp(mvp_sd, &md->bl, mexp,0, false);
log_mvp[1] = mexp;
- if( !(map->list[m].flag.nomvploot || type&1) ) {
+ if (!(map->list[m].flag.nomvploot || type&1)) {
/* pose them randomly in the list -- so on 100% drop servers it wont always drop the same item */
- int mdrop_id[MAX_MVP_DROP];
- int mdrop_p[MAX_MVP_DROP];
- struct item item;
-
- memset(&mdrop_id,0,MAX_MVP_DROP*sizeof(int));
-
- for(i = 0; i < MAX_MVP_DROP; i++) {
- while( 1 ) {
- int va = rnd()%MAX_MVP_DROP;
- if( !mdrop_id[va] || !md->db->mvpitem[i].nameid ) {
- mdrop_id[va] = md->db->mvpitem[i].nameid;
- mdrop_p[va] = md->db->mvpitem[i].p;
- break;
- }
- }
+ struct {
+ int nameid;
+ int p;
+ } mdrop[MAX_MVP_DROP] = { { 0 } };
+
+ for (i = 0; i < MAX_MVP_DROP; i++) {
+ int rpos;
+ if (md->db->mvpitem[i].nameid == 0)
+ continue;
+ do {
+ rpos = rnd()%MAX_MVP_DROP;
+ } while (mdrop[rpos].nameid != 0);
+
+ mdrop[rpos].nameid = md->db->mvpitem[i].nameid;
+ mdrop[rpos].p = md->db->mvpitem[i].p;
}
- for(i = 0; i < MAX_MVP_DROP; i++) {
- struct item_data *data;
- if(mdrop_id[i] <= 0)
+ for (i = 0; i < MAX_MVP_DROP; i++) {
+ struct item_data *data = NULL;
+ int rate = 0;
+
+ if (mdrop[i].nameid <= 0)
continue;
- if(! (data = itemdb->exists(mdrop_id[i])) )
+ if ((data = itemdb->exists(mdrop[i].nameid)) == NULL)
continue;
- temp = mdrop_p[i];
- if(temp <= 0 && !battle_config.drop_rate0item)
- temp = 1;
- if(temp <= rnd()%10000+1) //if ==0, then it doesn't drop
- continue;
+ rate = mdrop[i].p;
+ if (rate <= 0 && !battle_config.drop_rate0item)
+ rate = 1;
+ if (rate > rnd()%10000) {
+ struct item item = { 0 };
- memset(&item,0,sizeof(item));
- item.nameid=mdrop_id[i];
- item.identify= itemdb->isidentified2(data);
- clif->mvp_item(mvp_sd,item.nameid);
- log_mvp[0] = item.nameid;
-
- //A Rare MVP Drop Global Announce by Lupus
- if(temp<=battle_config.rare_drop_announce) {
- char message[128];
- sprintf (message, msg_txt(541), mvp_sd->status.name, md->name, data->jname, temp/100.);
- //MSG: "'%s' won %s's %s (chance: %0.02f%%)"
- intif->broadcast(message, strlen(message)+1, BC_DEFAULT);
- }
+ item.nameid = mdrop[i].nameid;
+ item.identify = itemdb->isidentified2(data);
+ clif->mvp_item(mvp_sd, item.nameid);
+ log_mvp[0] = item.nameid;
- if((temp = pc->additem(mvp_sd,&item,1,LOG_TYPE_PICKDROP_PLAYER)) != 0) {
- clif->additem(mvp_sd,0,0,temp);
- map->addflooritem(&md->bl, &item, 1, mvp_sd->bl.m, mvp_sd->bl.x, mvp_sd->bl.y, mvp_sd->status.char_id, (second_sd?second_sd->status.char_id : 0), (third_sd ? third_sd->status.char_id : 0), 1);
- }
+ if((temp = pc->additem(mvp_sd,&item,1,LOG_TYPE_PICKDROP_PLAYER)) != 0) {
+ clif->additem(mvp_sd,0,0,temp);
+ map->addflooritem(&md->bl, &item, 1, mvp_sd->bl.m, mvp_sd->bl.x, mvp_sd->bl.y, mvp_sd->status.char_id, (second_sd?second_sd->status.char_id : 0), (third_sd ? third_sd->status.char_id : 0), 1);
+ }
- //Logs items, MVP prizes [Lupus]
- logs->pick_mob(md, LOG_TYPE_MVP, -1, &item, data);
- break;
+ //Logs items, MVP prizes [Lupus]
+ logs->pick_mob(md, LOG_TYPE_MVP, -1, &item, data);
+ break;
+ }
}
}
@@ -2580,7 +2618,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) {
if( sd ) {
if( sd->mission_mobid == md->class_) { //TK_MISSION [Skotlex]
if (++sd->mission_count >= 100 && (temp = mob->get_random_id(0, 0xE, sd->status.base_level)) != 0) {
- pc->addfame(sd, 1);
+ pc->addfame(sd, RANKTYPE_TAEKWON, 1);
sd->mission_mobid = temp;
pc_setglobalreg(sd,script->add_str("TK_MISSION_ID"), temp);
sd->mission_count = 0;
@@ -2629,7 +2667,8 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) {
if( !rebirth ) {
- if( pc->db_checkid(md->vd->class_) ) {//Player mobs are not removed automatically by the client.
+ if (pc->db_checkid(md->vd->class)) {
+ // Player mobs are not removed automatically by the client.
/* first we set them dead, then we delay the out sight effect */
clif->clearunit_area(&md->bl,CLR_DEAD);
clif->clearunit_delayed(&md->bl, CLR_OUTSIGHT,tick+3000);
@@ -2659,6 +2698,8 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) {
void mob_revive(struct mob_data *md, unsigned int hp)
{
int64 tick = timer->gettick();
+
+ nullpo_retv(md);
md->state.skillstate = MSS_IDLE;
md->last_thinktime = tick;
md->next_walktime = tick+rnd()%1000+MIN_RANDOMWALKTIME;
@@ -2774,7 +2815,7 @@ int mob_class_change (struct mob_data *md, int class_) {
mob_stop_walking(md, STOPWALKING_FLAG_NONE);
unit->skillcastcancel(&md->bl, 0);
status->set_viewdata(&md->bl, class_);
- clif->class_change(&md->bl, md->vd->class_, 1);
+ clif->class_change(&md->bl, md->vd->class, 1, NULL);
status_calc_mob(md, SCO_FIRST);
md->ud.state.speed_changed = 1; //Speed change update.
@@ -2806,6 +2847,7 @@ int mob_class_change (struct mob_data *md, int class_) {
*------------------------------------------*/
void mob_heal(struct mob_data *md, unsigned int heal)
{
+ nullpo_retv(md);
if (battle_config.show_mob_info&3)
clif->charnameack (0, &md->bl);
#if PACKETVER >= 20131223
@@ -2840,6 +2882,7 @@ int mob_warpslave_sub(struct block_list *bl, va_list ap)
range = va_arg(ap, int);
nullpo_ret(bl);
+ nullpo_ret(master);
Assert_ret(bl->type == BL_MOB);
md = BL_UCAST(BL_MOB, bl);
@@ -2857,6 +2900,7 @@ int mob_warpslave_sub(struct block_list *bl, va_list ap)
* appear in randomly.
*------------------------------------------*/
int mob_warpslave(struct block_list *bl, int range) {
+ nullpo_ret(bl);
if (range < 1)
range = 1; //Min range needed to avoid crashes and stuff. [Skotlex]
@@ -2884,6 +2928,7 @@ int mob_countslave_sub(struct block_list *bl, va_list ap)
* Counts the number of slaves a mob has on the map.
*------------------------------------------*/
int mob_countslave(struct block_list *bl) {
+ nullpo_ret(bl);
return map->foreachinmap(mob->countslave_sub, bl->m, BL_MOB,bl->id);
}
@@ -2986,18 +3031,20 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,uint16 skill_id)
/*==========================================
* MOBskill lookup (get skillindex through skill_id)
- * Returns -1 if not found.
+ * Returns INDEX_NOT_FOUND if not found.
*------------------------------------------*/
int mob_skill_id2skill_idx(int class_,uint16 skill_id)
{
int i, max = mob->db(class_)->maxskill;
struct mob_skill *ms=mob->db(class_)->skill;
- if(ms==NULL)
- return -1;
+ if (ms == NULL)
+ return INDEX_NOT_FOUND;
- ARR_FIND( 0, max, i, ms[i].skill_id == skill_id );
- return ( i < max ) ? i : -1;
+ ARR_FIND(0, max, i, ms[i].skill_id == skill_id);
+ if (i == max)
+ return INDEX_NOT_FOUND;
+ return i;
}
/*==========================================
@@ -3010,6 +3057,8 @@ int mob_getfriendhprate_sub(struct block_list *bl,va_list ap)
struct mob_data *md;
md = va_arg(ap,struct mob_data *);
+ nullpo_ret(bl);
+ nullpo_ret(md);
min_rate=va_arg(ap,int);
max_rate=va_arg(ap,int);
fr=va_arg(ap,struct block_list **);
@@ -3226,6 +3275,7 @@ int mobskill_use(struct mob_data *md, int64 tick, int event) {
bl = map->id2bl(md->master_id);
if (bl) //Otherwise, fall through.
break;
+ FALLTHROUGH
case MST_FRIEND:
bl = fbl?fbl:(fmd?&fmd->bl:&md->bl);
break;
@@ -3268,6 +3318,7 @@ int mobskill_use(struct mob_data *md, int64 tick, int event) {
bl = map->id2bl(md->master_id);
if (bl) //Otherwise, fall through.
break;
+ FALLTHROUGH
case MST_FRIEND:
if (fbl) {
bl = fbl;
@@ -3276,6 +3327,7 @@ int mobskill_use(struct mob_data *md, int64 tick, int event) {
bl = &fmd->bl;
break;
} // else fall through
+ FALLTHROUGH
default:
bl = &md->bl;
break;
@@ -3320,6 +3372,8 @@ int mobskill_use(struct mob_data *md, int64 tick, int event) {
int mobskill_event(struct mob_data *md, struct block_list *src, int64 tick, int flag) {
int target_id, res = 0;
+ nullpo_ret(md);
+ nullpo_ret(src);
if(md->bl.prev == NULL || md->status.hp <= 0)
return 0;
@@ -3366,7 +3420,8 @@ int mob_is_clone(int class_)
//If mode is not passed, a default aggressive mode is used.
//If master_id is passed, clone is attached to him.
//Returns: ID of newly crafted copy.
-int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, const char *event, int master_id, int mode, int flag, unsigned int duration) {
+int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, const char *event, int master_id, uint32 mode, int flag, unsigned int duration)
+{
int class_;
int i,j,h,inf, fd;
struct mob_data *md;
@@ -3380,7 +3435,7 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons
return 0;
ARR_FIND( MOB_CLONE_START, MOB_CLONE_END, class_, mob->db_data[class_] == NULL );
- if(class_ >= MOB_CLONE_END)
+ if(class_ < 0 || class_ >= MOB_CLONE_END)
return 0;
db = mob->db_data[class_]=(struct mob_db*)aCalloc(1, sizeof(struct mob_db));
@@ -3396,7 +3451,7 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons
mstatus->lhw.atk2= mstatus->dex + mstatus->lhw.atk + mstatus->lhw.atk2; //Max ATK
mstatus->lhw.atk = mstatus->dex; //Min ATK
}
- if (mode) //User provided mode.
+ if (mode != MD_NONE) //User provided mode.
mstatus->mode = mode;
else if (flag&1) //Friendly Character, remove looting.
mstatus->mode &= ~MD_LOOTER;
@@ -3420,8 +3475,8 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons
//Go Backwards to give better priority to advanced skills.
for (i=0,j = MAX_SKILL_TREE-1;j>=0 && i< MAX_MOBSKILL ;j--) {
- int idx = pc->skill_tree[pc->class2idx(sd->status.class_)][j].idx;
- int skill_id = pc->skill_tree[pc->class2idx(sd->status.class_)][j].id;
+ int idx = pc->skill_tree[pc->class2idx(sd->status.class)][j].idx;
+ int skill_id = pc->skill_tree[pc->class2idx(sd->status.class)][j].id;
if (!skill_id || sd->status.skill[idx].lv < 1 ||
(skill->dbs->db[idx].inf2&(INF2_WEDDING_SKILL|INF2_GUILD_SKILL))
)
@@ -3570,7 +3625,10 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons
int mob_clone_delete(struct mob_data *md)
{
- const int class_ = md->class_;
+ int class_;
+
+ nullpo_ret(md);
+ class_ = md->class_;
if (class_ >= MOB_CLONE_START && class_ < MOB_CLONE_END
&& mob->db_data[class_]!=NULL) {
mob->destroy_mob_db(class_);
@@ -3634,13 +3692,19 @@ unsigned int mob_drop_adjust(int baserate, int rate_adjust, unsigned short rate_
{
int64 rate = baserate;
- if (battle_config.logarithmic_drops && rate_adjust > 0 && rate_adjust != 100 && baserate > 0) //Logarithmic drops equation by Ishizu-Chan
- //Equation: Droprate(x,y) = x * (5 - log(x)) ^ (ln(y) / ln(5))
- //x is the normal Droprate, y is the Modificator.
- rate = rate * pow((5.0 - log10(rate)), (log(rate_adjust/100.) / log(5.0))) + 0.5;
- else
- //Classical linear rate adjustment.
- rate = apply_percentrate64(rate, rate_adjust, 100);
+ Assert_ret(baserate >= 0);
+
+ if (rate_adjust != 100 && baserate > 0) {
+ if (battle_config.logarithmic_drops && rate_adjust > 0) {
+ // Logarithmic drops equation by Ishizu-Chan
+ //Equation: Droprate(x,y) = x * (5 - log(x)) ^ (ln(y) / ln(5))
+ //x is the normal Droprate, y is the Modificator.
+ rate = (int64)(baserate * pow((5.0 - log10(baserate)), (log(rate_adjust/100.) / log(5.0))) + 0.5);
+ } else {
+ //Classical linear rate adjustment.
+ rate = apply_percentrate64(baserate, rate_adjust, 100);
+ }
+ }
return (unsigned int)cap_value(rate,rate_min,rate_max);
}
@@ -3654,6 +3718,7 @@ unsigned int mob_drop_adjust(int baserate, int rate_adjust, unsigned short rate_
*/
void item_dropratio_adjust(int nameid, int mob_id, int *rate_adjust)
{
+ nullpo_retv(rate_adjust);
if( item_drop_ratio_db[nameid] ) {
if( item_drop_ratio_db[nameid]->mob_id[0] ) { // only for listed mobs
int i;
@@ -3685,9 +3750,10 @@ static inline int mob_parse_dbrow_cap_value(int class_, int min, int max, int va
* (mob_id is expected to be already set).
* @param[in] t The libconfig entry.
*/
-void mob_read_db_stats_sub(struct mob_db *entry, config_setting_t *t)
+void mob_read_db_stats_sub(struct mob_db *entry, struct config_setting_t *t)
{
int i32;
+ nullpo_retv(entry);
if (mob->lookup_const(t, "Str", &i32) && i32 >= 0) {
entry->status.str = mob_parse_dbrow_cap_value(entry->mob_id, UINT16_MIN, UINT16_MAX, i32);
}
@@ -3716,43 +3782,45 @@ void mob_read_db_stats_sub(struct mob_db *entry, config_setting_t *t)
*
* @return The parsed mode.
*/
-int mob_read_db_mode_sub(struct mob_db *entry, config_setting_t *t)
+uint32 mob_read_db_mode_sub(struct mob_db *entry, struct config_setting_t *t)
{
- int mode = 0;
- config_setting_t *t2;
+ uint32 mode = 0;
+ struct config_setting_t *t2;
if ((t2 = libconfig->setting_get_member(t, "CanMove")))
- mode |= libconfig->setting_get_bool(t2) ? MD_CANMOVE : 0;
+ mode |= libconfig->setting_get_bool(t2) ? MD_CANMOVE : MD_NONE;
if ((t2 = libconfig->setting_get_member(t, "Looter")))
- mode |= libconfig->setting_get_bool(t2) ? MD_LOOTER : 0;
+ mode |= libconfig->setting_get_bool(t2) ? MD_LOOTER : MD_NONE;
if ((t2 = libconfig->setting_get_member(t, "Aggressive")))
- mode |= libconfig->setting_get_bool(t2) ? MD_AGGRESSIVE : 0;
+ mode |= libconfig->setting_get_bool(t2) ? MD_AGGRESSIVE : MD_NONE;
if ((t2 = libconfig->setting_get_member(t, "Assist")))
- mode |= libconfig->setting_get_bool(t2) ? MD_ASSIST : 0;
+ mode |= libconfig->setting_get_bool(t2) ? MD_ASSIST : MD_NONE;
if ((t2 = libconfig->setting_get_member(t, "CastSensorIdle")))
- mode |= libconfig->setting_get_bool(t2) ? MD_CASTSENSOR_IDLE : 0;
+ mode |= libconfig->setting_get_bool(t2) ? MD_CASTSENSOR_IDLE : MD_NONE;
if ((t2 = libconfig->setting_get_member(t, "Boss")))
- mode |= libconfig->setting_get_bool(t2) ? MD_BOSS : 0;
+ mode |= libconfig->setting_get_bool(t2) ? MD_BOSS : MD_NONE;
if ((t2 = libconfig->setting_get_member(t, "Plant")))
- mode |= libconfig->setting_get_bool(t2) ? MD_PLANT : 0;
+ mode |= libconfig->setting_get_bool(t2) ? MD_PLANT : MD_NONE;
if ((t2 = libconfig->setting_get_member(t, "CanAttack")))
- mode |= libconfig->setting_get_bool(t2) ? MD_CANATTACK : 0;
+ mode |= libconfig->setting_get_bool(t2) ? MD_CANATTACK : MD_NONE;
if ((t2 = libconfig->setting_get_member(t, "Detector")))
- mode |= libconfig->setting_get_bool(t2) ? MD_DETECTOR : 0;
+ mode |= libconfig->setting_get_bool(t2) ? MD_DETECTOR : MD_NONE;
if ((t2 = libconfig->setting_get_member(t, "CastSensorChase")))
- mode |= libconfig->setting_get_bool(t2) ? MD_CASTSENSOR_CHASE : 0;
+ mode |= libconfig->setting_get_bool(t2) ? MD_CASTSENSOR_CHASE : MD_NONE;
if ((t2 = libconfig->setting_get_member(t, "ChangeChase")))
- mode |= libconfig->setting_get_bool(t2) ? MD_CHANGECHASE : 0;
+ mode |= libconfig->setting_get_bool(t2) ? MD_CHANGECHASE : MD_NONE;
if ((t2 = libconfig->setting_get_member(t, "Angry")))
- mode |= libconfig->setting_get_bool(t2) ? MD_ANGRY : 0;
+ mode |= libconfig->setting_get_bool(t2) ? MD_ANGRY : MD_NONE;
if ((t2 = libconfig->setting_get_member(t, "ChangeTargetMelee")))
- mode |= libconfig->setting_get_bool(t2) ? MD_CHANGETARGET_MELEE : 0;
+ mode |= libconfig->setting_get_bool(t2) ? MD_CHANGETARGET_MELEE : MD_NONE;
if ((t2 = libconfig->setting_get_member(t, "ChangeTargetChase")))
- mode |= libconfig->setting_get_bool(t2) ? MD_CHANGETARGET_CHASE : 0;
+ mode |= libconfig->setting_get_bool(t2) ? MD_CHANGETARGET_CHASE : MD_NONE;
if ((t2 = libconfig->setting_get_member(t, "TargetWeak")))
- mode |= libconfig->setting_get_bool(t2) ? MD_TARGETWEAK : 0;
+ mode |= libconfig->setting_get_bool(t2) ? MD_TARGETWEAK : MD_NONE;
+ if ((t2 = libconfig->setting_get_member(t, "NoKnockback")))
+ mode |= libconfig->setting_get_bool(t2) ? MD_NOKNOCKBACK : MD_NONE;
- return mode;
+ return mode & MD_MASK;
}
/**
@@ -3762,13 +3830,14 @@ int mob_read_db_mode_sub(struct mob_db *entry, config_setting_t *t)
* (mob_id is expected to be already set).
* @param[in] t The libconfig entry.
*/
-void mob_read_db_mvpdrops_sub(struct mob_db *entry, config_setting_t *t)
+void mob_read_db_mvpdrops_sub(struct mob_db *entry, struct config_setting_t *t)
{
- config_setting_t *drop;
+ struct config_setting_t *drop;
int i = 0;
int idx = 0;
int i32;
+ nullpo_retv(entry);
while (idx < MAX_MVP_DROP && (drop = libconfig->setting_get_elem(t, i))) {
const char *name = config_setting_name(drop);
int rate_adjust = battle_config.item_rate_mvp;
@@ -3818,14 +3887,15 @@ void mob_read_db_mvpdrops_sub(struct mob_db *entry, config_setting_t *t)
* (mob_id, status.mode are expected to be already set).
* @param[in] t The libconfig entry.
*/
-void mob_read_db_drops_sub(struct mob_db *entry, config_setting_t *t)
+void mob_read_db_drops_sub(struct mob_db *entry, struct config_setting_t *t)
{
- config_setting_t *drop;
+ struct config_setting_t *drop;
int i = 0;
int idx = 0;
int i32;
int k;
+ nullpo_retv(entry);
while (idx < MAX_MOB_DROP && (drop = libconfig->setting_get_elem(t, i))) {
const char *name = config_setting_name(drop);
int rate_adjust, type;
@@ -3947,6 +4017,7 @@ int mob_db_validate_entry(struct mob_db *entry, int n, const char *source)
{
struct mob_data data;
+ nullpo_ret(entry);
if (entry->mob_id <= 1000 || entry->mob_id > MAX_MOB_DB) {
ShowError("mob_db_validate_entry: Invalid monster ID %d, must be in range %d-%d.\n", entry->mob_id, 1000, MAX_MOB_DB);
return 0;
@@ -4045,10 +4116,10 @@ int mob_db_validate_entry(struct mob_db *entry, int n, const char *source)
* validation errors.
* @return Mob ID of the validated entry, or 0 in case of failure.
*/
-int mob_read_db_sub(config_setting_t *mobt, int n, const char *source)
+int mob_read_db_sub(struct config_setting_t *mobt, int n, const char *source)
{
struct mob_db md = { 0 };
- config_setting_t *t = NULL;
+ struct config_setting_t *t = NULL;
const char *str = NULL;
int i32 = 0;
bool inherit = false;
@@ -4100,6 +4171,7 @@ int mob_read_db_sub(config_setting_t *mobt, int n, const char *source)
* ChangeTargetMelee: true/false
* ChangeTargetChase: true/false
* TargetWeak: true/false
+ * NoKnockback: true/false
* }
* MoveSpeed: move speed
* AttackDelay: attack delay
@@ -4121,7 +4193,7 @@ int mob_read_db_sub(config_setting_t *mobt, int n, const char *source)
return 0;
}
md.mob_id = i32;
- md.vd.class_ = md.mob_id;
+ md.vd.class = md.mob_id;
if ((t = libconfig->setting_get_member(mobt, "Inherit")) && (inherit = libconfig->setting_get_bool(t))) {
if (!mob->db_data[md.mob_id]) {
@@ -4276,7 +4348,7 @@ int mob_read_db_sub(config_setting_t *mobt, int n, const char *source)
if (config_setting_is_group(t)) {
md.status.mode = mob->read_db_mode_sub(&md, t);
} else if (mob->lookup_const(mobt, "Mode", &i32) && i32 >= 0) {
- md.status.mode = i32;
+ md.status.mode = (uint32)i32 & MD_MASK;
}
}
if (!battle_config.monster_active_enable)
@@ -4353,12 +4425,12 @@ int mob_read_db_sub(config_setting_t *mobt, int n, const char *source)
* @param[in] source Source of the entry (file name), to be displayed in
* case of validation errors.
*/
-void mob_read_db_additional_fields(struct mob_db *entry, config_setting_t *t, int n, const char *source)
+void mob_read_db_additional_fields(struct mob_db *entry, struct config_setting_t *t, int n, const char *source)
{
// do nothing. plugins can do own work
}
-bool mob_lookup_const(const config_setting_t *it, const char *name, int *value)
+bool mob_lookup_const(const struct config_setting_t *it, const char *name, int *value)
{
if (libconfig->setting_lookup_int(it, name, value))
{
@@ -4376,9 +4448,11 @@ bool mob_lookup_const(const config_setting_t *it, const char *name, int *value)
return false;
}
-bool mob_get_const(const config_setting_t *it, int *value)
+bool mob_get_const(const struct config_setting_t *it, int *value)
{
const char *str = config_setting_get_string(it);
+
+ nullpo_retr(false, value);
if (str && *str && script->get_constant(str, value))
return true;
@@ -4413,10 +4487,10 @@ void mob_readdb(void) {
int mob_read_libconfig(const char *filename, bool ignore_missing)
{
bool duplicate[MAX_MOB_DB] = { 0 };
- config_t mob_db_conf;
+ struct config_t mob_db_conf;
char filepath[256];
- config_setting_t *mdb;
- config_setting_t *t;
+ struct config_setting_t *mdb;
+ struct config_setting_t *t;
int i = 0, count = 0;
nullpo_ret(filename);
@@ -4425,7 +4499,10 @@ int mob_read_libconfig(const char *filename, bool ignore_missing)
if (ignore_missing && !exists(filepath))
return 0;
- if (libconfig->read_file(&mob_db_conf, filepath) || !(mdb = libconfig->setting_get_member(mob_db_conf.root, "mob_db"))) {
+ if (!libconfig->load_file(&mob_db_conf, filepath))
+ return 0;
+
+ if ((mdb = libconfig->setting_get_member(mob_db_conf.root, "mob_db")) == NULL) {
ShowError("can't read %s\n", filepath);
return 0;
}
@@ -4470,8 +4547,9 @@ void mob_name_constants(void) {
*------------------------------------------*/
bool mob_readdb_mobavail(char* str[], int columns, int current)
{
- int class_, k;
+ int class_, view_class;
+ nullpo_retr(false, str);
class_=atoi(str[0]);
if(mob->db(class_) == mob->dummy) {
@@ -4480,13 +4558,13 @@ bool mob_readdb_mobavail(char* str[], int columns, int current)
return false;
}
- k=atoi(str[1]);
+ view_class = atoi(str[1]);
memset(&mob->db_data[class_]->vd, 0, sizeof(struct view_data));
- mob->db_data[class_]->vd.class_=k;
+ mob->db_data[class_]->vd.class = view_class;
//Player sprites
- if(pc->db_checkid(k) && columns==12) {
+ if (pc->db_checkid(view_class) && columns == 12) {
mob->db_data[class_]->vd.sex=atoi(str[2]);
mob->db_data[class_]->vd.hair_style=atoi(str[3]);
mob->db_data[class_]->vd.hair_color=atoi(str[4]);
@@ -4583,6 +4661,8 @@ bool mob_parse_row_chatdb(char** str, const char* source, int line, int* last_ms
int msg_id;
size_t len;
+ nullpo_retr(false, str);
+ nullpo_retr(false, last_msg_id);
msg_id = atoi(str[0]);
if (msg_id <= 0 || msg_id > MAX_MOB_CHAT)
@@ -4671,7 +4751,7 @@ void mob_readchatdb(void) {
if( j < 2 || str[2]==NULL)
{
- ShowError("mob_readchatdb: Insufficient number of fields for skill at %s, line %d\n", arc, lines);
+ ShowError("mob_readchatdb: Insufficient number of fields for skill at %s, line %u\n", arc, lines);
continue;
}
@@ -4767,6 +4847,7 @@ bool mob_parse_row_mobskilldb(char** str, int columns, int current)
int i =0, j, tmp;
uint16 sidx = 0;
+ nullpo_retr(false, str);
mob_id = atoi(str[0]);
if (mob_id > 0 && mob->db(mob_id) == mob->dummy)
@@ -4891,19 +4972,23 @@ bool mob_parse_row_mobskilldb(char** str, int columns, int current)
ms->val[3]=(int)strtol(str[15],NULL,0);
ms->val[4]=(int)strtol(str[16],NULL,0);
- if(ms->skill_id == NPC_EMOTION && mob_id>0 &&
- ms->val[1] == mob->db(mob_id)->status.mode)
- {
- ms->val[1] = 0;
+ if (ms->skill_id == NPC_EMOTION) {
+ ms->val[1] &= MD_MASK;
+ ms->val[2] &= MD_MASK;
+ ms->val[3] &= MD_MASK;
+ }
+ if (ms->skill_id == NPC_EMOTION && mob_id > 0
+ && (uint32)ms->val[1] == mob->db(mob_id)->status.mode) {
+ ms->val[1] = MD_NONE;
ms->val[4] = 1; //request to return mode to normal.
}
- if (ms->skill_id == NPC_EMOTION_ON && mob_id>0 && ms->val[1]) {
+ if (ms->skill_id == NPC_EMOTION_ON && mob_id>0 && ms->val[1] != MD_NONE) {
//Adds a mode to the mob.
//Remove aggressive mode when the new mob type is passive.
if (!(ms->val[1]&MD_AGGRESSIVE))
- ms->val[3]|=MD_AGGRESSIVE;
- ms->val[2]|= ms->val[1]; //Add the new mode.
- ms->val[1] = 0; //Do not "set" it.
+ ms->val[3] |= MD_AGGRESSIVE;
+ ms->val[2] |= (uint32)ms->val[1]; //Add the new mode.
+ ms->val[1] = MD_NONE; //Do not "set" it.
}
if(*str[17])
@@ -4961,7 +5046,7 @@ void mob_readskilldb(void) {
for( fi = 0; fi < ARRAYLENGTH(filename); ++fi ) {
if(fi > 0) {
char filepath[256];
- sprintf(filepath, "%s/%s", map->db_path, filename[fi]);
+ snprintf(filepath, 256, "%s/%s", map->db_path, filename[fi]);
if(!exists(filepath)) {
continue;
}
@@ -4978,6 +5063,7 @@ bool mob_readdb_race2(char* fields[], int columns, int current)
{
int race, i;
+ nullpo_retr(false, fields);
race = atoi(fields[0]);
if (race < RC2_NONE || race >= RC2_MAX) {
@@ -5002,6 +5088,8 @@ bool mob_readdb_race2(char* fields[], int columns, int current)
bool mob_readdb_itemratio(char* str[], int columns, int current)
{
int nameid, ratio, i;
+
+ nullpo_retr(false, str);
nameid = atoi(str[0]);
if( itemdb->exists(nameid) == NULL )
@@ -5103,7 +5191,9 @@ int do_init_mob(bool minimal) {
void mob_destroy_mob_db(int index)
{
- struct mob_db *data = mob->db_data[index];
+ struct mob_db *data;
+ Assert_retv(index >= 0 && index <= MAX_MOB_DB);
+ data = mob->db_data[index];
HPM->data_store_destroy(&data->hdata);
aFree(data);
mob->db_data[index] = NULL;