diff options
Diffstat (limited to 'src/map/mob.c')
-rw-r--r-- | src/map/mob.c | 855 |
1 files changed, 481 insertions, 374 deletions
diff --git a/src/map/mob.c b/src/map/mob.c index 74d25b805..d82e49bcc 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-2016 Hercules Dev Team + * Copyright (C) 2012-2018 Hercules Dev Team * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify @@ -44,6 +44,7 @@ #include "map/script.h" #include "map/skill.h" #include "map/status.h" +#include "map/achievement.h" #include "common/HPM.h" #include "common/cbasetypes.h" #include "common/conf.h" @@ -64,7 +65,7 @@ #include <stdlib.h> #include <string.h> -struct mob_interface mob_s; +static struct mob_interface mob_s; struct mob_interface *mob; #define ACTIVE_AI_RANGE 2 //Distance added on top of 'AREA_SIZE' at which mobs enter active AI mode. @@ -88,6 +89,7 @@ struct item_drop_ratio { int mob_id[MAX_ITEMRATIO_MOBS]; }; static struct item_drop_ratio *item_drop_ratio_db[MAX_ITEMDB]; +static struct DBMap *item_drop_ratio_other_db = NULL; static struct eri *item_drop_ers; //For loot drops delay structures. static struct eri *item_drop_list_ers; @@ -97,12 +99,14 @@ static struct { int class_[350]; } summon[MAX_RANDOMMONSTER]; -struct mob_db *mob_db(int index) { +static struct mob_db *mob_db(int index) +{ if (index < 0 || index > MAX_MOB_DB || mob->db_data[index] == NULL) return mob->dummy; return mob->db_data[index]; } -struct mob_chat *mob_chat(short id) { +static struct mob_chat *mob_chat(short id) +{ if(id <= 0 || id > MAX_MOB_CHAT || mob->chat_db[id] == NULL) return NULL; return mob->chat_db[id]; @@ -111,7 +115,7 @@ struct mob_chat *mob_chat(short id) { /*========================================== * Mob is searched with a name. *------------------------------------------*/ -int mobdb_searchname(const char *str) +static int mobdb_searchname(const char *str) { int i; @@ -130,7 +134,8 @@ int mobdb_searchname(const char *str) return 0; } -int mobdb_searchname_array_sub(struct mob_db* monster, const char *str, int flag) { +static int mobdb_searchname_array_sub(struct mob_db *monster, const char *str, int flag) +{ nullpo_ret(monster); if (monster == mob->dummy) @@ -157,7 +162,45 @@ int mobdb_searchname_array_sub(struct mob_db* monster, const char *str, int flag /*========================================== * MvP Tomb [GreenBox] *------------------------------------------*/ -void mvptomb_create(struct mob_data *md, char *killer, time_t time) + /// Creates a timer to spawn a tomb + /// @param nd : The tomb +static void mvptomb_spawn_delayed(struct npc_data *nd) +{ + nullpo_retv(nd); + + if (nd->u.tomb.spawn_timer != INVALID_TIMER) + timer->delete(nd->u.tomb.spawn_timer, mob->mvptomb_delayspawn); + + nd->u.tomb.spawn_timer = timer->add(timer->gettick() + battle_config.mvp_tomb_spawn_delay, mob->mvptomb_delayspawn, nd->bl.id, 0); +} + +/// Spawns a tomb after the delay has ended +/// @param tid : Timer id +/// @param tick : current tick +/// @param id : NPC Id +/// @param data : 0 +static int mvptomb_delayspawn(int tid, int64 tick, int id, intptr_t data) +{ + struct npc_data *nd = map->id2nd(id); + + if (nd == NULL) + return 0; + + if (nd->u.tomb.spawn_timer != tid) { + ShowError("mvptomb_delay_spawn: Timer mismatch: %d != %d\n", tid, nd->u.tomb.spawn_timer); + return 0; + } + + nd->u.tomb.spawn_timer = INVALID_TIMER; + + // Sets view data to make the tomb visible and notifies client + status->set_viewdata(&nd->bl, nd->class_); + clif->spawn(&(nd->bl)); + + return 0; +} + +static void mvptomb_create(struct mob_data *md, char *killer, time_t time) { struct npc_data *nd; @@ -172,6 +215,7 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time) nd->u.tomb.md = md; nd->u.tomb.kill_time = time; + nd->u.tomb.spawn_timer = INVALID_TIMER; if (killer) safestrncpy(nd->u.tomb.killer_name, killer, NAME_LENGTH); @@ -180,11 +224,13 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time) map->addnpc(nd->bl.m, nd); map->addblock(&nd->bl); - status->set_viewdata(&nd->bl, nd->class_); - clif->spawn(&nd->bl); + + // Tomb npc is created but not yet visible, we set view data and spawn it after some time + mob->mvptomb_spawn_delayed(nd); } -void mvptomb_destroy(struct mob_data *md) { +static void mvptomb_destroy(struct mob_data *md) +{ struct npc_data *nd; nullpo_retv(md); @@ -204,6 +250,9 @@ void mvptomb_destroy(struct mob_data *md) { map->list[m].npc[map->list[m].npc_num] = NULL; } + if (nd->u.tomb.spawn_timer != INVALID_TIMER) + timer->delete(nd->u.tomb.spawn_timer, mob->mvptomb_delayspawn); + map->deliddb(&nd->bl); aFree(nd); @@ -215,7 +264,7 @@ void mvptomb_destroy(struct mob_data *md) { /*========================================== * Founds up to N matches. Returns number of matches [Skotlex] *------------------------------------------*/ -int mobdb_searchname_array(struct mob_db** data, int size, const char *str, int flag) +static int mobdb_searchname_array(struct mob_db **data, int size, const char *str, int flag) { int count = 0, i; struct mob_db* monster; @@ -236,7 +285,7 @@ int mobdb_searchname_array(struct mob_db** data, int size, const char *str, int /*========================================== * Id Mob is checked. *------------------------------------------*/ -int mobdb_checkid(const int id) +static int mobdb_checkid(const int id) { if (mob->db(id) == mob->dummy) return 0; @@ -248,7 +297,7 @@ int mobdb_checkid(const int id) /*========================================== * Returns the view data associated to this mob class. *------------------------------------------*/ -struct view_data * mob_get_viewdata(int class_) +static struct view_data *mob_get_viewdata(int class_) { if (mob->db(class_) == mob->dummy) return 0; @@ -257,7 +306,7 @@ struct view_data * mob_get_viewdata(int class_) /*========================================== * Cleans up mob-spawn data to make it "valid" *------------------------------------------*/ -int mob_parse_dataset(struct spawn_data *data) +static int mob_parse_dataset(struct spawn_data *data) { size_t len; @@ -273,9 +322,9 @@ int mob_parse_dataset(struct spawn_data *data) memmove(data->eventname, data->eventname+1, len-1); } - if(strcmp(data->name,"--en--")==0) + if (strcmp(data->name, DEFAULT_MOB_NAME) == 0) safestrncpy(data->name, mob->db(data->class_)->name, sizeof(data->name)); - else if(strcmp(data->name,"--ja--")==0) + else if (strcmp(data->name, DEFAULT_MOB_JNAME) == 0) safestrncpy(data->name, mob->db(data->class_)->jname, sizeof(data->name)); return 1; @@ -283,7 +332,8 @@ int mob_parse_dataset(struct spawn_data *data) /*========================================== * Generates the basic mob data using the spawn_data provided. *------------------------------------------*/ -struct mob_data* mob_spawn_dataset(struct spawn_data *data) { +static 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); @@ -330,7 +380,7 @@ struct mob_data* mob_spawn_dataset(struct spawn_data *data) { * &8: Selected monster must have normal spawn. * lv: Mob level to check against *------------------------------------------*/ -int mob_get_random_id(int type, int flag, int lv) +static int mob_get_random_id(int type, int flag, int lv) { struct mob_db *monster; int i=0, class_; @@ -361,7 +411,8 @@ int mob_get_random_id(int type, int flag, int lv) /*========================================== * Kill Steal Protection [Zephyrus] *------------------------------------------*/ -bool mob_ksprotected(struct block_list *src, struct block_list *target) { +static bool mob_ksprotected(struct block_list *src, struct block_list *target) +{ struct block_list *s_bl, *t_bl; struct map_session_data *sd, // Source @@ -444,7 +495,7 @@ bool mob_ksprotected(struct block_list *src, struct block_list *target) { return false; } -struct mob_data *mob_once_spawn_sub(struct block_list *bl, int16 m, int16 x, int16 y, const char *mobname, int class_, const char *event, unsigned int size, unsigned int ai) +static struct mob_data *mob_once_spawn_sub(struct block_list *bl, int16 m, int16 x, int16 y, const char *mobname, int class_, const char *event, unsigned int size, unsigned int ai) { struct spawn_data data; @@ -455,13 +506,12 @@ struct mob_data *mob_once_spawn_sub(struct block_list *bl, int16 m, int16 x, int data.state.size = size; data.state.ai = ai; - if (mobname) + if (mobname != NULL) safestrncpy(data.name, mobname, sizeof(data.name)); + else if (battle_config.override_mob_names == 1) + strcpy(data.name, DEFAULT_MOB_NAME); else - if (battle_config.override_mob_names == 1) - strcpy(data.name, "--en--"); - else - strcpy(data.name, "--ja--"); + strcpy(data.name, DEFAULT_MOB_JNAME); if (event) safestrncpy(data.eventname, event, sizeof(data.eventname)); @@ -486,7 +536,8 @@ struct mob_data *mob_once_spawn_sub(struct block_list *bl, int16 m, int16 x, int /*========================================== * Spawn a single mob on the specified coordinates. *------------------------------------------*/ -int mob_once_spawn(struct map_session_data* sd, int16 m, int16 x, int16 y, const char* mobname, int class_, int amount, const char* event, unsigned int size, unsigned int ai) { +static int mob_once_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, const char *mobname, int class_, int amount, const char *event, unsigned int size, unsigned int ai) +{ struct mob_data* md = NULL; int count, lv; bool no_guardian_data = false; @@ -537,7 +588,7 @@ int mob_once_spawn(struct map_session_data* sd, int16 m, int16 x, int16 y, const /*========================================== * Spawn mobs in the specified area. *------------------------------------------*/ -int mob_once_spawn_area(struct map_session_data* sd, int16 m, int16 x0, int16 y0, int16 x1, int16 y1, const char* mobname, int class_, int amount, const char* event, unsigned int size, unsigned int ai) +static int mob_once_spawn_area(struct map_session_data *sd, int16 m, int16 x0, int16 y0, int16 x1, int16 y1, const char *mobname, int class_, int amount, const char *event, unsigned int size, unsigned int ai) { int i, max, id = 0; int lx = -1, ly = -1; @@ -595,7 +646,8 @@ int mob_once_spawn_area(struct map_session_data* sd, int16 m, int16 x0, int16 y0 * @retval Always 0 * @author Skotlex **/ -int mob_spawn_guardian_sub(int tid, int64 tick, int id, intptr_t data) { +static int mob_spawn_guardian_sub(int tid, int64 tick, int id, intptr_t data) +{ //Needed because the guild data may not be available at guardian spawn time. struct block_list* bl = map->id2bl(id); struct mob_data* md; @@ -638,7 +690,7 @@ int mob_spawn_guardian_sub(int tid, int64 tick, int id, intptr_t data) { /*========================================== * Summoning Guardians [Valaris] *------------------------------------------*/ -int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobname, int class_, const char* event, int guardian, bool has_index) +static int mob_spawn_guardian(const char *mapname, short x, short y, const char *mobname, int class_, const char *event, int guardian, bool has_index) { struct mob_data *md=NULL; struct spawn_data data; @@ -738,7 +790,7 @@ int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobnam /*========================================== * Summoning BattleGround [Zephyrus] *------------------------------------------*/ -int mob_spawn_bg(const char* mapname, short x, short y, const char* mobname, int class_, const char* event, unsigned int bg_id) +static int mob_spawn_bg(const char *mapname, short x, short y, const char *mobname, int class_, const char *event, unsigned int bg_id) { struct mob_data *md = NULL; struct spawn_data data; @@ -789,7 +841,7 @@ int mob_spawn_bg(const char* mapname, short x, short y, const char* mobname, int * - MSS_RUSH: Chasing attacking player, path is complex * - MSS_FOLLOW: Initiative/support seek, path is complex *------------------------------------------*/ -int mob_can_reach(struct mob_data *md,struct block_list *bl,int range, int state) +static int mob_can_reach(struct mob_data *md, struct block_list *bl, int range, int state) { int easy = 0; @@ -811,7 +863,7 @@ int mob_can_reach(struct mob_data *md,struct block_list *bl,int range, int state /*========================================== * Links nearby mobs (supportive mobs) *------------------------------------------*/ -int mob_linksearch(struct block_list *bl,va_list ap) +static int mob_linksearch(struct block_list *bl, va_list ap) { struct mob_data *md = NULL; int class_ = va_arg(ap, int); @@ -840,7 +892,8 @@ int mob_linksearch(struct block_list *bl,va_list ap) /*========================================== * mob spawn with delay (timer function) *------------------------------------------*/ -int mob_delayspawn(int tid, int64 tick, int id, intptr_t data) { +static int mob_delayspawn(int tid, int64 tick, int id, intptr_t data) +{ struct block_list* bl = map->id2bl(id); // TODO: Why does this not use map->bl2md? struct mob_data* md = BL_CAST(BL_MOB, bl); @@ -860,7 +913,7 @@ int mob_delayspawn(int tid, int64 tick, int id, intptr_t data) { /*========================================== * spawn timing calculation *------------------------------------------*/ -int mob_setdelayspawn(struct mob_data *md) +static int mob_setdelayspawn(struct mob_data *md) { unsigned int spawntime; uint32 mode; @@ -904,7 +957,8 @@ int mob_setdelayspawn(struct mob_data *md) return 0; } -int mob_count_sub(struct block_list *bl, va_list ap) { +static int mob_count_sub(struct block_list *bl, va_list ap) +{ int mobid[10] = { 0 }, i; ARR_FIND(0, 10, i, (mobid[i] = va_arg(ap, int)) == 0); //fetch till 0 if (mobid[0]) { //if there one let's check it otherwise go backward @@ -919,7 +973,7 @@ int mob_count_sub(struct block_list *bl, va_list ap) { /*========================================== * Mob spawning. Initialization is also variously here. *------------------------------------------*/ -int mob_spawn (struct mob_data *md) +static int mob_spawn(struct mob_data *md) { int i=0; int64 tick = timer->gettick(); @@ -1013,7 +1067,7 @@ int mob_spawn (struct mob_data *md) /*========================================== * Determines if the mob can change target. [Skotlex] *------------------------------------------*/ -int mob_can_changetarget(const struct mob_data *md, const struct block_list *target, uint32 mode) +static int mob_can_changetarget(const struct mob_data *md, const struct block_list *target, uint32 mode) { nullpo_ret(md); nullpo_ret(target); @@ -1047,7 +1101,7 @@ int mob_can_changetarget(const struct mob_data *md, const struct block_list *tar /*========================================== * Determination for an attack of a monster *------------------------------------------*/ -int mob_target(struct mob_data *md,struct block_list *bl,int dist) +static int mob_target(struct mob_data *md, struct block_list *bl, int dist) { nullpo_ret(md); nullpo_ret(bl); @@ -1071,7 +1125,7 @@ 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) +static int mob_ai_sub_hard_activesearch(struct block_list *bl, va_list ap) { struct mob_data *md; struct block_list **target; @@ -1134,7 +1188,8 @@ int mob_ai_sub_hard_activesearch(struct block_list *bl, va_list ap) /*========================================== * chase target-change routine. *------------------------------------------*/ -int mob_ai_sub_hard_changechase(struct block_list *bl,va_list ap) { +static int mob_ai_sub_hard_changechase(struct block_list *bl, va_list ap) +{ struct mob_data *md; struct block_list **target; @@ -1162,7 +1217,8 @@ int mob_ai_sub_hard_changechase(struct block_list *bl,va_list ap) { /*========================================== * finds nearby bg ally for guardians looking for users to follow. *------------------------------------------*/ -int mob_ai_sub_hard_bg_ally(struct block_list *bl,va_list ap) { +static int mob_ai_sub_hard_bg_ally(struct block_list *bl, va_list ap) +{ struct mob_data *md; struct block_list **target; @@ -1181,7 +1237,7 @@ int mob_ai_sub_hard_bg_ally(struct block_list *bl,va_list ap) { /*========================================== * loot monster item search *------------------------------------------*/ -int mob_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap) +static int mob_ai_sub_hard_lootsearch(struct block_list *bl, va_list ap) { struct mob_data* md; struct block_list **target; @@ -1203,7 +1259,8 @@ int mob_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap) return 0; } -int mob_warpchase_sub(struct block_list *bl,va_list ap) { +static int mob_warpchase_sub(struct block_list *bl, va_list ap) +{ int cur_distance; struct block_list *target = va_arg(ap, struct block_list *); struct npc_data **target_nd = va_arg(ap, struct npc_data **); @@ -1235,7 +1292,8 @@ int mob_warpchase_sub(struct block_list *bl,va_list ap) { /*========================================== * Processing of slave monsters *------------------------------------------*/ -int mob_ai_sub_hard_slavemob(struct mob_data *md, int64 tick) { +static int mob_ai_sub_hard_slavemob(struct mob_data *md, int64 tick) +{ struct block_list *bl; nullpo_ret(md); @@ -1318,7 +1376,8 @@ int mob_ai_sub_hard_slavemob(struct mob_data *md, int64 tick) { * when trying to pick new targets when the current chosen target is * unreachable. *------------------------------------------*/ -int mob_unlocktarget(struct mob_data *md, int64 tick) { +static int mob_unlocktarget(struct mob_data *md, int64 tick) +{ nullpo_ret(md); switch (md->state.skillstate) { @@ -1354,7 +1413,7 @@ int mob_unlocktarget(struct mob_data *md, int64 tick) { md->ud.target_to = 0; unit->set_target(&md->ud, 0); } - if(battle_config.official_cell_stack_limit && map->count_oncell(md->bl.m, md->bl.x, md->bl.y, BL_CHAR|BL_NPC, 1) > battle_config.official_cell_stack_limit) { + if(battle_config.official_cell_stack_limit && map->count_oncell(md->bl.m, md->bl.x, md->bl.y, BL_CHAR|BL_NPC, 0x1 | 0x2) > battle_config.official_cell_stack_limit) { unit->walktoxy(&md->bl, md->bl.x, md->bl.y, 8); } @@ -1363,7 +1422,8 @@ int mob_unlocktarget(struct mob_data *md, int64 tick) { /*========================================== * Random walk *------------------------------------------*/ -int mob_randomwalk(struct mob_data *md, int64 tick) { +static int mob_randomwalk(struct mob_data *md, int64 tick) +{ const int retrycount=20; int i,c,d; int speed; @@ -1413,7 +1473,7 @@ int mob_randomwalk(struct mob_data *md, int64 tick) { return 1; } -int mob_warpchase(struct mob_data *md, struct block_list *target) +static int mob_warpchase(struct mob_data *md, struct block_list *target) { struct npc_data *warp = NULL; int distance = AREA_SIZE; @@ -1440,7 +1500,8 @@ int mob_warpchase(struct mob_data *md, struct block_list *target) /*========================================== * AI of MOB whose is near a Player *------------------------------------------*/ -bool mob_ai_sub_hard(struct mob_data *md, int64 tick) { +static bool mob_ai_sub_hard(struct mob_data *md, int64 tick) +{ struct block_list *tbl = NULL, *abl = NULL; uint32 mode; int view_range, can_move; @@ -1720,7 +1781,7 @@ bool mob_ai_sub_hard(struct mob_data *md, int64 tick) { return true; } -int mob_ai_sub_hard_timer(struct block_list *bl, va_list ap) +static int mob_ai_sub_hard_timer(struct block_list *bl, va_list ap) { struct mob_data *md = NULL; int64 tick = va_arg(ap, int64); @@ -1741,7 +1802,8 @@ int mob_ai_sub_hard_timer(struct block_list *bl, va_list ap) /*========================================== * Serious processing for mob in PC field of view (foreachclient) *------------------------------------------*/ -int mob_ai_sub_foreachclient(struct map_session_data *sd, va_list ap) { +static int mob_ai_sub_foreachclient(struct map_session_data *sd, va_list ap) +{ int64 tick; nullpo_ret(sd); tick=va_arg(ap, int64); @@ -1753,7 +1815,8 @@ int mob_ai_sub_foreachclient(struct map_session_data *sd, va_list ap) { /*========================================== * Negligent mode MOB AI (PC is not in near) *------------------------------------------*/ -int mob_ai_sub_lazy(struct mob_data *md, va_list args) { +static int mob_ai_sub_lazy(struct mob_data *md, va_list args) +{ int64 tick; nullpo_ret(md); @@ -1817,7 +1880,8 @@ int mob_ai_sub_lazy(struct mob_data *md, va_list args) { /*========================================== * Negligent processing for mob outside PC field of view (interval timer function) *------------------------------------------*/ -int mob_ai_lazy(int tid, int64 tick, int id, intptr_t data) { +static int mob_ai_lazy(int tid, int64 tick, int id, intptr_t data) +{ map->foreachmob(mob->ai_sub_lazy,tick); return 0; } @@ -1825,7 +1889,8 @@ int mob_ai_lazy(int tid, int64 tick, int id, intptr_t data) { /*========================================== * Serious processing for mob in PC field of view (interval timer function) *------------------------------------------*/ -int mob_ai_hard(int tid, int64 tick, int id, intptr_t data) { +static int mob_ai_hard(int tid, int64 tick, int id, intptr_t data) +{ if (battle_config.mob_ai&0x20) map->foreachmob(mob->ai_sub_lazy,tick); @@ -1838,11 +1903,13 @@ int mob_ai_hard(int tid, int64 tick, int id, intptr_t data) { /*========================================== * Initializes the delay drop structure for mob-dropped items. *------------------------------------------*/ -struct item_drop* mob_setdropitem(int nameid, int qty, struct item_data *data) { +static struct item_drop *mob_setdropitem(int nameid, int qty, struct item_data *data) +{ struct item_drop *drop = ers_alloc(item_drop_ers, struct item_drop); drop->item_data.nameid = nameid; drop->item_data.amount = qty; drop->item_data.identify = data ? itemdb->isidentified2(data) : itemdb->isidentified(nameid); + drop->showdropeffect = true; drop->next = NULL; return drop; } @@ -1850,13 +1917,14 @@ struct item_drop* mob_setdropitem(int nameid, int qty, struct item_data *data) { /*========================================== * Initializes the delay drop structure for mob-looted items. *------------------------------------------*/ -struct item_drop* mob_setlootitem(struct item* item) +static struct item_drop *mob_setlootitem(struct item *item) { 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->showdropeffect = false; drop->next = NULL; return drop; } @@ -1864,7 +1932,8 @@ struct item_drop* mob_setlootitem(struct item* item) /*========================================== * item drop with delay (timer function) *------------------------------------------*/ -int mob_delay_item_drop(int tid, int64 tick, int id, intptr_t data) { +static int mob_delay_item_drop(int tid, int64 tick, int id, intptr_t data) +{ struct item_drop_list *list; struct item_drop *ditem; list=(struct item_drop_list *)data; @@ -1872,8 +1941,9 @@ int mob_delay_item_drop(int tid, int64 tick, int id, intptr_t data) { while (ditem) { struct item_drop *ditem_prev; map->addflooritem(NULL, &ditem->item_data,ditem->item_data.amount, - list->m,list->x,list->y, - list->first_charid,list->second_charid,list->third_charid,0); + list->m,list->x,list->y, + list->first_charid,list->second_charid,list->third_charid,0, + ditem->showdropeffect); ditem_prev = ditem; ditem = ditem->next; ers_free(item_drop_ers, ditem_prev); @@ -1888,7 +1958,7 @@ int mob_delay_item_drop(int tid, int64 tick, int id, intptr_t data) { * rate is the drop-rate of the item, required for autoloot. * flag : Killed only by homunculus? *------------------------------------------*/ -void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, struct item_drop *ditem, int loot, int drop_rate, unsigned short flag) +static void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, struct item_drop *ditem, int loot, int drop_rate, unsigned short flag) { struct map_session_data *sd = NULL; @@ -1904,6 +1974,7 @@ void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, struct ite if( sd && (drop_rate <= sd->state.autoloot || pc->isautolooting(sd, ditem->item_data.nameid)) + && (!map->list[sd->bl.m].flag.noautoloot) && (battle_config.idle_no_autoloot == 0 || DIFF_TICK(sockt->last_tick, sd->idletime) < battle_config.idle_no_autoloot) && (battle_config.homunculus_autoloot?1:!flag) #ifdef AUTOLOOT_DISTANCE @@ -1923,7 +1994,8 @@ void mob_item_drop(struct mob_data *md, struct item_drop_list *dlist, struct ite dlist->item = ditem; } -int mob_timer_delete(int tid, int64 tick, int id, intptr_t data) { +static int mob_timer_delete(int tid, int64 tick, int id, intptr_t data) +{ struct block_list* bl = map->id2bl(id); // TODO: Why does this not use map->id2md? struct mob_data* md = BL_CAST(BL_MOB, bl); @@ -1944,7 +2016,7 @@ int mob_timer_delete(int tid, int64 tick, int id, intptr_t data) { /*========================================== * *------------------------------------------*/ -int mob_deleteslave_sub(struct block_list *bl,va_list ap) +static int mob_deleteslave_sub(struct block_list *bl, va_list ap) { struct mob_data *md = NULL; int id = va_arg(ap, int); @@ -1961,14 +2033,16 @@ int mob_deleteslave_sub(struct block_list *bl,va_list ap) /*========================================== * *------------------------------------------*/ -int mob_deleteslave(struct mob_data *md) { +static int mob_deleteslave(struct mob_data *md) +{ nullpo_ret(md); map->foreachinmap(mob->deleteslave_sub, md->bl.m, BL_MOB,md->bl.id); return 0; } // Mob respawning through KAIZEL or NPC_REBIRTH [Skotlex] -int mob_respawn(int tid, int64 tick, int id, intptr_t data) { +static int mob_respawn(int tid, int64 tick, int id, intptr_t data) +{ struct block_list *bl = map->id2bl(id); if(!bl) return 0; @@ -1976,7 +2050,7 @@ int mob_respawn(int tid, int64 tick, int id, intptr_t data) { return 1; } -void mob_log_damage(struct mob_data *md, struct block_list *src, int damage) +static void mob_log_damage(struct mob_data *md, struct block_list *src, int damage) { int char_id = 0, flag = MDLF_NORMAL; @@ -2092,7 +2166,8 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage) return; } //Call when a mob has received damage. -void mob_damage(struct mob_data *md, struct block_list *src, int damage) { +static 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) @@ -2114,6 +2189,10 @@ void mob_damage(struct mob_data *md, struct block_list *src, int damage) { if (src) mob->log_damage(md, src, damage); md->dmgtick = timer->gettick(); + + // Achievements [Smokexyz/Hercules] + if (src != NULL && src->type == BL_PC) + achievement->validate_mob_damage(BL_UCAST(BL_PC, src), damage, false); } if (battle_config.show_mob_info&3) @@ -2146,11 +2225,13 @@ void mob_damage(struct mob_data *md, struct block_list *src, int damage) { * Signals death of mob. * type&1 -> no drops, type&2 -> no exp *------------------------------------------*/ -int mob_dead(struct mob_data *md, struct block_list *src, int type) { +static int mob_dead(struct mob_data *md, struct block_list *src, int type) +{ struct status_data *mstatus; 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; @@ -2344,6 +2425,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) { } if(zeny) // zeny from mobs [Valaris] pc->getzeny(tmpsd[i], zeny, LOG_TYPE_PICKDROP_MONSTER, NULL); + + if (!md->special_state.clone && !mob->is_clone(md->class_)) + achievement->validate_mob_kill(tmpsd[i], md->db->mob_id); // Achievements [Smokexyz/Hercules] } } @@ -2439,23 +2523,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, (int)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. */ - // TODO: This should be a field in the item db. - if (mvp_sd != NULL - && (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); @@ -2472,7 +2546,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) { if(sd) { // process script-granted extra drop bonuses int itemid = 0; - for (i = 0; i < ARRAYLENGTH(sd->add_drop) && (sd->add_drop[i].id || sd->add_drop[i].group); i++) + for (i = 0; i < ARRAYLENGTH(sd->add_drop) && (sd->add_drop[i].id != 0 || sd->add_drop[i].is_group); i++) { if ( sd->add_drop[i].race == -md->class_ || ( sd->add_drop[i].race > 0 && ( @@ -2494,7 +2568,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) { if (rnd()%10000 >= drop_rate) continue; - itemid = (sd->add_drop[i].id > 0) ? sd->add_drop[i].id : itemdb->chain_item(sd->add_drop[i].group,&drop_rate); + itemid = (!sd->add_drop[i].is_group) ? sd->add_drop[i].id : itemdb->chain_item(sd->add_drop[i].id, &drop_rate); if( itemid ) mob->item_drop(md, dlist, mob->setdropitem(itemid,1,NULL), 0, drop_rate, homkillonly); } @@ -2592,17 +2666,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) { clif->mvp_item(mvp_sd, item.nameid); log_mvp[0] = item.nameid; - //A Rare MVP Drop Global Announce by Lupus - if (rate <= battle_config.rare_drop_announce) { - char message[128]; - sprintf(message, msg_txt(541), mvp_sd->status.name, md->name, data->jname, rate/100.); - //MSG: "'%s' won %s's %s (chance: %0.02f%%)" - intif->broadcast(message, (int)strlen(message)+1, BC_DEFAULT); - } - 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); + 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, true); } //Logs items, MVP prizes [Lupus] @@ -2637,11 +2703,11 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) { if (++sd->mission_count >= 100 && (temp = mob->get_random_id(0, 0xE, sd->status.base_level)) != 0) { pc->addfame(sd, RANKTYPE_TAEKWON, 1); sd->mission_mobid = temp; - pc_setglobalreg(sd,script->add_str("TK_MISSION_ID"), temp); + pc_setglobalreg(sd,script->add_variable("TK_MISSION_ID"), temp); sd->mission_count = 0; clif->mission_info(sd, temp, 0); } - pc_setglobalreg(sd,script->add_str("TK_MISSION_COUNT"), sd->mission_count); + pc_setglobalreg(sd,script->add_variable("TK_MISSION_COUNT"), sd->mission_count); } if( sd->status.party_id ) @@ -2702,7 +2768,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) { return 5; // Note: Actually, it's 4. Oh well... // MvP tomb [GreenBox] - if (battle_config.mvp_tomb_enabled && md->spawn->state.boss && map->list[md->bl.m].flag.notomb != 1) + if (battle_config.mvp_tomb_enabled && md->spawn->state.boss == BTYPE_MVP && map->list[md->bl.m].flag.notomb != 1) mob->mvptomb_create(md, mvp_sd ? mvp_sd->status.name : NULL, time(NULL)); if( !rebirth ) { @@ -2712,7 +2778,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) { return 3; //Remove from map. } -void mob_revive(struct mob_data *md, unsigned int hp) +static void mob_revive(struct mob_data *md, unsigned int hp) { int64 tick = timer->gettick(); @@ -2733,7 +2799,7 @@ void mob_revive(struct mob_data *md, unsigned int hp) clif->charnameack (0, &md->bl); } -int mob_guardian_guildchange(struct mob_data *md) +static int mob_guardian_guildchange(struct mob_data *md) { struct guild *g; nullpo_ret(md); @@ -2772,7 +2838,7 @@ int mob_guardian_guildchange(struct mob_data *md) /*========================================== * Pick a random class for the mob *------------------------------------------*/ -int mob_random_class (int *value, size_t count) +static int mob_random_class(int *value, size_t count) { nullpo_ret(value); @@ -2794,7 +2860,8 @@ int mob_random_class (int *value, size_t count) /*========================================== * Change mob base class *------------------------------------------*/ -int mob_class_change (struct mob_data *md, int class_) { +static int mob_class_change(struct mob_data *md, int class_) +{ int64 tick = timer->gettick(), c = 0; int i, hp_rate; @@ -2862,7 +2929,7 @@ int mob_class_change (struct mob_data *md, int class_) { /*========================================== * mob heal, update display hp info of mob for players *------------------------------------------*/ -void mob_heal(struct mob_data *md, unsigned int heal) +static void mob_heal(struct mob_data *md, unsigned int heal) { nullpo_retv(md); if (battle_config.show_mob_info&3) @@ -2890,7 +2957,7 @@ void mob_heal(struct mob_data *md, unsigned int heal) /*========================================== * Added by RoVeRT *------------------------------------------*/ -int mob_warpslave_sub(struct block_list *bl, va_list ap) +static int mob_warpslave_sub(struct block_list *bl, va_list ap) { struct mob_data *md = NULL; struct block_list *master; @@ -2916,7 +2983,8 @@ int mob_warpslave_sub(struct block_list *bl, va_list ap) * Warps slaves. Range is the area around the master that they can * appear in randomly. *------------------------------------------*/ -int mob_warpslave(struct block_list *bl, int range) { +static 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] @@ -2927,7 +2995,7 @@ int mob_warpslave(struct block_list *bl, int range) { /*========================================== * Counts slave sub, currently checking if mob master is the given ID. *------------------------------------------*/ -int mob_countslave_sub(struct block_list *bl, va_list ap) +static int mob_countslave_sub(struct block_list *bl, va_list ap) { int id = va_arg(ap, int); struct mob_data *md = NULL; @@ -2944,7 +3012,8 @@ 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) { +static int mob_countslave(struct block_list *bl) +{ nullpo_ret(bl); return map->foreachinmap(mob->countslave_sub, bl->m, BL_MOB,bl->id); } @@ -2952,7 +3021,7 @@ int mob_countslave(struct block_list *bl) { /*========================================== * Summons amount slaves contained in the value[5] array using round-robin. [adapted by Skotlex] *------------------------------------------*/ -int mob_summonslave(struct mob_data *md2,int *value,int amount,uint16 skill_id) +static int mob_summonslave(struct mob_data *md2, int *value, int amount, uint16 skill_id) { struct mob_data *md; struct spawn_data data; @@ -3002,10 +3071,10 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,uint16 skill_id) } //These two need to be loaded from the db for each slave. - if(battle_config.override_mob_names==1) - strcpy(data.name,"--en--"); + if (battle_config.override_mob_names == 1) + strcpy(data.name, DEFAULT_MOB_NAME); else - strcpy(data.name,"--ja--"); + strcpy(data.name, DEFAULT_MOB_JNAME); if (!mob->parse_dataset(&data)) continue; @@ -3050,7 +3119,7 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,uint16 skill_id) * MOBskill lookup (get skillindex through skill_id) * Returns INDEX_NOT_FOUND if not found. *------------------------------------------*/ -int mob_skill_id2skill_idx(int class_,uint16 skill_id) +static 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; @@ -3067,7 +3136,7 @@ int mob_skill_id2skill_idx(int class_,uint16 skill_id) /*========================================== * Friendly Mob whose HP is decreasing by a nearby MOB is looked for. *------------------------------------------*/ -int mob_getfriendhprate_sub(struct block_list *bl,va_list ap) +static int mob_getfriendhprate_sub(struct block_list *bl, va_list ap) { int min_rate, max_rate,rate; struct block_list **fr; @@ -3095,7 +3164,8 @@ int mob_getfriendhprate_sub(struct block_list *bl,va_list ap) (*fr) = bl; return 1; } -struct block_list *mob_getfriendhprate(struct mob_data *md,int min_rate,int max_rate) { +static struct block_list *mob_getfriendhprate(struct mob_data *md, int min_rate, int max_rate) +{ struct block_list *fr=NULL; int type = BL_MOB; @@ -3110,7 +3180,8 @@ struct block_list *mob_getfriendhprate(struct mob_data *md,int min_rate,int max_ /*========================================== * Check hp rate of its master *------------------------------------------*/ -struct block_list *mob_getmasterhpltmaxrate(struct mob_data *md,int rate) { +static struct block_list *mob_getmasterhpltmaxrate(struct mob_data *md, int rate) +{ if( md && md->master_id > 0 ) { struct block_list *bl = map->id2bl(md->master_id); if( bl && get_percentage(status_get_hp(bl), status_get_max_hp(bl)) < rate ) @@ -3122,7 +3193,7 @@ struct block_list *mob_getmasterhpltmaxrate(struct mob_data *md,int rate) { /*========================================== * What a status state suits by nearby MOB is looked for. *------------------------------------------*/ -int mob_getfriendstatus_sub(struct block_list *bl,va_list ap) +static int mob_getfriendstatus_sub(struct block_list *bl, va_list ap) { int cond1,cond2; struct mob_data **fr = NULL, *md = NULL, *mmd = NULL; @@ -3155,7 +3226,8 @@ int mob_getfriendstatus_sub(struct block_list *bl,va_list ap) return 0; } -struct mob_data *mob_getfriendstatus(struct mob_data *md,int cond1,int cond2) { +static struct mob_data *mob_getfriendstatus(struct mob_data *md, int cond1, int cond2) +{ struct mob_data* fr = NULL; nullpo_ret(md); @@ -3166,7 +3238,8 @@ struct mob_data *mob_getfriendstatus(struct mob_data *md,int cond1,int cond2) { /*========================================== * Skill use judging *------------------------------------------*/ -int mobskill_use(struct mob_data *md, int64 tick, int event) { +static int mobskill_use(struct mob_data *md, int64 tick, int event) +{ struct mob_skill *ms; struct block_list *fbl = NULL; //Friend bl, which can either be a BL_PC or BL_MOB depending on the situation. [Skotlex] struct block_list *bl; @@ -3367,7 +3440,7 @@ int mobskill_use(struct mob_data *md, int64 tick, int event) { char name[NAME_LENGTH]; snprintf(name, sizeof name,"%s", md->name); strtok(name, "#"); // discard extra name identifier if present [Daegaladh] - snprintf(temp, sizeof temp,"%s : %s", name, mc->msg); + safesnprintf(temp, sizeof temp,"%s : %s", name, mc->msg); clif->messagecolor(&md->bl, mc->color, temp); } if(!(battle_config.mob_ai&0x200)) { //pass on delay to same skill. @@ -3386,7 +3459,8 @@ int mobskill_use(struct mob_data *md, int64 tick, int event) { /*========================================== * Skill use event processing *------------------------------------------*/ -int mobskill_event(struct mob_data *md, struct block_list *src, int64 tick, int flag) { +static int mobskill_event(struct mob_data *md, struct block_list *src, int64 tick, int flag) +{ int target_id, res = 0; nullpo_ret(md); @@ -3423,7 +3497,7 @@ int mobskill_event(struct mob_data *md, struct block_list *src, int64 tick, int } // Player cloned mobs. [Valaris] -int mob_is_clone(int class_) +static int mob_is_clone(int class_) { if(class_ < MOB_CLONE_START || class_ > MOB_CLONE_END) return 0; @@ -3437,7 +3511,7 @@ 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, uint32 mode, int flag, unsigned int duration) +static 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; @@ -3617,7 +3691,7 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons sd->fd = fd; //Finally, spawn it. - md = mob->once_spawn_sub(&sd->bl, m, x, y, "--en--", class_, event, SZ_SMALL, AI_NONE); + md = mob->once_spawn_sub(&sd->bl, m, x, y, DEFAULT_MOB_NAME, class_, event, SZ_SMALL, AI_NONE); if (!md) return 0; //Failed? md->special_state.clone = 1; @@ -3640,7 +3714,7 @@ int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, cons return md->bl.id; } -int mob_clone_delete(struct mob_data *md) +static int mob_clone_delete(struct mob_data *md) { int class_; @@ -3663,7 +3737,7 @@ int mob_clone_delete(struct mob_data *md) /*========================================== * Since un-setting [ mob ] up was used, it is an initial provisional value setup. *------------------------------------------*/ -int mob_makedummymobdb(int class_) +static int mob_makedummymobdb(int class_) { if (mob->dummy != NULL) { @@ -3705,7 +3779,7 @@ int mob_makedummymobdb(int class_) } //Adjusts the drop rate of item according to the criteria given. [Skotlex] -unsigned int mob_drop_adjust(int baserate, int rate_adjust, unsigned short rate_min, unsigned short rate_max) +static unsigned int mob_drop_adjust(int baserate, int rate_adjust, unsigned short rate_min, unsigned short rate_max) { int64 rate = baserate; @@ -3726,6 +3800,28 @@ unsigned int mob_drop_adjust(int baserate, int rate_adjust, unsigned short rate_ return (unsigned int)cap_value(rate,rate_min,rate_max); } +static struct item_drop_ratio *mob_get_item_drop_ratio(int nameid) +{ + Assert_retr(NULL, nameid > 0); + if (nameid < ARRAYLENGTH(item_drop_ratio_db)) { + return item_drop_ratio_db[nameid]; + } else { + return (struct item_drop_ratio *)idb_get(item_drop_ratio_other_db, nameid); + } +} + +static void mob_set_item_drop_ratio(int nameid, struct item_drop_ratio *ratio) +{ + Assert_retv(nameid > 0); + if (nameid < ARRAYLENGTH(item_drop_ratio_db)) { + Assert_retv(item_drop_ratio_db[nameid] == NULL); + item_drop_ratio_db[nameid] = ratio; + } else { + Assert_retv(idb_get(item_drop_ratio_other_db, nameid) == NULL); + idb_put(item_drop_ratio_other_db, nameid, ratio); + } +} + /** * Check if global item drop rate is overridden for given item * in db/mob_item_ratio.txt @@ -3733,23 +3829,27 @@ unsigned int mob_drop_adjust(int baserate, int rate_adjust, unsigned short rate_ * @param mob_id ID of the monster * @param rate_adjust pointer to store ratio if found */ -void item_dropratio_adjust(int nameid, int mob_id, int *rate_adjust) +static void item_dropratio_adjust(int nameid, int mob_id, int *rate_adjust) { + struct item_drop_ratio *dropRatio; nullpo_retv(rate_adjust); - if( item_drop_ratio_db[nameid] ) { - if( item_drop_ratio_db[nameid]->mob_id[0] ) { // only for listed mobs + + dropRatio = mob->get_item_drop_ratio(nameid); + if (dropRatio) { + if (dropRatio->mob_id[0] ) { // only for listed mobs int i; - ARR_FIND(0, MAX_ITEMRATIO_MOBS, i, item_drop_ratio_db[nameid]->mob_id[i] == mob_id); - if(i < MAX_ITEMRATIO_MOBS) // found - *rate_adjust = item_drop_ratio_db[nameid]->drop_ratio; + ARR_FIND(0, MAX_ITEMRATIO_MOBS, i, dropRatio->mob_id[i] == mob_id); + if (i < MAX_ITEMRATIO_MOBS) // found + *rate_adjust = dropRatio->drop_ratio; } else // for all mobs - *rate_adjust = item_drop_ratio_db[nameid]->drop_ratio; + *rate_adjust = dropRatio->drop_ratio; } } /* (mob_parse_dbrow)_cap_value */ -static inline int mob_parse_dbrow_cap_value(int class_, int min, int max, int value) { +static inline int mob_parse_dbrow_cap_value(int class_, int min, int max, int value) +{ if( value > max ) { ShowError("mob_parse_dbrow_cap_value: for class '%d', field value '%d' is higher than the maximum '%d'! capping...\n", class_, value, max); return max; @@ -3767,7 +3867,7 @@ 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, struct config_setting_t *t) +static void mob_read_db_stats_sub(struct mob_db *entry, struct config_setting_t *t) { int i32; nullpo_retv(entry); @@ -3799,7 +3899,7 @@ void mob_read_db_stats_sub(struct mob_db *entry, struct config_setting_t *t) * * @return The parsed mode. */ -uint32 mob_read_db_mode_sub(struct mob_db *entry, struct config_setting_t *t) +static uint32 mob_read_db_mode_sub(struct mob_db *entry, struct config_setting_t *t) { uint32 mode = 0; struct config_setting_t *t2; @@ -3847,7 +3947,7 @@ uint32 mob_read_db_mode_sub(struct mob_db *entry, struct 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, struct config_setting_t *t) +static void mob_read_db_mvpdrops_sub(struct mob_db *entry, struct config_setting_t *t) { struct config_setting_t *drop; int i = 0; @@ -3904,7 +4004,7 @@ void mob_read_db_mvpdrops_sub(struct mob_db *entry, struct 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, struct config_setting_t *t) +static void mob_read_db_drops_sub(struct mob_db *entry, struct config_setting_t *t) { struct config_setting_t *drop; int i = 0; @@ -4030,7 +4130,7 @@ void mob_read_db_drops_sub(struct mob_db *entry, struct config_setting_t *t) * (i.e. mob_db2 inheritance), as it will make sure not to free any data still * in use by the new entry. */ -int mob_db_validate_entry(struct mob_db *entry, int n, const char *source) +static int mob_db_validate_entry(struct mob_db *entry, int n, const char *source) { struct mob_data data; @@ -4133,7 +4233,7 @@ 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(struct config_setting_t *mobt, int n, const char *source) +static int mob_read_db_sub(struct config_setting_t *mobt, int n, const char *source) { struct mob_db md = { 0 }; struct config_setting_t *t = NULL; @@ -4281,7 +4381,7 @@ int mob_read_db_sub(struct config_setting_t *mobt, int n, const char *source) if (mob->lookup_const(mobt, "AttackRange", &i32) && i32 >= 0) { md.status.rhw.range = i32; - } else { + } else if (!inherit) { md.status.rhw.range = 1; } @@ -4442,12 +4542,12 @@ int mob_read_db_sub(struct 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, struct config_setting_t *t, int n, const char *source) +static 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 struct config_setting_t *it, const char *name, int *value) +static bool mob_lookup_const(const struct config_setting_t *it, const char *name, int *value) { if (libconfig->setting_lookup_int(it, name, value)) { @@ -4465,7 +4565,7 @@ bool mob_lookup_const(const struct config_setting_t *it, const char *name, int * return false; } -bool mob_get_const(const struct config_setting_t *it, int *value) +static bool mob_get_const(const struct config_setting_t *it, int *value) { const char *str = config_setting_get_string(it); @@ -4480,7 +4580,8 @@ bool mob_get_const(const struct config_setting_t *it, int *value) /*========================================== * mob_db.txt reading *------------------------------------------*/ -void mob_readdb(void) { +static void mob_readdb(void) +{ const char* filename[] = { DBPATH"mob_db.conf", "mob_db2.conf" }; @@ -4501,7 +4602,7 @@ void mob_readdb(void) { * @param ignore_missing Whether to ignore errors caused by a missing db file. * @return the number of found entries. */ -int mob_read_libconfig(const char *filename, bool ignore_missing) +static int mob_read_libconfig(const char *filename, bool ignore_missing) { bool duplicate[MAX_MOB_DB] = { 0 }; struct config_t mob_db_conf; @@ -4511,7 +4612,7 @@ int mob_read_libconfig(const char *filename, bool ignore_missing) int i = 0, count = 0; nullpo_ret(filename); - sprintf(filepath, "%s/%s", map->db_path, filename); + safesnprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, filename); if (ignore_missing && !exists(filepath)) return 0; @@ -4545,7 +4646,8 @@ int mob_read_libconfig(const char *filename, bool ignore_missing) return count; } -void mob_name_constants(void) { +static void mob_name_constants(void) +{ int i; #ifdef ENABLE_CASE_CHECK script->parser_current_file = "Mob Database (Likely an invalid or conflicting SpriteName)"; @@ -4562,7 +4664,7 @@ void mob_name_constants(void) { /*========================================== * MOB display graphic change data reading *------------------------------------------*/ -bool mob_readdb_mobavail(char* str[], int columns, int current) +static bool mob_readdb_mobavail(char *str[], int columns, int current) { int class_, view_class; @@ -4604,7 +4706,7 @@ bool mob_readdb_mobavail(char* str[], int columns, int current) /*========================================== * Reading of random monster data *------------------------------------------*/ -int mob_read_randommonster(void) +static int mob_read_randommonster(void) { char line[1024]; char *str[10],*p; @@ -4671,7 +4773,7 @@ int mob_read_randommonster(void) * processes one mob_chat_db entry [SnakeDrak] * @param last_msg_id ensures that only one error message per mob id is printed *------------------------------------------*/ -bool mob_parse_row_chatdb(char** str, const char* source, int line, int* last_msg_id) +static bool mob_parse_row_chatdb(char **str, const char *source, int line, int *last_msg_id) { char* msg; struct mob_chat *ms; @@ -4731,13 +4833,14 @@ bool mob_parse_row_chatdb(char** str, const char* source, int line, int* last_ms /*========================================== * mob_chat_db.txt reading [SnakeDrak] *-------------------------------------------------------------------------*/ -void mob_readchatdb(void) { +static void mob_readchatdb(void) +{ char arc[]="mob_chat_db.txt"; uint32 lines=0, count=0; char line[1024], filepath[256]; int i, tmp=0; FILE *fp; - sprintf(filepath, "%s/%s", map->db_path, arc); + safesnprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, arc); fp=fopen(filepath, "r"); if(fp == NULL) { ShowWarning("mob_readchatdb: File not found \"%s\", skipping.\n", filepath); @@ -4784,299 +4887,267 @@ void mob_readchatdb(void) { /*========================================== * processes one mob_skill_db entry *------------------------------------------*/ -bool mob_parse_row_mobskilldb(char** str, int columns, int current) +static bool mob_skill_db_libconfig(const char *filename, bool ignore_missing) { - static const struct { - char str[32]; - enum MobSkillState id; - } state[] = { - { "any", MSS_ANY }, //All states except Dead - { "idle", MSS_IDLE }, - { "walk", MSS_WALK }, - { "loot", MSS_LOOT }, - { "dead", MSS_DEAD }, - { "attack", MSS_BERSERK }, //Retaliating attack - { "angry", MSS_ANGRY }, //Preemptive attack (aggressive mobs) - { "chase", MSS_RUSH }, //Chase escaping target - { "follow", MSS_FOLLOW }, //Preemptive chase (aggressive mobs) - { "anytarget", MSS_ANYTARGET }, //Berserk+Angry+Rush+Follow - }; - static const struct { - char str[32]; - int id; - } cond1[] = { - { "always", MSC_ALWAYS }, - { "myhpltmaxrate", MSC_MYHPLTMAXRATE }, - { "myhpinrate", MSC_MYHPINRATE }, - { "friendhpltmaxrate", MSC_FRIENDHPLTMAXRATE }, - { "friendhpinrate", MSC_FRIENDHPINRATE }, - { "mystatuson", MSC_MYSTATUSON }, - { "mystatusoff", MSC_MYSTATUSOFF }, - { "friendstatuson", MSC_FRIENDSTATUSON }, - { "friendstatusoff", MSC_FRIENDSTATUSOFF }, - { "attackpcgt", MSC_ATTACKPCGT }, - { "attackpcge", MSC_ATTACKPCGE }, - { "slavelt", MSC_SLAVELT }, - { "slavele", MSC_SLAVELE }, - { "closedattacked", MSC_CLOSEDATTACKED }, - { "longrangeattacked", MSC_LONGRANGEATTACKED }, - { "skillused", MSC_SKILLUSED }, - { "afterskill", MSC_AFTERSKILL }, - { "casttargeted", MSC_CASTTARGETED }, - { "rudeattacked", MSC_RUDEATTACKED }, - { "masterhpltmaxrate", MSC_MASTERHPLTMAXRATE }, - { "masterattacked", MSC_MASTERATTACKED }, - { "alchemist", MSC_ALCHEMIST }, - { "onspawn", MSC_SPAWN }, - }, cond2[] ={ - { "anybad", -1 }, - { "stone", SC_STONE }, - { "freeze", SC_FREEZE }, - { "stun", SC_STUN }, - { "sleep", SC_SLEEP }, - { "poison", SC_POISON }, - { "curse", SC_CURSE }, - { "silence", SC_SILENCE }, - { "confusion", SC_CONFUSION }, - { "blind", SC_BLIND }, - { "hiding", SC_HIDING }, - { "sight", SC_SIGHT }, - }, target[] = { - { "target", MST_TARGET }, - { "randomtarget", MST_RANDOM }, - { "self", MST_SELF }, - { "friend", MST_FRIEND }, - { "master", MST_MASTER }, - { "around5", MST_AROUND5 }, - { "around6", MST_AROUND6 }, - { "around7", MST_AROUND7 }, - { "around8", MST_AROUND8 }, - { "around1", MST_AROUND1 }, - { "around2", MST_AROUND2 }, - { "around3", MST_AROUND3 }, - { "around4", MST_AROUND4 }, - { "around", MST_AROUND }, - }; - static int last_mob_id = 0; // ensures that only one error message per mob id is printed + struct config_t mob_skill_conf; + struct config_setting_t *it = NULL, *its = NULL, *mob_skill = NULL; + char filepath[256]; + int i = 0; - struct mob_skill *ms, gms; - int mob_id; - int i =0, j, tmp; - uint16 sidx = 0; + nullpo_retr(false, filename); - nullpo_retr(false, str); - mob_id = atoi(str[0]); + safesnprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, filename); - if (mob_id > 0 && mob->db(mob_id) == mob->dummy) - { - if (mob_id != last_mob_id) { - ShowError("mob_parse_row_mobskilldb: Non existant Mob id %d\n", mob_id); - last_mob_id = mob_id; + if (!exists(filepath)) { + if (!ignore_missing) { + ShowError("mob_skill_db_libconfig: can't find file %s\n", filepath); + } + return 0; + } + + if (!libconfig->load_file(&mob_skill_conf, filepath)) + return false; + + its = libconfig->lookup(&mob_skill_conf, "mob_skill_db"); + + if (its != NULL && (mob_skill = libconfig->setting_get_elem(its, 0)) != NULL) { + while ((it = libconfig->setting_get_elem(mob_skill, i++))) { + mob->skill_db_libconfig_sub(it, i); } + } + + libconfig->destroy(&mob_skill_conf); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, filepath); + return true; +} + +static bool mob_skill_db_libconfig_sub(struct config_setting_t *it, int n) +{ + int i = 0; + int mob_id; + struct config_setting_t *its; + const char *name = config_setting_name(it); + + nullpo_retr(false, it); + + if (!*name) { + ShowWarning("mob_skill_db_libconfig_sub: Invalid value for monster name, entry #%d, skipping.\n", n); + return false; + } + if (!script->get_constant(name, &mob_id)) { + ShowWarning("mob_skill_db_libconfig_sub: Invalid monster '%s', entry #%d, skipping.\n", name, n); + return false; + } + if (mob_id > 0 && mob->db(mob_id) == mob->dummy) { + ShowWarning("mob_skill_db_libconfig_sub: Non existant monster id %d, skipping.\n", mob_id); return false; } - if( strcmp(str[1],"clear")==0 ){ - if (mob_id < 0) + + while ((its = libconfig->setting_get_elem(it, i++))) { + mob->skill_db_libconfig_sub_skill(its, i, mob_id); + } + return true; +} + +static bool mob_skill_db_libconfig_sub_skill(struct config_setting_t *it, int n, int mob_id) +{ + int i, j, idx = 0; + int i32; + int skill_id = 0; + int skill_idx = 0; + bool clearskills = false; + const char *name = config_setting_name(it); + struct mob_skill *ms, gms; + + nullpo_retr(false, it); + Assert_retr(false, mob_id <= 0 || mob->db(mob_id) != mob->dummy); + + if (!(skill_id = skill->name2id(name))) { + ShowWarning("mob_skill_db_libconfig_sub_skill: Non existant skill id %d in monster %d, skipping.\n", skill_id, mob_id); + return false; + } + + // If ClearSkills flag is enabled clear all the previous skills. + if (libconfig->setting_lookup_bool_real(it, "ClearSkills", &clearskills) && clearskills) { + if (mob_id < 0) // Clearing skills globaly is not supported return false; - memset(mob->db_data[mob_id]->skill,0,sizeof(struct mob_skill) * MAX_MOBSKILL); - mob->db_data[mob_id]->maxskill=0; + memset(mob->db_data[mob_id]->skill, 0, sizeof(struct mob_skill) * MAX_MOBSKILL); + mob->db_data[mob_id]->maxskill = 0; return true; } if (mob_id < 0) { - //Prepare global skill. [Skotlex] + // Prepare global skill. [Skotlex] memset(&gms, 0, sizeof (struct mob_skill)); ms = &gms; } else { - ARR_FIND( 0, MAX_MOBSKILL, i, (ms = &mob->db_data[mob_id]->skill[i])->skill_id == 0 ); - if( i == MAX_MOBSKILL ) - { - if (mob_id != last_mob_id) { - ShowError("mob_parse_row_mobskilldb: Too many skills for monster %d[%s]\n", mob_id, mob->db_data[mob_id]->sprite); - last_mob_id = mob_id; - } + ARR_FIND(0, MAX_MOBSKILL, idx, (ms = &mob->db_data[mob_id]->skill[idx])->skill_id == 0); + if (idx == MAX_MOBSKILL) { + ShowError("mob_skill_db_libconfig_sub_skill: Too many skills for monster %d\n", mob_id); return false; } } + ms->skill_id = skill_id; - //State - ARR_FIND( 0, ARRAYLENGTH(state), j, strcmp(str[2],state[j].str) == 0 ); - if( j < ARRAYLENGTH(state) ) - ms->state = state[j].id; - else { - ShowWarning("mob_parse_row_mobskilldb: Unrecognized state %s\n", str[2]); - ms->state = MSS_ANY; + if (mob->lookup_const(it, "SkillState", &i32) && (i32 < MSS_ANY || i32 > MSS_ANYTARGET)) { + ShowWarning("mob_skill_db_libconfig_sub_skill: Invalid skill state %d for skill id %d in monster %d, defaulting to MSS_ANY.\n", i32, skill_id, mob_id); + i32 = MSS_ANY; } + ms->state = i32; - //Skill ID - j=atoi(str[3]); - if ( !(sidx = skill->get_index(j) ) ) { - if (mob_id < 0) - ShowError("mob_parse_row_mobskilldb: Invalid Skill ID (%d) for all mobs\n", j); - else - ShowError("mob_parse_row_mobskilldb: Invalid Skill ID (%d) for mob %d (%s)\n", j, mob_id, mob->db_data[mob_id]->sprite); - return false; - } - ms->skill_id=j; - - //Skill lvl - j= atoi(str[4])<=0 ? 1 : atoi(str[4]); - ms->skill_lv= j>battle_config.mob_max_skilllvl ? battle_config.mob_max_skilllvl : j; //we strip max skill level + if (!libconfig->setting_lookup_int(it, "SkillLevel", &i32) || i32 <= 0) + i32 = 1; + ms->skill_lv = i32 > battle_config.mob_max_skilllvl ? battle_config.mob_max_skilllvl : i32; //we strip max skill level //Apply battle_config modifiers to rate (permillage) and delay [Skotlex] - tmp = atoi(str[5]); + if (libconfig->setting_lookup_int(it, "Rate", &i32)) + ms->permillage = i32; + if (battle_config.mob_skill_rate != 100) - tmp = tmp*battle_config.mob_skill_rate/100; - if (tmp > 10000) - ms->permillage= 10000; - else if (!tmp && battle_config.mob_skill_rate) - ms->permillage= 1; - else - ms->permillage= tmp; - ms->casttime=atoi(str[6]); - ms->delay=atoi(str[7]); + ms->permillage = ms->permillage * battle_config.mob_skill_rate / 100; + if (ms->permillage > 10000) + ms->permillage = 10000; + else if (ms->permillage == 0 && battle_config.mob_skill_rate) + ms->permillage = 1; + + if (libconfig->setting_lookup_int(it, "CastTime", &i32) && i32 > 0) + ms->casttime = i32; + + if (libconfig->setting_lookup_int(it, "Delay", &i32)) + ms->delay = i32; if (battle_config.mob_skill_delay != 100) - ms->delay = ms->delay*battle_config.mob_skill_delay/100; + ms->delay = ms->delay * battle_config.mob_skill_delay / 100; if (ms->delay < 0 || ms->delay > MOB_MAX_DELAY) //time overflow? ms->delay = MOB_MAX_DELAY; - ms->cancel=atoi(str[8]); - if( strcmp(str[8],"yes")==0 ) ms->cancel=1; - - //Target - ARR_FIND( 0, ARRAYLENGTH(target), j, strcmp(str[9],target[j].str) == 0 ); - if( j < ARRAYLENGTH(target) ) - ms->target = target[j].id; - else { - ShowWarning("mob_parse_row_mobskilldb: Unrecognized target %s for %d\n", str[9], mob_id); + + if (libconfig->setting_lookup_bool(it, "Cancelable", &i32)) + ms->cancel = (i32 == 0) ? 0 : 1; + + if (mob->lookup_const(it, "SkillTarget", &i32) && (i32 < MST_TARGET || i32 > MST_AROUND)) { + ShowWarning("mob_skill_db_libconfig_sub_skill: Invalid skill target %d for skill id %d in monster %d, defaulting to MST_TARGET.\n", i32, skill_id, mob_id); ms->target = MST_TARGET; } + ms->target = i32; //Check that the target condition is right for the skill type. [Skotlex] - if ( skill->get_casttype2(sidx) == CAST_GROUND) {//Ground skill. + skill_idx = skill->get_index(skill_id); + if (skill->get_casttype2(skill_idx) == CAST_GROUND) {//Ground skill. if (ms->target > MST_AROUND) { - ShowWarning("mob_parse_row_mobskilldb: Wrong mob skill target for ground skill %d (%s) for %s.\n", - ms->skill_id, skill->dbs->db[sidx].name, - mob_id < 0?"all mobs":mob->db_data[mob_id]->sprite); + ShowWarning("mob_skill_db_libconfig_sub_skill: Wrong mob skill target for ground skill %d (%s) for %s.\n", + ms->skill_id, skill->dbs->db[skill_idx].name, + mob_id < 0 ? "all mobs" : mob->db_data[mob_id]->sprite); ms->target = MST_TARGET; } } else if (ms->target > MST_MASTER) { - ShowWarning("mob_parse_row_mobskilldb: Wrong mob skill target 'around' for non-ground skill %d (%s) for %s.\n", - ms->skill_id, skill->dbs->db[sidx].name, - mob_id < 0?"all mobs":mob->db_data[mob_id]->sprite); + ShowWarning("mob_skill_db_libconfig_sub_skill: Wrong mob skill target 'around' for non-ground skill %d (%s) for %s.\n", + ms->skill_id, skill->dbs->db[skill_idx].name, + mob_id < 0 ? "all mobs" : mob->db_data[mob_id]->sprite); ms->target = MST_TARGET; } - //Cond1 - ARR_FIND( 0, ARRAYLENGTH(cond1), j, strcmp(str[10],cond1[j].str) == 0 ); - if( j < ARRAYLENGTH(cond1) ) - ms->cond1 = cond1[j].id; - else { - ShowWarning("mob_parse_row_mobskilldb: Unrecognized condition 1 %s for %d\n", str[10], mob_id); - ms->cond1 = -1; + if (mob->lookup_const(it, "CastCondition", &i32) && (i32 < MSC_ALWAYS || i32 > MSC_SPAWN)) { + ShowWarning("mob_skill_db_libconfig_sub_skill: Invalid skill condition %d for skill id %d in monster %d, defaulting to MSC_ALWAYS.\n", i32, skill_id, mob_id); + ms->cond1 = MSC_ALWAYS; } + ms->cond1 = i32; - //Cond2 - // numeric value - ms->cond2 = atoi(str[11]); - // or special constant - ARR_FIND( 0, ARRAYLENGTH(cond2), j, strcmp(str[11],cond2[j].str) == 0 ); - if( j < ARRAYLENGTH(cond2) ) - ms->cond2 = cond2[j].id; + if (mob->lookup_const(it, "ConditionData", &i32)) + ms->cond2 = i32; - ms->val[0]=(int)strtol(str[12],NULL,0); - ms->val[1]=(int)strtol(str[13],NULL,0); - ms->val[2]=(int)strtol(str[14],NULL,0); - ms->val[3]=(int)strtol(str[15],NULL,0); - ms->val[4]=(int)strtol(str[16],NULL,0); + for (i = 0; i < 5; i++) { + char valname[16]; + sprintf(valname, "val%1d", i); + if (libconfig->setting_lookup_int(it, valname, &i32)) + ms->val[i] = i32; + } if (ms->skill_id == NPC_EMOTION) { ms->val[1] &= MD_MASK; ms->val[2] &= MD_MASK; ms->val[3] &= MD_MASK; + + if (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 && 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] != MD_NONE) { + + 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)) + if (!(ms->val[1] & MD_AGGRESSIVE)) 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]) - ms->emotion=atoi(str[17]); + if (libconfig->setting_lookup_int(it, "Emotion", &i32)) + ms->emotion = i32; else - ms->emotion=-1; + ms->emotion = -1; - if(str[18]!=NULL && mob->chat_db[atoi(str[18])]!=NULL) - ms->msg_id=atoi(str[18]); - else - ms->msg_id=0; + if (libconfig->setting_lookup_int(it, "ChatMsgID", &i32) && i32 > 0 && i32 <= MAX_MOB_CHAT) { + if (mob->chat_db[i32] == NULL) { + ShowWarning("mob_skill_db_libconfig_sub_skill: Invalid msg id %d for skill id %d in monster %d, ignoring.\n", i32, skill_id, mob_id); + } else { + ms->msg_id = i32; + } + } if (mob_id < 0) { - //Set this skill to ALL mobs. [Skotlex] + // Set this skill to ALL mobs. [Skotlex] mob_id *= -1; - for (i = 1; i < MAX_MOB_DB; i++) - { + for (i = 1; i < MAX_MOB_DB; i++) { if (mob->db_data[i] == NULL) continue; - if (mob->db_data[i]->status.mode&MD_BOSS) - { - if (!(mob_id&2)) //Skill not for bosses + if (mob->db_data[i]->status.mode & MD_BOSS) { + if (!(mob_id & 2)) //Skill not for bosses continue; - } else - if (!(mob_id&1)) //Skill not for normal enemies. + } else { + if (!(mob_id & 1)) //Skill not for normal enemies. continue; - - ARR_FIND( 0, MAX_MOBSKILL, j, mob->db_data[i]->skill[j].skill_id == 0 ); - if(j==MAX_MOBSKILL) + } + ARR_FIND(0, MAX_MOBSKILL, j, mob->db_data[i]->skill[j].skill_id == 0); + if (j == MAX_MOBSKILL) continue; - memcpy (&mob->db_data[i]->skill[j], ms, sizeof(struct mob_skill)); - mob->db_data[i]->maxskill=j+1; + memcpy(&mob->db_data[i]->skill[j], ms, sizeof(struct mob_skill)); + mob->db_data[i]->maxskill = j + 1; } - } else //Skill set on a single mob. - mob->db_data[mob_id]->maxskill=i+1; + } else { //Skill set on a single mob. + mob->db_data[mob_id]->maxskill = idx + 1; + } return true; } + /*========================================== * mob_skill_db.txt reading *------------------------------------------*/ -void mob_readskilldb(void) { - const char* filename[] = { - DBPATH"mob_skill_db.txt", - "mob_skill_db2.txt" }; - int fi; +static void mob_readskilldb(void) +{ - if( battle_config.mob_skill_rate == 0 ) { + const char *filename[] = { + DBPATH"mob_skill_db.conf", + "mob_skill_db2.conf" + }; + int i; + + if (battle_config.mob_skill_rate == 0) { ShowStatus("Mob skill use disabled. Not reading mob skills.\n"); return; } - for( fi = 0; fi < ARRAYLENGTH(filename); ++fi ) { - if(fi > 0) { - char filepath[256]; - snprintf(filepath, 256, "%s/%s", map->db_path, filename[fi]); - if(!exists(filepath)) { - continue; - } - } - - sv->readdb(map->db_path, filename[fi], ',', 19, 19, -1, mob->parse_row_mobskilldb); + for (i = 0; i < ARRAYLENGTH(filename); ++i) { + mob->skill_db_libconfig(filename[i], i > 0 ? true : false); } } /*========================================== * mob_race2_db.txt reading *------------------------------------------*/ -bool mob_readdb_race2(char* fields[], int columns, int current) +static bool mob_readdb_race2(char *fields[], int columns, int current) { int race, i; @@ -5102,9 +5173,10 @@ bool mob_readdb_race2(char* fields[], int columns, int current) /** * Read mob_item_ratio.txt */ -bool mob_readdb_itemratio(char* str[], int columns, int current) +static bool mob_readdb_itemratio(char *str[], int columns, int current) { int nameid, ratio, i; + struct item_drop_ratio *dropRatio; nullpo_retr(false, str); nameid = atoi(str[0]); @@ -5117,12 +5189,15 @@ bool mob_readdb_itemratio(char* str[], int columns, int current) ratio = atoi(str[1]); - if(item_drop_ratio_db[nameid] == NULL) - item_drop_ratio_db[nameid] = (struct item_drop_ratio*)aCalloc(1, sizeof(struct item_drop_ratio)); + dropRatio = mob->get_item_drop_ratio(nameid); + if (dropRatio == NULL) { + dropRatio = (struct item_drop_ratio*)aCalloc(1, sizeof(struct item_drop_ratio)); + mob->set_item_drop_ratio(nameid, dropRatio); + } - item_drop_ratio_db[nameid]->drop_ratio = ratio; - for(i = 0; i < columns-2; i++) - item_drop_ratio_db[nameid]->mob_id[i] = atoi(str[i+2]); + dropRatio->drop_ratio = ratio; + for (i = 0; i < columns - 2; i++) + dropRatio->mob_id[i] = atoi(str[i + 2]); return true; } @@ -5130,7 +5205,8 @@ bool mob_readdb_itemratio(char* str[], int columns, int current) /** * read all mob-related databases */ -void mob_load(bool minimal) { +static void mob_load(bool minimal) +{ if (minimal) { // Only read the mob db in minimal mode mob->readdb(); @@ -5145,7 +5221,21 @@ void mob_load(bool minimal) { sv->readdb(map->db_path, DBPATH"mob_race2_db.txt", ',', 2, 20, -1, mob->readdb_race2); } -void mob_reload(void) { +/** + * @see DBApply + */ +static int mob_final_ratio_sub(union DBKey key, struct DBData *data, va_list ap) +{ + struct item_drop_ratio *ratio = DB->data2ptr(data); + + if (ratio) + aFree(ratio); + + return 0; +} + +static void mob_reload(void) +{ int i; //Mob skills need to be cleared before re-reading them. [Skotlex] @@ -5162,6 +5252,7 @@ void mob_reload(void) { item_drop_ratio_db[i] = NULL; } } + mob->item_drop_ratio_other_db->clear(mob->item_drop_ratio_other_db, mob->final_ratio_sub); mob->load(false); } @@ -5169,7 +5260,7 @@ void mob_reload(void) { /** * Clears spawn related information for a script reload. */ -void mob_clear_spawninfo(void) +static void mob_clear_spawninfo(void) { int i; for (i = 0; i < MAX_MOB_DB; i++) @@ -5180,7 +5271,8 @@ void mob_clear_spawninfo(void) /*========================================== * Circumference initialization of mob *------------------------------------------*/ -int do_init_mob(bool minimal) { +static int do_init_mob(bool minimal) +{ // Initialize the mob database memset(mob->db_data,0,sizeof(mob->db_data)); //Clear the array mob->db_data[0] = (struct mob_db*)aCalloc(1, sizeof (struct mob_db)); //This mob is used for random spawns @@ -5200,13 +5292,14 @@ int do_init_mob(bool minimal) { timer->add_func_list(mob->timer_delete,"mob_timer_delete"); timer->add_func_list(mob->spawn_guardian_sub,"mob_spawn_guardian_sub"); timer->add_func_list(mob->respawn,"mob_respawn"); + timer->add_func_list(mob->mvptomb_delayspawn, "mvptomb_delayspawn"); timer->add_interval(timer->gettick()+MIN_MOBTHINKTIME,mob->ai_hard,0,0,MIN_MOBTHINKTIME); timer->add_interval(timer->gettick()+MIN_MOBTHINKTIME*10,mob->ai_lazy,0,0,MIN_MOBTHINKTIME*10); return 0; } -void mob_destroy_mob_db(int index) +static void mob_destroy_mob_db(int index) { struct mob_db *data; Assert_retv(index >= 0 && index <= MAX_MOB_DB); @@ -5219,7 +5312,7 @@ void mob_destroy_mob_db(int index) /*========================================== * Clean memory usage. *------------------------------------------*/ -int do_final_mob(void) +static int do_final_mob(void) { int i; if (mob->dummy) @@ -5250,12 +5343,15 @@ int do_final_mob(void) item_drop_ratio_db[i] = NULL; } } + mob->item_drop_ratio_other_db->clear(mob->item_drop_ratio_other_db, mob->final_ratio_sub); + db_destroy(mob->item_drop_ratio_other_db); ers_destroy(item_drop_ers); ers_destroy(item_drop_list_ers); return 0; } -void mob_defaults(void) { +void mob_defaults(void) +{ // Defines the Manuk/Splendide/Mora mob groups for the status reductions [Epoque & Frost] const int mob_manuk[8] = { MOBID_TATACHO, @@ -5292,6 +5388,10 @@ void mob_defaults(void) { memcpy(mob->splendide, mob_splendide, sizeof(mob->splendide)); memcpy(mob->mora, mob_mora, sizeof(mob->mora)); + item_drop_ratio_other_db = idb_alloc(DB_OPT_BASE); + mob->item_drop_ratio_db = item_drop_ratio_db; + mob->item_drop_ratio_other_db = item_drop_ratio_other_db; + /* */ mob->reload = mob_reload; mob->init = do_init_mob; @@ -5306,6 +5406,8 @@ void mob_defaults(void) { mob->db_searchname_array_sub = mobdb_searchname_array_sub; mob->mvptomb_create = mvptomb_create; mob->mvptomb_destroy = mvptomb_destroy; + mob->mvptomb_spawn_delayed = mvptomb_spawn_delayed; + mob->mvptomb_delayspawn = mvptomb_delayspawn; mob->db_searchname_array = mobdb_searchname_array; mob->db_checkid = mobdb_checkid; mob->get_viewdata = mob_get_viewdata; @@ -5390,11 +5492,16 @@ void mob_defaults(void) { mob->read_randommonster = mob_read_randommonster; mob->parse_row_chatdb = mob_parse_row_chatdb; mob->readchatdb = mob_readchatdb; - mob->parse_row_mobskilldb = mob_parse_row_mobskilldb; mob->readskilldb = mob_readskilldb; mob->readdb_race2 = mob_readdb_race2; mob->readdb_itemratio = mob_readdb_itemratio; mob->load = mob_load; + mob->get_item_drop_ratio = mob_get_item_drop_ratio; + mob->set_item_drop_ratio = mob_set_item_drop_ratio; + mob->final_ratio_sub = mob_final_ratio_sub; mob->clear_spawninfo = mob_clear_spawninfo; mob->destroy_mob_db = mob_destroy_mob_db; + mob->skill_db_libconfig = mob_skill_db_libconfig; + mob->skill_db_libconfig_sub = mob_skill_db_libconfig_sub; + mob->skill_db_libconfig_sub_skill = mob_skill_db_libconfig_sub_skill; } |