Browse Source

Script Command Adjustments and Additions
* Fixes #158 - Implemented 'getvar' script command to avoid blindly attaching players and messing up their NPC progress.
* Fixes #449 - Fixed 'unitskilluseid' and 'unitskillusepos' not casting skills that require stat info when the NPC's status wasn't loaded.
* Implemented 'getunittype' script command to return the object type of the given GID.
* Adjusted 'unitwalk' to support an Event Label which is executed when the object reaches the target.
* Added 'unitwalkto' when giving a target GID rather than coordinates. Also supports Event Labels.
- Thanks to @cydh.

aleos89 10 years ago
parent
commit
730311e009
7 changed files with 213 additions and 38 deletions
  1. 31 5
      doc/script_commands.txt
  2. 9 6
      npc/custom/quests/hunting_missions.txt
  3. 11 7
      src/map/npc.c
  4. 1 0
      src/map/npc.h
  5. 153 20
      src/map/script.c
  6. 6 0
      src/map/unit.c
  7. 2 0
      src/map/unit.h

+ 31 - 5
doc/script_commands.txt

@@ -1287,6 +1287,14 @@ getvariableofnpc will not work on them.
 
 
 ---------------------------------------
 ---------------------------------------
 
 
+*getvar <variable>,<char_id>;
+
+Get variable value from the specified player. Only player/account variables
+are allowed to be used (temporary character variable "@", permanent
+character "", permanent local account "#", and permanent global account "##").
+
+---------------------------------------
+
 *goto <label>;
 *goto <label>;
 
 
 This command will make the script jump to a label, usually used in conjunction 
 This command will make the script jump to a label, usually used in conjunction 
@@ -3374,7 +3382,8 @@ account ID.
 
 
 *getattachedrid();
 *getattachedrid();
 
 
-Returns RID from running script. Script may does not have RID.
+Returns RID from running script. Script may not be attached to any RID like
+a floating script or function and will return 0.
 
 
 ---------------------------------------
 ---------------------------------------
 
 
@@ -6958,8 +6967,8 @@ in this way.
 \\
 \\
 ---------------------------------------
 ---------------------------------------
 
 
-*unitwalk <GID>,<x>,<y>;
-*unitwalk <GID>,<Target ID>;
+*unitwalk <GID>,<x>,<y>{,"<event label>"};
+*unitwalkto <GID>,<Target GID>{,"<event label>"};
 
 
 This command will tell a <GID> to walk to a position, defined either as a set of
 This command will tell a <GID> to walk to a position, defined either as a set of
 coordinates or another object. The command returns a 1 for success and 0 upon failure.
 coordinates or another object. The command returns a 1 for success and 0 upon failure.
@@ -6968,11 +6977,14 @@ If coordinates are passed, the <GID> will walk to the given x,y coordinates on t
 unit's current map. While there is no way to move across an entire map with 1 command
 unit's current map. While there is no way to move across an entire map with 1 command
 use, this could be used in a loop to move long distances.
 use, this could be used in a loop to move long distances.
 
 
-If an object ID is passed, the initial <GID> will walk to the <Target ID> (similar to
+If an object ID is passed, the initial <GID> will walk to the <Target GID> (similar to
 walking to attack). This is based on the distance from <GID> to <Target ID>. This command
 walking to attack). This is based on the distance from <GID> to <Target ID>. This command
 uses a hard walk check, so it will calculate a walk path with obstacles. Sending a bad
 uses a hard walk check, so it will calculate a walk path with obstacles. Sending a bad
 target ID will result in an error.
 target ID will result in an error.
 
 
+An optional Event Label can be passed as well which will execute when the <GID> has reached
+the given coordinates or <Target GID>.
+
 Examples:
 Examples:
 
 
 // Makes player walk to the coordinates (150,150).
 // Makes player walk to the coordinates (150,150).
