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.c501
1 files changed, 335 insertions, 166 deletions
diff --git a/src/map/npc.c b/src/map/npc.c
index 5d8a0274e..090c03e58 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -1,5 +1,6 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
+// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// See the LICENSE file
+// Portions Copyright (c) Athena Dev Teams
#include "../common/cbasetypes.h"
#include "../common/timer.h"
@@ -95,6 +96,7 @@ static DBMap *npc_path_db;
//For holding the view data of npc classes. [Skotlex]
static struct view_data npc_viewdb[MAX_NPC_CLASS];
+static struct view_data npc_viewdb2[MAX_NPC_CLASS2_END-MAX_NPC_CLASS2_START];
static struct script_event_s
{ //Holds pointers to the commonly executed scripts for speedup. [Skotlex]
@@ -107,11 +109,34 @@ struct view_data* npc_get_viewdata(int class_)
{ //Returns the viewdata for normal npc classes.
if( class_ == INVISIBLE_CLASS )
return &npc_viewdb[0];
- if (npcdb_checkid(class_) || class_ == WARP_CLASS)
- return &npc_viewdb[class_];
+ if (npcdb_checkid(class_) || class_ == WARP_CLASS){
+ if( class_ > MAX_NPC_CLASS2_START ){
+ return &npc_viewdb2[class_-MAX_NPC_CLASS2_START];
+ }else{
+ return &npc_viewdb[class_];
+ }
+ }
return NULL;
}
+static int npc_isnear_sub(struct block_list* bl, va_list args) {
+ struct npc_data *nd = (struct npc_data*)bl;
+
+ if( nd->sc.option & (OPTION_HIDE|OPTION_INVISIBLE) )
+ return 0;
+
+ return 1;
+}
+
+bool npc_isnear(struct block_list * bl) {
+
+ if( battle_config.min_npc_vendchat_distance > 0 &&
+ map_foreachinrange(npc_isnear_sub,bl, battle_config.min_npc_vendchat_distance, BL_NPC) )
+ return true;
+
+ return false;
+}
+
int npc_ontouch_event(struct map_session_data *sd, struct npc_data *nd)
{
char name[EVENT_NAME_LENGTH];
@@ -180,24 +205,24 @@ int npc_enable(const char* name, int flag)
if (flag&1) {
nd->sc.option&=~OPTION_INVISIBLE;
- clif_spawn(&nd->bl);
+ clif->spawn(&nd->bl);
} else if (flag&2)
nd->sc.option&=~OPTION_HIDE;
else if (flag&4)
nd->sc.option|= OPTION_HIDE;
else { //Can't change the view_data to invisible class because the view_data for all npcs is shared! [Skotlex]
nd->sc.option|= OPTION_INVISIBLE;
- clif_clearunit_area(&nd->bl,CLR_OUTSIGHT); // Hack to trick maya purple card [Xazax]
+ clif->clearunit_area(&nd->bl,CLR_OUTSIGHT); // Hack to trick maya purple card [Xazax]
}
if (nd->class_ == WARP_CLASS || nd->class_ == FLAG_CLASS)
{ //Client won't display option changes for these classes [Toms]
if (nd->sc.option&(OPTION_HIDE|OPTION_INVISIBLE))
- clif_clearunit_area(&nd->bl, CLR_OUTSIGHT);
+ clif->clearunit_area(&nd->bl, CLR_OUTSIGHT);
else
- clif_spawn(&nd->bl);
+ clif->spawn(&nd->bl);
} else
- clif_changeoption(&nd->bl);
+ clif->changeoption(&nd->bl);
if( flag&3 && (nd->u.scr.xs >= 0 || nd->u.scr.ys >= 0) ) //check if player standing on a OnTouchArea
map_foreachinarea( npc_enable_sub, nd->bl.m, nd->bl.x-nd->u.scr.xs, nd->bl.y-nd->u.scr.ys, nd->bl.x+nd->u.scr.xs, nd->bl.y+nd->u.scr.ys, BL_PC, nd );
@@ -215,26 +240,41 @@ struct npc_data* npc_name2id(const char* name)
/**
* For the Secure NPC Timeout option (check config/Secure.h) [RR]
**/
-#if SECURE_NPCTIMEOUT
+#ifdef SECURE_NPCTIMEOUT
/**
* Timer to check for idle time and timeout the dialog if necessary
**/
int npc_rr_secure_timeout_timer(int tid, unsigned int tick, int id, intptr_t data) {
struct map_session_data* sd = NULL;
+ unsigned int timeout = NPC_SECURE_TIMEOUT_NEXT;
if( (sd = map_id2sd(id)) == NULL || !sd->npc_id ) {
if( sd ) sd->npc_idle_timer = INVALID_TIMER;
return 0;//Not logged in anymore OR no longer attached to a npc
}
- if( DIFF_TICK(tick,sd->npc_idle_tick) > (SECURE_NPCTIMEOUT*1000) ) {
+
+ switch( sd->npc_idle_type ) {
+ case NPCT_INPUT:
+ timeout = NPC_SECURE_TIMEOUT_INPUT;
+ break;
+ case NPCT_MENU:
+ timeout = NPC_SECURE_TIMEOUT_MENU;
+ break;
+ //case NPCT_WAIT: var starts with this value
+ }
+
+ if( DIFF_TICK(tick,sd->npc_idle_tick) > (timeout*1000) ) {
/**
* If we still have the NPC script attached, tell it to stop.
**/
if( sd->st )
sd->st->state = END;
+ sd->state.menu_or_input = 0;
+ sd->npc_menu = 0;
+
/**
* This guy's been idle for longer than allowed, close him.
**/
- clif_scriptclose(sd,sd->npc_id);
+ clif->scriptclose(sd,sd->npc_id);
sd->npc_idle_timer = INVALID_TIMER;
} else //Create a new instance of ourselves to continue
sd->npc_idle_timer = add_timer(gettick() + (SECURE_NPCTIMEOUT_INTERVAL*1000),npc_rr_secure_timeout_timer,sd->bl.id,0);
@@ -252,7 +292,7 @@ int npc_event_dequeue(struct map_session_data* sd)
if(sd->npc_id)
{ //Current script is aborted.
if(sd->state.using_fake_npc){
- clif_clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd);
+ clif->clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd);
sd->state.using_fake_npc = 0;
}
if (sd->st) {
@@ -313,7 +353,7 @@ int npc_event_doall_sub(DBKey key, DBData *data, va_list ap)
const char* name;
int rid;
- nullpo_ret(ev = db_data2ptr(data));
+ nullpo_ret(ev = DB->data2ptr(data));
nullpo_ret(c = va_arg(ap, int *));
nullpo_ret(name = va_arg(ap, const char *));
rid = va_arg(ap, int);
@@ -341,7 +381,7 @@ static int npc_event_do_sub(DBKey key, DBData *data, va_list ap)
int* c;
const char* name;
- nullpo_ret(ev = db_data2ptr(data));
+ nullpo_ret(ev = DB->data2ptr(data));
nullpo_ret(c = va_arg(ap, int *));
nullpo_ret(name = va_arg(ap, const char *));
@@ -488,7 +528,6 @@ struct timer_event_data {
*------------------------------------------*/
int npc_timerevent(int tid, unsigned int tick, int id, intptr_t data)
{
- int next;
int old_rid, old_timer;
unsigned int old_tick;
struct npc_data* nd=(struct npc_data *)map_id2bl(id);
@@ -526,6 +565,7 @@ int npc_timerevent(int tid, unsigned int tick, int id, intptr_t data)
ted->next++;
if( nd->u.scr.timeramount > ted->next )
{
+ int next;
next = nd->u.scr.timer_event[ ted->next ].timer - nd->u.scr.timer_event[ ted->next - 1 ].timer;
ted->time += next;
if( sd )
@@ -560,10 +600,9 @@ int npc_timerevent(int tid, unsigned int tick, int id, intptr_t data)
*------------------------------------------*/
int npc_timerevent_start(struct npc_data* nd, int rid)
{
- int j, next;
+ int j;
unsigned int tick = gettick();
struct map_session_data *sd = NULL; //Player to whom script is attached.
- struct timer_event_data *ted;
nullpo_ret(nd);
@@ -587,6 +626,8 @@ int npc_timerevent_start(struct npc_data* nd, int rid)
if (j < nd->u.scr.timeramount)
{
+ int next;
+ struct timer_event_data *ted;
// Arrange for the next event
ted = ers_alloc(timer_event_ers, struct timer_event_data);
ted->next = j; // Set event index
@@ -947,7 +988,7 @@ int npc_touch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y)
struct unit_data *ud = unit_bl2ud(&sd->bl);
if( ud && ud->walkpath.path_pos < ud->walkpath.path_len )
{ // Since walktimer always == INVALID_TIMER at this time, we stop walking manually. [Inkfish]
- clif_fixpos(&sd->bl);
+ clif->fixpos(&sd->bl);
ud->walkpath.path_pos = ud->walkpath.path_len;
}
sd->areanpc_id = map[m].npc[i]->bl.id;
@@ -1118,7 +1159,7 @@ int npc_globalmessage(const char* name, const char* mes)
return 0;
snprintf(temp, sizeof(temp), "%s : %s", name, mes);
- clif_GlobalMessage(&nd->bl,temp);
+ clif->GlobalMessage(&nd->bl,temp);
return 0;
}
@@ -1133,19 +1174,19 @@ void run_tomb(struct map_session_data* sd, struct npc_data* nd)
// TODO: Find exact color?
snprintf(buffer, sizeof(buffer), msg_txt(657), nd->u.tomb.md->db->name);
- clif_scriptmes(sd, nd->bl.id, buffer);
+ clif->scriptmes(sd, nd->bl.id, buffer);
- clif_scriptmes(sd, nd->bl.id, msg_txt(658));
+ clif->scriptmes(sd, nd->bl.id, msg_txt(658));
snprintf(buffer, sizeof(buffer), msg_txt(659), time);
- clif_scriptmes(sd, nd->bl.id, buffer);
+ clif->scriptmes(sd, nd->bl.id, buffer);
- clif_scriptmes(sd, nd->bl.id, msg_txt(660));
+ clif->scriptmes(sd, nd->bl.id, msg_txt(660));
snprintf(buffer, sizeof(buffer), msg_txt(661), nd->u.tomb.killer_name[0] ? nd->u.tomb.killer_name : "Unknown");
- clif_scriptmes(sd, nd->bl.id, buffer);
+ clif->scriptmes(sd, nd->bl.id, buffer);
- clif_scriptclose(sd, nd->bl.id);
+ clif->scriptclose(sd, nd->bl.id);
}
/*==========================================
@@ -1170,10 +1211,10 @@ int npc_click(struct map_session_data* sd, struct npc_data* nd)
switch(nd->subtype) {
case SHOP:
- clif_npcbuysell(sd,nd->bl.id);
+ clif->npcbuysell(sd,nd->bl.id);
break;
case CASHSHOP:
- clif_cashshop_show(sd,nd);
+ clif->cashshop_show(sd,nd);
break;
case SCRIPT:
run_script(nd->u.scr.script,0,sd->bl.id,nd->bl.id);
@@ -1189,7 +1230,7 @@ int npc_click(struct map_session_data* sd, struct npc_data* nd)
/*==========================================
*
*------------------------------------------*/
-int npc_scriptcont(struct map_session_data* sd, int id)
+int npc_scriptcont(struct map_session_data* sd, int id, bool closing)
{
nullpo_retr(1, sd);
@@ -1211,7 +1252,7 @@ int npc_scriptcont(struct map_session_data* sd, int id)
/**
* For the Secure NPC Timeout option (check config/Secure.h) [RR]
**/
-#if SECURE_NPCTIMEOUT
+#ifdef SECURE_NPCTIMEOUT
/**
* Update the last NPC iteration
**/
@@ -1224,6 +1265,9 @@ int npc_scriptcont(struct map_session_data* sd, int id)
if( sd->progressbar.npc_id && DIFF_TICK(sd->progressbar.timeout,gettick()) > 0 )
return 1;
+ if( closing && sd->st->state == CLOSE )
+ sd->st->state = END;
+
run_script_main(sd->st);
return 0;
@@ -1259,9 +1303,9 @@ int npc_buysellsel(struct map_session_data* sd, int id, int type)
sd->npc_shopid = id;
if (type==0) {
- clif_buylist(sd,nd);
+ clif->buylist(sd,nd);
} else {
- clif_selllist(sd);
+ clif->selllist(sd);
}
return 0;
}
@@ -1457,12 +1501,12 @@ int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount, int po
/// Player item purchase from npc shop.
///
/// @param item_list 'n' pairs <amount,itemid>
-/// @return result code for clif_parse_NpcBuyListSend
+/// @return result code for clif->parse_NpcBuyListSend
int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
{
struct npc_data* nd;
double z;
- int i,j,w,skill,new_;
+ int i,j,w,skill_t,new_, idx = skill->get_index(MC_DISCOUNT);
nullpo_retr(3, sd);
nullpo_retr(3, item_list);
@@ -1477,8 +1521,7 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
w = 0;
new_ = 0;
// process entries in buy list, one by one
- for( i = 0; i < n; ++i )
- {
+ for( i = 0; i < n; ++i ) {
int nameid, amount, value;
// find this entry in the shop's sell list
@@ -1497,20 +1540,19 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
if( !itemdb_exists(nameid) )
return 3; // item no longer in itemdb
- if( !itemdb_isstackable(nameid) && amount > 1 )
- { //Exploit? You can't buy more than 1 of equipment types o.O
+ if( !itemdb_isstackable(nameid) && amount > 1 ) {
+ //Exploit? You can't buy more than 1 of equipment types o.O
ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of nonstackable item %d!\n",
sd->status.name, sd->status.account_id, sd->status.char_id, amount, nameid);
amount = item_list[i*2+0] = 1;
}
- if( nd->master_nd )
- {// Script-controlled shops decide by themselves, what can be bought and for what price.
+ if( nd->master_nd ) {
+ // Script-controlled shops decide by themselves, what can be bought and for what price.
continue;
}
- switch( pc_checkadditem(sd,nameid,amount) )
- {
+ switch( pc_checkadditem(sd,nameid,amount) ) {
case ADDITEM_EXIST:
break;
@@ -1540,16 +1582,14 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
pc_payzeny(sd,(int)z,LOG_TYPE_NPC, NULL);
- for( i = 0; i < n; ++i )
- {
+ for( i = 0; i < n; ++i ) {
int nameid = item_list[i*2+1];
int amount = item_list[i*2+0];
struct item item_tmp;
if (itemdb_type(nameid) == IT_PETEGG)
pet_create_egg(sd, nameid);
- else
- {
+ else {
memset(&item_tmp,0,sizeof(item_tmp));
item_tmp.nameid = nameid;
item_tmp.identify = 1;
@@ -1559,14 +1599,12 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
}
// custom merchant shop exp bonus
- if( battle_config.shop_exp > 0 && z > 0 && (skill = pc_checkskill(sd,MC_DISCOUNT)) > 0 )
- {
- if( sd->status.skill[MC_DISCOUNT].flag >= SKILL_FLAG_REPLACED_LV_0 )
- skill = sd->status.skill[MC_DISCOUNT].flag - SKILL_FLAG_REPLACED_LV_0;
+ if( battle_config.shop_exp > 0 && z > 0 && (skill_t = pc_checkskill2(sd,idx)) > 0 ) {
+ if( sd->status.skill[idx].flag >= SKILL_FLAG_REPLACED_LV_0 )
+ skill_t = sd->status.skill[idx].flag - SKILL_FLAG_REPLACED_LV_0;
- if( skill > 0 )
- {
- z = z * (double)skill * (double)battle_config.shop_exp/10000.;
+ if( skill_t > 0 ) {
+ z = z * (double)skill_t * (double)battle_config.shop_exp/10000.;
if( z < 1 )
z = 1;
pc_gainexp(sd,NULL,0,(int)z, false);
@@ -1636,45 +1674,40 @@ static int npc_selllist_sub(struct map_session_data* sd, int n, unsigned short*
/// Player item selling to npc shop.
///
/// @param item_list 'n' pairs <index,amount>
-/// @return result code for clif_parse_NpcSellListSend
+/// @return result code for clif->parse_NpcSellListSend
int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list)
{
double z;
- int i,skill;
+ int i,skill_t, idx = skill->get_index(MC_OVERCHARGE);
struct npc_data *nd;
nullpo_retr(1, sd);
nullpo_retr(1, item_list);
- if( ( nd = npc_checknear(sd, map_id2bl(sd->npc_shopid)) ) == NULL || nd->subtype != SHOP )
- {
+ if( ( nd = npc_checknear(sd, map_id2bl(sd->npc_shopid)) ) == NULL || nd->subtype != SHOP ) {
return 1;
}
z = 0;
// verify the sell list
- for( i = 0; i < n; i++ )
- {
+ for( i = 0; i < n; i++ ) {
int nameid, amount, idx, value;
idx = item_list[i*2]-2;
amount = item_list[i*2+1];
- if( idx >= MAX_INVENTORY || idx < 0 || amount < 0 )
- {
+ if( idx >= MAX_INVENTORY || idx < 0 || amount < 0 ) {
return 1;
}
nameid = sd->status.inventory[idx].nameid;
- if( !nameid || !sd->inventory_data[idx] || sd->status.inventory[idx].amount < amount )
- {
+ if( !nameid || !sd->inventory_data[idx] || sd->status.inventory[idx].amount < amount ) {
return 1;
}
- if( nd->master_nd )
- {// Script-controlled shops decide by themselves, what can be sold and at what price.
+ if( nd->master_nd ) {// Script-controlled shops decide by themselves, what can be sold and at what price.
continue;
}
@@ -1683,23 +1716,19 @@ int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list)
z+= (double)value*amount;
}
- if( nd->master_nd )
- {// Script-controlled shops
+ if( nd->master_nd ) { // Script-controlled shops
return npc_selllist_sub(sd, n, item_list, nd->master_nd);
}
// delete items
- for( i = 0; i < n; i++ )
- {
+ for( i = 0; i < n; i++ ) {
int amount, idx;
idx = item_list[i*2]-2;
amount = item_list[i*2+1];
- if( sd->inventory_data[idx]->type == IT_PETEGG && sd->status.inventory[idx].card[0] == CARD0_PET )
- {
- if( search_petDB_index(sd->status.inventory[idx].nameid, PET_EGG) >= 0 )
- {
+ if( sd->inventory_data[idx]->type == IT_PETEGG && sd->status.inventory[idx].card[0] == CARD0_PET ) {
+ if( search_petDB_index(sd->status.inventory[idx].nameid, PET_EGG) >= 0 ) {
intif_delete_petdata(MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2]));
}
}
@@ -1713,14 +1742,12 @@ int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list)
pc_getzeny(sd, (int)z, LOG_TYPE_NPC, NULL);
// custom merchant shop exp bonus
- if( battle_config.shop_exp > 0 && z > 0 && ( skill = pc_checkskill(sd,MC_OVERCHARGE) ) > 0)
- {
- if( sd->status.skill[MC_OVERCHARGE].flag >= SKILL_FLAG_REPLACED_LV_0 )
- skill = sd->status.skill[MC_OVERCHARGE].flag - SKILL_FLAG_REPLACED_LV_0;
+ if( battle_config.shop_exp > 0 && z > 0 && ( skill_t = pc_checkskill2(sd,idx) ) > 0) {
+ if( sd->status.skill[idx].flag >= SKILL_FLAG_REPLACED_LV_0 )
+ skill_t = sd->status.skill[idx].flag - SKILL_FLAG_REPLACED_LV_0;
- if( skill > 0 )
- {
- z = z * (double)skill * (double)battle_config.shop_exp/10000.;
+ if( skill_t > 0 ) {
+ z = z * (double)skill_t * (double)battle_config.shop_exp/10000.;
if( z < 1 )
z = 1;
pc_gainexp(sd, NULL, 0, (int)z, false);
@@ -1740,7 +1767,7 @@ int npc_remove_map(struct npc_data* nd)
if(nd->bl.prev == NULL || nd->bl.m < 0)
return 1; //Not assigned to a map.
m = nd->bl.m;
- clif_clearunit_area(&nd->bl,CLR_RESPAWN);
+ clif->clearunit_area(&nd->bl,CLR_RESPAWN);
npc_unsetcells(nd);
map_delblock(&nd->bl);
//Remove npc from map[].npc list. [Skotlex]
@@ -1758,7 +1785,7 @@ int npc_remove_map(struct npc_data* nd)
*/
static int npc_unload_ev(DBKey key, DBData *data, va_list ap)
{
- struct event_data* ev = db_data2ptr(data);
+ struct event_data* ev = DB->data2ptr(data);
char* npcname = va_arg(ap, char *);
if(strcmp(ev->nd->exname,npcname)==0){
@@ -1825,7 +1852,7 @@ int npc_unload(struct npc_data* nd, bool single) {
ev_db->foreach(ev_db,npc_unload_ev,nd->exname); //Clean up all events related
iter = mapit_geteachpc();
- for( bl = (struct block_list*)mapit_first(iter); mapit_exists(iter); bl = (struct block_list*)mapit_next(iter) ) {
+ for( bl = (struct block_list*)mapit->first(iter); mapit->exists(iter); bl = (struct block_list*)mapit->next(iter) ) {
struct map_session_data *sd = ((TBL_PC*)bl);
if( sd && sd->npc_timer_id != INVALID_TIMER ) {
const struct TimerData *td = get_timer(sd->npc_timer_id);
@@ -1839,10 +1866,10 @@ int npc_unload(struct npc_data* nd, bool single) {
sd->npc_timer_id = INVALID_TIMER;
}
}
- mapit_free(iter);
+ mapit->free(iter);
if (nd->u.scr.timerid != INVALID_TIMER) {
- const struct TimerData *td = NULL;
+ const struct TimerData *td;
td = get_timer(nd->u.scr.timerid);
if (td && td->data)
ers_free(timer_event_ers, (void*)td->data);
@@ -1862,7 +1889,7 @@ int npc_unload(struct npc_data* nd, bool single) {
}
}
if( nd->u.scr.guild_id )
- guild_flag_remove(nd);
+ guild->flag_remove(nd);
}
script_stop_sleeptimers(nd->bl.id);
@@ -1915,7 +1942,7 @@ void npc_addsrcfile(const char* name)
file = (struct npc_src_list*)aMalloc(sizeof(struct npc_src_list) + strlen(name));
file->next = NULL;
- strncpy(file->name, name, strlen(name) + 1);
+ safestrncpy(file->name, name, strlen(name) + 1);
if( file_prev == NULL )
npc_src_files = file;
else
@@ -2076,7 +2103,7 @@ struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short
status_change_init(&nd->bl);
unit_dataset(&nd->bl);
if( map[nd->bl.m].users )
- clif_spawn(&nd->bl);
+ clif->spawn(&nd->bl);
strdb_put(npcname_db, nd->exname, nd);
return nd;
@@ -2107,6 +2134,11 @@ static const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const
return strchr(start,'\n');// skip and continue
}
+ if( m != -1 && ( x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) ) {
+ ShowError("npc_parse_warp: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d, in file '%s', line '%d'\n", map[m].name, x, y, map[m].xs, map[m].ys,filepath,strline(buffer,start-buffer));
+ return strchr(start,'\n');;//try next
+ }
+
CREATE(nd, struct npc_data, 1);
nd->bl.id = npc_get_new_npc_id();
@@ -2137,7 +2169,7 @@ static const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const
status_change_init(&nd->bl);
unit_dataset(&nd->bl);
if( map[nd->bl.m].users )
- clif_spawn(&nd->bl);
+ clif->spawn(&nd->bl);
strdb_put(npcname_db, nd->exname, nd);
return strchr(start,'\n');// continue
@@ -2154,13 +2186,10 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
struct npc_data *nd;
enum npc_subtype type;
- if( strcmp(w1,"-") == 0 )
- {// 'floating' shop?
+ if( strcmp(w1,"-") == 0 ) {// 'floating' shop?
x = y = dir = 0;
m = -1;
- }
- else
- {// w1=<map name>,<x>,<y>,<facing>
+ } else {// w1=<map name>,<x>,<y>,<facing>
char mapname[32];
if( sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4
|| strchr(w4, ',') == NULL )
@@ -2172,6 +2201,11 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
m = map_mapname2mapid(mapname);
}
+ if( m != -1 && ( x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) ) {
+ ShowError("npc_parse_shop: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d, in file '%s', line '%d'\n", map[m].name, x, y, map[m].xs, map[m].ys,filepath,strline(buffer,start-buffer));
+ return strchr(start,'\n');;//try next
+ }
+
if( !strcasecmp(w2,"cashshop") )
type = CASHSHOP;
else
@@ -2250,7 +2284,7 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
unit_dataset(&nd->bl);
nd->ud.dir = dir;
if( map[nd->bl.m].users )
- clif_spawn(&nd->bl);
+ clif->spawn(&nd->bl);
} else
{// 'floating' shop?
map_addiddb(&nd->bl);
@@ -2268,7 +2302,7 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
int npc_convertlabel_db(DBKey key, DBData *data, va_list ap)
{
const char* lname = (const char*)key.str;
- int lpos = db_data2i(data);
+ int lpos = DB->data2i(data);
struct npc_label_list** label_list;
int* label_list_num;
const char* filepath;
@@ -2463,7 +2497,7 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons
{
status_set_viewdata(&nd->bl, nd->class_);
if( map[nd->bl.m].users )
- clif_spawn(&nd->bl);
+ clif->spawn(&nd->bl);
}
}
else
@@ -2557,6 +2591,11 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
m = map_mapname2mapid(mapname);
}
+ if( m != -1 && ( x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) ) {
+ ShowError("npc_parse_duplicate: out-of-bounds coordinates (\"%s\",%d,%d), map is %dx%d, in file '%s', line '%d'\n", map[m].name, x, y, map[m].xs, map[m].ys,filepath,strline(buffer,start-buffer));
+ return end;//try next
+ }
+
if( type == WARP && sscanf(w4, "%d,%d", &xs, &ys) == 2 );// <spanx>,<spany>
else if( type == SCRIPT && sscanf(w4, "%d,%d,%d", &class_, &xs, &ys) == 3);// <sprite id>,<triggerX>,<triggerY>
else if( type != WARP ) class_ = atoi(w4);// <sprite id>
@@ -2624,7 +2663,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
{
status_set_viewdata(&nd->bl, nd->class_);
if( map[nd->bl.m].users )
- clif_spawn(&nd->bl);
+ clif->spawn(&nd->bl);
}
}
else
@@ -2702,7 +2741,7 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) {
status_change_init(&wnd->bl);
unit_dataset(&wnd->bl);
if( map[wnd->bl.m].users )
- clif_spawn(&wnd->bl);
+ clif->spawn(&wnd->bl);
strdb_put(npcname_db, wnd->exname, wnd);
}
else
@@ -2806,9 +2845,9 @@ void npc_movenpc(struct npc_data* nd, int16 x, int16 y)
x = cap_value(x, 0, map[m].xs-1);
y = cap_value(y, 0, map[m].ys-1);
- map_foreachinrange(clif_outsight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl);
+ map_foreachinrange(clif->outsight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl);
map_moveblock(&nd->bl, x, y, gettick());
- map_foreachinrange(clif_insight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl);
+ map_foreachinrange(clif->insight, &nd->bl, AREA_SIZE, BL_PC, &nd->bl);
}
/// Changes the display name of the npc.
@@ -2821,7 +2860,7 @@ void npc_setdisplayname(struct npc_data* nd, const char* newname)
safestrncpy(nd->name, newname, sizeof(nd->name));
if( map[nd->bl.m].users )
- clif_charnameack(0, &nd->bl);
+ clif->charnameack(0, &nd->bl);
}
/// Changes the display class of the npc.
@@ -2836,11 +2875,11 @@ void npc_setclass(struct npc_data* nd, short class_)
return;
if( map[nd->bl.m].users )
- clif_clearunit_area(&nd->bl, CLR_OUTSIGHT);// fade out
+ clif->clearunit_area(&nd->bl, CLR_OUTSIGHT);// fade out
nd->class_ = class_;
status_set_viewdata(&nd->bl, class_);
if( map[nd->bl.m].users )
- clif_spawn(&nd->bl);// fade in
+ clif->spawn(&nd->bl);// fade in
}
// @commands (script based)
@@ -2880,24 +2919,25 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c
setd_sub(st, NULL, ".@atcmd_command$", 0, (void *)command, NULL);
// split atcmd parameters based on spaces
- i = 0;
- j = 0;
-
temp = (char*)aMalloc(strlen(message) + 1);
- while( message[i] != '\0' ) {
- if( message[i] == ' ' && k < 127 ) {
- temp[j] = '\0';
- setd_sub(st, NULL, ".@atcmd_parameters$", k++, (void *)temp, NULL);
- j = 0;
- ++i;
- } else
- temp[j++] = message[i++];
+ for( i = 0; i < ( strlen( message ) + 1 ) && k < 127; i ++ ) {
+ if( message[i] == ' ' || message[i] == '\0' ) {
+ if( message[ ( i - 1 ) ] == ' ' ) {
+ continue; // To prevent "@atcmd [space][space]" and .@atcmd_numparameters return 1 without any parameter.
+ }
+ temp[k] = '\0';
+ k = 0;
+ if( temp[0] != '\0' ) {
+ setd_sub( st, NULL, ".@atcmd_parameters$", j++, (void *)temp, NULL );
+ }
+ } else {
+ temp[k] = message[i];
+ k++;
+ }
}
- temp[j] = '\0';
- setd_sub(st, NULL, ".@atcmd_parameters$", k++, (void *)temp, NULL);
- setd_sub(st, NULL, ".@atcmd_numparameters", 0, (void *)&k, NULL);
+ setd_sub(st, NULL, ".@atcmd_numparameters", 0, (void *)__64BPTRSIZE(j), NULL);
aFree(temp);
run_script_main(st);
@@ -2932,9 +2972,9 @@ static const char* npc_parse_function(char* w1, char* w2, char* w3, char* w4, co
return end;
func_db = script_get_userfunc_db();
- if (func_db->put(func_db, db_str2key(w3), db_ptr2data(script), &old_data))
+ if (func_db->put(func_db, DB->str2key(w3), DB->ptr2data(script), &old_data))
{
- struct script_code *oldscript = (struct script_code*)db_data2ptr(&old_data);
+ struct script_code *oldscript = (struct script_code*)DB->data2ptr(&old_data);
ShowInfo("npc_parse_function: Overwriting user function [%s] (%s:%d)\n", w3, filepath, strline(buffer,start-buffer));
script_free_vars(oldscript->script_vars);
aFree(oldscript->script_buf);
@@ -3132,14 +3172,12 @@ static const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const c
return strchr(start,'\n');// continue
}
-
/*==========================================
* Set or disable mapflag on map
* eg : bat_c01 mapflag battleground 2
* also chking if mapflag conflict with another
*------------------------------------------*/
-static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath)
-{
+const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath) {
int16 m;
char mapname[32];
int state = 1;
@@ -3206,19 +3244,23 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con
map[m].flag.nozenypenalty=state;
}
else if (!strcmpi(w3,"pvp")) {
+ struct map_zone_data *zone;
map[m].flag.pvp = state;
- if( state && (map[m].flag.gvg || map[m].flag.gvg_dungeon || map[m].flag.gvg_castle) )
- {
+ if( state && (map[m].flag.gvg || map[m].flag.gvg_dungeon || map[m].flag.gvg_castle) ) {
map[m].flag.gvg = 0;
map[m].flag.gvg_dungeon = 0;
map[m].flag.gvg_castle = 0;
ShowWarning("npc_parse_mapflag: You can't set PvP and GvG flags for the same map! Removing GvG flags from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer));
}
- if( state && map[m].flag.battleground )
- {
+ if( state && map[m].flag.battleground ) {
map[m].flag.battleground = 0;
ShowWarning("npc_parse_mapflag: You can't set PvP and BattleGround flags for the same map! Removing BattleGround flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer));
}
+ if( state && (zone = strdb_get(zone_db, MAP_ZONE_PVP_NAME)) && map[m].zone != zone ) {
+ map_zone_change(m,zone,start,buffer,filepath);
+ } else if ( !state ) {
+ map[m].zone = &map_zone_pk;
+ }
}
else if (!strcmpi(w3,"pvp_noparty"))
map[m].flag.pvp_noparty=state;
@@ -3226,9 +3268,9 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con
map[m].flag.pvp_noguild=state;
else if (!strcmpi(w3, "pvp_nightmaredrop")) {
char drop_arg1[16], drop_arg2[16];
- int drop_id = 0, drop_type = 0, drop_per = 0;
+ int drop_per = 0;
if (sscanf(w4, "%[^,],%[^,],%d", drop_arg1, drop_arg2, &drop_per) == 3) {
- int i;
+ int drop_id = 0, drop_type = 0;
if (!strcmpi(drop_arg1, "random"))
drop_id = -1;
else if (itemdb_exists((drop_id = atoi(drop_arg1))) == NULL)
@@ -3241,6 +3283,7 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con
drop_type = 3;
if (drop_id != 0){
+ int i;
for (i = 0; i < MAX_DROP_PER_MAP; i++) {
if (map[m].drop_list[i].drop_id == 0){
map[m].drop_list[i].drop_id = drop_id;
@@ -3257,17 +3300,20 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con
else if (!strcmpi(w3,"pvp_nocalcrank"))
map[m].flag.pvp_nocalcrank=state;
else if (!strcmpi(w3,"gvg")) {
+ struct map_zone_data *zone;
+
map[m].flag.gvg = state;
- if( state && map[m].flag.pvp )
- {
+ if( state && map[m].flag.pvp ) {
map[m].flag.pvp = 0;
ShowWarning("npc_parse_mapflag: You can't set PvP and GvG flags for the same map! Removing PvP flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer));
}
- if( state && map[m].flag.battleground )
- {
+ if( state && map[m].flag.battleground ) {
map[m].flag.battleground = 0;
ShowWarning("npc_parse_mapflag: You can't set GvG and BattleGround flags for the same map! Removing BattleGround flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer));
}
+ if( state && (zone = strdb_get(zone_db, MAP_ZONE_GVG_NAME)) && map[m].zone != zone ) {
+ map_zone_change(m,zone,start,buffer,filepath);
+ }
}
else if (!strcmpi(w3,"gvg_noparty"))
map[m].flag.gvg_noparty=state;
@@ -3280,28 +3326,29 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con
if (state) map[m].flag.pvp=0;
}
else if (!strcmpi(w3,"battleground")) {
- if( state )
- {
+ struct map_zone_data *zone;
+ if( state ) {
if( sscanf(w4, "%d", &state) == 1 )
map[m].flag.battleground = state;
else
map[m].flag.battleground = 1; // Default value
- }
- else
+ } else
map[m].flag.battleground = 0;
- if( map[m].flag.battleground && map[m].flag.pvp )
- {
+ if( map[m].flag.battleground && map[m].flag.pvp ) {
map[m].flag.pvp = 0;
ShowWarning("npc_parse_mapflag: You can't set PvP and BattleGround flags for the same map! Removing PvP flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer));
}
- if( map[m].flag.battleground && (map[m].flag.gvg || map[m].flag.gvg_dungeon || map[m].flag.gvg_castle) )
- {
+ if( map[m].flag.battleground && (map[m].flag.gvg || map[m].flag.gvg_dungeon || map[m].flag.gvg_castle) ) {
map[m].flag.gvg = 0;
map[m].flag.gvg_dungeon = 0;
map[m].flag.gvg_castle = 0;
ShowWarning("npc_parse_mapflag: You can't set GvG and BattleGround flags for the same map! Removing GvG flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer));
}
+
+ if( state && (zone = strdb_get(zone_db, MAP_ZONE_BG_NAME)) && map[m].zone != zone ) {
+ map_zone_change(m,zone,start,buffer,filepath);
+ }
}
else if (!strcmpi(w3,"noexppenalty"))
map[m].flag.noexppenalty=state;
@@ -3331,15 +3378,8 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con
map[m].flag.sakura=state;
else if (!strcmpi(w3,"leaves"))
map[m].flag.leaves=state;
- /**
- * No longer available, keeping here just in case it's back someday. [Ind]
- **/
- //else if (!strcmpi(w3,"rain"))
- // map[m].flag.rain=state;
else if (!strcmpi(w3,"nightenabled"))
map[m].flag.nightenabled=state;
- else if (!strcmpi(w3,"nogo"))
- map[m].flag.nogo=state;
else if (!strcmpi(w3,"noexp")) {
map[m].flag.nobaseexp=state;
map[m].flag.nojobexp=state;
@@ -3365,16 +3405,6 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con
} else
map[m].nocommand=0;
}
- else if (!strcmpi(w3,"restricted")) {
- if (state) {
- map[m].flag.restricted=1;
- sscanf(w4, "%d", &state);
- map[m].zone |= 1<<(state+1);
- } else {
- map[m].flag.restricted=0;
- map[m].zone = 0;
- }
- }
else if (!strcmpi(w3,"jexp")) {
map[m].jexp = (state) ? atoi(w4) : 100;
if( map[m].jexp < 0 ) map[m].jexp = 100;
@@ -3395,7 +3425,140 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con
map[m].flag.guildlock=state;
else if (!strcmpi(w3,"reset"))
map[m].flag.reset=state;
- else
+ else if (!strcmpi(w3,"adjust_unit_duration")) {
+ int skill_id, k;
+ char skill_name[MAP_ZONE_MAPFLAG_LENGTH], modifier[MAP_ZONE_MAPFLAG_LENGTH];
+ int len = strlen(w4);
+
+ modifier[0] = '\0';
+ memcpy(skill_name, w4, MAP_ZONE_MAPFLAG_LENGTH);
+
+ for(k = 0; k < len; k++) {
+ if( skill_name[k] == '\t' ) {
+ memcpy(modifier, &skill_name[k+1], len - k);
+ skill_name[k] = '\0';
+ break;
+ }
+ }
+
+ if( modifier[0] == '\0' ) {
+ ShowWarning("npc_parse_mapflag: Missing 5th param for 'adjust_unit_duration' flag! removing flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer));
+ } else if( !( skill_id = skill->name2id(skill_name) ) || !skill->get_unit_id( skill->name2id(skill_name), 0) ) {
+ ShowWarning("npc_parse_mapflag: Unknown skill (%s) for 'adjust_unit_duration' flag! removing flag from %s (file '%s', line '%d').\n",skill_name, map[m].name, filepath, strline(buffer,start-buffer));
+ } else if ( atoi(modifier) < 1 || atoi(modifier) > USHRT_MAX ) {
+ ShowWarning("npc_parse_mapflag: Invalid modifier '%d' for skill '%s' for 'adjust_unit_duration' flag! removing flag from %s (file '%s', line '%d').\n", atoi(modifier), skill_name, map[m].name, filepath, strline(buffer,start-buffer));
+ } else {
+ int idx = map[m].unit_count;
+
+ ARR_FIND(0, idx, k, map[m].units[k]->skill_id == skill_id);
+
+ if( k < idx ) {
+ if( atoi(modifier) != 100 )
+ map[m].units[k]->modifier = (unsigned short)atoi(modifier);
+ else { /* remove */
+ int cursor = 0;
+ aFree(map[m].units[k]);
+ map[m].units[k] = NULL;
+ for( k = 0; k < idx; k++ ) {
+ if( map[m].units[k] == NULL )
+ continue;
+
+ memmove(&map[m].units[cursor], &map[m].units[k], sizeof(struct mapflag_skill_adjust));
+
+ cursor++;
+ }
+ if( !( map[m].unit_count = cursor ) ) {
+ aFree(map[m].units);
+ map[m].units = NULL;
+ }
+ }
+ } else if( atoi(modifier) != 100 ) {
+ RECREATE(map[m].units, struct mapflag_skill_adjust*, ++map[m].unit_count);
+ CREATE(map[m].units[idx],struct mapflag_skill_adjust,1);
+ map[m].units[idx]->skill_id = (unsigned short)skill_id;
+ map[m].units[idx]->modifier = (unsigned short)atoi(modifier);
+ }
+ }
+ } else if (!strcmpi(w3,"adjust_skill_damage")) {
+ int skill_id, k;
+ char skill_name[MAP_ZONE_MAPFLAG_LENGTH], modifier[MAP_ZONE_MAPFLAG_LENGTH];
+ int len = strlen(w4);
+
+ modifier[0] = '\0';
+ memcpy(skill_name, w4, MAP_ZONE_MAPFLAG_LENGTH);
+
+ for(k = 0; k < len; k++) {
+ if( skill_name[k] == '\t' ) {
+ memcpy(modifier, &skill_name[k+1], len - k);
+ skill_name[k] = '\0';
+ break;
+ }
+ }
+
+ if( modifier[0] == '\0' ) {
+ ShowWarning("npc_parse_mapflag: Missing 5th param for 'adjust_skill_damage' flag! removing flag from %s (file '%s', line '%d').\n", map[m].name, filepath, strline(buffer,start-buffer));
+ } else if( !( skill_id = skill->name2id(skill_name) ) ) {
+ ShowWarning("npc_parse_mapflag: Unknown skill (%s) for 'adjust_skill_damage' flag! removing flag from %s (file '%s', line '%d').\n", skill_name, map[m].name, filepath, strline(buffer,start-buffer));
+ } else if ( atoi(modifier) < 1 || atoi(modifier) > USHRT_MAX ) {
+ ShowWarning("npc_parse_mapflag: Invalid modifier '%d' for skill '%s' for 'adjust_skill_damage' flag! removing flag from %s (file '%s', line '%d').\n", atoi(modifier), skill_name, map[m].name, filepath, strline(buffer,start-buffer));
+ } else {
+ int idx = map[m].skill_count;
+
+ ARR_FIND(0, idx, k, map[m].skills[k]->skill_id == skill_id);
+
+ if( k < idx ) {
+ if( atoi(modifier) != 100 )
+ map[m].skills[k]->modifier = (unsigned short)atoi(modifier);
+ else { /* remove */
+ int cursor = 0;
+ aFree(map[m].skills[k]);
+ map[m].skills[k] = NULL;
+ for( k = 0; k < idx; k++ ) {
+ if( map[m].skills[k] == NULL )
+ continue;
+
+ memmove(&map[m].skills[cursor], &map[m].skills[k], sizeof(struct mapflag_skill_adjust));
+
+ cursor++;
+ }
+ if( !( map[m].skill_count = cursor ) ) {
+ aFree(map[m].skills);
+ map[m].skills = NULL;
+ }
+ }
+ } else if( atoi(modifier) != 100 ) {
+ RECREATE(map[m].skills, struct mapflag_skill_adjust*, ++map[m].skill_count);
+ CREATE(map[m].skills[idx],struct mapflag_skill_adjust,1);
+ map[m].skills[idx]->skill_id = (unsigned short)skill_id;
+ map[m].skills[idx]->modifier = (unsigned short)atoi(modifier);
+ }
+
+ }
+ } else if (!strcmpi(w3,"zone")) {
+ struct map_zone_data *zone;
+
+ if( !(zone = strdb_get(zone_db, w4)) ) {
+ ShowWarning("npc_parse_mapflag: Invalid zone '%s'! removing flag from %s (file '%s', line '%d').\n", w4, map[m].name, filepath, strline(buffer,start-buffer));
+ } else if( map[m].zone != zone ) {
+ map_zone_change(m,zone,start,buffer,filepath);
+ }
+ } else if ( !strcmpi(w3,"nomapchannelautojoin") ) {
+ map[m].flag.chsysnolocalaj = state;
+ } else if ( !strcmpi(w3,"invincible_time_inc") ) {
+ map[m].invincible_time_inc = (state) ? atoi(w4) : 0;
+ } else if ( !strcmpi(w3,"noknockback") ) {
+ map[m].flag.noknockback = state;
+ } else if ( !strcmpi(w3,"weapon_damage_rate") ) {
+ map[m].weapon_damage_rate = (state) ? atoi(w4) : 100;
+ } else if ( !strcmpi(w3,"magic_damage_rate") ) {
+ map[m].magic_damage_rate = (state) ? atoi(w4) : 100;
+ } else if ( !strcmpi(w3,"misc_damage_rate") ) {
+ map[m].misc_damage_rate = (state) ? atoi(w4) : 100;
+ } else if ( !strcmpi(w3,"short_damage_rate") ) {
+ map[m].short_damage_rate = (state) ? atoi(w4) : 100;
+ } else if ( !strcmpi(w3,"long_damage_rate") ) {
+ map[m].long_damage_rate = (state) ? atoi(w4) : 100;
+ } else
ShowError("npc_parse_mapflag: unrecognized mapflag '%s' (file '%s', line '%d').\n", w3, filepath, strline(buffer,start-buffer));
return strchr(start,'\n');// continue
@@ -3443,7 +3606,7 @@ void npc_parsesrcfile(const char* filepath, bool runOnInit)
lines++;
// w1<TAB>w2<TAB>w3<TAB>w4
- count = sv_parse(p, len+buffer-p, 0, '\t', pos, ARRAYLENGTH(pos), (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF));
+ count = sv->parse(p, len+buffer-p, 0, '\t', pos, ARRAYLENGTH(pos), (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF));
if( count < 0 )
{
ShowError("npc_parsesrcfile: Parse error in file '%s', line '%d'. Stopping...\n", filepath, strline(buffer,p-buffer));
@@ -3606,14 +3769,14 @@ void npc_read_event_script(void)
DBData *data;
char name[64]="::";
- strncpy(name+2,config[i].event_name,62);
+ safestrncpy(name+2,config[i].event_name,62);
script_event[i].event_count = 0;
iter = db_iterator(ev_db);
for( data = iter->first(iter,&key); iter->exists(iter); data = iter->next(iter,&key) )
{
const char* p = key.str;
- struct event_data* ed = db_data2ptr(data);
+ struct event_data* ed = DB->data2ptr(data);
unsigned char count = script_event[i].event_count;
if( count >= ARRAYLENGTH(script_event[i].event) )
@@ -3661,7 +3824,7 @@ int npc_reload(void) {
struct block_list* bl;
/* clear guild flag cache */
- guild_flags_clear();
+ guild->flags_clear();
npc_clear_pathlist();
@@ -3673,7 +3836,7 @@ int npc_reload(void) {
//Remove all npcs/mobs. [Skotlex]
iter = mapit_geteachiddb();
- for( bl = (struct block_list*)mapit_first(iter); mapit_exists(iter); bl = (struct block_list*)mapit_next(iter) ) {
+ for( bl = (struct block_list*)mapit->first(iter); mapit->exists(iter); bl = (struct block_list*)mapit->next(iter) ) {
switch(bl->type) {
case BL_NPC:
if( bl->id != fake_nd->bl.id )// don't remove fake_nd
@@ -3684,7 +3847,7 @@ int npc_reload(void) {
break;
}
}
- mapit_free(iter);
+ mapit->free(iter);
if(battle_config.dynamic_mobs)
{// dynamic check by [random]
@@ -3728,12 +3891,14 @@ int npc_reload(void) {
"\t-'"CL_WHITE"%d"CL_RESET"' Mobs Cached\n"
"\t-'"CL_WHITE"%d"CL_RESET"' Mobs Not Cached\n",
npc_id - npc_new_min, npc_warp, npc_shop, npc_script, npc_mob, npc_cache_mob, npc_delay_mob);
-
+
do_final_instance();
for( i = 0; i < ARRAYLENGTH(instance); ++i )
instance_init(instance[i].instance_id);
+ map_zone_init();
+
//Re-read the NPC Script Events cache.
npc_read_event_script();
@@ -3840,6 +4005,8 @@ int do_init_npc(void)
npc_viewdb[0].class_ = INVISIBLE_CLASS; //Invisible class is stored here.
for( i = 1; i < MAX_NPC_CLASS; i++ )
npc_viewdb[i].class_ = i;
+ for( i = MAX_NPC_CLASS2_START; i < MAX_NPC_CLASS2_END; i++ )
+ npc_viewdb2[i - MAX_NPC_CLASS2_START].class_ = i;
ev_db = strdb_alloc((DBOptions)(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA),2*NAME_LENGTH+2+1);
npcname_db = strdb_alloc(DB_OPT_BASE,NAME_LENGTH);
@@ -3862,6 +4029,8 @@ int do_init_npc(void)
"\t-'"CL_WHITE"%d"CL_RESET"' Mobs Not Cached\n",
npc_id - START_NPC_NUM, npc_warp, npc_shop, npc_script, npc_mob, npc_cache_mob, npc_delay_mob);
+ map_zone_init();
+
// set up the events cache
memset(script_event, 0, sizeof(script_event));
npc_read_event_script();