summaryrefslogtreecommitdiff
path: root/src/map/npc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/npc.c')
-rw-r--r--src/map/npc.c298
1 files changed, 212 insertions, 86 deletions
diff --git a/src/map/npc.c b/src/map/npc.c
index 2b1a541d8..6b55bf5ae 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -47,6 +47,7 @@
#include "common/nullpo.h"
#include "common/showmsg.h"
#include "common/socket.h"
+#include "common/sql.h"
#include "common/strlib.h"
#include "common/timer.h"
#include "common/utils.h"
@@ -61,17 +62,6 @@
struct npc_interface npc_s;
struct npc_interface *npc;
-static int npc_id=START_NPC_NUM;
-static int npc_warp=0;
-static int npc_shop=0;
-static int npc_script=0;
-static int npc_mob=0;
-static int npc_delay_mob=0;
-static int npc_cache_mob=0;
-
-static const char *npc_last_path;
-static const char *npc_last_ref;
-struct npc_path_data *npc_last_npd;
//For holding the view data of npc classes. [Skotlex]
static struct view_data npc_viewdb[MAX_NPC_CLASS];
@@ -131,15 +121,15 @@ bool npc_db_checkid(int id)
/// Returns a new npc id that isn't being used in id_db.
/// Fatal error if nothing is available.
int npc_get_new_npc_id(void) {
- if( npc_id >= START_NPC_NUM && !map->blid_exists(npc_id) )
- return npc_id++;// available
+ if (npc->npc_id >= START_NPC_NUM && !map->blid_exists(npc->npc_id))
+ return npc->npc_id++;// available
else {// find next id
- int base_id = npc_id;
- while( base_id != ++npc_id ) {
- if( npc_id < START_NPC_NUM )
- npc_id = START_NPC_NUM;
- if( !map->blid_exists(npc_id) )
- return npc_id++;// available
+ int base_id = npc->npc_id;
+ while (base_id != ++npc->npc_id) {
+ if (npc->npc_id < START_NPC_NUM)
+ npc->npc_id = START_NPC_NUM;
+ if (!map->blid_exists(npc->npc_id))
+ return npc->npc_id++;// available
}
// full loop, nothing available
ShowFatalError("npc_get_new_npc_id: All ids are taken. Exiting...");
@@ -176,6 +166,7 @@ int npc_ontouch_event(struct map_session_data *sd, struct npc_data *nd)
{
char name[EVENT_NAME_LENGTH];
+ nullpo_retr(1, nd);
if( nd->touching_id )
return 0; // Attached a player already. Can't trigger on anyone else.
@@ -190,6 +181,8 @@ int npc_ontouch2_event(struct map_session_data *sd, struct npc_data *nd)
{
char name[EVENT_NAME_LENGTH];
+ nullpo_retr(1, sd);
+ nullpo_retr(1, nd);
if (sd->areanpc_id == nd->bl.id)
return 0;
@@ -201,6 +194,8 @@ int npc_onuntouch_event(struct map_session_data *sd, struct npc_data *nd)
{
char name[EVENT_NAME_LENGTH];
+ nullpo_ret(sd);
+ nullpo_ret(nd);
if (sd->areanpc_id != nd->bl.id)
return 0;
@@ -366,7 +361,7 @@ int npc_event_dequeue(struct map_session_data* sd)
/**
* @see DBCreateData
*/
-DBData npc_event_export_create(DBKey key, va_list args)
+struct DBData npc_event_export_create(union DBKey key, va_list args)
{
struct linkdb_node** head_ptr;
CREATE(head_ptr, struct linkdb_node*, 1);
@@ -380,8 +375,12 @@ DBData npc_event_export_create(DBKey key, va_list args)
*------------------------------------------*/
int npc_event_export(struct npc_data *nd, int i)
{
- char* lname = nd->u.scr.label_list[i].name;
- int pos = nd->u.scr.label_list[i].pos;
+ char* lname;
+ int pos;
+ nullpo_ret(nd);
+ Assert_ret(i >= 0 && i < nd->u.scr.label_list_num);
+ lname = nd->u.scr.label_list[i].name;
+ pos = nd->u.scr.label_list[i].pos;
if ((lname[0] == 'O' || lname[0] == 'o') && (lname[1] == 'N' || lname[1] == 'n')) {
struct event_data *ev;
struct linkdb_node **label_linkdb = NULL;
@@ -434,6 +433,7 @@ void npc_event_doall_sub(void *key, void *data, va_list ap)
// runs the specified event (supports both single-npc and global events)
int npc_event_do(const char* name)
{
+ nullpo_ret(name);
if( name[0] == ':' && name[1] == ':' ) {
return npc->event_doall(name+2); // skip leading "::"
}
@@ -538,9 +538,12 @@ void npc_event_do_oninit( bool reload )
int npc_timerevent_export(struct npc_data *nd, int i)
{
int t = 0, len = 0;
- char *lname = nd->u.scr.label_list[i].name;
- int pos = nd->u.scr.label_list[i].pos;
- if (sscanf(lname, "OnTimer%d%n", &t, &len) == 1 && lname[len] == '\0') {
+ char *lname;
+ int pos;
+ nullpo_ret(nd);
+ lname = nd->u.scr.label_list[i].name;
+ pos = nd->u.scr.label_list[i].pos;
+ if (sscanf(lname, "OnTimer%d%n", &t, &len) == 1 && len < NAME_LENGTH && lname[len] == '\0') {
// Timer event
struct npc_timerevent_list *te = nd->u.scr.timer_event;
int j, k = nd->u.scr.timeramount;
@@ -580,6 +583,8 @@ int npc_timerevent(int tid, int64 tick, int id, intptr_t data)
struct timer_event_data *ted = (struct timer_event_data*)data;
struct map_session_data *sd=NULL;
+ nullpo_ret(ted);
+
if( nd == NULL ) {
ShowError("npc_timerevent: NPC not found??\n");
return 0;
@@ -732,6 +737,7 @@ void npc_timerevent_quit(struct map_session_data* sd)
struct npc_data* nd;
struct timer_event_data *ted;
+ nullpo_retv(sd);
// Check timer existence
if( sd->npc_timer_id == INVALID_TIMER )
return;
@@ -763,6 +769,7 @@ void npc_timerevent_quit(struct map_session_data* sd)
{
int old_rid,old_timer;
int64 old_tick;
+ nullpo_retv(ted);
//Set timer related info.
old_rid = (nd->u.scr.rid == sd->bl.id ? 0 : nd->u.scr.rid); // Detach rid if the last attached player logged off.
@@ -831,6 +838,8 @@ int npc_settimerevent_tick(struct npc_data* nd, int newtimer)
int npc_event_sub(struct map_session_data* sd, struct event_data* ev, const char* eventname)
{
+ nullpo_retr(2, sd);
+ nullpo_retr(2, eventname);
if ( sd->npc_id != 0 )
{
//Enqueue the event trigger.
@@ -915,9 +924,11 @@ int npc_touch_areanpc_sub(struct block_list *bl, va_list ap) {
* If not, it unsets it and searches for another player in range.
*------------------------------------------*/
int npc_touchnext_areanpc(struct map_session_data* sd, bool leavemap) {
- struct npc_data *nd = map->id2nd(sd->touching_id);
+ struct npc_data *nd;
short xs, ys;
+ nullpo_retr(1, sd);
+ nd = map->id2nd(sd->touching_id);
if( !nd || nd->touching_id != sd->bl.id )
return 1;
@@ -949,7 +960,7 @@ int npc_touch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y)
int j, found_warp = 0;
nullpo_retr(1, sd);
-
+ Assert_retr(1, m >= 0 && m < map->count);
#if 0 // Why not enqueue it? [Inkfish]
if(sd->npc_id)
return 1;
@@ -1034,6 +1045,7 @@ int npc_untouch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y)
{
struct npc_data *nd = NULL;
nullpo_retr(1, sd);
+ Assert_retr(1, m >= 0 && m < map->count);
if (!sd->areanpc_id)
return 0;
@@ -1053,11 +1065,16 @@ int npc_untouch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y)
// Return 1 if Warped
int npc_touch_areanpc2(struct mob_data *md)
{
- int i, m = md->bl.m, x = md->bl.x, y = md->bl.y, id;
+ int i, m, x, y, id;
char eventname[EVENT_NAME_LENGTH];
struct event_data* ev;
int xs, ys;
+ nullpo_ret(md);
+ m = md->bl.m;
+ x = md->bl.x;
+ y = md->bl.y;
+
for( i = 0; i < map->list[m].npc_num; i++ ) {
if( map->list[m].npc[i]->option&OPTION_INVISIBLE )
continue;
@@ -1116,6 +1133,8 @@ int npc_check_areanpc(int flag, int16 m, int16 x, int16 y, int16 range) {
int x0,y0,x1,y1;
int xs,ys;
+ Assert_retr(1, m >= 0 && m < map->count);
+
if (range < 0) return 0;
x0 = max(x-range, 0);
y0 = max(y-range, 0);
@@ -1187,6 +1206,7 @@ struct npc_data* npc_checknear(struct map_session_data* sd, struct block_list* b
if (distance > nd->area_size)
distance = nd->area_size;
+ nullpo_retr(NULL, bl);
if (bl->m != sd->bl.m ||
bl->x < sd->bl.x - distance || bl->x > sd->bl.x + distance ||
bl->y < sd->bl.y - distance || bl->y > sd->bl.y + distance)
@@ -1208,6 +1228,9 @@ int npc_globalmessage(const char* name, const char* mes)
if (!nd)
return 0;
+ nullpo_ret(name);
+ nullpo_ret(mes);
+
snprintf(temp, sizeof(temp), "%s : %s", name, mes);
clif->GlobalMessage(&nd->bl,temp);
@@ -1219,6 +1242,7 @@ void run_tomb(struct map_session_data* sd, struct npc_data* nd) {
char buffer[200];
char time[10];
+ nullpo_retv(nd);
strftime(time, sizeof(time), "%H:%M", localtime(&nd->u.tomb.kill_time));
// TODO: Find exact color?
@@ -1393,6 +1417,8 @@ int npc_cashshop_buylist(struct map_session_data *sd, int points, struct itemlis
struct npc_item_list *shop = NULL;
unsigned short shop_size = 0;
+ nullpo_retr(ERROR_TYPE_SYSTEM, sd);
+ nullpo_retr(ERROR_TYPE_SYSTEM, item_list);
if( sd->state.trading )
return ERROR_TYPE_EXCHANGE;
@@ -1492,6 +1518,9 @@ int npc_buylist_sub(struct map_session_data *sd, struct itemlist *item_list, str
int key_nameid = 0;
int key_amount = 0;
+ nullpo_ret(item_list);
+ nullpo_ret(nd);
+
// discard old contents
script->cleararray_pc(sd, "@bought_nameid", (void*)0);
script->cleararray_pc(sd, "@bought_quantity", (void*)0);
@@ -1514,8 +1543,9 @@ int npc_buylist_sub(struct map_session_data *sd, struct itemlist *item_list, str
/**
* Loads persistent NPC Market Data from SQL
**/
-void npc_market_fromsql(void) {
- SqlStmt* stmt = SQL->StmtMalloc(map->mysql_handle);
+void npc_market_fromsql(void)
+{
+ struct SqlStmt *stmt = SQL->StmtMalloc(map->mysql_handle);
char name[NAME_LENGTH+1];
int itemid;
int amount;
@@ -1565,6 +1595,8 @@ void npc_market_fromsql(void) {
* Saves persistent NPC Market Data into SQL
**/
void npc_market_tosql(struct npc_data *nd, unsigned short index) {
+ nullpo_retv(nd);
+ Assert_retv(index < nd->u.scr.shop->items);
if (SQL_ERROR == SQL->Query(map->mysql_handle, "REPLACE INTO `%s` VALUES ('%s','%d','%u')",
map->npc_market_data_db, nd->exname, nd->u.scr.shop->item[index].nameid, nd->u.scr.shop->item[index].qty))
Sql_ShowDebug(map->mysql_handle);
@@ -1586,12 +1618,16 @@ void npc_market_delfromsql_sub(const char *npcname, unsigned short index) {
* Removes persistent NPC Market Data from SQL
**/
void npc_market_delfromsql(struct npc_data *nd, unsigned short index) {
+ nullpo_retv(nd);
+ Assert_retv(index == USHRT_MAX || index < nd->u.scr.shop->items);
npc->market_delfromsql_sub(nd->exname, index == USHRT_MAX ? index : nd->u.scr.shop->item[index].nameid);
}
/**
* Judges whether to allow and spawn a trader's window.
**/
bool npc_trader_open(struct map_session_data *sd, struct npc_data *nd) {
+ nullpo_retr(false, sd);
+ nullpo_retr(false, nd);
if( !nd->u.scr.shop || !nd->u.scr.shop->items )
return false;
@@ -1630,7 +1666,7 @@ bool npc_trader_open(struct map_session_data *sd, struct npc_data *nd) {
* @param master id of the original npc
**/
void npc_trader_update(int master) {
- DBIterator* iter;
+ struct DBIterator *iter;
struct block_list* bl;
struct npc_data *master_nd = map->id2nd(master);
@@ -1657,6 +1693,9 @@ void npc_trader_count_funds(struct npc_data *nd, struct map_session_data *sd) {
char evname[EVENT_NAME_LENGTH];
struct event_data *ev = NULL;
+ nullpo_retv(nd);
+ nullpo_retv(sd);
+
npc->trader_funds[0] = npc->trader_funds[1] = 0;/* clear */
switch( nd->u.scr.shop->type ) {
@@ -1694,6 +1733,8 @@ bool npc_trader_pay(struct npc_data *nd, struct map_session_data *sd, int price,
char evname[EVENT_NAME_LENGTH];
struct event_data *ev = NULL;
+ nullpo_retr(false, nd);
+ nullpo_retr(false, sd);
npc->trader_ok = false;/* clear */
snprintf(evname, EVENT_NAME_LENGTH, "%s::OnPayFunds",nd->exname);
@@ -1716,6 +1757,7 @@ int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount, int po
int i, price, w;
unsigned short shop_size = 0;
+ nullpo_retr(ERROR_TYPE_SYSTEM, sd);
if( amount <= 0 )
return ERROR_TYPE_ITEM_ID;
@@ -2055,6 +2097,10 @@ int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_list, st
int key_identify = 0;
int key_card[MAX_SLOTS];
+ nullpo_ret(sd);
+ nullpo_ret(item_list);
+ nullpo_ret(nd);
+
// discard old contents
script->cleararray_pc(sd, "@sold_nameid", (void*)0);
script->cleararray_pc(sd, "@sold_quantity", (void*)0);
@@ -2222,7 +2268,7 @@ int npc_remove_map(struct npc_data* nd) {
/**
* @see DBApply
*/
-int npc_unload_ev(DBKey key, DBData *data, va_list ap)
+int npc_unload_ev(union DBKey key, struct DBData *data, va_list ap)
{
struct event_data* ev = DB->data2ptr(data);
char* npcname = va_arg(ap, char *);
@@ -2237,7 +2283,7 @@ int npc_unload_ev(DBKey key, DBData *data, va_list ap)
/**
* @see DBApply
*/
-int npc_unload_ev_label(DBKey key, DBData *data, va_list ap)
+int npc_unload_ev_label(union DBKey key, struct DBData *data, va_list ap)
{
struct linkdb_node **label_linkdb = DB->data2ptr(data);
struct npc_data* nd = va_arg(ap, struct npc_data *);
@@ -2253,6 +2299,7 @@ int npc_unload_dup_sub(struct npc_data* nd, va_list args)
{
int src_id;
+ nullpo_ret(nd);
src_id = va_arg(args, int);
if (nd->src_id == src_id)
npc->unload(nd, true);
@@ -2261,6 +2308,7 @@ int npc_unload_dup_sub(struct npc_data* nd, va_list args)
//Removes all npcs that are duplicates of the passed one. [Skotlex]
void npc_unload_duplicates(struct npc_data* nd) {
+ nullpo_retv(nd);
map->foreachnpc(npc->unload_dup_sub,nd->bl.id);
}
@@ -2384,6 +2432,7 @@ void npc_addsrcfile(const char* name)
struct npc_src_list* file;
struct npc_src_list* file_prev = NULL;
+ nullpo_retv(name);
if( strcmpi(name, "clear") == 0 )
{
npc->clearsrcfile();
@@ -2415,6 +2464,7 @@ void npc_delsrcfile(const char* name)
struct npc_src_list* file = npc->src_files;
struct npc_src_list* file_prev = NULL;
+ nullpo_retv(name);
if( strcmpi(name, "all") == 0 )
{
npc->clearsrcfile();
@@ -2448,10 +2498,10 @@ const char *npc_retainpathreference(const char *filepath)
struct npc_path_data * npd = NULL;
nullpo_ret(filepath);
- if (npc_last_path == filepath) {
- if (npc_last_npd != NULL)
- npc_last_npd->references++;
- return npc_last_ref;
+ if (npc->npc_last_path == filepath) {
+ if (npc->npc_last_npd != NULL)
+ npc->npc_last_npd->references++;
+ return npc->npc_last_ref;
}
if ((npd = strdb_get(npc->path_db,filepath)) == NULL) {
@@ -2466,9 +2516,9 @@ const char *npc_retainpathreference(const char *filepath)
npd->references++;
- npc_last_npd = npd;
- npc_last_ref = npd->path;
- npc_last_path = filepath;
+ npc->npc_last_npd = npd;
+ npc->npc_last_ref = npd->path;
+ npc->npc_last_path = filepath;
return npd->path;
}
@@ -2484,7 +2534,7 @@ void npc_releasepathreference(const char *filepath)
nullpo_retv(filepath);
- if (filepath != npc_last_ref) {
+ if (filepath != npc->npc_last_ref) {
npd = strdb_get(npc->path_db, filepath);
}
@@ -2502,6 +2552,8 @@ void npc_parsename(struct npc_data* nd, const char* name, const char* start, con
struct npc_data* dnd;// duplicate npc
char newname[NAME_LENGTH];
+ nullpo_retv(nd);
+ nullpo_retv(name);
// parse name
p = strstr(name,"::");
if( p ) { // <Display name>::<Unique name>
@@ -2557,6 +2609,7 @@ int npc_parseview(const char* w4, const char* start, const char* buffer, const c
int val = FAKE_NPC, i = 0;
char viewid[1024]; // Max size of name from constants.conf, see script->read_constdb.
+ nullpo_retr(FAKE_NPC, w4);
// Extract view ID / constant
while (w4[i] != '\0') {
if (ISSPACE(w4[i]) || w4[i] == '/' || w4[i] == ',')
@@ -2588,6 +2641,7 @@ int npc_parseview(const char* w4, const char* start, const char* buffer, const c
// Checks if given view is an ID or constant.
bool npc_viewisid(const char * viewid)
{
+ nullpo_retr(false, viewid);
if (atoi(viewid) != FAKE_NPC) {
// Loop through view, looking for non-numeric character.
while (*viewid) {
@@ -2634,6 +2688,8 @@ struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short
int i, flag = 0;
struct npc_data *nd;
+ nullpo_retr(NULL, name);
+
nd = npc->create_npc(WARP, from_mapid, from_x, from_y, 0, battle_config.warp_point_debug ? WARP_DEBUG_CLASS : WARP_CLASS);
safestrncpy(nd->exname, name, ARRAYLENGTH(nd->exname));
@@ -2682,6 +2738,9 @@ const char *npc_parse_warp(const char *w1, const char *w2, const char *w3, const
char mapname[32], to_mapname[32];
struct npc_data *nd;
+ nullpo_retr(strchr(start,'\n'), w1);
+ nullpo_retr(strchr(start,'\n'), w4);
+
// w1=<from map name>,<fromX>,<fromY>,<facing>
// w4=<spanx>,<spany>,<to map name>,<toX>,<toY>
if( sscanf(w1, "%31[^,],%d,%d", mapname, &x, &y) != 3
@@ -2715,7 +2774,7 @@ const char *npc_parse_warp(const char *w1, const char *w2, const char *w3, const
nd->u.warp.y = to_y;
nd->u.warp.xs = xs;
nd->u.warp.ys = ys;
- npc_warp++;
+ npc->npc_warp++;
npc->add_to_location(nd);
@@ -2753,6 +2812,8 @@ const char *npc_parse_shop(const char *w1, const char *w2, const char *w3, const
struct npc_data *nd;
enum npc_subtype type;
+ nullpo_retr(strchr(start,'\n'), w1);
+ nullpo_retr(strchr(start,'\n'), w4);
if( strcmp(w1,"-") == 0 ) {
// 'floating' shop
x = y = dir = 0;
@@ -2858,7 +2919,7 @@ const char *npc_parse_shop(const char *w1, const char *w2, const char *w3, const
npc->parsename(nd, w3, start, buffer, filepath);
nd->path = npc->retainpathreference(filepath);
- ++npc_shop;
+ ++npc->npc_shop;
npc->add_to_location(nd);
return strchr(start,'\n');// continue
@@ -2867,6 +2928,7 @@ const char *npc_parse_shop(const char *w1, const char *w2, const char *w3, const
void npc_convertlabel_db(struct npc_label_list* label_list, const char *filepath) {
int i;
+ nullpo_retv(label_list);
for( i = 0; i < script->label_count; i++ ) {
const char* lname = script->get_str(script->labels[i].key);
int lpos = script->labels[i].pos;
@@ -2993,6 +3055,7 @@ const char *npc_parse_script(const char *w1, const char *w2, const char *w3, con
int label_list_num;
struct npc_data* nd;
+ nullpo_retr(NULL, w1);
if (strcmp(w1, "-") == 0) {
// floating npc
x = 0;
@@ -3062,7 +3125,7 @@ const char *npc_parse_script(const char *w1, const char *w2, const char *w3, con
if( options&NPO_TRADER )
nd->u.scr.trader = true;
nd->u.scr.shop = NULL;
- ++npc_script;
+ ++npc->npc_script;
npc->add_to_location(nd);
//-----------------------------------------
@@ -3129,7 +3192,10 @@ bool npc_duplicate_script_sub(struct npc_data *nd, const struct npc_data *snd, i
int i;
bool retval = true;
- ++npc_script;
+ nullpo_retr(false, nd);
+ nullpo_retr(false, snd);
+
+ ++npc->npc_script;
nd->u.scr.xs = xs;
nd->u.scr.ys = ys;
nd->u.scr.script = snd->u.scr.script;
@@ -3173,7 +3239,10 @@ bool npc_duplicate_script_sub(struct npc_data *nd, const struct npc_data *snd, i
*/
bool npc_duplicate_shop_sub(struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options)
{
- ++npc_shop;
+ nullpo_retr(false, nd);
+ nullpo_retr(false, snd);
+
+ ++npc->npc_shop;
nd->u.shop.shop_item = snd->u.shop.shop_item;
nd->u.shop.count = snd->u.shop.count;
@@ -3188,7 +3257,10 @@ bool npc_duplicate_shop_sub(struct npc_data *nd, const struct npc_data *snd, int
*/
bool npc_duplicate_warp_sub(struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options)
{
- ++npc_warp;
+ nullpo_retr(false, nd);
+ nullpo_retr(false, snd);
+
+ ++npc->npc_warp;
nd->u.warp.xs = xs;
nd->u.warp.ys = ys;
nd->u.warp.mapindex = snd->u.warp.mapindex;
@@ -3217,6 +3289,9 @@ bool npc_duplicate_warp_sub(struct npc_data *nd, const struct npc_data *snd, int
*/
bool npc_duplicate_sub(struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options)
{
+ nullpo_retr(false, nd);
+ nullpo_retr(false, snd);
+
nd->src_id = snd->bl.id;
switch (nd->subtype) {
case SCRIPT:
@@ -3282,6 +3357,8 @@ const char *npc_parse_duplicate(const char *w1, const char *w2, const char *w3,
struct npc_data* dnd;
end = strchr(start,'\n');
+ nullpo_retr(end, w2);
+ nullpo_retr(end, w4);
length = strlen(w2);
// get the npc being duplicated
@@ -3366,7 +3443,13 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m)
int dm = -1, im = -1, xs = -1, ys = -1;
struct npc_data *nd = NULL;
- if( m == -1 || map->list[m].instance_id == -1 )
+ if (m == -1)
+ return 1;
+
+ Assert_retr(1, m >= 0 && m < map->count);
+ nullpo_retr(1, snd);
+
+ if (map->list[m].instance_id == -1)
return 1;
snprintf(newname, ARRAYLENGTH(newname), "dup_%d_%d", map->list[m].instance_id, snd->bl.id);
@@ -3410,10 +3493,15 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m)
}
//Set mapcell CELL_NPC to trigger event later
-void npc_setcells(struct npc_data* nd) {
- int16 m = nd->bl.m, x = nd->bl.x, y = nd->bl.y, xs, ys;
+void npc_setcells(struct npc_data* nd)
+{
+ int16 m, x, y, xs, ys;
int i,j;
+ nullpo_retv(nd);
+ m = nd->bl.m;
+ x = nd->bl.x;
+ y = nd->bl.y;
switch(nd->subtype) {
case WARP:
xs = nd->u.warp.xs;
@@ -3455,9 +3543,13 @@ int npc_unsetcells_sub(struct block_list *bl, va_list ap)
}
void npc_unsetcells(struct npc_data* nd) {
- int16 m = nd->bl.m, x = nd->bl.x, y = nd->bl.y, xs, ys;
+ int16 m, x, y, xs, ys;
int i,j, x0, x1, y0, y1;
+ nullpo_retv(nd);
+ m = nd->bl.m;
+ x = nd->bl.x;
+ y = nd->bl.y;
switch(nd->subtype) {
case WARP:
xs = nd->u.warp.xs;
@@ -3492,7 +3584,9 @@ void npc_unsetcells(struct npc_data* nd) {
void npc_movenpc(struct npc_data* nd, int16 x, int16 y)
{
- const int16 m = nd->bl.m;
+ int16 m;
+ nullpo_retv(nd);
+ m = nd->bl.m;
if (m < 0 || nd->bl.prev == NULL) return; //Not on a map.
x = cap_value(x, 0, map->list[m].xs-1);
@@ -3510,6 +3604,7 @@ void npc_movenpc(struct npc_data* nd, int16 x, int16 y)
void npc_setdisplayname(struct npc_data* nd, const char* newname)
{
nullpo_retv(nd);
+ nullpo_retv(newname);
safestrncpy(nd->name, newname, sizeof(nd->name));
if( map->list[nd->bl.m].users )
@@ -3544,6 +3639,7 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c
size_t len;
nullpo_ret(sd);
+ nullpo_ret(message);
if( ev == NULL || (nd = ev->nd) == NULL ) {
ShowError("npc_event: event not found [%s]\n", eventname);
@@ -3567,7 +3663,7 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c
}
st = script->alloc_state(ev->nd->u.scr.script, ev->pos, sd->bl.id, ev->nd->bl.id);
- script->setd_sub(st, NULL, ".@atcmd_command$", 0, (void *)command, NULL);
+ script->setd_sub(st, NULL, ".@atcmd_command$", 0, command, NULL);
len = strlen(message);
if (len) {
@@ -3623,12 +3719,19 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c
*/
const char *npc_parse_function(const char *w1, const char *w2, const char *w3, const char *w4, const char *start, const char *buffer, const char *filepath, int *retval)
{
- DBMap* func_db;
- DBData old_data;
+ struct DBMap *func_db;
+ struct DBData old_data;
struct script_code *scriptroot;
const char* end;
const char* script_start;
+ nullpo_retr(NULL, w1);
+ nullpo_retr(NULL, w2);
+ nullpo_retr(NULL, w3);
+ nullpo_retr(NULL, w4);
+ nullpo_retr(NULL, start);
+ nullpo_retr(NULL, retval);
+
script_start = strstr(start,"\t{");
end = strchr(start,'\n');
if( *w4 != '{' || script_start == NULL || (end != NULL && script_start > end) ) {
@@ -3672,6 +3775,7 @@ void npc_parse_mob2(struct spawn_data* mobspawn)
{
int i;
+ nullpo_retv(mobspawn);
for( i = mobspawn->active; i < mobspawn->num; ++i ) {
struct mob_data* md = mob->spawn_dataset(mobspawn);
md->spawn = mobspawn;
@@ -3705,6 +3809,11 @@ const char *npc_parse_mob(const char *w1, const char *w2, const char *w3, const
struct spawn_data mobspawn, *data;
struct mob_db* db;
+ nullpo_retr(strchr(start,'\n'), w1);
+ nullpo_retr(strchr(start,'\n'), w2);
+ nullpo_retr(strchr(start,'\n'), w3);
+ nullpo_retr(strchr(start,'\n'), w4);
+
memset(&mobspawn, 0, sizeof(struct spawn_data));
mobspawn.state.boss = (strcmp(w2,"boss_monster") == 0 ? 1 : 0);
@@ -3847,7 +3956,7 @@ const char *npc_parse_mob(const char *w1, const char *w2, const char *w3, const
// spawn / cache the new mobs
if( battle_config.dynamic_mobs && map->addmobtolist(data->m, data) >= 0 ) {
data->state.dynamic = true;
- npc_cache_mob += data->num;
+ npc->npc_cache_mob += data->num;
// check if target map has players
// (usually shouldn't occur when map server is just starting,
@@ -3858,10 +3967,10 @@ const char *npc_parse_mob(const char *w1, const char *w2, const char *w3, const
} else {
data->state.dynamic = false;
npc->parse_mob2(data);
- npc_delay_mob += data->num;
+ npc->npc_delay_mob += data->num;
}
- npc_mob++;
+ npc->npc_mob++;
return strchr(start,'\n');// continue
}
@@ -3911,6 +4020,9 @@ const char *npc_parse_mapflag(const char *w1, const char *w2, const char *w3, co
char mapname[32];
int state = 1;
+ nullpo_retr(strchr(start,'\n'), w1);
+ nullpo_retr(strchr(start,'\n'), w3);
+
// w1=<mapname>
if( sscanf(w1, "%31[^,]", mapname) != 1 )
{
@@ -4335,6 +4447,7 @@ const char *npc_parse_mapflag(const char *w1, const char *w2, const char *w3, co
*/
const char *npc_parse_unknown_object(const char *w1, const char *w2, const char *w3, const char *w4, const char *start, const char *buffer, const char *filepath, int *retval)
{
+ nullpo_retr(start, retval);
ShowError("npc_parsesrcfile: Unable to parse, probably a missing or extra TAB in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
start = strchr(start,'\n');// skip and continue
*retval = EXIT_FAILURE;
@@ -4359,6 +4472,8 @@ int npc_parsesrcfile(const char* filepath, bool runOnInit) {
char* buffer;
const char* p;
+ nullpo_retr(EXIT_FAILURE, filepath);
+
// read whole file to buffer
fp = fopen(filepath, "rb");
if( fp == NULL ) {
@@ -4567,11 +4682,10 @@ void npc_read_event_script(void)
{"Kill NPC Event",script->config.kill_mob_event_name},
};
- for (i = 0; i < NPCE_MAX; i++)
- {
- DBIterator* iter;
- DBKey key;
- DBData *data;
+ for (i = 0; i < NPCE_MAX; i++) {
+ struct DBIterator *iter;
+ union DBKey key;
+ struct DBData *data;
char name[64]="::";
safestrncpy(name+2,config[i].event_name,62);
@@ -4614,9 +4728,10 @@ void npc_read_event_script(void)
/**
* @see DBApply
*/
-int npc_path_db_clear_sub(DBKey key, DBData *data, va_list args)
+int npc_path_db_clear_sub(union DBKey key, struct DBData *data, va_list args)
{
struct npc_path_data *npd = DB->data2ptr(data);
+ nullpo_ret(npd);
if (npd->path)
aFree(npd->path);
return 0;
@@ -4625,7 +4740,7 @@ int npc_path_db_clear_sub(DBKey key, DBData *data, va_list args)
/**
* @see DBApply
*/
-int npc_ev_label_db_clear_sub(DBKey key, DBData *data, va_list args)
+int npc_ev_label_db_clear_sub(union DBKey key, struct DBData *data, va_list args)
{
struct linkdb_node **label_linkdb = DB->data2ptr(data);
linkdb_final(label_linkdb); // linked data (struct event_data*) is freed when clearing ev_db
@@ -4652,12 +4767,12 @@ void npc_process_files( int npc_min ) {
"\t-'"CL_WHITE"%d"CL_RESET"' Spawn sets\n"
"\t-'"CL_WHITE"%d"CL_RESET"' Mobs Cached\n"
"\t-'"CL_WHITE"%d"CL_RESET"' Mobs Not Cached\n",
- npc_id - npc_min, npc_warp, npc_shop, npc_script, npc_mob, npc_cache_mob, npc_delay_mob);
+ npc->npc_id - npc_min, npc->npc_warp, npc->npc_shop, npc->npc_script, npc->npc_mob, npc->npc_cache_mob, npc->npc_delay_mob);
}
//Clear then reload npcs files
int npc_reload(void) {
- int npc_new_min = npc_id;
+ int npc_new_min = npc->npc_id;
struct s_mapiterator* iter;
struct block_list* bl;
@@ -4673,9 +4788,9 @@ int npc_reload(void) {
db_clear(npc->ev_db);
npc->ev_label_db->clear(npc->ev_label_db, npc->ev_label_db_clear_sub);
- npc_last_npd = NULL;
- npc_last_path = NULL;
- npc_last_ref = NULL;
+ npc->npc_last_npd = NULL;
+ npc->npc_last_path = NULL;
+ npc->npc_last_ref = NULL;
//Remove all npcs/mobs. [Skotlex]
iter = mapit_geteachiddb();
@@ -4715,8 +4830,8 @@ int npc_reload(void) {
// clear mob spawn lookup index
mob->clear_spawninfo();
- npc_warp = npc_shop = npc_script = 0;
- npc_mob = npc_cache_mob = npc_delay_mob = 0;
+ npc->npc_warp = npc->npc_shop = npc->npc_script = 0;
+ npc->npc_mob = npc->npc_cache_mob = npc->npc_delay_mob = 0;
// reset mapflags
map->flags_init();
@@ -4754,11 +4869,14 @@ int npc_reload(void) {
}
//Unload all npc in the given file
-bool npc_unloadfile( const char* filepath ) {
- DBIterator * iter = db_iterator(npc->name_db);
+bool npc_unloadfile(const char *filepath)
+{
+ struct DBIterator *iter = db_iterator(npc->name_db);
struct npc_data* nd = NULL;
bool found = false;
+ nullpo_retr(false, filepath);
+
for( nd = dbi_first(iter); dbi_exists(iter); nd = dbi_next(iter) ) {
if( nd->path && strcasecmp(nd->path,filepath) == 0 ) { // FIXME: This can break in case-sensitive file systems
found = true;
@@ -4797,6 +4915,9 @@ int do_final_npc(void) {
void npc_debug_warps_sub(struct npc_data* nd) {
int16 m;
+
+ nullpo_retv(nd);
+
if (nd->bl.type != BL_NPC || nd->subtype != WARP || nd->bl.m < 0)
return;
@@ -4833,14 +4954,8 @@ static void npc_debug_warps(void) {
int do_init_npc(bool minimal) {
int i;
- memset(&npc->base_ud, 0, sizeof( struct unit_data) );
- npc->base_ud.bl = NULL;
- npc->base_ud.walktimer = INVALID_TIMER;
- npc->base_ud.skilltimer = INVALID_TIMER;
- npc->base_ud.attacktimer = INVALID_TIMER;
- npc->base_ud.attackabletime =
- npc->base_ud.canact_tick =
- npc->base_ud.canmove_tick = timer->gettick();
+ unit->init_ud(&npc->base_ud);
+ npc->base_ud.bl = NULL;
//Stock view data for normal npcs.
memset(&npc_viewdb, 0, sizeof(npc_viewdb));
@@ -4856,9 +4971,9 @@ int do_init_npc(bool minimal) {
npc->name_db = strdb_alloc(DB_OPT_BASE, NAME_LENGTH);
npc->path_db = strdb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, 0);
- npc_last_npd = NULL;
- npc_last_path = NULL;
- npc_last_ref = NULL;
+ npc->npc_last_npd = NULL;
+ npc->npc_last_path = NULL;
+ npc->npc_last_ref = NULL;
// Should be loaded before npc processing, otherwise labels could overwrite constant values
// and lead to undefined behavior [Panikon]
@@ -4902,7 +5017,7 @@ int do_init_npc(bool minimal) {
strcpy(npc->fake_nd->name,"FAKE_NPC");
memcpy(npc->fake_nd->exname, npc->fake_nd->name, 9);
- npc_script++;
+ npc->npc_script++;
npc->fake_nd->bl.type = BL_NPC;
npc->fake_nd->subtype = SCRIPT;
@@ -4916,6 +5031,17 @@ int do_init_npc(bool minimal) {
void npc_defaults(void) {
npc = &npc_s;
+ npc->npc_id = START_NPC_NUM;
+ npc->npc_warp = 0;
+ npc->npc_shop = 0;
+ npc->npc_script = 0;
+ npc->npc_mob = 0;
+ npc->npc_delay_mob = 0;
+ npc->npc_cache_mob = 0;
+ npc->npc_last_path = NULL;
+ npc->npc_last_ref = NULL;
+ npc->npc_last_npd = NULL;
+
npc->motd = NULL;
npc->ev_db = NULL;
npc->ev_label_db = NULL;