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.c855
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;
}