@@ -6985,7 +6997,7 @@ Examples:
 		dispbottom "That's too far away, man.";
 		dispbottom "That's too far away, man.";
 
 
 // Makes player walk to another character named "WalkToMe".
 // Makes player walk to another character named "WalkToMe".
-	unitwalk getcharid(3),getcharid(3,"WalkToMe");
+	unitwalkto getcharid(3),getcharid(3,"WalkToMe");
 
 
 ---------------------------------------
 ---------------------------------------
 
 
@@ -7058,6 +7070,20 @@ For the position, the x and y are given in the UnitSkillUsePos.
 
 
 ---------------------------------------
 ---------------------------------------
 
 
+*getunittype <GID>;
+
+Returns the type of object from the given Game ID. Returns -1 if the given <GID> does not
+exist.
+
+ 0 - Monster
+ 1 - Homunculus
+ 2 - Pet
+ 3 - Mercenary
+ 4 - Elemental
+ 5 - NPC
+
+---------------------------------------
+
 *getunitname <GID>;
 *getunitname <GID>;
 
 
 Gets the name of the given unit. Supported types are monster, homunculus, pet, and NPC.
 Gets the name of the given unit. Supported types are monster, homunculus, pet, and NPC.

+ 9 - 6
npc/custom/quests/hunting_missions.txt

