summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/script_commands.txt62
-rw-r--r--src/map/clif.c2
-rw-r--r--src/map/npc.c53
-rw-r--r--src/map/npc.h3
-rw-r--r--src/map/script.c185
-rw-r--r--src/map/script.h1
-rw-r--r--src/map/status.c8
-rw-r--r--src/map/unit.c6
8 files changed, 287 insertions, 33 deletions
diff --git a/doc/script_commands.txt b/doc/script_commands.txt
index 3467a5366..3c99afcf1 100644
--- a/doc/script_commands.txt
+++ b/doc/script_commands.txt
@@ -259,7 +259,8 @@ direction across Y. Walking into that area will trigger the NPC. If no
'OnTouch:' special label is present in the NPC code, the execution will
start from the beginning of the script, otherwise, it will start from the
'OnTouch:' label. Monsters can also trigger the NPC, though the label
-'OnTouchNPC:' is used in this case.
+'OnTouchNPC:' is used in this case. If player left area npc will called
+if present label 'OnUnTouch'.
The code part is the script code that will execute whenever the NPC is
triggered. It may contain commands and function calls, descriptions of
@@ -1040,6 +1041,12 @@ OnTouch_:
Similar to OnTouch, but will only run one instance. Another character is
chosen once the triggering character leaves the area.
+OnUnTouch:
+
+This label will be executed if plater leave trigger area is defined for the NPC
+object it's in. If it isn't present, nothing will happend.
+The RID of the triggering character object will be attached.
+
OnPCLoginEvent:
OnPCLogoutEvent:
OnPCBaseLvUpEvent:
@@ -3226,15 +3233,22 @@ let you enter.
---------------------------------------
-*getareausers("<map name>",<x1>,<y1>,<x2>,<y2>)
+*getareausers({"<map name>",}{<x1>,<y1>,<x2>,<y2>})
+*getareausers({"<map name>",}{<radius>})
This function will return the count of connected characters which are
-located within the specified area - an x1/y1-x2/y2 square - on the
-specified map.
+located within the specified area. Area can be x1/y1-x2/y2 square,
+or radius from npc position. If map name missing, used attached player map.
This is useful for maps that are split into many buildings, such as all
the "*_in" maps, due to all the shops and houses.
+Examples:
+ // return players in area npc area on current map.
+ .@num = getareausers();
+ // return players in square (1, 1) - (10, 10)
+ .@num = "players: " + getareausers(1, 1, 10, 10);
+
---------------------------------------
*getusersname;
@@ -7558,6 +7572,46 @@ config, and will not work properly if the NPC has a mob sprite.
---------------------------------------
+*setnpcdistance <distance>
+
+This command can reduce distance from where npc can be clicked.
+Usefull to use from OnInit event.
+
+ // Set distance to one tile on server load
+ OnInit:
+ setnpcdistance 1;
+
+---------------------------------------
+
+*getnpcdir {<name>};
+
+Return current npc direction for parameter "name" or for attached npc
+if it missing. If name missing and not attached npc, return -1.
+
+Example:
+ .@dir = getnpcdir();
+
+---------------------------------------
+
+*setnpcdir {<name>,} <direction>;
+
+Set npc direction. If npc name missing, will be used attached npc.
+
+Example:
+ setnpcdir 2;
+
+---------------------------------------
+
+*getnpcclass {<name>};
+
+Return npc class/sprite id for npc with given name or for attached npc.
+If name missing and no attached npc, return -1.
+
+Example:
+ .@class = getnpcclass();
+
+---------------------------------------
+
*day;
*night;
diff --git a/src/map/clif.c b/src/map/clif.c
index 173175260..3515bb806 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -9597,7 +9597,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) {
if (map->getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKNPC))
npc->touch_areanpc(sd,sd->bl.m,sd->bl.x,sd->bl.y);
else
- sd->areanpc_id = 0;
+ npc->untouch_areanpc(sd, sd->bl.m, sd->bl.x, sd->bl.y);
/* it broke at some point (e.g. during a crash), so we make it visibly dead again. */
if( !sd->status.hp && !pc_isdead(sd) && status->isdead(&sd->bl) )
diff --git a/src/map/npc.c b/src/map/npc.c
index 8c2f61d58..8b5bbc83e 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -139,11 +139,22 @@ int npc_ontouch2_event(struct map_session_data *sd, struct npc_data *nd)
{
char name[EVENT_NAME_LENGTH];
- if( sd->areanpc_id == nd->bl.id )
+ if (sd->areanpc_id == nd->bl.id)
return 0;
snprintf(name, ARRAYLENGTH(name), "%s::%s", nd->exname, script->config.ontouch2_name);
- return npc->event(sd,name,2);
+ return npc->event(sd, name, 2);
+}
+
+int npc_onuntouch_event(struct map_session_data *sd, struct npc_data *nd)
+{
+ char name[EVENT_NAME_LENGTH];
+
+ if (sd->areanpc_id != nd->bl.id)
+ return 0;
+
+ snprintf(name, ARRAYLENGTH(name), "%s::%s", nd->exname, script->config.onuntouch_name);
+ return npc->event(sd, name, 2);
}
/*==========================================
@@ -964,6 +975,23 @@ int npc_touch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y)
return 0;
}
+/*==========================================
+ * Exec OnUnTouch for player if out range of area event
+ *------------------------------------------*/
+int npc_untouch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y)
+{
+ struct npc_data *nd;
+ nullpo_retr(1, sd);
+
+ if (!sd->areanpc_id)
+ return 0;
+
+ nd = (struct npc_data *) map->id2bl(sd->areanpc_id);
+ npc->onuntouch_event(sd, nd);
+ sd->areanpc_id = 0;
+ return 0;
+}
+
// OnTouch NPC or Warp for Mobs
// Return 1 if Warped
int npc_touch_areanpc2(struct mob_data *md)
@@ -1086,22 +1114,28 @@ int npc_check_areanpc(int flag, int16 m, int16 x, int16 y, int16 range) {
struct npc_data* npc_checknear(struct map_session_data* sd, struct block_list* bl)
{
struct npc_data *nd;
+ int distance = AREA_SIZE + 1;
nullpo_retr(NULL, sd);
- if(bl == NULL) return NULL;
- if(bl->type != BL_NPC) return NULL;
+ if (bl == NULL) return NULL;
+ if (bl->type != BL_NPC) return NULL;
nd = (TBL_NPC*)bl;
- if(sd->state.using_fake_npc && sd->npc_id == bl->id)
+ if (sd->npc_id == bl->id)
return nd;
if (nd->class_<0) //Class-less npc, enable click from anywhere.
return nd;
- if (bl->m!=sd->bl.m ||
- bl->x<sd->bl.x-AREA_SIZE-1 || bl->x>sd->bl.x+AREA_SIZE+1 ||
- bl->y<sd->bl.y-AREA_SIZE-1 || bl->y>sd->bl.y+AREA_SIZE+1)
+ if (distance > nd->area_size)
+ distance = nd->area_size;
+
+ 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)
+ {
return NULL;
+ }
return nd;
}
@@ -2505,6 +2539,7 @@ struct npc_data* npc_create_npc(int m, int x, int y)
nd->bl.m = m;
nd->bl.x = x;
nd->bl.y = y;
+ nd->area_size = AREA_SIZE + 1;
return nd;
}
@@ -4607,6 +4642,7 @@ void npc_defaults(void) {
npc->isnear = npc_isnear;
npc->ontouch_event = npc_ontouch_event;
npc->ontouch2_event = npc_ontouch2_event;
+ npc->onuntouch_event = npc_onuntouch_event;
npc->enable_sub = npc_enable_sub;
npc->enable = npc_enable;
npc->name2id = npc_name2id;
@@ -4631,6 +4667,7 @@ void npc_defaults(void) {
npc->touch_areanpc_sub = npc_touch_areanpc_sub;
npc->touchnext_areanpc = npc_touchnext_areanpc;
npc->touch_areanpc = npc_touch_areanpc;
+ npc->untouch_areanpc = npc_untouch_areanpc;
npc->touch_areanpc2 = npc_touch_areanpc2;
npc->check_areanpc = npc_check_areanpc;
npc->checknear = npc_checknear;
diff --git a/src/map/npc.h b/src/map/npc.h
index fba14d485..a5a2b4676 100644
--- a/src/map/npc.h
+++ b/src/map/npc.h
@@ -61,6 +61,7 @@ struct npc_data {
int touching_id;
int64 next_walktime;
uint8 dir;
+ uint8 area_size;
unsigned size : 2;
@@ -181,6 +182,7 @@ struct npc_interface {
bool (*isnear) (struct block_list *bl);
int (*ontouch_event) (struct map_session_data *sd, struct npc_data *nd);
int (*ontouch2_event) (struct map_session_data *sd, struct npc_data *nd);
+ int (*onuntouch_event) (struct map_session_data *sd, struct npc_data *nd);
int (*enable_sub) (struct block_list *bl, va_list ap);
int (*enable) (const char *name, int flag);
struct npc_data* (*name2id) (const char *name);
@@ -205,6 +207,7 @@ struct npc_interface {
int (*touch_areanpc_sub) (struct block_list *bl, va_list ap);
int (*touchnext_areanpc) (struct map_session_data *sd, bool leavemap);
int (*touch_areanpc) (struct map_session_data *sd, int16 m, int16 x, int16 y);
+ int (*untouch_areanpc) (struct map_session_data *sd, int16 m, int16 x, int16 y);
int (*touch_areanpc2) (struct mob_data *md);
int (*check_areanpc) (int flag, int16 m, int16 x, int16 y, int16 range);
struct npc_data* (*checknear) (struct map_session_data *sd, struct block_list *bl);
diff --git a/src/map/script.c b/src/map/script.c
index a458bab49..3ccb6a45a 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -10093,20 +10093,64 @@ int buildin_getareausers_sub(struct block_list *bl,va_list ap)
}
BUILDIN(getareausers)
{
- const char *str;
- int16 m,x0,y0,x1,y1,users=0; //doubt we can have more then 32k users on
- str=script_getstr(st,2);
- x0=script_getnum(st,3);
- y0=script_getnum(st,4);
- x1=script_getnum(st,5);
- y1=script_getnum(st,6);
- if( (m=map->mapname2mapid(str))< 0) {
- script_pushint(st,-1);
- return true;
+ int16 m = -1, x0, y0, x1, y1;
+ int users = 0;
+ int idx = 2;
+ struct npc_data *nd = NULL;
+ if (script_hasdata(st, 2) && script_isstringtype(st, 2)) {
+ const char *str = script_getstr(st, 2);
+ if ((m = map->mapname2mapid(str)) < 0) {
+ script_pushint(st, -1);
+ return true;
+ }
+ idx = 3;
+ }
+ if (m == -1)
+ {
+ TBL_PC *sd = NULL;
+ sd = script->rid2sd(st);
+ if (!sd)
+ {
+ script_pushint(st, -1);
+ return false;
+ }
+ m = sd->bl.m;
+ }
+ if (st->oid)
+ nd = map->id2nd(st->oid);
+ if (script_hasdata(st, idx + 3)) {
+ x0 = script_getnum(st, idx + 0);
+ y0 = script_getnum(st, idx + 1);
+ x1 = script_getnum(st, idx + 2);
+ y1 = script_getnum(st, idx + 3);
+ } else if (script_hasdata(st, idx)) {
+ if (!nd)
+ {
+ script_pushint(st, -1);
+ return true;
+ }
+ int sz = script_getnum(st, idx);
+ x0 = nd->bl.x - sz;
+ y0 = nd->bl.y - sz;
+ x1 = nd->bl.x + sz;
+ y1 = nd->bl.y + sz;
+ } else if (st->oid) {
+ if (!nd || nd->u.scr.xs == -1 || nd->u.scr.ys == -1)
+ {
+ script_pushint(st, -1);
+ return true;
+ }
+ x0 = nd->bl.x - nd->u.scr.xs;
+ y0 = nd->bl.y - nd->u.scr.ys;
+ x1 = nd->bl.x + nd->u.scr.xs;
+ y1 = nd->bl.y + nd->u.scr.ys;
+ } else {
+ script_pushint(st, -1);
+ return false;
}
map->foreachinarea(script->buildin_getareausers_sub,
- m,x0,y0,x1,y1,BL_PC,&users);
- script_pushint(st,users);
+ m, x0, y0, x1, y1, BL_PC, &users);
+ script_pushint(st, users);
return true;
}
@@ -13311,6 +13355,112 @@ BUILDIN(npcstop) {
return true;
}
+// set click npc distance [4144]
+BUILDIN(setnpcdistance) {
+ struct npc_data *nd = (struct npc_data *) map->id2bl (st->oid);
+ if (!nd)
+ return false;
+
+ nd->area_size = script_getnum(st, 2);
+
+ return true;
+}
+
+// return current npc direction [4144]
+BUILDIN(getnpcdir)
+{
+ struct npc_data *nd = 0;
+
+ if (script_hasdata(st, 2))
+ {
+ nd = npc->name2id (script_getstr(st, 2));
+ }
+ if (!nd && !st->oid)
+ {
+ script_pushint(st, -1);
+ return true;
+ }
+
+ if (!nd)
+ nd = (struct npc_data *) map->id2bl (st->oid);
+
+ if (!nd)
+ {
+ script_pushint(st, -1);
+ return true;
+ }
+
+ script_pushint(st, (int)nd->dir);
+
+ return true;
+}
+
+// set npc direction [4144]
+BUILDIN(setnpcdir)
+{
+ int newdir;
+ struct npc_data *nd = 0;
+
+ if (script_hasdata(st, 3))
+ {
+ nd = npc->name2id (script_getstr(st, 2));
+ newdir = script_getnum(st, 3);
+ }
+ else if (script_hasdata(st, 2))
+ {
+ if (!st->oid)
+ return false;
+
+ nd = (struct npc_data *) map->id2bl (st->oid);
+ newdir = script_getnum(st, 2);
+ }
+ if (!nd)
+ return false;
+
+ if (newdir < 0)
+ newdir = 0;
+ else if (newdir > 7)
+ newdir = 7;
+
+ nd->dir = newdir;
+ if (nd->ud)
+ nd->ud->dir = newdir;
+
+ clif->clearunit_area(&nd->bl, CLR_OUTSIGHT);
+ clif->spawn(&nd->bl);
+
+ return true;
+}
+
+// return npc class [4144]
+BUILDIN(getnpcclass)
+{
+ struct npc_data *nd = 0;
+
+ if (script_hasdata(st, 2))
+ {
+ nd = npc->name2id (script_getstr(st, 2));
+ }
+ if (!nd && !st->oid)
+ {
+ script_pushint(st, -1);
+ return false;
+ }
+
+ if (!nd)
+ nd = (struct npc_data *) map->id2bl(st->oid);
+
+ if (!nd)
+ {
+ script_pushint(st, -1);
+ return false;
+ }
+
+ script_pushint(st, (int)nd->class_);
+
+ return true;
+}
+
/*==========================================
* getlook char info. getlook(arg)
@@ -19275,7 +19425,7 @@ void script_parse_builtin(void) {
BUILDIN_DEF(getusers,"i"),
BUILDIN_DEF(getmapguildusers,"si"),
BUILDIN_DEF(getmapusers,"s"),
- BUILDIN_DEF(getareausers,"siiii"),
+ BUILDIN_DEF(getareausers,"*"),
BUILDIN_DEF(getareadropitem,"siiiiv"),
BUILDIN_DEF(enablenpc,"s"),
BUILDIN_DEF(disablenpc,"s"),
@@ -19378,6 +19528,10 @@ void script_parse_builtin(void) {
BUILDIN_DEF(npcspeed,"i"), // [Valaris]
BUILDIN_DEF(npcwalkto,"ii"), // [Valaris]
BUILDIN_DEF(npcstop,""), // [Valaris]
+ BUILDIN_DEF(setnpcdistance,"i"), // [4144]
+ BUILDIN_DEF(getnpcdir,"?"), // [4144]
+ BUILDIN_DEF(setnpcdir,"*"), // [4144]
+ BUILDIN_DEF(getnpcclass,"?"), // [4144]
BUILDIN_DEF(getmapxy,"rrri?"), //by Lorky [Lupus]
BUILDIN_DEF(checkoption1,"i"),
BUILDIN_DEF(checkoption2,"i"),
@@ -19970,8 +20124,9 @@ void script_defaults(void) {
script->config.loadmap_event_name = "OnPCLoadMapEvent";
script->config.baselvup_event_name = "OnPCBaseLvUpEvent";
script->config.joblvup_event_name = "OnPCJobLvUpEvent";
- script->config.ontouch_name = "OnTouch_";//ontouch_name (runs on first visible char to enter area, picks another char if the first char leaves)
- script->config.ontouch2_name = "OnTouch";//ontouch2_name (run whenever a char walks into the OnTouch area)
+ script->config.ontouch_name = "OnTouch_"; //ontouch_name (runs on first visible char to enter area, picks another char if the first char leaves)
+ script->config.ontouch2_name = "OnTouch"; //ontouch2_name (run whenever a char walks into the OnTouch area)
+ script->config.onuntouch_name = "OnUnTouch"; //onuntouch_name (run whenever a char walks from the OnTouch area)
// for ENABLE_CASE_CHECK
script->calc_hash_ci = calc_hash_ci;
diff --git a/src/map/script.h b/src/map/script.h
index e28abf970..548c0f261 100644
--- a/src/map/script.h
+++ b/src/map/script.h
@@ -343,6 +343,7 @@ struct Script_Config {
const char* ontouch_name;
const char* ontouch2_name;
+ const char* onuntouch_name;
};
/**
diff --git a/src/map/status.c b/src/map/status.c
index 54b4a4358..e0d8d4f9b 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -10466,8 +10466,12 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
if(opt_flag&4) //Out of hiding, invoke on place.
skill->unit_move(bl,timer->gettick(),1);
- if(opt_flag&2 && sd && map->getcell(bl->m,bl->x,bl->y,CELL_CHKNPC))
- npc->touch_areanpc(sd,bl->m,bl->x,bl->y); //Trigger on-touch event.
+ if (opt_flag & 2 && sd) {
+ if (map->getcell(bl->m,bl->x,bl->y,CELL_CHKNPC))
+ npc->touch_areanpc(sd,bl->m,bl->x,bl->y); //Trigger on-touch event.
+ else
+ npc->untouch_areanpc(sd, bl->m, bl->x, bl->y);
+ }
ers_free(status->data_ers, sce);
return 1;
diff --git a/src/map/unit.c b/src/map/unit.c
index 64885541f..0924e6cf2 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -309,7 +309,7 @@ int unit_walktoxy_timer(int tid, int64 tick, int id, intptr_t data) {
if (bl->prev == NULL) //Script could have warped char, abort remaining of the function.
return 0;
} else
- sd->areanpc_id=0;
+ npc->untouch_areanpc(sd, bl->m, x, y);
if( sd->md ) { // mercenary should be warped after being 3 seconds too far from the master [greenbox]
if( !check_distance_bl(&sd->bl, &sd->md->bl, MAX_MER_DISTANCE) ) {
@@ -767,7 +767,7 @@ int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool
if (bl->prev == NULL) //Script could have warped char, abort remaining of the function.
return 0;
} else
- sd->areanpc_id=0;
+ npc->untouch_areanpc(sd, bl->m, bl->x, bl->y);
if( sd->status.pet_id > 0 && sd->pd && sd->pd->pet.intimate > 0 )
{ // Check if pet needs to be teleported. [Skotlex]
@@ -867,7 +867,7 @@ int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag)
if(map->getcell(bl->m, bl->x, bl->y, CELL_CHKNPC)) {
npc->touch_areanpc(sd, bl->m, bl->x, bl->y);
} else {
- sd->areanpc_id = 0;
+ npc->untouch_areanpc(sd, bl->m, bl->x, bl->y);;
}
}
}