summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2013-07-19 17:10:09 +0200
committerHaru <haru@dotalux.com>2013-07-21 18:45:31 +0200
commit5f7320cda31036120ab11d9f719b34bf2809cbb4 (patch)
tree273a3ca6ae1c597c7eb70e8da8c6f91e79bf89e9 /src
parent9bcb1423969870a6b60819e6f3846fe0235e28a9 (diff)
downloadhercules-5f7320cda31036120ab11d9f719b34bf2809cbb4.tar.gz
hercules-5f7320cda31036120ab11d9f719b34bf2809cbb4.tar.bz2
hercules-5f7320cda31036120ab11d9f719b34bf2809cbb4.tar.xz
hercules-5f7320cda31036120ab11d9f719b34bf2809cbb4.zip
Fixed various unit* script commands to work with NPCs (issue #7548)
http://hercules.ws/board/tracker/issue-7548-unitwalk-do-not-work/ Follow-up to 20bdc01. Thanks to Ind for his support and suggestions. Signed-off-by: Haru <haru@dotalux.com>
Diffstat (limited to 'src')
-rw-r--r--src/map/script.c59
-rw-r--r--src/map/unit.c26
-rw-r--r--src/map/unit.h1
3 files changed, 50 insertions, 36 deletions
diff --git a/src/map/script.c b/src/map/script.c
index 27368a174..04d834f74 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -12619,20 +12619,15 @@ BUILDIN(npctalk)
}
// change npc walkspeed [Valaris]
-BUILDIN(npcspeed)
-{
+BUILDIN(npcspeed) {
struct npc_data* nd;
int speed;
speed = script_getnum(st,2);
- nd =(struct npc_data *)iMap->id2bl(st->oid);
+ nd = (struct npc_data *)iMap->id2bl(st->oid);
if( nd ) {
- if( nd->ud == &npc_base_ud ) {
- nd->ud = NULL;
- CREATE(nd->ud, struct unit_data, 1);
- unit_dataset(&nd->bl);
- }
+ unit_bl2ud2(&nd->bl); // ensure nd->ud is safe to edit
nd->speed = speed;
nd->ud->state.speed_changed = 1;
}
@@ -12647,13 +12642,8 @@ BUILDIN(npcwalkto) {
x=script_getnum(st,2);
y=script_getnum(st,3);
- if(nd) {
- if( nd->ud == &npc_base_ud ) {
- nd->ud = NULL;
- CREATE(nd->ud, struct unit_data, 1);
- unit_dataset(&nd->bl);
- }
-
+ if( nd ) {
+ unit_bl2ud2(&nd->bl); // ensure nd->ud is safe to edit
if (!nd->status.hp) {
status_calc_npc(nd, true);
} else {
@@ -12665,11 +12655,11 @@ BUILDIN(npcwalkto) {
return true;
}
// stop an npc's movement [Valaris]
-BUILDIN(npcstop)
-{
- struct npc_data *nd=(struct npc_data *)iMap->id2bl(st->oid);
+BUILDIN(npcstop) {
+ struct npc_data *nd = (struct npc_data *)iMap->id2bl(st->oid);
- if(nd) {
+ if( nd ) {
+ unit_bl2ud2(&nd->bl); // ensure nd->ud is safe to edit
unit_stop_walking(&nd->bl,1|4);
}
@@ -14910,23 +14900,23 @@ BUILDIN(pcstopfollow)
///
/// unitwalk(<unit_id>,<x>,<y>) -> <bool>
/// unitwalk(<unit_id>,<map_id>) -> <bool>
-BUILDIN(unitwalk)
-{
+BUILDIN(unitwalk) {
struct block_list* bl;
bl = iMap->id2bl(script_getnum(st,2));
- if( bl == NULL )
- {
+ if( bl == NULL ) {
script_pushint(st, 0);
+ return true;
}
- else if( script_hasdata(st,4) )
- {
+
+ if( bl->type == BL_NPC ) {
+ unit_bl2ud2(bl); // ensure the ((TBL_NPC*)bl)->ud is safe to edit
+ }
+ if( script_hasdata(st,4) ) {
int x = script_getnum(st,3);
int y = script_getnum(st,4);
script_pushint(st, unit_walktoxy(bl,x,y,0));// We'll use harder calculations.
- }
- else
- {
+ } else {
int map_id = script_getnum(st,3);
script_pushint(st, unit_walktobl(bl,iMap->id2bl(map_id),65025,1));
}
@@ -14950,8 +14940,7 @@ BUILDIN(unitkill)
/// Returns if it was successfull
///
/// unitwarp(<unit_id>,"<map name>",<x>,<y>) -> <bool>
-BUILDIN(unitwarp)
-{
+BUILDIN(unitwarp) {
int unit_id;
int map;
short x;
@@ -14974,10 +14963,12 @@ BUILDIN(unitwarp)
else
map = iMap->mapname2mapid(mapname);
- if( map >= 0 && bl != NULL )
+ if( map >= 0 && bl != NULL ) {
+ unit_bl2ud2(bl); // ensure ((TBL_NPC*)bl)->ud is safe to edit
script_pushint(st, unit_warp(bl,map,x,y,CLR_OUTSIGHT));
- else
+ } else {
script_pushint(st, 0);
+ }
return true;
}
@@ -15047,8 +15038,7 @@ BUILDIN(unitattack)
/// Makes the unit stop attacking and moving
///
/// unitstop <unit_id>;
-BUILDIN(unitstop)
-{
+BUILDIN(unitstop) {
int unit_id;
struct block_list* bl;
@@ -15057,6 +15047,7 @@ BUILDIN(unitstop)
bl = iMap->id2bl(unit_id);
if( bl != NULL )
{
+ unit_bl2ud2(bl); // ensure ((TBL_NPC*)bl)->ud is safe to edit
unit_stop_attack(bl);
unit_stop_walking(bl,4);
if( bl->type == BL_MOB )
diff --git a/src/map/unit.c b/src/map/unit.c
index ce097dda0..4a8a87920 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -44,8 +44,13 @@
const short dirx[8]={0,-1,-1,-1,0,1,1,1};
const short diry[8]={1,1,0,-1,-1,-1,0,1};
-struct unit_data* unit_bl2ud(struct block_list *bl)
-{
+/**
+ * Returns the unit_data for the given block_list. If the object is using
+ * shared unit_data (i.e. in case of BL_NPC), it returns the shared data.
+ * @param bl block_list to process
+ * @return a pointer to the given object's unit_data
+ **/
+struct unit_data* unit_bl2ud(struct block_list *bl) {
if( bl == NULL) return NULL;
if( bl->type == BL_PC) return &((struct map_session_data*)bl)->ud;
if( bl->type == BL_MOB) return &((struct mob_data*)bl)->ud;
@@ -57,6 +62,23 @@ struct unit_data* unit_bl2ud(struct block_list *bl)
return NULL;
}
+/**
+ * Returns the unit_data for the given block_list. If the object is using
+ * shared unit_data (i.e. in case of BL_NPC), it recreates a copy of the
+ * data so that it's safe to modify.
+ * @param bl block_list to process
+ * @return a pointer to the given object's unit_data
+ */
+struct unit_data* unit_bl2ud2(struct block_list *bl) {
+ if( bl && bl->type == BL_NPC && ((struct npc_data*)bl)->ud == &npc_base_ud ) {
+ struct npc_data *nd = (struct npc_data *)bl;
+ nd->ud = NULL;
+ CREATE(nd->ud, struct unit_data, 1);
+ unit_dataset(&nd->bl);
+ }
+ return unit_bl2ud(bl);
+}
+
static int unit_attack_timer(int tid, unsigned int tick, int id, intptr_t data);
static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data);
diff --git a/src/map/unit.h b/src/map/unit.h
index 9d1c02a31..a4c7fc0cc 100644
--- a/src/map/unit.h
+++ b/src/map/unit.h
@@ -124,6 +124,7 @@ void unit_dataset(struct block_list *bl);
int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2);
// ‚»‚Ì‘¼
struct unit_data* unit_bl2ud(struct block_list *bl);
+struct unit_data* unit_bl2ud2(struct block_list *bl);
void unit_remove_map_pc(struct map_session_data *sd, clr_type clrtype);
void unit_free_pc(struct map_session_data *sd);
#define unit_remove_map(bl,clrtype) unit_remove_map_(bl,clrtype,__FILE__,__LINE__,__func__)