@@ -285,15 +285,18 @@ OnNPCKillEvent:
 		getpartymember getcharid(1),2;
 		getpartymember getcharid(1),2;
 		for (.@i = 0; .@i < $@partymembercount; .@i++) {
 		for (.@i = 0; .@i < $@partymembercount; .@i++) {
 			if (isloggedin($@partymemberaid[.@i], $@partymembercid[.@i])) {
 			if (isloggedin($@partymemberaid[.@i], $@partymembercid[.@i])) {
-				attachrid $@partymemberaid[.@i];
-				if (#Mission_Count && Mission0 && HP > 0) {
+				set .@Mission_Count, getvar(#Mission_Count, $@partymembercid[.@i]);
+				set .@Mission0, getvar(Mission0, $@partymembercid[.@i]);
+				set .@HP, getvar(HP, $@partymembercid[.@i]);
+
+				if (.@Mission_Count && .@Mission0 && .@HP > 0) {
 					getmapxy(.@map2$,.@x2,.@y2,0);
 					getmapxy(.@map2$,.@x2,.@y2,0);
 					if ((.@map1$ == .@map2$ || .Party == 1) && (distance(.@x1,.@y1,.@x2,.@y2) <= 30 || .Party < 3)) {
 					if ((.@map1$ == .@map2$ || .Party == 1) && (distance(.@x1,.@y1,.@x2,.@y2) <= 30 || .Party < 3)) {
 						for (.@j = 0; .@j < .Quests; .@j++) {
 						for (.@j = 0; .@j < .Quests; .@j++) {
-							if (strmobinfo(1,.@mob) == strmobinfo(1,getd("Mission"+.@j))) {
-								if (getd("Mission"+.@j+"_") < #Mission_Count) {
-									dispbottom "[Hunting Mission] Killed " + (set(getd("Mission" + .@j + "_"),getd("Mission" + .@j + "_") + 1)) +
-									           " of " + #Mission_Count + " " + strmobinfo(1,.@mob) + ".";
+							if (strmobinfo(1,.@mob) == strmobinfo(1,getvar(getd("Mission"+.@j), $@partymembercid[.@i]))) {
+								if (getvar(getd("Mission"+.@j+"_"), $@partymembercid[.@i]) < .@Mission_Count) {
+									dispbottom "[Hunting Mission] Killed " + (set(getvar(getd("Mission" + .@j + "_"), $@partymembercid[.@i]), getvar(getd("Mission" + .@j + "_") + 1, $@partymembercid[.@i]))) +
+									           " of " + .@Mission_Count + " " + strmobinfo(1,.@mob) + ".";
 									break;
 									break;
 								}
 								}
 							}
 							}

+ 11 - 7
src/map/npc.c

@@ -385,35 +385,39 @@ static int npc_event_do_sub(DBKey key, DBData *data, va_list ap)
 {
 {
 	const char* p = key.str;
 	const char* p = key.str;
 	struct event_data* ev;
 	struct event_data* ev;
-	int* c;
+	int* c, rid;
 	const char* name;
 	const char* name;
 
 
 	nullpo_ret(ev = db_data2ptr(data));
 	nullpo_ret(ev = db_data2ptr(data));
 	nullpo_ret(c = va_arg(ap, int *));
 	nullpo_ret(c = va_arg(ap, int *));
 	nullpo_ret(name = va_arg(ap, const char *));
 	nullpo_ret(name = va_arg(ap, const char *));
+	rid = va_arg(ap, int);
 
 
 	if( p && strcmpi(name, p) == 0 )
 	if( p && strcmpi(name, p) == 0 )
 	{
 	{
-		run_script(ev->nd->u.scr.script,ev->pos,0,ev->nd->bl.id);
+		run_script(ev->nd->u.scr.script,ev->pos,rid,ev->nd->bl.id);
 		(*c)++;
 		(*c)++;
 	}
 	}
 
 
 	return 0;
 	return 0;
 }
 }
 
 
-// runs the specified event (supports both single-npc and global events)
-int npc_event_do(const char* name)
-{
+int npc_event_do_id(const char* name, int rid) {
 	int c = 0;
 	int c = 0;
 
 
 	if( name[0] == ':' && name[1] == ':' )
 	if( name[0] == ':' && name[1] == ':' )
-		ev_db->foreach(ev_db,npc_event_doall_sub,&c,name,0);
+		ev_db->foreach(ev_db,npc_event_doall_sub,&c,name,0,rid);
 	else
 	else
-		ev_db->foreach(ev_db,npc_event_do_sub,&c,name);
+		ev_db->foreach(ev_db,npc_event_do_sub,&c,name,rid);
 
 
 	return c;
 	return c;
 }
 }
 
 
+// runs the specified event (supports both single-npc and global events)
+int npc_event_do(const char* name) {
+	return npc_event_do_id(name, 0);
+}
+
 // runs the specified event (global only)
 // runs the specified event (global only)
 int npc_event_doall(const char* name)
 int npc_event_doall(const char* name)
 {
 {

+ 1 - 0
src/map/npc.h

@@ -168,6 +168,7 @@ void npc_event_do_oninit(void);
 int npc_do_ontimer(int npc_id, int option);
 int npc_do_ontimer(int npc_id, int option);
 
 
 int npc_event_do(const char* name);
 int npc_event_do(const char* name);
+int npc_event_do_id(const char* name, int rid);
 int npc_event_doall(const char* name);
 int npc_event_doall(const char* name);
 int npc_event_doall_id(const char* name, int rid);
 int npc_event_doall_id(const char* name, int rid);
 
 

+ 153 - 20
src/map/script.c

@@ -2707,16 +2707,17 @@ TBL_PC *script_rid2sd(struct script_state *st)
 	return sd;
 	return sd;
 }
 }
 
 
-/// Dereferences a variable/constant, replacing it with a copy of the value.
-///
-/// @param st Script state
-/// @param data Variable/constant
-void get_val(struct script_state* st, struct script_data* data)
+/**
+ * Dereferences a variable/constant, replacing it with a copy of the value.
+ * @param st Script state
+ * @param data Variable/constant
+ * @param sd If NULL, will try to use sd from st->rid (for player's variables)
+ */
+void get_val_(struct script_state* st, struct script_data* data, struct map_session_data *sd)
 {
 {
 	const char* name;
 	const char* name;
 	char prefix;
 	char prefix;
 	char postfix;
 	char postfix;
-	TBL_PC* sd = NULL;
 
 
 	if( !data_isreference(data) )
 	if( !data_isreference(data) )
 		return;// not a variable/constant
 		return;// not a variable/constant
@@ -2728,7 +2729,8 @@ void get_val(struct script_state* st, struct script_data* data)
 	//##TODO use reference_tovariable(data) when it's confirmed that it works [FlavioJS]
 	//##TODO use reference_tovariable(data) when it's confirmed that it works [FlavioJS]
 	if( !reference_toconstant(data) && not_server_variable(prefix) )
 	if( !reference_toconstant(data) && not_server_variable(prefix) )
 	{
 	{
-		sd = script_rid2sd(st);
+		if (sd == NULL)
+			sd = script_rid2sd(st);
 		if( sd == NULL )
 		if( sd == NULL )
 		{// needs player attached
 		{// needs player attached
 			if( postfix == '$' )
 			if( postfix == '$' )
@@ -2865,6 +2867,11 @@ void get_val(struct script_state* st, struct script_data* data)
 	return;
 	return;
 }
 }
 
 
+void get_val(struct script_state* st, struct script_data* data)
+{
+	get_val_(st,data,NULL);
+}
+
 struct script_data* push_val2(struct script_stack* stack, enum c_op type, int val, struct DBMap** ref);
 struct script_data* push_val2(struct script_stack* stack, enum c_op type, int val, struct DBMap** ref);
 
 
 /// Retrieves the value of a reference identified by uid (variable, constant, param)
 /// Retrieves the value of a reference identified by uid (variable, constant, param)
@@ -2982,12 +2989,17 @@ void setd_sub(struct script_state *st, TBL_PC *sd, const char *varname, int elem
 	set_reg(st, sd, reference_uid(add_str(varname),elem), varname, value, ref);
 	set_reg(st, sd, reference_uid(add_str(varname),elem), varname, value, ref);
 }
 }
 
 
-/// Converts the data to a string
-const char* conv_str(struct script_state* st, struct script_data* data)
+/**
+ * Converts the data to a string
+ * @param st
+ * @param data
+ * @param sd
+ */
+const char* conv_str_(struct script_state* st, struct script_data* data, struct map_session_data *sd)
 {
 {
 	char* p;
 	char* p;
 
 
-	get_val(st, data);
+	get_val_(st, data, sd);
 	if( data_isstring(data) )
 	if( data_isstring(data) )
 	{// nothing to convert
 	{// nothing to convert
 	}
 	}
@@ -3016,10 +3028,20 @@ const char* conv_str(struct script_state* st, struct script_data* data)
 	return data->u.str;
 	return data->u.str;
 }
 }
 
 
-/// Converts the data to an int
-int conv_num(struct script_state* st, struct script_data* data)
+const char* conv_str(struct script_state* st, struct script_data* data)
 {
 {
-	get_val(st, data);
+	conv_str_(st, data, NULL);
+}
+
+/**
+ * Converts the data to an int
+ * @param st
+ * @param data
+ * @param sd
+ */
+int conv_num_(struct script_state* st, struct script_data* data, struct map_session_data *sd)
+{
+	get_val_(st, data, sd);
 	if( data_isint(data) )
 	if( data_isint(data) )
 	{// nothing to convert
 	{// nothing to convert
 		
 		
@@ -3072,6 +3094,11 @@ int conv_num(struct script_state* st, struct script_data* data)
 	return data->u.num;
 	return data->u.num;
 }
 }
 
 
+int conv_num(struct script_state* st, struct script_data* data)
+{
+	conv_num_(st, data, NULL);
+}
+
 //
 //
 // Stack operations
 // Stack operations
 //
 //
@@ -16391,6 +16418,35 @@ BUILDIN_FUNC(pcstopfollow)
 // <--- [zBuffer] List of player cont commands
 // <--- [zBuffer] List of player cont commands
 // [zBuffer] List of unit control commands --->
 // [zBuffer] List of unit control commands --->
 
 
+/// Gets the type of the given Game ID.
+///
+/// getunittype <unit id>;
+BUILDIN_FUNC(getunittype)
+{
+	struct block_list* bl;
+	uint8 value = 0;
+
+	bl = map_id2bl(script_getnum(st, 2));
+
+	if (!bl) {
+		ShowWarning("buildin_getunittype: Error in finding object with given game ID %d!\n", script_getnum(st, 2));
+		script_pushint(st, -1);
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	switch (bl->type) {
+		case BL_MOB:  value = 0; break;
+		case BL_HOM:  value = 1; break;
+		case BL_PET:  value = 2; break;
+		case BL_MER:  value = 3; break;
+		case BL_ELEM: value = 4; break;
+		case BL_NPC:  value = 5; break;
+	}
+
+	script_pushint(st, value);
+	return SCRIPT_CMD_SUCCESS;
+}
+
 /// Gets specific live information of a bl.
 /// Gets specific live information of a bl.
 ///
 ///
 /// getunitdata <unit id>,<arrayname>;
 /// getunitdata <unit id>,<arrayname>;
@@ -16946,17 +17002,26 @@ BUILDIN_FUNC(setunitname)
 /// Makes the unit walk to target position or map.
 /// Makes the unit walk to target position or map.
 /// Returns if it was successful.
 /// Returns if it was successful.
 ///
 ///
-/// unitwalk(<unit_id>,<x>,<y>) -> <bool>
-/// unitwalk(<unit_id>,<target_id>) -> <bool>
+/// unitwalk(<unit_id>,<x>,<y>{,<event_label>}) -> <bool>
+/// unitwalkto(<unit_id>,<target_id>{,<event_label>}) -> <bool>
 BUILDIN_FUNC(unitwalk)
 BUILDIN_FUNC(unitwalk)
 {
 {
 	struct block_list* bl;
 	struct block_list* bl;
+	struct unit_data *ud = NULL;
+	const char *cmd = script_getfuncname(st), *done_label = "", *fail_label = "";
+	uint8 off = 5;
 
 
 	bl = map_id2bl(script_getnum(st,2));
 	bl = map_id2bl(script_getnum(st,2));
 
 
-	if (!bl)
+	if (!bl) {
+		ShowError("buildin_unitwalk: Invalid unit with ID '%d'.\n", script_getnum(st,2));
 		script_pushint(st, 0);
 		script_pushint(st, 0);
-	else if( script_hasdata(st,4) ) {
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	ud = unit_bl2ud(bl);
+
+	if (strcmp(cmd,"unitwalk")) {
 		int x = script_getnum(st,3);
 		int x = script_getnum(st,3);
 		int y = script_getnum(st,4);
 		int y = script_getnum(st,4);
 
 
@@ -16971,6 +17036,13 @@ BUILDIN_FUNC(unitwalk)
 			return SCRIPT_CMD_FAILURE;
 			return SCRIPT_CMD_FAILURE;
 		} else if (script_pushint(st, unit_can_reach_bl(bl, tbl, distance_bl(bl, tbl)+1, 0, NULL, NULL)))
 		} else if (script_pushint(st, unit_can_reach_bl(bl, tbl, distance_bl(bl, tbl)+1, 0, NULL, NULL)))
 			add_timer(gettick()+50, unit_delay_walktobl_timer, bl->id, tbl->id); // Need timer to avoid mismatches
 			add_timer(gettick()+50, unit_delay_walktobl_timer, bl->id, tbl->id); // Need timer to avoid mismatches
+		off = 3;
+	}
+
+	if (ud && script_hasdata(st, off)) {
+		done_label = script_getstr(st, off);
+		check_event(st, done_label);
+		safestrncpy(ud->walk_done_event, done_label, sizeof(ud->walk_done_event));
 	}
 	}
 
 
 	return SCRIPT_CMD_SUCCESS;
 	return SCRIPT_CMD_SUCCESS;
@@ -17194,8 +17266,15 @@ BUILDIN_FUNC(unitskilluseid)
 	casttime = ( script_hasdata(st,6) ? script_getnum(st,6) : 0 );
 	casttime = ( script_hasdata(st,6) ? script_getnum(st,6) : 0 );
 	bl = map_id2bl(unit_id);
 	bl = map_id2bl(unit_id);
 
 
-	if (bl != NULL)
+	if (bl != NULL) {
+		if (bl->type == BL_NPC) {
+			if (!((TBL_NPC*)bl)->status.hp)
+				status_calc_npc(((TBL_NPC*)bl), true);
+			else
+				status_calc_npc(((TBL_NPC*)bl), false);
+		}
 		unit_skilluse_id2(bl, target_id, skill_id, skill_lv, (casttime * 1000) + skill_castfix(bl, skill_id, skill_lv), skill_get_castcancel(skill_id));
 		unit_skilluse_id2(bl, target_id, skill_id, skill_lv, (casttime * 1000) + skill_castfix(bl, skill_id, skill_lv), skill_get_castcancel(skill_id));
+	}
 
 
 	return SCRIPT_CMD_SUCCESS;
 	return SCRIPT_CMD_SUCCESS;
 }
 }
@@ -17221,8 +17300,15 @@ BUILDIN_FUNC(unitskillusepos)
 	casttime = ( script_hasdata(st,7) ? script_getnum(st,7) : 0 );
 	casttime = ( script_hasdata(st,7) ? script_getnum(st,7) : 0 );
 	bl = map_id2bl(unit_id);
 	bl = map_id2bl(unit_id);
 
 
-	if (bl != NULL)
+	if (bl != NULL) {
+		if (bl->type == BL_NPC) {
+			if (!((TBL_NPC*)bl)->status.hp)
+				status_calc_npc(((TBL_NPC*)bl), true);
+			else
+				status_calc_npc(((TBL_NPC*)bl), false);
+		}
 		unit_skilluse_pos2(bl, skill_x, skill_y, skill_id, skill_lv, (casttime * 1000) + skill_castfix(bl, skill_id, skill_lv), skill_get_castcancel(skill_id));
 		unit_skilluse_pos2(bl, skill_x, skill_y, skill_id, skill_lv, (casttime * 1000) + skill_castfix(bl, skill_id, skill_lv), skill_get_castcancel(skill_id));
+	}
 
 
 	return SCRIPT_CMD_SUCCESS;
 	return SCRIPT_CMD_SUCCESS;
 }
 }
@@ -20097,6 +20183,50 @@ BUILDIN_FUNC(getattachedrid) {
 	return SCRIPT_CMD_SUCCESS;
 	return SCRIPT_CMD_SUCCESS;
 }
 }
 
 
+/**
+ * Get variable from a Player
+ * getvar <variable>,<char_id>;
+ */
+BUILDIN_FUNC(getvar) {
+	int char_id = script_getnum(st, 3);
+	struct map_session_data *sd = map_charid2sd(char_id);
+	struct script_data *data = NULL;
+	const char *name = NULL;
+
+	if (!sd) {
+		ShowError("buildin_getvar: No player found with char id '%d'.\n", char_id);
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	data = script_getdata(st, 2);
+	if (!data_isreference(data)) {
+		ShowError("buildin_getvar: Not a variable\n");
+		script_reportdata(data);
+		script_pushnil(st);
+		st->state = END;
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	name = reference_getname(data);
+	if (name[0] == '.' || name[0] == '$' || name[0] == '\'') { // Not a PC variable
+		ShowError("buildin_getvar: Invalid scope (not PC variable)\n");
+		script_reportdata(data);
+		script_pushnil(st);
+		st->state = END;
+		return SCRIPT_CMD_FAILURE;
+	}
+
+	get_val_(st, data, sd);
+	if (data_isint(data))
+		script_pushint(st, conv_num_(st, data, sd));
+	else
+		script_pushstrcopy(st, conv_str_(st, data, sd));
+
+
+	push_val2(st->stack, C_NAME, reference_getuid(data), reference_getref(data));
+	return SCRIPT_CMD_SUCCESS;
+}
+
 #include "../custom/script.inc"
 #include "../custom/script.inc"
 
 
 // declarations that were supposed to be exported from npc_chat.c
 // declarations that were supposed to be exported from npc_chat.c
@@ -20497,11 +20627,13 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(pcblockmove,"ii"),
 	BUILDIN_DEF(pcblockmove,"ii"),
 	// <--- [zBuffer] List of player cont commands
 	// <--- [zBuffer] List of player cont commands
 	// [zBuffer] List of mob control commands --->
 	// [zBuffer] List of mob control commands --->
+	BUILDIN_DEF(getunittype,"i"),
 	BUILDIN_DEF(getunitname,"i"),
 	BUILDIN_DEF(getunitname,"i"),
 	BUILDIN_DEF(setunitname,"is"),
 	BUILDIN_DEF(setunitname,"is"),
 	BUILDIN_DEF(getunitdata,"i*"),
 	BUILDIN_DEF(getunitdata,"i*"),
 	BUILDIN_DEF(setunitdata,"iii"),
 	BUILDIN_DEF(setunitdata,"iii"),
-	BUILDIN_DEF(unitwalk,"ii?"),
+	BUILDIN_DEF(unitwalk,"ii??"),
+	BUILDIN_DEF2(unitwalk,"unitwalkto","ii?"),
 	BUILDIN_DEF(unitkill,"i"),
 	BUILDIN_DEF(unitkill,"i"),
 	BUILDIN_DEF(unitwarp,"isii"),
 	BUILDIN_DEF(unitwarp,"isii"),
 	BUILDIN_DEF(unitattack,"iv?"),
 	BUILDIN_DEF(unitattack,"iv?"),
@@ -20648,6 +20780,7 @@ struct script_function buildin_func[] = {
 	BUILDIN_DEF(mergeitem,"??"),
 	BUILDIN_DEF(mergeitem,"??"),
 	BUILDIN_DEF(npcshopupdate,"sii?"),
 	BUILDIN_DEF(npcshopupdate,"sii?"),
 	BUILDIN_DEF(getattachedrid,""),
 	BUILDIN_DEF(getattachedrid,""),
+	BUILDIN_DEF(getvar,"vi"),
 
 
 #include "../custom/script_def.inc"
 #include "../custom/script_def.inc"
 
 

+ 6 - 0
src/map/unit.c

@@ -406,6 +406,12 @@ static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data
 	map_foreachinmovearea(clif_insight, bl, AREA_SIZE, -dx, -dy, sd?BL_ALL:BL_PC, bl);
 	map_foreachinmovearea(clif_insight, bl, AREA_SIZE, -dx, -dy, sd?BL_ALL:BL_PC, bl);
 	ud->walktimer = INVALID_TIMER;
 	ud->walktimer = INVALID_TIMER;
 
 
+	if (ud->state.walk_script && bl->x == ud->to_x && bl->y == ud->to_y) {
+		if (ud->walk_done_event[0])
+			npc_event_do_id(ud->walk_done_event,bl->id);
+		ud->state.walk_script = 0;
+	}
+
 	switch(bl->type) {
 	switch(bl->type) {
 		case BL_PC:
 		case BL_PC:
 			if( sd->touching_id )
 			if( sd->touching_id )

+ 2 - 0
src/map/unit.h

@@ -52,7 +52,9 @@ struct unit_data {
 		unsigned walk_easy : 1 ;
 		unsigned walk_easy : 1 ;
 		unsigned running : 1;
 		unsigned running : 1;
 		unsigned speed_changed : 1;
 		unsigned speed_changed : 1;
+		unsigned walk_script : 1;
 	} state;
 	} state;
+	char walk_done_event[EVENT_NAME_LENGTH];
 };
 };
 
 
 struct view_data {
 struct view_data {