summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorskotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec>2006-03-22 23:58:16 +0000
committerskotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec>2006-03-22 23:58:16 +0000
commit021b26b8409a84b4c83eb0cc1eedbd65eedfd4e0 (patch)
tree63b8507c38f428421d56c9d816c1d2b2b5c4cd7a /src
parent2e2f6aff261555ae5eaee6b7777d5844b7d20544 (diff)
downloadhercules-021b26b8409a84b4c83eb0cc1eedbd65eedfd4e0.tar.gz
hercules-021b26b8409a84b4c83eb0cc1eedbd65eedfd4e0.tar.bz2
hercules-021b26b8409a84b4c83eb0cc1eedbd65eedfd4e0.tar.xz
hercules-021b26b8409a84b4c83eb0cc1eedbd65eedfd4e0.zip
- Merged the unit_data structure from jA for handling unit-related data (attack times, walking, auto-attack timers, skill related data)
- Modified unit_skillcastcancel to receive flag&2, which stands for "cancel casting only if current skill is cancellable" - Battle config options changed from yes/no to BL_TYPE settings: skillrange_by_distance, skill_noreiteration, skill_nofootset, gvg_traps_target_all, skill_log, attack_direction_change, auto_counter_type - Clif.c will disconnect sessions that send an unknown command packet above 0x30000 instead of just ignoring it. - Cleaned up/rewrite of the pet ai, same for pet_calc_pos - Implemented use of mob variable attacked_players as it is used on jA - Cleaned up error reporting during mob-skill loading to be less spamy with non-loaded mobs. - Corrected water_height reading. I forgot to give credits to LittleWolf for providing the water-reading function :X git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@5707 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src')
-rw-r--r--src/common/mapindex.c1
-rw-r--r--src/map/Makefile6
-rw-r--r--src/map/atcommand.c15
-rw-r--r--src/map/battle.c419
-rw-r--r--src/map/battle.h25
-rw-r--r--src/map/clif.c182
-rw-r--r--src/map/log.c2
-rw-r--r--src/map/map.c312
-rw-r--r--src/map/map.h261
-rw-r--r--src/map/mob.c1844
-rw-r--r--src/map/mob.h24
-rw-r--r--src/map/npc.c372
-rw-r--r--src/map/npc.h4
-rw-r--r--src/map/pc.c740
-rw-r--r--src/map/pc.h15
-rw-r--r--src/map/pet.c1057
-rw-r--r--src/map/pet.h12
-rw-r--r--src/map/script.c173
-rw-r--r--src/map/skill.c1616
-rw-r--r--src/map/skill.h11
-rw-r--r--src/map/status.c141
-rw-r--r--src/map/status.h1
-rw-r--r--src/map/unit.c1680
-rw-r--r--src/map/unit.h69
24 files changed, 3575 insertions, 5407 deletions
diff --git a/src/common/mapindex.c b/src/common/mapindex.c
index 156dc6243..8fbf2da12 100644
--- a/src/common/mapindex.c
+++ b/src/common/mapindex.c
@@ -123,6 +123,7 @@ void mapindex_init(void) {
}
last_index = index;
}
+ fclose(fp);
}
void mapindex_final(void) {
diff --git a/src/map/Makefile b/src/map/Makefile
index 071bfb38b..20934f7fc 100644
--- a/src/map/Makefile
+++ b/src/map/Makefile
@@ -24,7 +24,8 @@ OBJECTS = obj/map.o obj/chrif.o obj/clif.o obj/pc.o obj/status.o obj/npc.o \
obj/npc_chat.o obj/chat.o obj/path.o obj/itemdb.o obj/mob.o obj/script.o \
obj/storage.o obj/skill.o obj/atcommand.o obj/charcommand.o obj/battle.o \
obj/intif.o obj/trade.o obj/party.o obj/vending.o obj/guild.o obj/pet.o \
- obj/log.o obj/mail.o obj/charsave.o obj/date.o obj/irc.o $(COMMON_OBJ)
+ obj/log.o obj/mail.o obj/charsave.o obj/date.o obj/irc.o obj/unit.o \
+ $(COMMON_OBJ)
map-server: $(OBJECTS:obj/%=txtobj/%)
$(CC) -o ../../$@ $> $(LIBS) $(LIB_S)
@@ -69,7 +70,7 @@ txtobj/log.o: log.c log.h map.h $(COMMON_H)
txtobj/charcommand.o: charcommand.c charcommand.h itemdb.h pc.h map.h skill.h clif.h mob.h intif.h battle.h storage.h guild.h pet.h log.h $(COMMON_H)
txtobj/date.o: date.c date.h $(COMMON_H)
txtobj/irc.o: irc.c irc.h map.h pc.h $(COMMON_H)
-
+txtobj/unit.o: unit.c unit.h $(COMMON_H)
sqlobj/map.o: map.c map.h chrif.h clif.h npc.h pc.h mob.h chat.h skill.h itemdb.h storage.h party.h pet.h atcommand.h log.h irc.h $(COMMON_H)
sqlobj/chrif.o: chrif.c map.h battle.h chrif.h clif.h intif.h pc.h npc.h $(COMMON_H)
@@ -99,3 +100,4 @@ sqlobj/charcommand.o: charcommand.c charcommand.h itemdb.h pc.h map.h skill.h cl
sqlobj/charsave.o: charsave.c charsave.h $(COMMON_H)
sqlobj/date.o: date.c date.h $(COMMON_H)
sqlobj/irc.o: irc.c irc.h map.h pc.h $(COMMON_H)
+sqlobj/unit.o: unit.c unit.h $(COMMON_H)
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index d624afa73..ecb446dda 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -32,6 +32,7 @@
#include "script.h"
#include "npc.h"
#include "trade.h"
+#include "unit.h"
#ifndef TXT_ONLY
#include "mail.h"
@@ -3639,7 +3640,7 @@ static int atkillmonster_sub(struct block_list *bl, va_list ap) {
if (flag)
mob_damage(NULL, md, md->hp, 2);
else
- mob_delete(md);
+ unit_remove_map(&md->bl,1);
return 1;
}
@@ -5733,7 +5734,7 @@ int atcommand_mapinfo(
clif_displaymessage(fd, "----- NPCs in Map -----");
for (i = 0; i < map[m_id].npc_num;) {
nd = map[m_id].npc[i];
- switch(nd->dir) {
+ switch(nd->ud.dir) {
case 0: strcpy(direction, "North"); break;
case 1: strcpy(direction, "North West"); break;
case 2: strcpy(direction, "West"); break;
@@ -7288,10 +7289,10 @@ atcommand_useskill(const int fd, struct map_session_data* sd,
return -1;
}
- if (skill_get_inf(skillnum) & INF_GROUND_SKILL)
- skill_use_pos(sd, pl_sd->bl.x, pl_sd->bl.y, skillnum, skilllv);
+ if (skill_get_inf(skillnum)&INF_GROUND_SKILL)
+ unit_skilluse_pos(&sd->bl, pl_sd->bl.x, pl_sd->bl.y, skillnum, skilllv);
else
- skill_use_id(sd, pl_sd->bl.id, skillnum, skilllv);
+ unit_skilluse_id(&sd->bl, pl_sd->bl.id, skillnum, skilllv);
return 0;
}
@@ -7531,9 +7532,9 @@ atcommand_grind(const int fd, struct map_session_data* sd,
inf = skill_get_inf(skillnum);
if (inf & INF_GROUND_SKILL)
- skill_use_pos(sd, pl_sd->bl.x+5, pl_sd->bl.y+5, skillnum, 1);
+ unit_skilluse_pos(&sd->bl, pl_sd->bl.x, pl_sd->bl.y, skillnum, 1);
else if (!(inf & INF_SUPPORT_SKILL))
- skill_use_id(sd, pl_sd->bl.id, skillnum, 1);
+ unit_skilluse_id(&sd->bl, pl_sd->bl.id, skillnum, 1);
}
return 0;
diff --git a/src/map/battle.c b/src/map/battle.c
index ede843da1..9c8c94d57 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -31,53 +31,16 @@ int attr_fix_table[4][10][10];
struct Battle_Config battle_config;
static struct eri *delay_damage_ers; //For battle delay damage structures.
-/*==========================================
- * Ž©•ª‚ðƒ?ƒbƒN‚µ‚Ä‚¢‚éMOB‚Ì?‚ð?‚¦‚é(foreachclient)
- *------------------------------------------
- */
-static int battle_counttargeted_sub(struct block_list *bl, va_list ap)
-{
- int id, target_lv;
- struct block_list *src;
-
- nullpo_retr(0, bl);
- nullpo_retr(0, ap);
-
- id = va_arg(ap,int);
- src = va_arg(ap,struct block_list *);
- target_lv = va_arg(ap,int);
+int battle_getcurrentskill(struct block_list *bl)
+{ //Returns the current/last skill in use by this bl.
+ struct unit_data *ud;
- if (id == bl->id || (src && id == src->id))
- return 0;
- if (bl->type == BL_PC) {
- struct map_session_data *sd = (struct map_session_data *)bl;
- if (sd && sd->attacktarget == id && sd->attacktimer != -1 && sd->attacktarget_lv >= target_lv)
- return 1;
- }
- else if (bl->type == BL_MOB) {
- struct mob_data *md = (struct mob_data *)bl;
- if (md && md->target_id == id && md->timer != -1 && md->state.state == MS_ATTACK && md->target_lv >= target_lv)
- return 1;
- //printf("md->target_lv:%d, target_lv:%d\n", md->target_lv, target_lv);
+ if (bl->type == BL_SKILL) {
+ struct skill_unit * su = (struct skill_unit*)bl;
+ return su->group?su->group->skill_id:0;
}
- else if (bl->type == BL_PET) {
- struct pet_data *pd = (struct pet_data *)bl;
- if (pd && pd->target_id == id && pd->timer != -1 && pd->state.state == MS_ATTACK && pd->target_lv >= target_lv)
- return 1;
- }
-
- return 0;
-}
-/*==========================================
- * Ž©•ª‚ðƒ?ƒbƒN‚µ‚Ä‚¢‚é‘Î?Û‚Ì?”‚ð•Ô‚·(”Ä—p)
- * –ß‚è‚Í?®?”‚Å0ˆÈ?ã
- *------------------------------------------
- */
-int battle_counttargeted(struct block_list *bl,struct block_list *src,int target_lv)
-{
- nullpo_retr(0, bl);
- return (map_foreachinrange(battle_counttargeted_sub, bl, AREA_SIZE, BL_CHAR,
- bl->id, src, target_lv));
+ ud = unit_bl2ud(bl);
+ return ud?ud->skillid:0;
}
/*==========================================
@@ -87,67 +50,53 @@ int battle_counttargeted(struct block_list *bl,struct block_list *src,int target
static int battle_gettargeted_sub(struct block_list *bl, va_list ap)
{
struct block_list **bl_list;
- struct block_list *target;
+ struct unit_data *ud;
+ int target_id;
int *c;
nullpo_retr(0, bl);
nullpo_retr(0, ap);
bl_list = va_arg(ap, struct block_list **);
- nullpo_retr(0, c = va_arg(ap, int *));
- nullpo_retr(0, target = va_arg(ap, struct block_list *));
+ c = va_arg(ap, int *);
+ target_id = va_arg(ap, int);
- if (bl->id == target->id)
+ if (bl->id == target_id)
return 0;
if (*c >= 24)
return 0;
- if (bl->type == BL_PC) {
- struct map_session_data *sd = (struct map_session_data *)bl;
- if (!sd || sd->attacktarget != target->id || sd->attacktimer == -1)
- return 0;
- } else if (bl->type == BL_MOB) {
- struct mob_data *md = (struct mob_data *)bl;
- if (!md || md->target_id != target->id || md->timer == -1 || md->state.state != MS_ATTACK)
- return 0;
- } else if (bl->type == BL_PET) {
- struct pet_data *pd = (struct pet_data *)bl;
- if (!pd || pd->target_id != target->id || pd->timer == -1 || pd->state.state != MS_ATTACK)
- return 0;
- }
+ ud = unit_bl2ud(bl);
+ if (!ud) return 0;
- bl_list[(*c)++] = bl;
- return 1;
+ if (ud->attacktarget == target_id || ud->skilltarget == target_id) {
+ bl_list[(*c)++] = bl;
+ return 1;
+ }
+ return 0;
}
-int battle_getcurrentskill(struct block_list *bl)
-{ //Returns the current/last skill in use by this bl.
- switch (bl->type)
- {
- case BL_PC:
- return ((struct map_session_data*)bl)->skillid;
- case BL_MOB:
- return ((struct mob_data*)bl)->skillid;
- case BL_PET:
- return ((struct pet_data*)bl)->skillid;
- case BL_SKILL:
- {
- struct skill_unit * su = (struct skill_unit*)bl;
- if (su->group)
- return su->group->skill_id;
- }
- break;
- }
- return 0;
+struct block_list* battle_gettargeted(struct block_list *target)
+{
+ struct block_list *bl_list[24];
+ int c = 0;
+ nullpo_retr(NULL, target);
+
+ memset(bl_list, 0, sizeof(bl_list));
+ map_foreachinrange(battle_gettargeted_sub, target, AREA_SIZE, BL_CHAR, bl_list, &c, target->id);
+ if (c == 0 || c > 24)
+ return NULL;
+ return bl_list[rand()%c];
}
+
//Returns the id of the current targetted character of the passed bl. [Skotlex]
int battle_gettarget(struct block_list *bl)
{
switch (bl->type)
{
case BL_PC:
- return ((struct map_session_data*)bl)->attacktarget;
+ return ((struct map_session_data*)bl)->ud.attacktarget;
case BL_MOB:
return ((struct mob_data*)bl)->target_id;
case BL_PET:
@@ -155,20 +104,6 @@ int battle_gettarget(struct block_list *bl)
}
return 0;
}
-
-struct block_list* battle_gettargeted(struct block_list *target)
-{
- struct block_list *bl_list[24];
- int c = 0;
- nullpo_retr(NULL, target);
-
- memset(bl_list, 0, sizeof(bl_list));
- map_foreachinrange(battle_gettargeted_sub, target, AREA_SIZE, BL_CHAR, bl_list, &c, target);
- if (c == 0 || c > 24)
- return NULL;
- return bl_list[rand()%c];
-}
-
// ƒ_ƒ??[ƒW‚Ì’x‰„
struct delay_damage {
struct block_list *src;
@@ -271,35 +206,23 @@ int battle_damage(struct block_list *bl,struct block_list *target,int damage, in
if (sc->data[SC_CHASEWALK].timer != -1)
status_change_end(target, SC_CHASEWALK, -1);
}
-
- if (target->type == BL_MOB) { // MOB
- struct mob_data *md = (struct mob_data *)target;
- if (md && md->skilltimer != -1 && md->state.skillcastcancel) // ‰r?¥–WŠQ
- skill_castcancel(target,0);
- return mob_damage(bl,md,damage,0);
- } else if (target->type == BL_PC) { // PC
- struct map_session_data *tsd = (struct map_session_data *)target;
- if (!tsd)
+
+ if (sc && sc->count && sc->data[SC_DEVOTION].val1 && bl && battle_getcurrentskill(bl) != PA_PRESSURE)
+ { //Devotion only works on attacks from a source (to prevent it from absorbing coma) [Skotlex]
+ struct map_session_data *sd2 = map_id2sd(sc->data[SC_DEVOTION].val1);
+ if (sd2 && sd2->devotion[sc->data[SC_DEVOTION].val2] == target->id)
+ {
+ clif_damage(bl, &sd2->bl, gettick(), 0, 0, damage, 0, 0, 0);
+ pc_damage(&sd2->bl, sd2, damage);
return 0;
- if (sc->count && sc->data[SC_DEVOTION].val1 && bl && battle_getcurrentskill(bl) != PA_PRESSURE)
- { //Devotion only works on attacks from a source (prevent it from absorbing coma) [Skotlex]
- struct map_session_data *sd2 = map_id2sd(tsd->sc.data[SC_DEVOTION].val1);
- if (sd2 && sd2->devotion[sc->data[SC_DEVOTION].val2] == target->id)
- {
- clif_damage(bl, &sd2->bl, gettick(), 0, 0, damage, 0, 0, 0);
- pc_damage(&sd2->bl, sd2, damage);
- return 0;
- } else
- status_change_end(target, SC_DEVOTION, -1);
- }
-
- if (tsd->skilltimer != -1) { // ‰r?¥–WŠQ
- // ƒtƒFƒ“ƒJ?[ƒh‚â–WŠQ‚³‚ê‚È‚¢ƒXƒLƒ‹‚©‚ÌŒŸ?¸
- if ((!tsd->special_state.no_castcancel || map_flag_gvg(target->m)) && tsd->state.skillcastcancel &&
- !tsd->special_state.no_castcancel2)
- skill_castcancel(target,0);
- }
- return pc_damage(bl,tsd,damage);
+ } else
+ status_change_end(target, SC_DEVOTION, -1);
+ }
+ unit_skillcastcancel(target, 2);
+ if (target->type == BL_MOB) {
+ return mob_damage(bl,(TBL_MOB*)target, damage,0);
+ } else if (target->type == BL_PC) {
+ return pc_damage(bl,(TBL_PC*)target,damage);
} else if (target->type == BL_SKILL)
return skill_unit_ondamaged((struct skill_unit *)target, bl, damage, gettick());
return 0;
@@ -309,16 +232,9 @@ int battle_heal(struct block_list *bl,struct block_list *target,int hp,int sp,in
{
nullpo_retr(0, target); //bl‚ÍNULL‚ŌĂ΂ê‚邱‚Æ‚ª‚ ‚é‚Ì‚Å‘¼‚Ń`ƒFƒbƒN
- if (target->type == BL_PET)
- return 0;
- if (target->type == BL_PC && pc_isdead((struct map_session_data *)target) )
- return 0;
- if (hp == 0 && sp == 0)
- return 0;
-//If battle_heal was invoked, HP/SP should just be reduced without damage animation. [Skotlex]
-// if (hp < 0)
-// return battle_damage(bl,target,-hp,flag);
+ if (status_isdead(target))
+ return 0;
if (target->type == BL_MOB)
return mob_heal((struct mob_data *)target,hp);
@@ -327,47 +243,6 @@ int battle_heal(struct block_list *bl,struct block_list *target,int hp,int sp,in
return 0;
}
-// ?UŒ‚’âŽ~
-int battle_stopattack(struct block_list *bl)
-{
- nullpo_retr(0, bl);
- if (bl->type == BL_MOB)
- return mob_stopattack((struct mob_data*)bl);
- else if (bl->type == BL_PC)
- return pc_stopattack((struct map_session_data*)bl);
- else if (bl->type == BL_PET)
- return pet_stopattack((struct pet_data*)bl);
- return 0;
-}
-
-// Returns whether the given object is moving or not.
-int battle_iswalking(struct block_list *bl) {
- switch (bl->type)
- {
- case BL_PC:
- return (((struct map_session_data*)bl)->walktimer != -1);
- case BL_MOB:
- return (((struct mob_data*)bl)->state.state == MS_WALK);
- case BL_PET:
- return (((struct pet_data*)bl)->state.state == MS_WALK);
- default:
- return 0;
- }
-}
-// ˆÚ“®’âŽ~
-int battle_stopwalking(struct block_list *bl,int type)
-{
- nullpo_retr(0, bl);
- if (bl->type == BL_MOB)
- return mob_stop_walking((struct mob_data*)bl,type);
- else if (bl->type == BL_PC)
- return pc_stop_walking((struct map_session_data*)bl,type);
- else if (bl->type == BL_PET)
- return pet_stop_walking((struct pet_data*)bl,type);
- return 0;
-}
-
-
/*==========================================
* Does attribute fix modifiers.
* Added passing of the chars so that the status changes can affect it. [Skotlex]
@@ -451,81 +326,6 @@ int battle_attr_fix(struct block_list *src, struct block_list *target, int damag
}
/*==========================================
- * Applies walk delay to character, considering that
- * if type is 0, this is a damage induced delay: if previous delay is active, do not change it.
- * if type is 1, this is a skill induced delay: walk-delay may only be increased, not decreased.
- *------------------------------------------
- */
-int battle_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int type)
-{
- unsigned int *canmove_tick=NULL;
- if (delay <= 0) return 0;
-
- switch (bl->type) {
- case BL_PC:
- canmove_tick = &((TBL_PC*)bl)->canmove_tick;
- break;
- case BL_MOB:
- canmove_tick = &((TBL_MOB*)bl)->canmove_tick;
- break;
- case BL_NPC:
- canmove_tick = &((TBL_NPC*)bl)->canmove_tick;
- break;
- }
- if (!canmove_tick)
- return 0;
- if (type) {
- if (DIFF_TICK(*canmove_tick, tick+delay) > 0)
- return 0;
- } else {
- if (DIFF_TICK(*canmove_tick, tick) > 0)
- return 0;
- }
- *canmove_tick = tick + delay;
- return 1;
-}
-
-static int battle_walkdelay_sub(int tid, unsigned int tick, int id, int data)
-{
- struct block_list *bl = map_id2bl(id);
- if (!bl || status_isdead(bl))
- return 0;
-
- if (battle_set_walkdelay(bl, tick, data, 0))
- battle_stopwalking(bl,3);
- return 0;
-}
-
-/*==========================================
- * Applies walk delay based on attack type. [Skotlex]
- *------------------------------------------
- */
-int battle_walkdelay(struct block_list *bl, unsigned int tick, int adelay, int delay, int div_) {
-
- if (status_isdead(bl))
- return 0;
-
- if (bl->type == BL_PC) {
- if (battle_config.pc_walk_delay_rate != 100)
- delay = delay*battle_config.pc_walk_delay_rate/100;
- } else
- if (battle_config.walk_delay_rate != 100)
- delay = delay*battle_config.walk_delay_rate/100;
-
- if (div_ > 1) //Multi-hit skills mean higher delays.
- delay += battle_config.multihit_delay*(div_-1);
-
- if (delay <= 0)
- return 0;
-
- if (adelay > 0)
- add_timer(tick+adelay, battle_walkdelay_sub, bl->id, delay);
- else
- battle_set_walkdelay(bl, tick, delay, 0);
- return 1;
-}
-
-/*==========================================
* ƒ_ƒ??[ƒW?Å?IŒvŽZ
*------------------------------------------
*/
@@ -585,7 +385,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i
delay = 200;
else
delay = 100;
- battle_set_walkdelay(bl, gettick(), delay, 1);
+ unit_set_walkdelay(bl, gettick(), delay, 1);
if(sc->data[SC_SHRINK].timer != -1 && rand()%100<5*sc->data[SC_AUTOGUARD].val1)
skill_blown(bl,src,skill_get_blewcount(CR_SHRINK,1));
@@ -1309,17 +1109,13 @@ static struct Damage battle_calc_weapon_attack(
}
}
- if (skill_num && battle_config.skillrange_by_distance)
- { //Skill range based on distance between src/target [Skotlex]
- if ((sd && battle_config.skillrange_by_distance&1)
- || (md && battle_config.skillrange_by_distance&2)
- || (pd && battle_config.skillrange_by_distance&4)
- ) {
- if (check_distance_bl(src, target, 3))
- wd.flag=(wd.flag&~BF_RANGEMASK)|BF_SHORT;
- else
- wd.flag=(wd.flag&~BF_RANGEMASK)|BF_LONG;
- }
+ if (skill_num && battle_config.skillrange_by_distance &&
+ (src->type&battle_config.skillrange_by_distance)
+ ) { //Skill range based on distance between src/target [Skotlex]
+ if (check_distance_bl(src, target, 3))
+ wd.flag=(wd.flag&~BF_RANGEMASK)|BF_SHORT;
+ else
+ wd.flag=(wd.flag&~BF_RANGEMASK)|BF_LONG;
}
if(is_boss(target)) //Bosses can't be knocked-back
@@ -1405,7 +1201,8 @@ static struct Damage battle_calc_weapon_attack(
switch (skill_num)
{
case KN_AUTOCOUNTER:
- if(!(battle_config.pc_auto_counter_type&1))
+ if(battle_config.auto_counter_type &&
+ (battle_config.auto_counter_type&src->type))
flag.cri = 1;
else
cri <<= 1;
@@ -1476,7 +1273,7 @@ static struct Damage battle_calc_weapon_attack(
if(battle_config.agi_penalty_type)
{
unsigned char target_count; //256 max targets should be a sane max
- target_count = 1+battle_counttargeted(target,src,battle_config.agi_penalty_count_lv);
+ target_count = unit_counttargeted(target,battle_config.agi_penalty_count_lv);
if(target_count >= battle_config.agi_penalty_count)
{
if (battle_config.agi_penalty_type == 1)
@@ -2052,7 +1849,7 @@ static struct Damage battle_calc_weapon_attack(
if(battle_config.vit_penalty_type)
{
unsigned char target_count; //256 max targets should be a sane max
- target_count = 1 + battle_counttargeted(target,src,battle_config.vit_penalty_count_lv);
+ target_count = unit_counttargeted(target,battle_config.vit_penalty_count_lv);
if(target_count >= battle_config.vit_penalty_count) {
if(battle_config.vit_penalty_type == 1) {
def1 = (def1 * (100 - (target_count - (battle_config.vit_penalty_count - 1))*battle_config.vit_penalty_num))/100;
@@ -2537,17 +2334,13 @@ struct Damage battle_calc_magic_attack(
}
}
- if (battle_config.skillrange_by_distance)
- { //Skill range based on distance between src/target [Skotlex]
- if ((sd && battle_config.skillrange_by_distance&1)
- || (md && battle_config.skillrange_by_distance&2)
- || (pd && battle_config.skillrange_by_distance&4)
- ) {
- if (check_distance_bl(src, target, 3))
- ad.flag=(ad.flag&~BF_RANGEMASK)|BF_SHORT;
- else
- ad.flag=(ad.flag&~BF_RANGEMASK)|BF_LONG;
- }
+ if (battle_config.skillrange_by_distance &&
+ (src->type&battle_config.skillrange_by_distance)
+ ) { //Skill range based on distance between src/target [Skotlex]
+ if (check_distance_bl(src, target, 3))
+ ad.flag=(ad.flag&~BF_RANGEMASK)|BF_SHORT;
+ else
+ ad.flag=(ad.flag&~BF_RANGEMASK)|BF_LONG;
}
flag.infdef=(t_mode&MD_PLANT?1:0);
@@ -3073,17 +2866,13 @@ struct Damage battle_calc_misc_attack(
if(is_boss(target))
blewcount = 0;
- if (battle_config.skillrange_by_distance)
- { //Skill range based on distance between src/target [Skotlex]
- if ((bl->type == BL_PC && battle_config.skillrange_by_distance&1)
- || (bl->type == BL_MOB && battle_config.skillrange_by_distance&2)
- || (bl->type == BL_PET && battle_config.skillrange_by_distance&4)
- ) {
- if (check_distance_bl(bl, target, 3))
- aflag=(aflag&~BF_RANGEMASK)|BF_SHORT;
- else
- aflag=(aflag&~BF_RANGEMASK)|BF_LONG;
- }
+ if (battle_config.skillrange_by_distance &&
+ (bl->type&battle_config.skillrange_by_distance)
+ ) { //Skill range based on distance between src/target [Skotlex]
+ if (check_distance_bl(bl, target, 3))
+ aflag=(aflag&~BF_RANGEMASK)|BF_SHORT;
+ else
+ aflag=(aflag&~BF_RANGEMASK)|BF_LONG;
}
if (skill_num != PA_PRESSURE) //Pressure ignores all these things...
@@ -3218,7 +3007,7 @@ int battle_weapon_attack( struct block_list *src,struct block_list *target,
status_check_skilluse(target, src, KN_AUTOCOUNTER, 0)
) {
int dir = map_calc_dir(target,src->x,src->y);
- int t_dir = status_get_dir(target);
+ int t_dir = unit_getdir(target);
int dist = distance_bl(src, target);
if(dist <= 0 || (!map_check_dir(dir,t_dir) && dist <= status_get_range(target)+1))
{
@@ -3738,9 +3527,8 @@ static const struct battle_data_short {
{ "delay_dependon_dex", &battle_config.delay_dependon_dex },
{ "skill_delay_attack_enable", &battle_config.sdelay_attack_enable },
{ "left_cardfix_to_right", &battle_config.left_cardfix_to_right },
- { "player_skill_add_range", &battle_config.pc_skill_add_range },
+ { "skill_add_range", &battle_config.skill_add_range },
{ "skill_out_range_consume", &battle_config.skill_out_range_consume },
- { "monster_skill_add_range", &battle_config.mob_skill_add_range },
{ "skillrange_by_distance", &battle_config.skillrange_by_distance },
{ "skillrange_from_weapon", &battle_config.use_weapon_skill_range },
{ "player_damage_delay_rate", &battle_config.pc_damage_delay_rate },
@@ -3844,16 +3632,14 @@ static const struct battle_data_short {
{ "max_baby_parameter", &battle_config.max_baby_parameter },
{ "max_def", &battle_config.max_def },
{ "over_def_bonus", &battle_config.over_def_bonus },
- { "player_skill_log", &battle_config.pc_skill_log },
- { "monster_skill_log", &battle_config.mob_skill_log },
+ { "skill_log", &battle_config.skill_log },
{ "battle_log", &battle_config.battle_log },
{ "save_log", &battle_config.save_log },
{ "error_log", &battle_config.error_log },
{ "etc_log", &battle_config.etc_log },
{ "save_clothcolor", &battle_config.save_clothcolor },
{ "undead_detect_type", &battle_config.undead_detect_type },
- { "player_auto_counter_type", &battle_config.pc_auto_counter_type },
- { "monster_auto_counter_type", &battle_config.monster_auto_counter_type},
+ { "auto_counter_type", &battle_config.auto_counter_type },
{ "min_hitrate", &battle_config.min_hitrate },
{ "max_hitrate", &battle_config.max_hitrate },
{ "agi_penalty_type", &battle_config.agi_penalty_type },
@@ -3868,10 +3654,8 @@ static const struct battle_data_short {
{ "monster_defense_type", &battle_config.monster_defense_type },
{ "pet_defense_type", &battle_config.pet_defense_type },
{ "magic_defense_type", &battle_config.magic_defense_type },
- { "player_skill_reiteration", &battle_config.pc_skill_reiteration },
- { "monster_skill_reiteration", &battle_config.monster_skill_reiteration},
- { "player_skill_nofootset", &battle_config.pc_skill_nofootset },
- { "monster_skill_nofootset", &battle_config.monster_skill_nofootset },
+ { "skill_reiteration", &battle_config.skill_reiteration },
+ { "skill_nofootset", &battle_config.skill_nofootset },
{ "player_cloak_check_type", &battle_config.pc_cloak_check_type },
{ "monster_cloak_check_type", &battle_config.monster_cloak_check_type },
{ "sense_type", &battle_config.estimation_type },
@@ -3882,10 +3666,8 @@ static const struct battle_data_short {
{ "gvg_misc_attack_damage_rate", &battle_config.gvg_misc_damage_rate },
{ "gvg_flee_penalty", &battle_config.gvg_flee_penalty },
{ "mob_changetarget_byskill", &battle_config.mob_changetarget_byskill},
- { "player_attack_direction_change", &battle_config.pc_attack_direction_change },
- { "monster_attack_direction_change", &battle_config.monster_attack_direction_change },
- { "player_land_skill_limit", &battle_config.pc_land_skill_limit },
- { "monster_land_skill_limit", &battle_config.monster_land_skill_limit},
+ { "attack_direction_change", &battle_config.attack_direction_change },
+ { "land_skill_limit", &battle_config.land_skill_limit },
{ "party_skill_penalty", &battle_config.party_skill_penalty },
{ "monster_class_change_full_recover", &battle_config.monster_class_change_full_recover },
{ "produce_item_name_input", &battle_config.produce_item_name_input },
@@ -4117,14 +3899,13 @@ void battle_set_defaults() {
battle_config.delay_dependon_dex=0;
battle_config.sdelay_attack_enable=0;
battle_config.left_cardfix_to_right=0;
- battle_config.pc_skill_add_range=0;
+ battle_config.skill_add_range=0;
battle_config.skill_out_range_consume=1;
- battle_config.mob_skill_add_range=0;
- battle_config.skillrange_by_distance=6;
+ battle_config.skillrange_by_distance=BL_MOB|BL_PET;
battle_config.use_weapon_skill_range=0;
battle_config.pc_damage_delay_rate=100;
battle_config.defnotenemy=0;
- battle_config.vs_traps_bctall=1;
+ battle_config.vs_traps_bctall=BL_PC;
battle_config.clear_unit_ondeath=1;
battle_config.random_monster_checklv=1;
battle_config.attr_recover=1;
@@ -4168,7 +3949,6 @@ void battle_set_defaults() {
battle_config.monster_active_enable=1;
battle_config.monster_damage_delay_rate=100;
battle_config.monster_loot_type=0;
-// battle_config.mob_skill_use=1;
battle_config.mob_skill_rate=100;
battle_config.mob_skill_delay=100;
battle_config.mob_count_rate=100;
@@ -4193,7 +3973,7 @@ void battle_set_defaults() {
battle_config.pet_friendly_rate=100;
battle_config.pet_hungry_delay_rate=100;
battle_config.pet_hungry_friendly_decrease=5;
- battle_config.pet_str=1;
+ battle_config.pet_str=0;
battle_config.pet_status_support=0;
battle_config.pet_attack_support=0;
battle_config.pet_damage_support=0;
@@ -4239,18 +4019,16 @@ void battle_set_defaults() {
battle_config.max_cart_weight = 8000;
battle_config.max_def = 99; // [Skotlex]
battle_config.over_def_bonus = 0; // [Skotlex]
- battle_config.pc_skill_log = 0;
- battle_config.mob_skill_log = 0;
+ battle_config.skill_log = 0;
battle_config.battle_log = 0;
battle_config.save_log = 0;
battle_config.error_log = 1;
battle_config.etc_log = 1;
battle_config.save_clothcolor = 0;
battle_config.undead_detect_type = 0;
- battle_config.pc_auto_counter_type = 1;
- battle_config.monster_auto_counter_type = 1;
+ battle_config.auto_counter_type = 0;
battle_config.min_hitrate = 5;
- battle_config.max_hitrate = 95;
+ battle_config.max_hitrate = 100;
battle_config.agi_penalty_type = 1;
battle_config.agi_penalty_count = 3;
battle_config.agi_penalty_num = 10;
@@ -4263,10 +4041,8 @@ void battle_set_defaults() {
battle_config.monster_defense_type = 0;
battle_config.pet_defense_type = 0;
battle_config.magic_defense_type = 0;
- battle_config.pc_skill_reiteration = 0;
- battle_config.monster_skill_reiteration = 0;
- battle_config.pc_skill_nofootset = 0;
- battle_config.monster_skill_nofootset = 0;
+ battle_config.skill_reiteration = 0;
+ battle_config.skill_nofootset = BL_PC;
battle_config.pc_cloak_check_type = 1;
battle_config.monster_cloak_check_type = 0;
battle_config.estimation_type = 3;
@@ -4278,10 +4054,8 @@ void battle_set_defaults() {
battle_config.gvg_flee_penalty = 20;
battle_config.gvg_eliminate_time = 7000;
battle_config.mob_changetarget_byskill = 0;
- battle_config.pc_attack_direction_change = 1;
- battle_config.monster_attack_direction_change = 1;
- battle_config.pc_land_skill_limit = 1;
- battle_config.monster_land_skill_limit = 1;
+ battle_config.attack_direction_change = BL_ALL;
+ battle_config.land_skill_limit = BL_ALL;
battle_config.party_skill_penalty = 1;
battle_config.monster_class_change_full_recover = 0;
battle_config.produce_item_name_input = 1;
@@ -4684,7 +4458,6 @@ int battle_config_read(const char *cfgName)
if (--count == 0) {
battle_validate_conf();
add_timer_func_list(battle_delay_damage_sub, "battle_delay_damage_sub");
- add_timer_func_list(battle_walkdelay_sub, "battle_walkdelay_sub");
}
return 0;
diff --git a/src/map/battle.h b/src/map/battle.h
index 0f92c3160..8ec793e8c 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -47,23 +47,16 @@ enum { // ÅIŒvŽZ‚̃tƒ‰ƒO
};
// ŽÀÛ‚ÉHP‚𑌸
-int battle_walkdelay(struct block_list *bl, unsigned int tick, int adelay, int delay, int div_); //Calcs walk delay based on attack type. [Skotlex]
int battle_delay_damage (unsigned int tick, struct block_list *src, struct block_list *target, int attack_type, int skill_id, int skill_lv, int damage, int dmg_lv, int flag);
int battle_damage(struct block_list *bl,struct block_list *target,int damage,int flag);
int battle_heal(struct block_list *bl,struct block_list *target,int hp,int sp,int flag);
-// UŒ‚‚âˆÚ“®‚ðŽ~‚ß‚é
-int battle_stopattack(struct block_list *bl);
-int battle_iswalking(struct block_list *bl);
-int battle_stopwalking(struct block_list *bl,int type);
-int battle_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int type);
// ’ÊíUŒ‚ˆ—‚Ü‚Æ‚ß
int battle_weapon_attack( struct block_list *bl,struct block_list *target,
unsigned int tick,int flag);
// ŠeŽíƒpƒ‰ƒ[ƒ^‚𓾂é
-int battle_counttargeted(struct block_list *bl,struct block_list *src,int target_lv);
struct block_list* battle_gettargeted(struct block_list *target);
int battle_gettarget(struct block_list *bl);
int battle_getcurrentskill(struct block_list *bl);
@@ -109,9 +102,8 @@ extern struct Battle_Config {
unsigned short cast_rate,delay_rate,delay_dependon_dex;
unsigned short sdelay_attack_enable;
unsigned short left_cardfix_to_right;
- unsigned short pc_skill_add_range;
+ unsigned short skill_add_range;
unsigned short skill_out_range_consume;
- unsigned short mob_skill_add_range;
unsigned short skillrange_by_distance; //[Skotlex]
unsigned short use_weapon_skill_range; //[Skotlex]
unsigned short pc_damage_delay_rate;
@@ -222,8 +214,7 @@ extern struct Battle_Config {
unsigned short max_lv, aura_lv;
unsigned short max_parameter, max_baby_parameter;
int max_cart_weight;
- unsigned short pc_skill_log;
- unsigned short mob_skill_log;
+ unsigned short skill_log;
unsigned short battle_log;
unsigned short save_log;
unsigned short error_log;
@@ -244,10 +235,8 @@ extern struct Battle_Config {
unsigned short monster_defense_type;
unsigned short pet_defense_type;
unsigned short magic_defense_type;
- unsigned short pc_skill_reiteration;
- unsigned short monster_skill_reiteration;
- unsigned short pc_skill_nofootset;
- unsigned short monster_skill_nofootset;
+ unsigned short skill_reiteration;
+ unsigned short skill_nofootset;
unsigned short pc_cloak_check_type;
unsigned short monster_cloak_check_type;
unsigned short estimation_type;
@@ -259,10 +248,8 @@ extern struct Battle_Config {
unsigned short gvg_flee_penalty;
int gvg_eliminate_time;
unsigned short mob_changetarget_byskill;
- unsigned short pc_attack_direction_change;
- unsigned short monster_attack_direction_change;
- unsigned short pc_land_skill_limit;
- unsigned short monster_land_skill_limit;
+ unsigned short attack_direction_change;
+ unsigned short land_skill_limit;
unsigned short party_skill_penalty;
unsigned short monster_class_change_full_recover;
unsigned short produce_item_name_input;
diff --git a/src/map/clif.c b/src/map/clif.c
index 17d6c454c..3f9e5e6c4 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -46,6 +46,7 @@
#include "battle.h"
#include "mob.h"
#include "party.h"
+#include "unit.h"
#include "guild.h"
#include "vending.h"
#include "pet.h"
@@ -808,7 +809,7 @@ static int clif_set0078(struct map_session_data *sd, unsigned char *buf) {
WBUFB(buf,44)=sd->status.karma;
WBUFB(buf,45)=sd->sex;
WBUFPOS(buf,46,sd->bl.x,sd->bl.y);
- WBUFB(buf,48)|=sd->dir&0x0f;
+ WBUFB(buf,48)|=sd->ud.dir&0x0f;
WBUFB(buf,49)=5;
WBUFB(buf,50)=5;
WBUFB(buf,51)=clif_deadsit(sd);
@@ -847,7 +848,7 @@ static int clif_set0078(struct map_session_data *sd, unsigned char *buf) {
WBUFB(buf,44)=sd->status.karma;
WBUFB(buf,45)=sd->sex;
WBUFPOS(buf,46,sd->bl.x,sd->bl.y);
- WBUFB(buf,48)|=sd->dir & 0x0f;
+ WBUFB(buf,48)|=sd->ud.dir & 0x0f;
WBUFB(buf,49)=5;
WBUFB(buf,50)=5;
WBUFB(buf,51)=clif_deadsit(sd);
@@ -876,7 +877,7 @@ static int clif_dis0078(struct map_session_data *sd, unsigned char *buf) {
WBUFW(buf,42)=0;
WBUFB(buf,44)=0;
WBUFPOS(buf,46,sd->bl.x,sd->bl.y);
- WBUFB(buf,48)|=sd->dir&0x0f;
+ WBUFB(buf,48)|=sd->ud.dir&0x0f;
WBUFB(buf,49)=5;
WBUFB(buf,50)=5;
WBUFB(buf,51)=clif_deadsit(sd);
@@ -932,7 +933,7 @@ static int clif_set007b(struct map_session_data *sd,unsigned char *buf) {
WBUFW(buf,46)=sd->sc.opt3;
WBUFB(buf,48)=sd->status.karma;
WBUFB(buf,49)=sd->sex;
- WBUFPOS2(buf,50,sd->bl.x,sd->bl.y,sd->to_x,sd->to_y);
+ WBUFPOS2(buf,50,sd->bl.x,sd->bl.y,sd->ud.to_x,sd->ud.to_y);
WBUFB(buf,55)=0x88; // Deals with acceleration in directions. [Valaris]
WBUFB(buf,56)=5;
WBUFB(buf,57)=5;
@@ -971,7 +972,7 @@ static int clif_set007b(struct map_session_data *sd,unsigned char *buf) {
WBUFW(buf,46)=sd->sc.opt3;
WBUFB(buf,48)=sd->status.karma;
WBUFB(buf,49)=sd->sex;
- WBUFPOS2(buf,50,sd->bl.x,sd->bl.y,sd->to_x,sd->to_y);
+ WBUFPOS2(buf,50,sd->bl.x,sd->bl.y,sd->ud.to_x,sd->ud.to_y);
WBUFB(buf,55)=0x88; // Deals with acceleration in directions. [Valaris]
WBUFB(buf,56)=5;
WBUFB(buf,57)=5;
@@ -998,7 +999,7 @@ static int clif_dis007b(struct map_session_data *sd,unsigned char *buf) {
WBUFL(buf,22)=gettick();
//WBUFL(buf,38)=sd->status.guild_id;
//WBUFL(buf,42)=sd->guild_emblem_id;
- WBUFPOS2(buf,50,sd->bl.x,sd->bl.y,sd->to_x,sd->to_y);
+ WBUFPOS2(buf,50,sd->bl.x,sd->bl.y,sd->ud.to_x,sd->ud.to_y);
WBUFB(buf,55)=0x88; // Deals with acceleration in directions. [Valaris]
WBUFB(buf,56)=5;
WBUFB(buf,57)=5;
@@ -1097,7 +1098,7 @@ static int clif_mob0078(struct mob_data *md, unsigned char *buf)
WBUFW(buf,26)=mob_get_head_mid(md->class_);
WBUFW(buf,28)=mob_get_hair_color(md->class_);
WBUFW(buf,30)=mob_get_clothes_color(md->class_);
- WBUFW(buf,32)|=md->dir&0x0f; // head direction
+ WBUFW(buf,32)|=md->ud.dir&0x0f; // head direction
if (md->guardian_data && md->guardian_data->guild_id) { // Added guardian emblems [Valaris]
WBUFL(buf,34)=md->guardian_data->guild_id;
WBUFL(buf,38)=md->guardian_data->emblem_id;
@@ -1106,7 +1107,7 @@ static int clif_mob0078(struct mob_data *md, unsigned char *buf)
WBUFB(buf,44)=0; // karma
WBUFB(buf,45)=mob_get_sex(md->class_);
WBUFPOS(buf,46,md->bl.x,md->bl.y);
- WBUFB(buf,48)|=md->dir&0x0f;
+ WBUFB(buf,48)|=md->ud.dir&0x0f;
WBUFB(buf,49)=5;
WBUFB(buf,50)=5;
WBUFB(buf,51)=0; // dead or sit state
@@ -1132,7 +1133,7 @@ static int clif_mob0078(struct mob_data *md, unsigned char *buf)
WBUFW(buf,26)=mob_get_head_mid(md->class_);
WBUFW(buf,28)=mob_get_hair_color(md->class_);
WBUFW(buf,30)=mob_get_clothes_color(md->class_);
- WBUFW(buf,32)|=md->dir&0x0f; // head direction
+ WBUFW(buf,32)|=md->ud.dir&0x0f; // head direction
WBUFL(buf,34)=0; // guild id
WBUFW(buf,38)=0; // emblem id
WBUFW(buf,40)=0; // manner
@@ -1140,7 +1141,7 @@ static int clif_mob0078(struct mob_data *md, unsigned char *buf)
WBUFB(buf,44)=0; // karma
WBUFB(buf,45)=mob_get_sex(md->class_);
WBUFPOS(buf,46,md->bl.x,md->bl.y);
- WBUFB(buf,48)|=md->dir&0x0f;
+ WBUFB(buf,48)|=md->ud.dir&0x0f;
WBUFB(buf,49)=5;
WBUFB(buf,50)=5;
WBUFB(buf,51)=0; // dead or sit state
@@ -1164,7 +1165,7 @@ static int clif_mob0078(struct mob_data *md, unsigned char *buf)
WBUFL(buf,38)=md->guardian_data->emblem_id;
} // End addition
WBUFPOS(buf,46,md->bl.x,md->bl.y);
- WBUFB(buf,48)|=md->dir&0x0f;
+ WBUFB(buf,48)|=md->ud.dir&0x0f;
WBUFB(buf,49)=5;
WBUFB(buf,50)=5;
WBUFW(buf,52)=clif_setlevel(level);
@@ -1204,7 +1205,7 @@ static int clif_mob007b(struct mob_data *md, unsigned char *buf) {
WBUFW(buf,30)=mob_get_head_mid(md->class_);
WBUFW(buf,32)=mob_get_hair_color(md->class_);
WBUFW(buf,34)=mob_get_clothes_color(md->class_);
- WBUFW(buf,36)=md->dir&0x0f; // head direction
+ WBUFW(buf,36)=md->ud.dir&0x0f; // head direction
if (md->guardian_data && md->guardian_data->guild_id) { // Added guardian emblems [Valaris]
WBUFL(buf,38)=md->guardian_data->guild_id;
WBUFL(buf,42)=md->guardian_data->emblem_id;
@@ -1212,7 +1213,7 @@ static int clif_mob007b(struct mob_data *md, unsigned char *buf) {
WBUFW(buf,46)=md->sc.opt3;
WBUFB(buf,48)=0; // karma
WBUFB(buf,49)=mob_get_sex(md->class_);
- WBUFPOS2(buf,50,md->bl.x,md->bl.y,md->to_x,md->to_y);
+ WBUFPOS2(buf,50,md->bl.x,md->bl.y,md->ud.to_x,md->ud.to_y);
WBUFB(buf,55)=0x88; // Deals with acceleration in directions. [Valaris]
WBUFB(buf,56)=5;
WBUFB(buf,57)=5;
@@ -1239,7 +1240,7 @@ static int clif_mob007b(struct mob_data *md, unsigned char *buf) {
WBUFW(buf,30)=mob_get_head_mid(md->class_);
WBUFW(buf,32)=mob_get_hair_color(md->class_);
WBUFW(buf,34)=mob_get_clothes_color(md->class_);
- WBUFW(buf,36)=md->dir&0x0f; // head direction
+ WBUFW(buf,36)=md->ud.dir&0x0f; // head direction
if (md->guardian_data && md->guardian_data->guild_id) { // Added guardian emblems [Valaris]
WBUFL(buf,38)=md->guardian_data->guild_id;
WBUFW(buf,42)=md->guardian_data->emblem_id;
@@ -1248,7 +1249,7 @@ static int clif_mob007b(struct mob_data *md, unsigned char *buf) {
WBUFW(buf,46)=md->sc.opt3;
WBUFB(buf,48)=0; // karma
WBUFB(buf,49)=mob_get_sex(md->class_);
- WBUFPOS2(buf,50,md->bl.x,md->bl.y,md->to_x,md->to_y);
+ WBUFPOS2(buf,50,md->bl.x,md->bl.y,md->ud.to_x,md->ud.to_y);
WBUFB(buf,55)=0x88; // Deals with acceleration in directions. [Valaris]
WBUFB(buf,56)=5;
WBUFB(buf,57)=5;
@@ -1272,7 +1273,7 @@ static int clif_mob007b(struct mob_data *md, unsigned char *buf) {
WBUFL(buf,38)=md->guardian_data->guild_id;
WBUFL(buf,42)=md->guardian_data->emblem_id;
} // End addition
- WBUFPOS2(buf,50,md->bl.x,md->bl.y,md->to_x,md->to_y);
+ WBUFPOS2(buf,50,md->bl.x,md->bl.y,md->ud.to_x,md->ud.to_y);
WBUFB(buf,55)=0x88; // Deals with acceleration in directions. [Valaris]
WBUFB(buf,56)=5;
WBUFB(buf,57)=5;
@@ -1319,7 +1320,7 @@ static int clif_npc0078(struct npc_data *nd, unsigned char *buf) {
WBUFW(buf,26)=mob_get_head_mid(nd->class_);
WBUFW(buf,28)=mob_get_hair_color(nd->class_);
WBUFW(buf,30)=mob_get_clothes_color(nd->class_);
- WBUFW(buf,32)|=nd->dir&0x0f; // head direction
+ WBUFW(buf,32)|=nd->ud.dir&0x0f; // head direction
if (g) {
WBUFL(buf,34)=g->guild_id;
WBUFL(buf,38)=g->emblem_id;
@@ -1328,7 +1329,7 @@ static int clif_npc0078(struct npc_data *nd, unsigned char *buf) {
WBUFB(buf,44)=0; // karma
WBUFB(buf,45)=mob_get_sex(nd->class_);
WBUFPOS(buf,46,nd->bl.x,nd->bl.y);
- WBUFB(buf,48)|=nd->dir&0x0f;
+ WBUFB(buf,48)|=nd->ud.dir&0x0f;
WBUFB(buf,49)=5;
WBUFB(buf,50)=5;
WBUFB(buf,51)=0; // dead or sit state
@@ -1354,7 +1355,7 @@ static int clif_npc0078(struct npc_data *nd, unsigned char *buf) {
WBUFW(buf,26)=mob_get_head_mid(nd->class_);
WBUFW(buf,28)=mob_get_hair_color(nd->class_);
WBUFW(buf,30)=mob_get_clothes_color(nd->class_);
- WBUFW(buf,32)|=nd->dir&0x0f; // head direction
+ WBUFW(buf,32)|=nd->ud.dir&0x0f; // head direction
WBUFL(buf,34)=0; // guild id
WBUFW(buf,38)=0; // emblem id
WBUFW(buf,40)=0; // manner
@@ -1362,7 +1363,7 @@ static int clif_npc0078(struct npc_data *nd, unsigned char *buf) {
WBUFB(buf,44)=0; // karma
WBUFB(buf,45)=mob_get_sex(nd->class_);
WBUFPOS(buf,46,nd->bl.x,nd->bl.y);
- WBUFB(buf,48)|=nd->dir&0x0f;
+ WBUFB(buf,48)|=nd->ud.dir&0x0f;
WBUFB(buf,49)=5;
WBUFB(buf,50)=5;
WBUFB(buf,51)=0; // dead or sit state
@@ -1383,7 +1384,7 @@ static int clif_npc0078(struct npc_data *nd, unsigned char *buf) {
// WBUFL(buf,38)=g->guild_id;
}
WBUFPOS(buf,46,nd->bl.x,nd->bl.y);
- WBUFB(buf,48)|=nd->dir&0x0f;
+ WBUFB(buf,48)|=nd->ud.dir&0x0f;
WBUFB(buf,49)=5;
WBUFB(buf,50)=5;
@@ -1424,7 +1425,7 @@ static int clif_npc007b(struct npc_data *nd, unsigned char *buf) {
WBUFW(buf,30)=mob_get_head_mid(nd->class_);
WBUFW(buf,32)=mob_get_hair_color(nd->class_);
WBUFW(buf,34)=mob_get_clothes_color(nd->class_);
- WBUFW(buf,36)=nd->dir&0x0f; // head direction
+ WBUFW(buf,36)=nd->ud.dir&0x0f; // head direction
if (g) {
WBUFL(buf,38)=g->guild_id;
WBUFL(buf,42)=g->emblem_id;
@@ -1432,7 +1433,7 @@ static int clif_npc007b(struct npc_data *nd, unsigned char *buf) {
WBUFW(buf,46)=nd->sc.opt3;
WBUFB(buf,48)=0; // karma
WBUFB(buf,49)=mob_get_sex(nd->class_);
- WBUFPOS2(buf,50,nd->bl.x,nd->bl.y,nd->to_x,nd->to_y);
+ WBUFPOS2(buf,50,nd->bl.x,nd->bl.y,nd->ud.to_x,nd->ud.to_y);
WBUFB(buf,55)=0x88; // Deals with acceleration in directions. [Valaris]
WBUFB(buf,56)=5;
WBUFB(buf,57)=5;
@@ -1459,7 +1460,7 @@ static int clif_npc007b(struct npc_data *nd, unsigned char *buf) {
WBUFW(buf,30)=mob_get_head_mid(nd->class_);
WBUFW(buf,32)=mob_get_hair_color(nd->class_);
WBUFW(buf,34)=mob_get_clothes_color(nd->class_);
- WBUFW(buf,36)=nd->dir&0x0f; // head direction
+ WBUFW(buf,36)=nd->ud.dir&0x0f; // head direction
if (g) {
WBUFL(buf,38)=g->guild_id;
WBUFW(buf,42)=g->emblem_id;
@@ -1468,7 +1469,7 @@ static int clif_npc007b(struct npc_data *nd, unsigned char *buf) {
WBUFW(buf,46)=nd->sc.opt3;
WBUFB(buf,48)=0; // karma
WBUFB(buf,49)=mob_get_sex(nd->class_);
- WBUFPOS2(buf,50,nd->bl.x,nd->bl.y,nd->to_x,nd->to_y);
+ WBUFPOS2(buf,50,nd->bl.x,nd->bl.y,nd->ud.to_x,nd->ud.to_y);
WBUFB(buf,55)=0x88; // Deals with acceleration in directions. [Valaris]
WBUFB(buf,56)=5;
WBUFB(buf,57)=5;
@@ -1490,7 +1491,7 @@ static int clif_npc007b(struct npc_data *nd, unsigned char *buf) {
// WBUFL(buf,42)=g->guild_id;
}
WBUFL(buf,22)=gettick();
- WBUFPOS2(buf,50,nd->bl.x,nd->bl.y,nd->to_x,nd->to_y);
+ WBUFPOS2(buf,50,nd->bl.x,nd->bl.y,nd->ud.to_x,nd->ud.to_y);
WBUFB(buf,55)=0x88; // Deals with acceleration in directions. [Valaris]
WBUFB(buf,56)=5;
WBUFB(buf,57)=5;
@@ -1528,14 +1529,14 @@ static int clif_pet0078(struct pet_data *pd, unsigned char *buf) {
WBUFW(buf,26)=mob_get_head_mid(pd->class_);
WBUFW(buf,28)=mob_get_hair_color(pd->class_);
WBUFW(buf,30)=mob_get_clothes_color(pd->class_);
- WBUFW(buf,32)|=pd->dir&0x0f; // head direction
+ WBUFW(buf,32)|=pd->ud.dir&0x0f; // head direction
WBUFL(buf,34)=0; //Guild id
WBUFL(buf,38)=0; //Guild emblem
WBUFW(buf,42)=0; //opt3;
WBUFB(buf,44)=0; // karma
WBUFB(buf,45)=mob_get_sex(pd->class_);
WBUFPOS(buf,46,pd->bl.x,pd->bl.y);
- WBUFB(buf,48)|=pd->dir&0x0f;
+ WBUFB(buf,48)|=pd->ud.dir&0x0f;
WBUFB(buf,49)=5;
WBUFB(buf,50)=5;
WBUFB(buf,51)=0; // dead or sit state
@@ -1561,7 +1562,7 @@ static int clif_pet0078(struct pet_data *pd, unsigned char *buf) {
WBUFW(buf,26)=mob_get_head_mid(pd->class_);
WBUFW(buf,28)=mob_get_hair_color(pd->class_);
WBUFW(buf,30)=mob_get_clothes_color(pd->class_);
- WBUFW(buf,32)|=pd->dir&0x0f; // head direction
+ WBUFW(buf,32)|=pd->ud.dir&0x0f; // head direction
WBUFL(buf,34)=0; // guild id
WBUFW(buf,38)=0; // emblem id
WBUFW(buf,40)=0; // manner
@@ -1569,7 +1570,7 @@ static int clif_pet0078(struct pet_data *pd, unsigned char *buf) {
WBUFB(buf,44)=0; // karma
WBUFB(buf,45)=mob_get_sex(pd->class_);
WBUFPOS(buf,46,pd->bl.x,pd->bl.y);
- WBUFB(buf,48)|=pd->dir&0x0f;
+ WBUFB(buf,48)|=pd->ud.dir&0x0f;
WBUFB(buf,49)=5;
WBUFB(buf,50)=5;
WBUFB(buf,51)=0; // dead or sit state
@@ -1590,7 +1591,7 @@ static int clif_pet0078(struct pet_data *pd, unsigned char *buf) {
else
WBUFW(buf,20)=pd->equip;
WBUFPOS(buf,46,pd->bl.x,pd->bl.y);
- WBUFB(buf,48)|=pd->dir&0x0f;
+ WBUFB(buf,48)|=pd->ud.dir&0x0f;
WBUFB(buf,49)=0;
WBUFB(buf,50)=0;
WBUFW(buf,52)=clif_setlevel(level);
@@ -1630,13 +1631,13 @@ static int clif_pet007b(struct pet_data *pd, unsigned char *buf) {
WBUFW(buf,30)=mob_get_head_mid(pd->class_);
WBUFW(buf,32)=mob_get_hair_color(pd->class_);
WBUFW(buf,34)=mob_get_clothes_color(pd->class_);
- WBUFW(buf,36)=pd->dir&0x0f; // head direction
+ WBUFW(buf,36)=pd->ud.dir&0x0f; // head direction
WBUFL(buf,38)=0; // guild id
WBUFL(buf,42)=0; // emblem id
WBUFW(buf,46)=0; // opt3;
WBUFB(buf,48)=0; // karma
WBUFB(buf,49)=mob_get_sex(pd->class_);
- WBUFPOS2(buf,50,pd->bl.x,pd->bl.y,pd->to_x,pd->to_y);
+ WBUFPOS2(buf,50,pd->bl.x,pd->bl.y,pd->ud.to_x,pd->ud.to_y);
WBUFB(buf,55)=0x88; // Deals with acceleration in directions. [Valaris]
WBUFB(buf,56)=0; //0? These are always five for mobs and pets, /hmm [Skotlex]
WBUFB(buf,57)=0;
@@ -1663,14 +1664,14 @@ static int clif_pet007b(struct pet_data *pd, unsigned char *buf) {
WBUFW(buf,30)=mob_get_head_mid(pd->class_);
WBUFW(buf,32)=mob_get_hair_color(pd->class_);
WBUFW(buf,34)=mob_get_clothes_color(pd->class_);
- WBUFW(buf,36)=pd->dir&0x0f; // head direction
+ WBUFW(buf,36)=pd->ud.dir&0x0f; // head direction
WBUFL(buf,38)=0; // guild id
WBUFW(buf,42)=0; // emblem id
WBUFW(buf,44)=0; // manner
WBUFW(buf,46)=0; // opt3
WBUFB(buf,48)=0; // karma
WBUFB(buf,49)=mob_get_sex(pd->class_);
- WBUFPOS2(buf,50,pd->bl.x,pd->bl.y,pd->to_x,pd->to_y);
+ WBUFPOS2(buf,50,pd->bl.x,pd->bl.y,pd->ud.to_x,pd->ud.to_y);
WBUFB(buf,55)=0x88; // Deals with acceleration in directions. [Valaris]
WBUFB(buf,56)=0;
WBUFB(buf,57)=0;
@@ -1692,7 +1693,7 @@ static int clif_pet007b(struct pet_data *pd, unsigned char *buf) {
else
WBUFW(buf,20)=pd->equip;
WBUFL(buf,22)=gettick();
- WBUFPOS2(buf,50,pd->bl.x,pd->bl.y,pd->to_x,pd->to_y);
+ WBUFPOS2(buf,50,pd->bl.x,pd->bl.y,pd->ud.to_x,pd->ud.to_y);
WBUFB(buf,55)=0x88; // Deals with acceleration in directions. [Valaris]
WBUFB(buf,56)=0;
WBUFB(buf,57)=0;
@@ -2065,7 +2066,7 @@ int clif_walkok(struct map_session_data *sd)
WFIFOHEAD(fd, packet_len_table[0x87]);
WFIFOW(fd,0)=0x87;
WFIFOL(fd,2)=gettick();
- WFIFOPOS2(fd,6,sd->bl.x,sd->bl.y,sd->to_x,sd->to_y);
+ WFIFOPOS2(fd,6,sd->bl.x,sd->bl.y,sd->ud.to_x,sd->ud.to_y);
WFIFOB(fd,11)=0x88;
WFIFOSET(fd,packet_len_table[0x87]);
@@ -2099,7 +2100,7 @@ int clif_movechar(struct map_session_data *sd) {
WBUFW(buf,12)=OPTION_INVISIBLE;
WBUFW(buf,14)=100;
WBUFL(buf,22)=gettick();
- WBUFPOS2(buf,50,sd->bl.x,sd->bl.y,sd->to_x,sd->to_y);
+ WBUFPOS2(buf,50,sd->bl.x,sd->bl.y,sd->ud.to_x,sd->ud.to_y);
WBUFB(buf,56)=5;
WBUFB(buf,57)=5;
clif_send(buf, len, &sd->bl, SELF);
@@ -3404,11 +3405,10 @@ int clif_arrowequip(struct map_session_data *sd,int val)
nullpo_retr(0, sd);
- if(sd->attacktarget && sd->attacktarget > 0) // [Valaris]
- sd->attacktarget = 0;
+ pc_stop_attack(sd); // [Valaris]
fd=sd->fd;
- WFIFOHEAD(fd, packet_len_table[0x013c]);
+ WFIFOHEAD(fd, packet_len_table[0x013c]);
WFIFOW(fd,0)=0x013c;
WFIFOW(fd,2)=val+2;//–î‚̃AƒCƒeƒ€ID
@@ -4172,7 +4172,7 @@ void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* ds
nullpo_retv(sd);
nullpo_retv(dstsd);
- if(dstsd->walktimer != -1){
+ if(dstsd->ud.walktimer != -1){
#if PACKETVER < 4
WFIFOHEAD(sd->fd, packet_len_table[0x7b]);
#else
@@ -4252,7 +4252,7 @@ void clif_getareachar_npc(struct map_session_data* sd,struct npc_data* nd)
nullpo_retv(nd);
if(nd->class_ < 0 || nd->flag&1 || nd->class_ == INVISIBLE_CLASS)
return;
- if(nd->state.state == MS_WALK){
+ if(nd->ud.walktimer != -1){
WFIFOHEAD(sd->fd, packet_len_table[0x7b]);
len = clif_npc007b(nd,WFIFOP(sd->fd,0));
WFIFOSET(sd->fd,len);
@@ -4305,7 +4305,7 @@ int clif_fixmobpos(struct mob_data *md)
nullpo_retr(0, md);
- if(md->state.state == MS_WALK){
+ if(md->ud.walktimer != -1){
len = clif_mob007b(md,buf);
clif_send(buf,len,&md->bl,AREA);
} else {
@@ -4327,7 +4327,7 @@ int clif_fixpcpos(struct map_session_data *sd)
nullpo_retr(0, sd);
- if(sd->walktimer != -1){
+ if(sd->ud.walktimer != -1){
len = clif_set007b(sd,buf);
clif_send(buf,len,&sd->bl,AREA);
} else {
@@ -4349,7 +4349,7 @@ int clif_fixpetpos(struct pet_data *pd)
nullpo_retr(0, pd);
- if(pd->state.state == MS_WALK){
+ if(pd->ud.walktimer != -1){
len = clif_pet007b(pd,buf);
clif_send(buf,len,&pd->bl,AREA);
} else {
@@ -4368,7 +4368,7 @@ int clif_fixnpcpos(struct npc_data *nd)
nullpo_retr(0, nd);
- if(nd->state.state == MS_WALK){
+ if(nd->ud.walktimer != -1){
len = clif_npc007b(nd,buf);
clif_send(buf,len,&nd->bl,AREA);
} else {
@@ -4460,7 +4460,7 @@ int clif_damage(struct block_list *src,struct block_list *dst,unsigned int tick,
}
//Because the damage delay must be synced with the client, here is where the can-walk tick must be updated. [Skotlex]
if (type != 4 && type != 9 && damage+damage2 > 0) //Non-endure/Non-flinch attack, update walk delay.
- battle_walkdelay(dst, tick, sdelay, ddelay, div);
+ unit_walkdelay(dst, tick, sdelay, ddelay, div);
// [Valaris]
if(battle_config.save_clothcolor && src->type==BL_MOB &&
@@ -4483,7 +4483,7 @@ void clif_getareachar_mob(struct map_session_data* sd,struct mob_data* md)
if (session[sd->fd] == NULL)
return;
- if(md->state.state == MS_WALK){
+ if(md->ud.walktimer != -1){
#if PACKETVER < 4
WFIFOHEAD(sd->fd,packet_len_table[0x78]);
#else
@@ -4526,7 +4526,7 @@ void clif_getareachar_pet(struct map_session_data* sd,struct pet_data* pd)
nullpo_retv(sd);
nullpo_retv(pd);
- if(pd->state.state == MS_WALK){
+ if(pd->ud.walktimer != -1){
#if PACKETVER < 4
WFIFOHEAD(sd->fd,packet_len_table[0x7b]);
#else
@@ -5099,8 +5099,7 @@ int clif_skill_fail(struct map_session_data *sd,int skill_id,int type,int btype)
fd=sd->fd;
// reset all variables [celest]
- sd->skillx = sd->skilly = -1;
- sd->skillid = sd->skilllv = -1;
+ // Should be handled now by the unit_* code.
sd->skillitem = sd->skillitemlv = -1;
if(type==0x4 && !sd->state.showdelay)
@@ -5181,7 +5180,7 @@ int clif_skill_damage(struct block_list *src,struct block_list *dst,
//Because the damage delay must be synced with the client, here is where the can-walk tick must be updated. [Skotlex]
if (type != 4 && type != 9 && damage > 0) //Non-endure/Non-flinch attack, update walk delay.
- battle_walkdelay(dst, tick, sdelay, ddelay, div);
+ unit_walkdelay(dst, tick, sdelay, ddelay, div);
return 0;
}
@@ -5223,7 +5222,7 @@ int clif_skill_damage2(struct block_list *src,struct block_list *dst,
//Because the damage delay must be synced with the client, here is where the can-walk tick must be updated. [Skotlex]
if (type != 4 && type != 9 && damage > 0) //Non-endure/Non-flinch attack, update walk delay.
- battle_walkdelay(dst, tick, sdelay, ddelay, div);
+ unit_walkdelay(dst, tick, sdelay, ddelay, div);
return 0;
}
@@ -5990,7 +5989,7 @@ int clif_item_repair_list(struct map_session_data *sd,struct map_session_data *d
sd->menuskill_id = BS_REPAIRWEAPON;
sd->menuskill_lv = dstsd->bl.id;
}else
- clif_skill_fail(sd,sd->skillid,0,0);
+ clif_skill_fail(sd,sd->ud.skillid,0,0);
return 0;
}
@@ -8924,20 +8923,10 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd) {
return;
}
- // Redundancy, used in pc_can_move already
- //if (pc_issit(sd)) //No walking when you are sit!
- // return;
-
if (clif_cant_act(sd))
return;
- if (sd->skilltimer != -1 && pc_checkskill(sd, SA_FREECAST) <= 0) // ƒtƒŠ[ƒLƒƒƒXƒg
- return;
-
- if (!pc_can_move(sd))
- return;
-
- if(sd->state.blockedmove)
+ if (!unit_can_move(&sd->bl))
return;
if(sd->sc.count && sd->sc.data[SC_RUN].timer != -1)
@@ -8946,7 +8935,7 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd) {
if (sd->invincible_timer != -1)
pc_delinvincibletimer(sd);
- pc_stopattack(sd);
+ pc_stop_attack(sd);
cmd = RFIFOW(fd,0);
x = RFIFOB(fd,packet_db[sd->packet_ver][cmd].pos[0]) * 4 +
@@ -8956,7 +8945,7 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd) {
//Set last idle time... [Skotlex]
sd->idletime = last_tick;
- pc_walktoxy(sd, x, y);
+ unit_walktoxy(&sd->bl, x, y, 0);
}
@@ -9251,14 +9240,14 @@ void clif_changed_dir(struct block_list *bl) {
WBUFL(buf,2) = bl->id;
if (sd)
WBUFW(buf,6) = sd->head_dir;
- WBUFB(buf,8) = status_get_dir(bl);
+ WBUFB(buf,8) = unit_getdir(bl);
clif_send(buf, packet_len_table[0x9c], bl, AREA_WOS);
if(sd && sd->disguise) {
WBUFL(buf,2) = -bl->id;
WBUFW(buf,6) = 0;
- WBUFB(buf,8) = status_get_dir(bl);
+ WBUFB(buf,8) = unit_getdir(bl);
clif_send(buf, packet_len_table[0x9c], bl, AREA);
}
@@ -9347,8 +9336,8 @@ void clif_parse_ActionRequest(int fd, struct map_session_data *sd) {
tick = gettick();
- pc_stop_walking(sd, 0);
- pc_stopattack(sd);
+ pc_stop_walking(sd, 1);
+ pc_stop_attack(sd);
target_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
action_type = RFIFOB(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[1]);
@@ -9364,26 +9353,24 @@ void clif_parse_ActionRequest(int fd, struct map_session_data *sd) {
if(sd->view_class==JOB_WEDDING || sd->view_class==JOB_XMAS)
return;
if (!battle_config.sdelay_attack_enable && pc_checkskill(sd, SA_FREECAST) <= 0) {
- if (DIFF_TICK(tick, sd->canact_tick) < 0) {
+ if (DIFF_TICK(tick, sd->ud.canact_tick) < 0) {
clif_skill_fail(sd, 1, 4, 0);
return;
}
}
if (sd->invincible_timer != -1)
pc_delinvincibletimer(sd);
- pc_attack(sd, target_id, action_type != 0);
+ unit_attack(&sd->bl, target_id, action_type != 0);
break;
case 0x02: // sitdown
if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, NV_BASIC) >= 3) {
- if (sd->skilltimer != -1) //No sitting while casting :P
+ if (sd->ud.skilltimer != -1) //No sitting while casting :P
break;
if (sd->sc.count && (
sd->sc.data[SC_DANCING].timer != -1 ||
(sd->sc.data[SC_GRAVITATION].timer != -1 && sd->sc.data[SC_GRAVITATION].val3 == BCT_SELF)
)) //No sitting during these states neither.
break;
- pc_stopattack(sd);
- pc_stop_walking(sd, 1);
pc_setsit(sd);
skill_gangsterparadise(sd, 1); // ƒMƒƒƒ“ƒOƒXƒ^[ƒpƒ‰ƒ_ƒCƒXÝ’è fixed Valaris
skill_rest(sd, 1); // TK_HPTIME sitting down mode [Dralnu]
@@ -9999,7 +9986,7 @@ void clif_parse_TradeCommit(int fd,struct map_session_data *sd)
*/
void clif_parse_StopAttack(int fd,struct map_session_data *sd)
{
- pc_stopattack(sd);
+ pc_stop_attack(sd);
}
/*==========================================
@@ -10096,10 +10083,10 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) {
skill_get_inf(skillnum)&INF_SELF_SKILL)
target_id = sd->bl.id; //What good is it to mess up the target in self skills? Wished I knew... [Skotlex]
- if (sd->skilltimer != -1) {
+ if (sd->ud.skilltimer != -1) {
if (skillnum != SA_CASTCANCEL)
return;
- } else if (DIFF_TICK(tick, sd->canact_tick) < 0 &&
+ } else if (DIFF_TICK(tick, sd->ud.canact_tick) < 0 &&
// allow monk combos to ignore this delay [celest]
!(sd->sc.count && sd->sc.data[SC_COMBO].timer!=-1 &&
(skillnum == MO_EXTREMITYFIST ||
@@ -10124,7 +10111,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) {
if (sd->skillitem >= 0 && sd->skillitem == skillnum) {
if (skilllv != sd->skillitemlv)
skilllv = sd->skillitemlv;
- skill_use_id(sd, target_id, skillnum, skilllv);
+ unit_skilluse_id(&sd->bl, target_id, skillnum, skilllv);
} else {
sd->skillitem = sd->skillitemlv = -1;
if (skillnum == MO_EXTREMITYFIST) {
@@ -10156,10 +10143,13 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) {
}
}
+ if (skillnum >= GD_SKILLBASE && sd->state.gmaster_flag)
+ skilllv = guild_checkskill(sd->state.gmaster_flag, skillnum);
+
if ((lv = pc_checkskill(sd, skillnum)) > 0) {
if (skilllv > lv)
skilllv = lv;
- skill_use_id(sd, target_id, skillnum, skilllv);
+ unit_skilluse_id(&sd->bl, target_id, skillnum, skilllv);
if (sd->state.skill_flag)
sd->state.skill_flag = 0;
}
@@ -10191,9 +10181,9 @@ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, int skilll
talkie_mes[MESSAGE_SIZE-1] = '\0'; //Overflow protection [Skotlex]
}
- if (sd->skilltimer != -1)
+ if (sd->ud.skilltimer != -1)
return;
- else if (DIFF_TICK(tick, sd->canact_tick) < 0)
+ if (DIFF_TICK(tick, sd->ud.canact_tick) < 0)
{
clif_skill_fail(sd, skillnum, 4, 0);
return;
@@ -10207,13 +10197,13 @@ void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, int skilll
if (sd->skillitem >= 0 && sd->skillitem == skillnum) {
if (skilllv != sd->skillitemlv)
skilllv = sd->skillitemlv;
- skill_use_pos(sd, x, y, skillnum, skilllv);
+ unit_skilluse_pos(&sd->bl, x, y, skillnum, skilllv);
} else {
sd->skillitem = sd->skillitemlv = -1;
if ((lv = pc_checkskill(sd, skillnum)) > 0) {
if (skilllv > lv)
skilllv = lv;
- skill_use_pos(sd, x, y, skillnum,skilllv);
+ unit_skilluse_pos(&sd->bl, x, y, skillnum,skilllv);
}
}
}
@@ -10293,7 +10283,7 @@ void clif_parse_ProduceMix(int fd,struct map_session_data *sd)
if (clif_trading(sd)) {
//Make it fail to avoid shop exploits where you sell something different than you see.
- clif_skill_fail(sd,sd->skillid,0,0);
+ clif_skill_fail(sd,sd->ud.skillid,0,0);
sd->menuskill_lv = sd->menuskill_id = 0;
return;
}
@@ -10312,7 +10302,7 @@ void clif_parse_RepairItem(int fd, struct map_session_data *sd)
return;
if (clif_trading(sd)) {
//Make it fail to avoid shop exploits where you sell something different than you see.
- clif_skill_fail(sd,sd->skillid,0,0);
+ clif_skill_fail(sd,sd->ud.skillid,0,0);
sd->menuskill_lv = sd->menuskill_id = 0;
return;
}
@@ -10332,7 +10322,7 @@ void clif_parse_WeaponRefine(int fd, struct map_session_data *sd) {
return;
if (clif_trading(sd)) {
//Make it fail to avoid shop exploits where you sell something different than you see.
- clif_skill_fail(sd,sd->skillid,0,0);
+ clif_skill_fail(sd,sd->ud.skillid,0,0);
sd->menuskill_lv = sd->menuskill_id = 0;
return;
}
@@ -10433,7 +10423,7 @@ void clif_parse_SelectArrow(int fd,struct map_session_data *sd)
return;
if (clif_trading(sd)) {
//Make it fail to avoid shop exploits where you sell something different than you see.
- clif_skill_fail(sd,sd->skillid,0,0);
+ clif_skill_fail(sd,sd->ud.skillid,0,0);
sd->menuskill_lv = sd->menuskill_id = 0;
return;
}
@@ -11852,8 +11842,8 @@ int clif_parse(int fd) {
// ŠÇ——pƒpƒPƒbƒgˆ—
if (cmd >= 30000) {
switch(cmd) {
- case 0x7530: { // Athenaî•ñŠ“¾
- WFIFOHEAD(fd, 10);
+ case 0x7530: { //Why are we letting people know which version we are running?
+ WFIFOHEAD(fd, 10);
WFIFOW(fd,0) = 0x7531;
WFIFOB(fd,2) = ATHENA_MAJOR_VERSION;
WFIFOB(fd,3) = ATHENA_MINOR_VERSION;
@@ -11865,13 +11855,16 @@ int clif_parse(int fd) {
WFIFOSET(fd,10);
RFIFOSKIP(fd,2);
break;
- }
+ }
case 0x7532: // Ú‘±‚ÌØ’f
ShowWarning("clif_parse: session #%d disconnected for sending packet 0x04%x\n", fd, cmd);
session[fd]->eof=1;
break;
+ default:
+ ShowWarning("Unknown incoming packet (command: 0x%04x, session: %d), disconnecting.\n", cmd, fd);
+ session[fd]->eof=1;
+ break;
}
- ShowWarning("Ignoring incoming packet (command: 0x%04x, session: %d)\n", cmd, fd);
return 0;
}
@@ -12254,6 +12247,7 @@ static int packetdb_readdb(void)
// if(packet_db[clif_config.packet_db_ver][cmd].len > 2 /* && packet_db[cmd].pos[0] == 0 */)
// printf("packet_db ver %d: %d 0x%x %d %s %p\n",packet_ver,ln,cmd,packet_db[packet_ver][cmd].len,str[2],packet_db[packet_ver][cmd].func);
}
+ fclose(fp);
if (!clif_config.connect_cmd[clif_config.packet_db_ver])
{ //Locate the nearest version that we still support. [Skotlex]
for(j = clif_config.packet_db_ver; j >= 0 && !clif_config.connect_cmd[j]; j--);
diff --git a/src/map/log.c b/src/map/log.c
index 0fa09d9f0..e03d5f55e 100644
--- a/src/map/log.c
+++ b/src/map/log.c
@@ -116,7 +116,7 @@ int log_pick(struct map_session_data *sd, char *type, int mob_id, int nameid, in
if(mob_id) {
struct mob_data *md = (struct mob_data*)sd;
obj_id = mob_id;
- mapname = map[md->m].name;
+ mapname = map[md->bl.m].name;
} else {
obj_id = sd->char_id;
mapname = (char*)mapindex_id2name(sd->mapindex);
diff --git a/src/map/map.c b/src/map/map.c
index c06f7ef1b..f218572b3 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -36,6 +36,7 @@
#include "skill.h"
#include "trade.h"
#include "party.h"
+#include "unit.h"
#include "battle.h"
#include "script.h"
#include "guild.h"
@@ -1501,191 +1502,70 @@ void map_deliddb(struct block_list *bl) {
* quit?—‚ÌŽå?‚ªˆá‚¤‚悤‚È?‚à‚µ‚Ä‚«‚½
*------------------------------------------
*/
-int map_quit(struct map_session_data *sd) {
-
- //nullpo_retr(0, sd); //Utterly innecessary, all invokations to this function already have an SD non-null check.
- //Learn to use proper coding and stop relying on nullpo_'s for safety :P [Skotlex]
-
-
- if(!sd->state.waitingdisconnect) {
- if (sd->npc_timer_id != -1) //Cancel the event timer.
- npc_timerevent_quit(sd);
- if (sd->state.event_disconnect) {
- if (script_config.event_script_type == 0) {
- struct npc_data *npc;
- if ((npc = npc_name2id(script_config.logout_event_name))) {
- run_script(npc->u.scr.script,0,sd->bl.id,npc->bl.id); // PCLogoutNPC
- ShowStatus("Event '"CL_WHITE"%s"CL_RESET"' executed.\n", script_config.logout_event_name);
- }
- } else {
- ShowStatus("%d '"CL_WHITE"%s"CL_RESET"' events executed.\n",
- npc_event_doall_id(script_config.logout_event_name, sd->bl.id), script_config.logout_event_name);
- }
- }
-
- if(sd->chatID) // ƒ`ƒƒƒbƒg‚©‚ço‚é
- chat_leavechat(sd);
-
- if(sd->trade_partner) // Žæˆø‚ð’†?‚·‚é
- trade_tradecancel(sd);
-
- if(sd->party_invite>0) // ƒp?ƒeƒB?—U‚ð‹‘”Û‚·‚é
- party_reply_invite(sd,sd->party_invite_account,0);
-
- if(sd->guild_invite>0) // ƒMƒ‹ƒh?—U‚ð‹‘”Û‚·‚é
- guild_reply_invite(sd,sd->guild_invite,0);
- if(sd->guild_alliance>0) // ƒMƒ‹ƒh“¯–¿?—U‚ð‹‘”Û‚·‚é
- guild_reply_reqalliance(sd,sd->guild_alliance_account,0);
-
- // Force exiting from duel and rejecting
- // all duel invitations when player quit [LuzZza]
- if(sd->duel_group > 0)
- duel_leave(sd->duel_group, sd);
-
- if(sd->duel_invite > 0)
- duel_reject(sd->duel_invite, sd);
-
- party_send_logout(sd); // ƒp?ƒeƒB‚̃ƒOƒAƒEƒgƒƒbƒZ?ƒW‘—M
-
- party_send_dot_remove(sd);//minimap dot fix [Kevin]
-
- guild_send_memberinfoshort(sd,0); // ƒMƒ‹ƒh‚̃ƒOƒAƒEƒgƒƒbƒZ?ƒW‘—M
-
- guild_send_dot_remove(sd);
-
- pc_cleareventtimer(sd); // ƒCƒxƒ“ƒgƒ^ƒCƒ}‚ð”jŠü‚·‚é
-
- // check if we've been authenticated [celest]
- if (sd->state.auth)
- skill_castcancel(&sd->bl,0); // ‰r¥‚ð’†?‚·‚é
-
- skill_stop_dancing(&sd->bl);// ƒ_ƒ“ƒX/‰‰‘t’†?
-
- //Status that are not saved...
- if(sd->sc.count) {
- if(sd->sc.data[SC_HIDING].timer!=-1)
- status_change_end(&sd->bl,SC_HIDING,-1);
- if(sd->sc.data[SC_CLOAKING].timer!=-1)
- status_change_end(&sd->bl,SC_CLOAKING,-1);
- if(sd->sc.data[SC_RUN].timer!=-1)
- status_change_end(&sd->bl,SC_RUN,-1);
- if(sd->sc.data[SC_SPURT].timer!=-1)
- status_change_end(&sd->bl,SC_SPURT,-1);
- if(sd->sc.data[SC_BERSERK].timer!=-1)
- status_change_end(&sd->bl,SC_BERSERK,-1);
- if(sd->sc.data[SC_TRICKDEAD].timer!=-1)
- status_change_end(&sd->bl,SC_TRICKDEAD,-1);
- if (battle_config.debuff_on_logout) {
- if(sd->sc.data[SC_STRIPWEAPON].timer!=-1)
- status_change_end(&sd->bl,SC_STRIPWEAPON,-1);
- if(sd->sc.data[SC_STRIPARMOR].timer!=-1)
- status_change_end(&sd->bl,SC_STRIPARMOR,-1);
- if(sd->sc.data[SC_STRIPSHIELD].timer!=-1)
- status_change_end(&sd->bl,SC_STRIPSHIELD,-1);
- if(sd->sc.data[SC_STRIPHELM].timer!=-1)
- status_change_end(&sd->bl,SC_STRIPHELM,-1);
- if(sd->sc.data[SC_EXTREMITYFIST].timer!=-1)
- status_change_end(&sd->bl,SC_EXTREMITYFIST,-1);
- if(sd->sc.data[SC_EXPLOSIONSPIRITS].timer!=-1)
- status_change_end(&sd->bl,SC_EXPLOSIONSPIRITS,-1);
- }
- }
- skill_clear_unitgroup(&sd->bl); // ƒXƒLƒ‹ƒ†ƒjƒbƒgƒOƒ‹?ƒv‚Ìíœ
-
- // check if we've been authenticated [celest]
- if (sd->state.auth) {
- skill_cleartimerskill(&sd->bl);
- pc_stop_walking(sd,0);
- pc_stopattack(sd);
- pc_stop_following(sd);
- pc_delinvincibletimer(sd);
- }
- pc_delspiritball(sd,sd->spiritball,1);
- skill_gangsterparadise(sd,0);
- skill_unit_move(&sd->bl,gettick(),4);
-
- if (sd->state.auth)
- status_calc_pc(sd,4);
- // skill_clear_unitgroup(&sd->bl); // [Sara-chan]
-
- if (!(sd->sc.option & OPTION_INVISIBLE))
- clif_clearchar_area(&sd->bl,2);
-
- chrif_save_scdata(sd); //Save status changes, then clear'em out from memory. [Skotlex]
- status_change_clear(&sd->bl,1);
-
- if(sd->status.pet_id && sd->pd) {
- pet_lootitem_drop(sd->pd,sd);
- pet_remove_map(sd);
- if(sd->pet.intimate <= 0) {
- intif_delete_petdata(sd->status.pet_id);
- sd->status.pet_id = 0;
- sd->pd = NULL;
- sd->petDB = NULL;
- }
- else
- intif_save_petdata(sd->status.account_id,&sd->pet);
- }
-
- if(pc_isdead(sd))
- pc_setrestartvalue(sd,2);
-
- pc_clean_skilltree(sd);
-
- //The storage closing routines will save the char if needed. [Skotlex]
- if (!sd->state.storage_flag)
- chrif_save(sd,1);
- else if (sd->state.storage_flag == 1)
- storage_storage_quit(sd,1);
- else if (sd->state.storage_flag == 2)
- storage_guild_storage_quit(sd,1);
-
- map_delblock(&sd->bl);
- } else { //Try to free some data, without saving anything (this could be invoked on map server change. [Skotlex]
- if (sd->bl.prev != NULL)
- { //Remove from map...
- if (!(sd->sc.option & OPTION_INVISIBLE))
- clif_clearchar_area(&sd->bl,2);
- map_delblock(&sd->bl);
- }
- if (sd->pd)
- pet_remove_map(sd);
- }
-
- if (sd->stack) {
- script_free_stack(sd->stack);
- sd->stack= NULL;
- }
-
-// chrif_char_offline(sd); //chrif_save handles this now.
-
- //Do we really need to remove the name?
- idb_remove(charid_db,sd->status.char_id);
- idb_remove(id_db,sd->bl.id);
- idb_remove(pc_db,sd->bl.id);
-
- // Notify friends that this char logged out. [Skotlex]
- clif_foreachclient(clif_friendslist_toggle_sub, sd->status.account_id, sd->status.char_id, 0);
-
- if(sd->reg)
- { //Double logout already freed pointer fix... [Skotlex]
- aFree(sd->reg);
- sd->reg = NULL;
- sd->reg_num = 0;
- }
-
- if(sd->regstr)
- {
- aFree(sd->regstr);
- sd->regstr = NULL;
- sd->regstr_num = 0;
- }
-
- if(!sd->fd) //There is no session connected, and as such socket.c won't free the data, we must do it. [Skotlex]
- aFree(sd);
- return 0;
-}
-
+int map_quit(struct map_session_data *sd) {
+
+ //nullpo_retr(0, sd); //Utterly innecessary, all invokations to this function already have an SD non-null check.
+ //Learn to use proper coding and stop relying on nullpo_'s for safety :P [Skotlex]
+
+ if(!sd->state.waitingdisconnect) {
+ if (sd->npc_timer_id != -1) //Cancel the event timer.
+ npc_timerevent_quit(sd);
+ if (sd->state.event_disconnect) {
+ if (script_config.event_script_type == 0) {
+ struct npc_data *npc;
+ if ((npc = npc_name2id(script_config.logout_event_name))) {
+ run_script(npc->u.scr.script,0,sd->bl.id,npc->bl.id); // PCLogoutNPC
+ ShowStatus("Event '"CL_WHITE"%s"CL_RESET"' executed.\n", script_config.logout_event_name);
+ }
+ } else {
+ ShowStatus("%d '"CL_WHITE"%s"CL_RESET"' events executed.\n",
+ npc_event_doall_id(script_config.logout_event_name, sd->bl.id), script_config.logout_event_name);
+ }
+ }
+ if (sd->pd) unit_free(&sd->pd->bl);
+ unit_free(&sd->bl);
+ pc_clean_skilltree(sd);
+ status_calc_pc(sd,4);
+ if(sd->pet.intimate > 0)
+ intif_save_petdata(sd->status.account_id,&sd->pet);
+ chrif_save(sd,1);
+ } else { //Try to free some data, without saving anything (this could be invoked on map server change. [Skotlex]
+ if (sd->bl.prev != NULL)
+ { //Remove from map...
+ unit_remove_map(&sd->bl, 0);
+ if (sd->pd && sd->pd->bl.prev != NULL)
+ unit_remove_map(&sd->pd->bl, 0);
+ }
+ }
+ if (sd->stack) {
+ script_free_stack(sd->stack);
+ sd->stack= NULL;
+ }
+
+ //Do we really need to remove the name?
+ idb_remove(charid_db,sd->status.char_id);
+ idb_remove(id_db,sd->bl.id);
+ idb_remove(pc_db,sd->bl.id);
+
+ if(sd->reg)
+ { //Double logout already freed pointer fix... [Skotlex]
+ aFree(sd->reg);
+ sd->reg = NULL;
+ sd->reg_num = 0;
+ }
+ if(sd->regstr)
+ {
+ aFree(sd->regstr);
+ sd->regstr = NULL;
+ sd->regstr_num = 0;
+ }
+
+ if(!sd->fd) //There is no session connected, and as such socket.c won't free the data, we must do it. [Skotlex]
+ aFree(sd);
+ return 0;
+}
+
+
/*==========================================
* id”Ô?‚ÌPC‚ð’T‚·B‹‚È‚¯‚ê‚ÎNULL
*------------------------------------------
@@ -1894,16 +1774,16 @@ void map_removenpc(void) {
// allocates a struct when it there is place free in the cache,
// and returns NULL otherwise
// -- i'll just leave the old code in case it's needed ^^;
-struct mob_list* map_addmobtolist(unsigned short m)
+int map_addmobtolist(unsigned short m, struct spawn_data *spawn)
{
size_t i;
for (i = 0; i < MAX_MOB_LIST_PER_MAP; i++) {
if (map[m].moblist[i] == NULL) {
- map[m].moblist[i] = (struct mob_list *) aMalloc (sizeof(struct mob_list));
- return map[m].moblist[i];
+ map[m].moblist[i] = spawn;
+ return i;
}
}
- return NULL;
+ return -1;
}
void map_spawnmobs(int m)
@@ -1919,7 +1799,7 @@ void map_spawnmobs(int m)
if(map[m].moblist[i]!=NULL)
{
k+=map[m].moblist[i]->num;
- npc_parse_mob2(map[m].moblist[i],1);
+ npc_parse_mob2(map[m].moblist[i],i);
}
if (battle_config.etc_log && k > 0)
@@ -1940,10 +1820,7 @@ int mob_cache_cleanup_sub(struct block_list *bl, va_list ap) {
md->hp < md->db->max_hp) //don't use status_get_maxhp for speed (by the time you have to remove a mob, their status changes should have expired anyway)
return 0; //Do not remove damaged mobs.
- mob_remove_map(md, 0);
- map_deliddb(&md->bl);
- aFree(md);
- md = NULL;
+ unit_free(&md->bl);
return 1;
}
@@ -2408,15 +2285,20 @@ int map_waterheight(char *mapname) {
char *rsw;
float whtemp;
int wh;
-#ifdef _WIN32
+
+ //Look up for clone map.
+ if(waterlist){
+ int i;
+ for(i=0;waterlist[i].mapname[0] && i < MAX_MAP_PER_SERVER;i++)
+ if(strcmp(waterlist[i].mapname,mapname)==0)
+ return map_waterheight(waterlist[i].clonemapname);
+ }
+ //Look up for the rsw
sprintf(fn,"data\\%s",mapname);
-#else
- sprintf(fn,"data/%s",mapname);
-#endif
+
rsw = strstr(fn, ".");
- if (rsw && strstr(fn, ".rsw") == NULL)
- strcat (rsw, "rsw");
-
+ if (rsw && strstr(fn, ".rsw") == NULL)
+ sprintf(rsw,".rsw");
// read & convert fn
// again, might not need to be unsigned char
rsw = (char *) grfio_read (fn);
@@ -2427,13 +2309,7 @@ int map_waterheight(char *mapname) {
aFree(rsw);
return wh;
}
- //Look up for clone map.
- if(waterlist){
- int i;
- for(i=0;waterlist[i].mapname[0] && i < MAX_MAP_PER_SERVER;i++)
- if(strcmp(waterlist[i].mapname,mapname)==0)
- return map_waterheight(waterlist[i].clonemapname);
- }
+ ShowWarning("Failed to find water level for (%s)\n", mapname, fn);
return NO_WATER;
}
@@ -2930,19 +2806,11 @@ int map_readgat (struct map_data *m)
if ((pt = strstr(m->name,"<")) != NULL) { // [MouseJstr]
char buf[64];
*pt++ = '\0';
-#ifdef _WIN32
sprintf(buf,"data\\%s", pt);
-#else
- sprintf(buf,"data/%s", pt);
-#endif
m->alias = aStrdup(buf);
}
-#ifdef _WIN32
sprintf(fn,"data\\%s",m->name);
-#else
- sprintf(fn,"data/%s",m->name);
-#endif
// read & convert fn
// again, might not need to be unsigned char
@@ -3675,11 +3543,10 @@ int cleanup_sub(struct block_list *bl, va_list ap) {
npc_unload((struct npc_data *)bl);
break;
case BL_MOB:
- mob_unload((struct mob_data *)bl);
+ unit_free(bl);
break;
case BL_PET:
- //There is no need for this, the pet is removed together with the player. [Skotlex]
-// pet_remove_map(((struct pet_data *)bl)->msd);
+ //There is no need for this, the pet is removed together with the player. [Skotlex]
break;
case BL_ITEM:
map_clearflooritem(bl->id);
@@ -3689,9 +3556,13 @@ int cleanup_sub(struct block_list *bl, va_list ap) {
break;
}
- return 0;
+ return 1;
}
+static int cleanup_db_sub(DBKey key,void *data,va_list va) {
+ return cleanup_sub((struct block_list*)data, NULL);
+}
+
/*==========================================
* mapŽII—¹E—
*------------------------------------------
@@ -3715,6 +3586,7 @@ void do_final(void) {
for (i = 0; i < j; i++)
map_quit(pl_allsd[i]);
+ i = id_db->foreach(id_db,cleanup_db_sub);
chrif_char_reset_offline();
chrif_flush_fifo();
diff --git a/src/map/map.h b/src/map/map.h
index 28bc785bc..4ba04c905 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -32,11 +32,9 @@
#define SC_COMMON_MAX 10
#define MAX_SKILL_LEVEL 100
-#define MAX_SKILLUNITGROUP 32
-#define MAX_MOBSKILLUNITGROUP 8
-#define MAX_SKILLUNITGROUPTICKSET 32
-#define MAX_SKILLTIMERSKILL 32
-#define MAX_MOBSKILLTIMERSKILL 10
+#define MAX_SKILLUNITGROUP 16
+#define MAX_SKILLUNITGROUPTICKSET 16
+#define MAX_SKILLTIMERSKILL 16
#define MAX_MOBSKILL 50
#define MAX_MOB_LIST_PER_MAP 128
#define MAX_EVENTQUEUE 2
@@ -271,15 +269,15 @@ enum {
BL_PC = 0x001,
BL_MOB = 0x002,
BL_PET = 0x004,
- BL_ITEM = 0x008,
- BL_SKILL = 0x010,
- BL_NPC = 0x020,
- BL_CHAT = 0x040,
- BL_HOMUNCULUS = 0x080 //[blackhole89]
+ BL_HOMUNCULUS = 0x008, //[blackhole89]
+ BL_ITEM = 0x010,
+ BL_SKILL = 0x020,
+ BL_NPC = 0x040,
+ BL_CHAT = 0x080,
};
//For common mapforeach calls. Since pets cannot be affected, they aren't included here yet.
-#define BL_CHAR (BL_PC|BL_MOB|BL_HOMUNCULUS) //[blackhole89]
+#define BL_CHAR (BL_PC|BL_MOB|BL_HOMUNCULUS)
#define BL_ALL 0xfff
enum { WARP, SHOP, SCRIPT, MONS };
@@ -302,6 +300,78 @@ struct shootpath_data {
int y[MAX_WALKPATH];
};
+struct skill_timerskill {
+ int timer;
+ int src_id;
+ int target_id;
+ int map;
+ short x,y;
+ short skill_id,skill_lv;
+ int type;
+ int flag;
+};
+
+struct skill_unit_group;
+struct skill_unit {
+ struct block_list bl;
+
+ struct skill_unit_group *group;
+
+ int limit;
+ int val1,val2;
+ short alive,range;
+};
+
+struct skill_unit_group {
+ int src_id;
+ int party_id;
+ int guild_id;
+ int map;
+ int target_flag; //Holds BCT_* flag for battle_check_target
+ int bl_flag; //Holds BL_* flag for map_foreachin* functions
+ unsigned int tick;
+ int limit,interval;
+
+ int skill_id,skill_lv;
+ int val1,val2,val3;
+ char *valstr;
+ int unit_id;
+ int group_id;
+ int unit_count,alive_count;
+ struct skill_unit *unit;
+};
+struct skill_unit_group_tickset {
+ unsigned int tick;
+ int id;
+};
+
+struct unit_data {
+ struct block_list *bl;
+ int walktimer;
+ struct walkpath_data walkpath;
+ short to_x,to_y;
+ unsigned char dir;
+ short skillx,skilly;
+ short skillid,skilllv;
+ int skilltarget;
+ int skilltimer;
+ struct skill_timerskill skilltimerskill[MAX_SKILLTIMERSKILL];
+ struct skill_unit_group skillunit[MAX_SKILLUNITGROUP];
+ struct skill_unit_group_tickset skillunittick[MAX_SKILLUNITGROUPTICKSET];
+ int attacktimer;
+ int attacktarget;
+ short attacktarget_lv;
+ unsigned int attackabletime;
+ unsigned int canact_tick;
+ unsigned int canmove_tick;
+ struct {
+ unsigned change_walk_target : 1 ;
+ unsigned skillcastcancel : 1 ;
+ unsigned attack_continue : 1 ;
+ unsigned walk_easy : 1 ;
+ } state;
+};
+
struct script_reg {
int index;
int data;
@@ -360,49 +430,6 @@ struct weapon_data {
int add_damage_class_count;
};
-struct skill_unit_group;
-struct skill_unit {
- struct block_list bl;
-
- struct skill_unit_group *group;
-
- int limit;
- int val1,val2;
- short alive,range;
-};
-struct skill_unit_group {
- int src_id;
- int party_id;
- int guild_id;
- int map;
- int target_flag; //Holds BCT_* flag for battle_check_target
- int bl_flag; //Holds BL_* flag for map_foreachin* functions
- unsigned int tick;
- int limit,interval;
-
- int skill_id,skill_lv;
- int val1,val2,val3;
- char *valstr;
- int unit_id;
- int group_id;
- int unit_count,alive_count;
- struct skill_unit *unit;
-};
-struct skill_unit_group_tickset {
- unsigned int tick;
- int id;
-};
-struct skill_timerskill {
- int timer;
- int src_id;
- int target_id;
- int map;
- short x,y;
- short skill_id,skill_lv;
- int type;
- int flag;
-};
-
struct npc_data;
struct pet_db;
struct item_data;
@@ -410,15 +437,14 @@ struct square;
struct map_session_data {
struct block_list bl;
+ struct unit_data ud;
+ struct status_change sc;
//NOTE: When deciding to add a flag to state or special_state, take into consideration that state is preserved in
//status_calc_pc, while special_state is recalculated in each call. [Skotlex]
struct {
unsigned auth : 1;
- unsigned change_walk_target : 1;
- unsigned attack_continue : 1;
unsigned menu_or_input : 1;
unsigned dead_sit : 2;
- unsigned skillcastcancel : 1;
unsigned waitingdisconnect : 1;
unsigned lr_flag : 2;
unsigned connect_new : 1;
@@ -483,10 +509,8 @@ struct map_session_data {
unsigned short mapindex;
short to_x,to_y;
short speed,prev_speed;
- unsigned char dir,head_dir;
+ unsigned char head_dir;
unsigned int client_tick,server_tick;
- struct walkpath_data walkpath;
- int walktimer;
int npc_id,areanpc_id,npc_shopid;
int npc_item_flag; //Marks the npc_id with which you can use items during interactions with said npc (see script command enable_itemuse)
int npc_pos;
@@ -505,36 +529,19 @@ struct map_session_data {
} ignore[MAX_IGNORE_LIST];
int ignoreAll;
- int attacktimer;
-
- int attacktarget;
- short attacktarget_lv;
- unsigned int attackabletime;
-
int followtimer; // [MouseJstr]
int followtarget;
time_t emotionlasttime; // to limit flood with emotion packets
- int skilltimer;
- int skilltarget;
- short skillx,skilly;
- short skillid,skilllv;
short skillitem,skillitemlv;
short skillid_old,skilllv_old;
short skillid_dance,skilllv_dance;
- struct skill_unit_group skillunit[MAX_SKILLUNITGROUP];
- struct skill_unit_group_tickset skillunittick[MAX_SKILLUNITGROUPTICKSET];
- struct skill_timerskill skilltimerskill[MAX_SKILLTIMERSKILL];
char blockskill[MAX_SKILL]; // [celest]
- //unsigned int skillstatictimer[MAX_SKILL];
- unsigned short timerskill_count; // [celest]
int cloneskill_id;
int menuskill_id, menuskill_lv;
int invincible_timer;
- unsigned int canact_tick;
- unsigned int canmove_tick;
unsigned int canlog_tick;
unsigned int canregen_tick;
unsigned int canuseitem_tick; // [Skotlex]
@@ -678,7 +685,6 @@ struct map_session_data {
int regstr_num;
struct script_regstr *regstr;
- struct status_change sc;
short mission_mobid; //Stores the target mob_id for TK_MISSION
short mission_count; //Stores the bounty kill count for TK_MISSION
int devotion[5]; //Stores the char IDs of chars devoted to.
@@ -760,24 +766,19 @@ struct npc_item_list {
};
struct npc_data {
struct block_list bl;
+ struct unit_data ud; //Because they need to be able to move....
+ struct status_change sc; //They can't have status changes, but.. they want the visual opt values.
short n;
- short class_,dir;
+ short class_;
short speed;
unsigned char name[NAME_LENGTH];
unsigned char exname[NAME_LENGTH];
int chat_id;
short flag;
- int walktimer; // [Valaris]
- short to_x,to_y; // [Valaris]
- struct walkpath_data walkpath;
unsigned int next_walktime;
- unsigned int canmove_tick;
- struct status_change sc; //They can't have status changes, but.. they want the visual opt values.
struct { // [Valaris]
unsigned state : 8;
- unsigned change_walk_target : 1;
- unsigned walk_easy : 1;
} state;
char eventqueue[MAX_EVENTQUEUE][50];
@@ -818,8 +819,26 @@ struct guardian_data {
struct guild_castle* castle;
};
+// Mob List Held in memory for Dynamic Mobs [Wizputer]
+// Expanded to specify all mob-related spawn data by [Skotlex]
+struct spawn_data {
+ short class_; //Class, used because a mob can change it's class
+ unsigned short m,x,y,xs,ys; //Spawn information (map, point, spawn-area around point)
+ unsigned short num; //Number of mobs using this structure.
+ unsigned int level; //Custom level.
+ unsigned int delay1,delay2; //Min delay before respawning after spawn/death
+ struct {
+ unsigned size :2; //Holds if mob has to be tiny/large
+ unsigned ai :1; //Holds if mob is special ai.
+ } state;
+ char name[NAME_LENGTH],eventname[50]; //Name/event
+};
+
+
struct mob_data {
struct block_list bl;
+ struct unit_data ud;
+ struct status_change sc;
struct mob_db *db; //For quick data access (saves doing mob_db(md->class_) all the time) [Skotlex]
char name[NAME_LENGTH];
struct {
@@ -828,85 +847,63 @@ struct mob_data {
unsigned ai : 3; //Special ai for summoned monsters.
} special_state; //Special mob information that does not needs to be zero'ed on mob respawn.
struct {
- unsigned state : 8;
unsigned skillstate : 8;
unsigned aggressive : 1; //Signals whether the mob AI is in aggressive mode or reactive mode. [Skotlex]
- unsigned targettype : 1;
unsigned steal_flag : 1;
unsigned steal_coin_flag : 1;
- unsigned skillcastcancel : 1;
- unsigned change_walk_target : 1;
- unsigned walk_easy : 1;
unsigned soul_change_flag : 1; // Celest
unsigned alchemist: 1;
int provoke_flag; // Celest
} state;
- struct status_change sc;
- struct walkpath_data walkpath;
struct guardian_data* guardian_data;
- struct item *lootitem;
struct {
int id;
int dmg;
} dmglog[DAMAGELOG_SIZE];
- short n;
- short base_class,class_,dir,mode;
- short m,x0,y0,xs,ys;
- short to_x,to_y;
- short target_dir;
+ struct spawn_data *spawn; //Spawn data.
+ struct item *lootitem;
+ short spawn_n; //Spawn data index on the map server.
+ short class_,mode;
short speed;
short attacked_count;
- short target_lv;
unsigned short level;
- unsigned long tdmg; //Stores total damage given to the mob, for exp calculations. [Skotlex]
- int timer;
+ unsigned short attacked_players;
+ unsigned int tdmg; //Stores total damage given to the mob, for exp calculations. [Skotlex]
int hp, max_hp;
int target_id,attacked_id;
- int spawndelay1,spawndelay2;
- unsigned int attackabletime, canmove_tick, next_walktime;
+ unsigned int next_walktime;
unsigned int last_deadtime,last_spawntime,last_thinktime,last_linktime;
short move_fail_count;
short lootitem_count;
short min_chase;
int deletetimer;
- int skilltimer;
- int skilltarget;
int def_ele;
int master_id,master_dist;
struct npc_data *nd;
- short skillx,skilly,skillid,skilllv,skillidx;
+ short skillidx;
unsigned int skilldelay[MAX_MOBSKILL];
- struct skill_timerskill skilltimerskill[MAX_MOBSKILLTIMERSKILL];
- struct skill_unit_group skillunit[MAX_MOBSKILLUNITGROUP];
- struct skill_unit_group_tickset skillunittick[MAX_SKILLUNITGROUPTICKSET];
char npc_event[50];
};
struct pet_data {
struct block_list bl;
- short n;
- short class_,dir;
+ struct unit_data ud;
struct mob_db *db;
+ int target_id;
+ short n;
+ short class_;
short speed;
char name[NAME_LENGTH];
struct {
- unsigned state : 8 ;
unsigned skillstate : 8 ;
- unsigned change_walk_target : 1 ;
- unsigned casting_flag :1 ;//Skotlex: Used to identify when we are casting.
short skillbonus;
} state;
- int timer;
- short to_x,to_y;
short equip;
- struct walkpath_data walkpath;
- int target_id;
- short target_lv;
int move_fail_count;
- unsigned int attackabletime,next_walktime,last_thinktime;
+ unsigned int next_walktime,last_thinktime;
short rate_fix; //Support rate as modified by intimacy (1000 = 100%) [Skotlex]
struct pet_status { //Pet Status data
short level;
@@ -950,22 +947,11 @@ struct pet_data {
unsigned short count;
unsigned short weight;
unsigned short max;
- int timer;
} *loot; //[Valaris] / Rewritten by [Skotlex]
- struct skill_timerskill skilltimerskill[MAX_MOBSKILLTIMERSKILL]; // [Valaris]
- struct skill_unit_group skillunit[MAX_MOBSKILLUNITGROUP]; // [Valaris]
- struct skill_unit_group_tickset skillunittick[MAX_SKILLUNITGROUPTICKSET]; // [Valaris]
struct map_session_data *msd;
-
- int skilltarget;
- short skillx,skilly,skillid,skilllv;
};
-enum { MS_IDLE,MS_WALK,MS_ATTACK,MS_DEAD,MS_DELAY };
-
-enum { NONE_ATTACKABLE,ATTACKABLE };
-
enum { ATK_LUCKY=1,ATK_FLEE,ATK_DEF}; // ˆÍ‚Ü‚êƒyƒiƒ‹ƒeƒBŒvŽZ—p
// For equipment breaking/stripping effects
@@ -976,12 +962,6 @@ enum {
EQP_HELM = 8, // Top-head headgear
};
-// Mob List Held in memory for Dynamic Mobs [Wizputer]
-struct mob_list {
- int m,x,y,xs,ys,class_,num,delay1,delay2,level;
- char mobname[NAME_LENGTH],eventname[NAME_LENGTH];
-};
-
struct map_data {
char name[MAP_NAME_LENGTH];
unsigned short index; //Index is the map index used by the mapindex* functions.
@@ -1051,7 +1031,8 @@ struct map_data {
int drop_type;
int drop_per;
} drop_list[MAX_DROP_PER_MAP];
- struct mob_list *moblist[MAX_MOB_LIST_PER_MAP]; // [Wizputer]
+
+ struct spawn_data *moblist[MAX_MOB_LIST_PER_MAP]; // [Wizputer]
int mob_delete_timer; // [Skotlex]
int zone; // [Komurka]
};
@@ -1325,7 +1306,7 @@ int cleanup_sub(struct block_list *bl, va_list ap);
void map_helpscreen(int flag); // [Valaris]
int map_delmap(char *mapname);
-struct mob_list* map_addmobtolist(unsigned short m); // [Wizputer]
+int map_addmobtolist(unsigned short m, struct spawn_data *spawn); // [Wizputer]
void map_spawnmobs(int); // [Wizputer]
void map_removemobs(int); // [Wizputer]
diff --git a/src/map/mob.c b/src/map/mob.c
index 959a71cf9..fdf1911cb 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -34,7 +34,6 @@
#include "irc.h"
#define MIN_MOBTHINKTIME 100
-#define MIN_MOBLINKTIME 1000
#define MOB_LAZYSKILLPERC 10 // Probability for mobs far from players from doing their IDLE skill. (rate of 1000 minute)
#define MOB_LAZYMOVEPERC 50 // Move probability in the negligent mode MOB (rate of 1000 minute)
@@ -56,12 +55,9 @@ struct mob_db *mob_db(int index) { if (index < 0 || index > MAX_MOB_DB || mob_db
*------------------------------------------
*/
static int mob_makedummymobdb(int);
-static int mob_timer(int,unsigned int,int,int);
static int mob_spawn_guardian_sub(int,unsigned int,int,int);
int mobskill_use(struct mob_data *md,unsigned int tick,int event);
-int mobskill_deltimer(struct mob_data *md );
int mob_skillid2skillidx(int class_,int skillid);
-int mobskill_use_id(struct mob_data *md,struct block_list *target,int skill_idx);
/*==========================================
* Mob is searched with a name.
@@ -114,8 +110,6 @@ int mobdb_searchname_array(struct mob_db** data, int size, const char *str)
return count;
}
-
-
/*==========================================
* Id Mob is checked.
*------------------------------------------
@@ -130,37 +124,85 @@ int mobdb_checkid(const int id)
}
/*==========================================
- * The minimum data set for MOB spawning
+ * Cleans up mob-spawn data to make it "valid"
*------------------------------------------
*/
-int mob_spawn_dataset(struct mob_data *md,const char *mobname,int class_)
-{
- nullpo_retr(0, md);
-
- md->bl.prev=NULL;
- md->bl.next=NULL;
+int mob_parse_dataset(struct spawn_data *data) {
+ int i;
+ //FIXME: This implementation is not stable, npc scripts will stop working once MAX_MOB_DB changes value! [Skotlex]
+ if(data->class_ > 2*MAX_MOB_DB){ // large/tiny mobs [Valaris]
+ data->state.size=2;
+ data->class_ -= 2*MAX_MOB_DB;
+ } else if (data->class_ > MAX_MOB_DB) {
+ data->state.size=1;
+ data->class_ -= MAX_MOB_DB;
+ }
- md->base_class = md->class_ = class_;
- md->db = mob_db(class_);
+ if ((!mobdb_checkid(data->class_) && !mob_is_clone(data->class_)) || !data->num)
+ return 0;
- if(strcmp(mobname,"--en--")==0)
- strncpy(md->name,md->db->name,NAME_LENGTH-1);
- else if(strcmp(mobname,"--ja--")==0)
- strncpy(md->name,md->db->jname,NAME_LENGTH-1);
- else
- strncpy(md->name,mobname,NAME_LENGTH-1);
+ //better safe than sorry, current md->npc_event has a size of 50
+ if (strlen(data->eventname) >= 50)
+ return 0;
+
+ if (data->eventname[0] && strlen(data->eventname) <= 2)
+ { //Portable monster big/small implementation. [Skotlex]
+ i = atoi(data->eventname);
+ if (i) {
+ if (i&2)
+ data->state.size=1;
+ else if (i&4)
+ data->state.size=2;
+ if (i&8)
+ data->state.ai=1;
+ data->eventname[0] = '\0'; //Clear event as it is not used.
+ }
+ }
+ if (!data->level)
+ data->level = mob_db(data->class_)->lv;
+
+ if(strcmp(data->name,"--en--")==0)
+ strncpy(data->name,mob_db(data->class_)->name,NAME_LENGTH-1);
+ else if(strcmp(data->name,"--ja--")==0)
+ strncpy(data->name,mob_db(data->class_)->jname,NAME_LENGTH-1);
- md->n = 0;
+ return 1;
+}
+/*==========================================
+ * Generates the basic mob data using the spawn_data provided.
+ *------------------------------------------
+ */
+struct mob_data* mob_spawn_dataset(struct spawn_data *data)
+{
+ struct mob_data *md = aCalloc(1, sizeof(struct mob_data));
+ int i;
md->bl.id= npc_get_new_npc_id();
-
- memset(&md->state,0,sizeof(md->state));
- md->timer = -1;
- md->target_id=0;
- md->attacked_id=0;
- md->attacked_count=0;
- md->speed=md->db->speed;
+ md->bl.type = BL_MOB;
+ md->bl.subtype = MONS;
+ md->bl.m = data->m;
+ md->bl.x = data->x;
+ md->bl.y = data->y;
+ md->class_ = data->class_;
+ md->db = mob_db(md->class_);
+ md->speed = md->db->speed;
+ memcpy(md->name, data->name, NAME_LENGTH-1);
+ if (data->state.ai)
+ md->special_state.ai = data->state.ai;
+ if (data->state.size)
+ md->special_state.size = data->state.size;
+ if (data->eventname[0] && strlen(data->eventname) >= 4)
+ memcpy(md->npc_event, data->eventname, 50);
+ md->level = data->level;
+
+ if(md->db->mode&MD_LOOTER)
+ md->lootitem = (struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item));
+ md->spawn_n = -1;
+ md->deletetimer = -1;
+ for (i = 0; i < MAX_STATUSCHANGE; i++)
+ md->sc.data[i].timer = -1;
- return 0;
+ map_addiddb(&md->bl);
+ return md;
}
/*==========================================
@@ -204,6 +246,7 @@ int mob_once_spawn (struct map_session_data *sd, char *mapname,
int x, int y, const char *mobname, int class_, int amount, const char *event)
{
struct mob_data *md = NULL;
+ struct spawn_data data;
int m, count, lv = 255;
int i, j;
@@ -214,9 +257,21 @@ int mob_once_spawn (struct map_session_data *sd, char *mapname,
else
m = map_mapname2mapid(mapname);
- if (m < 0 || amount <= 0 || (class_ >= 0 && class_ <= 1000) || class_ > MAX_MOB_DB + 2*MAX_MOB_DB) // ’l‚ªˆÙí‚Ȃ碊«‚ðŽ~‚ß‚é
+ memset(&data, 0, sizeof(struct spawn_data));
+ if (m < 0 || amount <= 0) // ’l‚ªˆÙí‚Ȃ碊«‚ðŽ~‚ß‚é
return 0;
-
+ data.m = m;
+ data.num = amount;
+ data.class_ = class_;
+ strncpy(data.name, mobname, NAME_LENGTH-1);
+
+ if (class_ < 0) {
+ data.class_ = mob_get_random_id(-class_ -1, battle_config.random_monster_checklv?3:1, lv);
+ if (!data.class_)
+ return 0;
+ }
+ strncpy(data.eventname, event, 50);
+
if (sd) { //even if the coords were wrong, spawn mob anyways (but look for most suitable coords first) Got from Freya [Lupus]
if (x <= 0 || y <= 0) {
if (x <= 0) x = sd->bl.x + rand() % 3 - 1;
@@ -237,53 +292,20 @@ int mob_once_spawn (struct map_session_data *sd, char *mapname,
y = 0;
}
}
+ data.x = x;
+ data.y = y;
+ if (!mob_parse_dataset(&data))
+ return 0;
+
for (count = 0; count < amount; count++) {
- md = (struct mob_data *)aCalloc(1,sizeof(struct mob_data));
-
- if (class_ > 2*MAX_MOB_DB) { // large/tiny mobs [Valaris]
- md->special_state.size = 2;
- class_ -= 2*MAX_MOB_DB;
- } else if (class_ > MAX_MOB_DB) {
- md->special_state.size = 1;
- class_ -= MAX_MOB_DB;
- }
+ md =mob_spawn_dataset (&data);
- if (class_ < 0) {
- class_ = mob_get_random_id(-class_ -1, battle_config.random_monster_checklv?3:1, lv);
- if (!class_) {
- aFree(md);
- return 0;
- }
- if (battle_config.dead_branch_active)
+ if (class_ < 0 && battle_config.dead_branch_active)
//Behold Aegis's masterful decisions yet again...
//"I understand the "Aggressive" part, but the "Can Move" and "Can Attack" is just stupid" - Poki#3
- md->mode = mob_db(class_)->mode|MD_AGGRESSIVE|MD_CANATTACK|MD_CANMOVE;
- }
-
-
- if(mob_db(class_)->mode & MD_LOOTER)
- md->lootitem = (struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item));
-
- mob_spawn_dataset (md, mobname, class_);
- md->bl.m = m;
- md->bl.x = x;
- md->bl.y = y;
- md->m = m;
- md->x0 = x;
- md->y0 = y;
- //md->xs = 0;
- //md->ys = 0;
- md->spawndelay1 = -1; // ˆê“x‚̂݃tƒ‰ƒO
- md->spawndelay2 = -1; // ˆê“x‚̂݃tƒ‰ƒO
-
- //better safe than sorry, current md->npc_event has a size of 50
- if (strlen(event) < 50)
- memcpy(md->npc_event, event, strlen(event));
-
- md->bl.type = BL_MOB;
- map_addiddb (&md->bl);
- mob_spawn (md->bl.id);
+ md->mode = md->db->mode|MD_AGGRESSIVE|MD_CANATTACK|MD_CANMOVE;
+ mob_spawn (md);
if(class_ == MOBID_EMPERIUM) { // emperium hp based on defense level [Valaris]
struct guild_castle *gc = guild_mapname2gc(map[md->bl.m].name);
@@ -305,7 +327,7 @@ int mob_once_spawn (struct map_session_data *sd, char *mapname,
}
} // end addition [Valaris]
}
- return (amount > 0) ? md->bl.id : 0;
+ return (md)?md->bl.id : 0;
}
/*==========================================
* The MOB appearance for one time (& area specification for scripts)
@@ -326,7 +348,7 @@ int mob_once_spawn_area(struct map_session_data *sd,char *mapname,
max=(y1-y0+1)*(x1-x0+1)*3;
if(max>1000)max=1000;
- if (m < 0 || amount <= 0 || (class_ >= 0 && class_ <= 1000) || class_ > MAX_MOB_DB + 2*MAX_MOB_DB) // ’l‚ªˆÙí‚Ȃ碊«‚ðŽ~‚ß‚é
+ if (m < 0 || amount <= 0) // ’l‚ªˆÙí‚Ȃ碊«‚ðŽ~‚ß‚é
return 0;
for(i=0;i<amount;i++){
@@ -335,7 +357,6 @@ int mob_once_spawn_area(struct map_session_data *sd,char *mapname,
x=rand()%(x1-x0+1)+x0;
y=rand()%(y1-y0+1)+y0;
} while (map_getcell(m,x,y,CELL_CHKNOPASS) && (++j)<max);
- // freya }while( ( (c=map_getcell(m,x,y))==1 || c==5)&& (++j)<max );
if(j>=max){
if(lx>=0){ // Since reference went wrong, the place which boiled before is used.
x=lx;
@@ -390,7 +411,7 @@ static int mob_spawn_guardian_sub(int tid,unsigned int tick,int id,int data)
guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
guild_castledatasave(md->guardian_data->castle->castle_id, 18+md->guardian_data->number,0);
}
- mob_delete(md); //Remove guardian.
+ unit_free(&md->bl); //Remove guardian.
}
return 0;
}
@@ -408,21 +429,25 @@ int mob_spawn_guardian(struct map_session_data *sd,char *mapname,
int x,int y,const char *mobname,int class_,int amount,const char *event,int guardian)
{
struct mob_data *md=NULL;
+ struct spawn_data data;
struct guild *g=NULL;
struct guild_castle *gc;
-
- int m,count=1;
+ int m, count;
+ memset(&data, 0, sizeof(struct spawn_data));
+ data.num = 1;
if( sd && strcmp(mapname,"this")==0)
m=sd->bl.m;
else
m=map_mapname2mapid(mapname);
- if(m<0 || amount<=0 || (class_>=0 && class_<=1000) || class_>MAX_MOB_DB) // Invalid monster classes
+ if(m<0 || amount<=0)
return 0;
-
+ data.m = m;
+ data.num = amount;
if(class_<0)
return 0;
+ data.class_ = class_;
if(guardian < 0 || guardian >= MAX_GUARDIANS)
{
@@ -438,7 +463,13 @@ int mob_spawn_guardian(struct map_session_data *sd,char *mapname,
}
else if(x<=0 || y<=0)
ShowWarning("mob_spawn_guardian: Invalid coordinates (%d,%d)\n",x,y);
-
+ data.x = x;
+ data.y = y;
+ strncpy(data.name, mobname, NAME_LENGTH-1);
+ strncpy(data.eventname, event, 50);
+ if (!mob_parse_dataset(&data))
+ return 0;
+
gc=guild_mapname2gc(map[m].name);
if (gc == NULL)
{
@@ -453,27 +484,9 @@ int mob_spawn_guardian(struct map_session_data *sd,char *mapname,
if (gc->guardian[guardian].id)
ShowWarning("mob_spawn_guardian: Spawning guardian in position %d which already has a guardian (castle map %s)\n", guardian, map[m].name);
- for(count=0;count<amount;count++){
- md=(struct mob_data *) aCalloc(1, sizeof(struct mob_data));
- mob_spawn_dataset(md,mobname,class_);
- md->bl.m=m;
- md->bl.x=x;
- md->bl.y=y;
- md->m =m;
- md->x0=x;
- md->y0=y;
- md->xs=0;
- md->ys=0;
- md->spawndelay1=-1; // Only once is a flag.
- md->spawndelay2=-1; // Only once is a flag.
-
- //better safe than sorry, current md->npc_event has a size of 50 [Skotlex]
- if (strlen(event) < 50)
- memcpy(md->npc_event, event, strlen(event));
-
- md->bl.type=BL_MOB;
- map_addiddb(&md->bl);
- mob_spawn(md->bl.id);
+ for(count=0;count<data.num;count++){
+ md= mob_spawn_dataset(&data);
+ mob_spawn(md);
md->max_hp += 2000 * gc->defense;
md->guardian_data = aCalloc(1, sizeof(struct guardian_data));
@@ -495,125 +508,6 @@ int mob_spawn_guardian(struct map_session_data *sd,char *mapname,
}
/*==========================================
- * Is MOB in the state in which the present movement is possible or not?
- *------------------------------------------
- */
-int mob_can_move(struct mob_data *md)
-{
- nullpo_retr(0, md);
-
- if(DIFF_TICK(md->canmove_tick, gettick()) > 0 || md->skilltimer != -1 || (md->sc.opt1 > 0 && md->sc.opt1 != OPT1_STONEWAIT) || md->sc.option&OPTION_HIDE)
- return 0;
- // ƒAƒ“ƒNƒ‹’†‚Å“®‚¯‚È‚¢‚Æ‚©
- if(md->sc.count && (
- md->sc.data[SC_ANKLE].timer != -1 || //ƒAƒ“ƒNƒ‹ƒXƒlƒA
- md->sc.data[SC_AUTOCOUNTER].timer != -1 || //ƒI[ƒgƒJƒEƒ“ƒ^[
- md->sc.data[SC_BLADESTOP].timer != -1 || //”’nŽæ‚è
- md->sc.data[SC_SPIDERWEB].timer != -1 || //ƒXƒpƒCƒ_[ƒEƒFƒbƒu
- (md->sc.data[SC_DANCING].timer !=-1 && md->sc.data[SC_DANCING].val1 == CG_HERMODE) || //cannot move while Hermod is active.
- (md->sc.data[SC_GOSPEL].timer !=-1 && md->sc.data[SC_GOSPEL].val4 == BCT_SELF) || // cannot move while gospel is in effect
- md->sc.data[SC_STOP].timer != -1 ||
- md->sc.data[SC_CLOSECONFINE].timer != -1 ||
- md->sc.data[SC_CLOSECONFINE2].timer != -1
- ))
- return 0;
-
- return 1;
-}
-
-/*==========================================
- * Time calculation concerning one step next to mob
- *------------------------------------------
- */
-static int calc_next_walk_step(struct mob_data *md)
-{
- nullpo_retr(0, md);
-
- if(md->walkpath.path_pos>=md->walkpath.path_len)
- return -1;
- if(md->walkpath.path[md->walkpath.path_pos]&1)
- return status_get_speed(&md->bl)*14/10;
- return status_get_speed(&md->bl);
-}
-
-static int mob_walktoxy_sub(struct mob_data *md);
-
-/*==========================================
- * Mob Walk processing
- *------------------------------------------
- */
-static int mob_walk(struct mob_data *md,unsigned int tick,int data)
-{
- int i;
- static int dirx[8]={0,-1,-1,-1,0,1,1,1};
- static int diry[8]={1,1,0,-1,-1,-1,0,1};
- int x,y,dx,dy;
-
- nullpo_retr(0, md);
-
- md->state.state=MS_IDLE;
- if(md->walkpath.path_pos>=md->walkpath.path_len || md->walkpath.path_pos!=data)
- return 0;
-
- md->walkpath.path_half ^= 1;
- if(md->walkpath.path_half==0){
- md->walkpath.path_pos++;
- if(md->state.change_walk_target){
- mob_walktoxy_sub(md);
- return 0;
- }
- }
- else {
- if(md->walkpath.path[md->walkpath.path_pos]>=8)
- return 1;
-
- x = md->bl.x;
- y = md->bl.y;
-#ifndef CELL_NOSTACK
- if(map_getcell(md->bl.m,x,y,CELL_CHKNOPASS)) {
- mob_stop_walking(md,1);
- return 0;
- }
-#endif
- md->dir=md->walkpath.path[md->walkpath.path_pos];
- dx = dirx[md->dir];
- dy = diry[md->dir];
-
- if (map_getcell(md->bl.m,x+dx,y+dy,CELL_CHKNOPASS)) {
- mob_walktoxy_sub(md);
- return 0;
- }
-
- md->state.state=MS_WALK;
- map_foreachinmovearea(clif_moboutsight,md->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_PC,md);
-
- if ( md->min_chase > md->db->range2)
- md->min_chase--;
-
- x += dx;
- y += dy;
- map_moveblock(&md->bl, x, y, tick);
-
- map_foreachinmovearea(clif_mobinsight,md->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,-dx,-dy,BL_PC,md);
- md->state.state=MS_IDLE;
-
- }
- if((i=calc_next_walk_step(md))>0){
- i = i>>1;
- if(i < 1 && md->walkpath.path_half == 0)
- i = 1;
-
- if(md->walkpath.path_pos>=md->walkpath.path_len)
- clif_fixmobpos(md); // ‚Æ‚Ü‚Á‚½‚Æ‚«‚Ɉʒu‚ÌÄ‘—M
- else {
- md->timer=add_timer(tick+i,mob_timer,md->bl.id,md->walkpath.path_pos);
- md->state.state=MS_WALK;
- }
- }
- return 0;
-}
-
-/*==========================================
* Reachability to a Specification ID existence place
* state indicates type of 'seek' mob should do:
* - MSS_LOOT: Looking for item, path must be easy.
@@ -680,7 +574,7 @@ int mob_can_reach(struct mob_data *md,struct block_list *bl,int range, int state
* Links nearby mobs (supportive mobs)
*------------------------------------------
*/
-static int mob_linksearch(struct block_list *bl,va_list ap)
+int mob_linksearch(struct block_list *bl,va_list ap)
{
struct mob_data *md;
int class_;
@@ -695,13 +589,11 @@ static int mob_linksearch(struct block_list *bl,va_list ap)
tick=va_arg(ap, unsigned int);
if (md->class_ == class_ && DIFF_TICK(md->last_linktime, tick) < MIN_MOBLINKTIME
- && (!md->target_id || md->state.targettype == NONE_ATTACKABLE))
+ && !md->target_id)
{
md->last_linktime = tick;
if( mob_can_reach(md,target,md->db->range2, MSS_FOLLOW) ){ // Reachability judging
md->target_id = target->id;
- md->attacked_count = 0;
- md->state.targettype = ATTACKABLE;
md->state.aggressive = (status_get_mode(&md->bl)&MD_ANGRY)?1:0;
md->min_chase=md->db->range3;
return 1;
@@ -712,274 +604,14 @@ static int mob_linksearch(struct block_list *bl,va_list ap)
}
/*==========================================
- * Attack processing of mob
- *------------------------------------------
- */
-static int mob_attack(struct mob_data *md,unsigned int tick,int data)
-{
- struct block_list *tbl=NULL;
-
- int range;
-
- nullpo_retr(0, md);
-
- md->min_chase=md->db->range3;
- md->state.state=MS_IDLE;
- md->state.skillstate=MSS_IDLE;
-
- if( md->skilltimer!=-1 ) // ƒXƒLƒ‹Žg—p’†
- return 0;
-
- if((tbl=map_id2bl(md->target_id))==NULL || !status_check_skilluse(&md->bl, tbl, 0, 0)){
- md->target_id=0;
- md->state.targettype = NONE_ATTACKABLE;
- return 0;
- }
-
- if (!check_distance_bl(&md->bl, tbl, md->db->range3)){
- mob_stopattack(md);
- return 0;
- }
-
- range = md->db->range;
- if (range <= 3)
- range++; //Melee attackers get a bonus range cell when attacking.
-
- /* It seems mobs always teleport the last two tiles when chasing players, so do not give them this bonus range tile.[Skotlex]
- if(battle_iswalking(tbl)) range++;
- */
- if(!check_distance_bl(&md->bl, tbl, range))
- return 0;
- if(battle_config.monster_attack_direction_change)
- md->dir=map_calc_dir(&md->bl, tbl->x,tbl->y ); // Œü‚«Ý’è
-
- if (status_get_mode(&md->bl)&MD_ASSIST && DIFF_TICK(md->last_linktime, tick) < MIN_MOBLINKTIME)
- { // Link monsters nearby [Skotlex]
- md->last_linktime = tick;
- map_foreachinrange(mob_linksearch, &md->bl, md->db->range2,
- BL_MOB, md->class_, tbl, tick);
- }
-
- md->state.skillstate=md->state.aggressive?MSS_ANGRY:MSS_BERSERK;
- if( mobskill_use(md,tick,-1) ) // ƒXƒLƒ‹Žg—p
- return 0;
-
- if(md->sc.count && md->sc.data[SC_WINKCHARM].timer != -1)
- clif_emotion(&md->bl, 3);
- else
- md->target_lv = battle_weapon_attack(&md->bl,tbl,tick,0);
-
- if(!(battle_config.monster_cloak_check_type&2) && md->sc.data[SC_CLOAKING].timer != -1)
- status_change_end(&md->bl,SC_CLOAKING,-1);
-
- //Mobs can't move if they can't attack neither.
- //Use the attack delay for next can attack try
- //But use the attack motion to know when it can start moving. [Skotlex]
- md->attackabletime = tick + status_get_adelay(&md->bl);
- battle_set_walkdelay(&md->bl, tick, status_get_amotion(&md->bl), 1);
-
- md->timer=add_timer(md->attackabletime,mob_timer,md->bl.id,0);
- md->state.state=MS_ATTACK;
-
- return 0;
-}
-
-/*==========================================
- * The attack of PC which is attacking id is stopped.
- * The callback function of clif_foreachclient
- *------------------------------------------
- */
-int mob_stopattacked(struct map_session_data *sd,va_list ap)
-{
- int id;
-
- nullpo_retr(0, sd);
- nullpo_retr(0, ap);
-
- id=va_arg(ap,int);
- if(sd->attacktarget==id)
- pc_stopattack(sd);
- return 0;
-}
-/*==========================================
- * The timer in which the mob's states changes
- *------------------------------------------
- */
-int mob_changestate(struct mob_data *md,int state,int type)
-{
- unsigned int tick;
- int i;
-
- nullpo_retr(0, md);
-
- if(md->timer != -1)
- delete_timer(md->timer,mob_timer);
- md->timer=-1;
- md->state.state=state;
-
- switch(state){
- case MS_WALK:
- if((i=calc_next_walk_step(md))>0){
- i = i>>2;
- md->timer=add_timer(gettick()+i,mob_timer,md->bl.id, md->walkpath.path_pos);
- }
- else
- md->state.state=MS_IDLE;
- break;
- case MS_ATTACK:
- tick = gettick();
- i=DIFF_TICK(md->attackabletime,tick);
- if(i>0 && i<2000)
- md->timer=add_timer(md->attackabletime,mob_timer,md->bl.id,0);
- else if(type) {
- md->attackabletime = tick + status_get_amotion(&md->bl);
- md->timer=add_timer(md->attackabletime,mob_timer,md->bl.id,0);
- }
- else {
- md->attackabletime = tick + 1;
- md->timer=add_timer(md->attackabletime,mob_timer,md->bl.id,0);
- }
- break;
- case MS_DELAY:
- md->timer=add_timer(gettick()+type,mob_timer,md->bl.id,0);
- break;
- case MS_DEAD:
- skill_castcancel(&md->bl,0);
-// mobskill_deltimer(md);
- md->state.skillstate=MSS_DEAD;
- md->last_deadtime=gettick();
- // Since it died, all aggressors' attack to this mob is stopped.
- clif_foreachclient(mob_stopattacked,md->bl.id);
- skill_unit_move(&md->bl,gettick(),4);
- status_change_clear(&md->bl,2); // ƒXƒe[ƒ^ƒXˆÙí‚ð‰ðœ‚·‚é
- if (battle_config.clear_unit_ondeath)
- skill_clear_unitgroup(&md->bl);
- skill_cleartimerskill(&md->bl);
- if(md->deletetimer!=-1)
- delete_timer(md->deletetimer,mob_timer_delete);
- md->deletetimer=-1;
- md->hp = md->target_id = md->attacked_id = md->attacked_count = 0;
- md->state.targettype = NONE_ATTACKABLE;
- break;
- }
-
- return 0;
-}
-
-/*==========================================
- * timer processing of mob (timer function)
- * It branches to a walk and an attack.
- *------------------------------------------
- */
-static int mob_timer(int tid,unsigned int tick,int id,int data)
-{
- struct mob_data *md;
- struct block_list *bl;
-
- if( (bl=map_id2bl(id)) == NULL ){ //UŒ‚‚µ‚Ä‚«‚½“G‚ª‚à‚¤‚¢‚È‚¢‚̂ͳí‚̂悤‚¾
- return 1;
- }
-
- if(!bl || !bl->type || bl->type!=BL_MOB)
- return 1;
-
- nullpo_retr(1, md=(struct mob_data*)bl);
-
- if(md->timer != tid){
- if(battle_config.error_log)
- ShowError("mob_timer %d != %d\n",md->timer,tid);
- return 0;
- }
- md->timer=-1;
- if(md->bl.prev == NULL || md->state.state == MS_DEAD)
- return 1;
-
- map_freeblock_lock();
- switch(md->state.state){
- case MS_WALK:
- mob_walk(md,tick,data);
- break;
- case MS_ATTACK:
- mob_attack(md,tick,data);
- break;
- case MS_DELAY:
- mob_changestate(md,MS_IDLE,0);
- break;
- default:
- if(battle_config.error_log)
- ShowError("mob_timer : %d ?\n",md->state.state);
- break;
- }
-
- if (md->timer == -1)
- mob_changestate(md,MS_WALK,0);
-
- map_freeblock_unlock();
- return 0;
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static int mob_walktoxy_sub(struct mob_data *md)
-{
- struct walkpath_data wpd;
- nullpo_retr(0, md);
- memset(&wpd, 0, sizeof(wpd));
-
- if(path_search(&wpd,md->bl.m,md->bl.x,md->bl.y,md->to_x,md->to_y,md->state.walk_easy))
- return 1;
- if (wpd.path[0] >= 8)
- return 1;
-
- memcpy(&md->walkpath,&wpd,sizeof(wpd));
-
- md->state.change_walk_target=0;
- mob_changestate(md,MS_WALK,0);
- clif_movemob(md);
-
- return 0;
-}
-
-/*==========================================
- * mob move start
- *------------------------------------------
- */
-int mob_walktoxy(struct mob_data *md,int x,int y,int easy)
-{
- struct walkpath_data wpd;
-
- nullpo_retr(0, md);
-
- if(md->bl.prev == NULL || md->state.state == MS_DEAD) //Just-in-case check to prevent dead mobs from moving. [Skotlex]
- return 1;
-
- if(md->state.state == MS_WALK && path_search(&wpd,md->bl.m,md->bl.x,md->bl.y,x,y,easy) )
- return 1;
-
- md->state.walk_easy = easy;
- md->to_x=x;
- md->to_y=y;
-
- if (md->sc.data[SC_CONFUSION].timer != -1) //Randomize target direction.
- map_random_dir(&md->bl, &md->to_x, &md->to_y);
-
- if(md->state.state == MS_WALK)
- md->state.change_walk_target=1;
- else
- return mob_walktoxy_sub(md);
-
- return 0;
-}
-
-/*==========================================
* mob spawn with delay (timer function)
*------------------------------------------
*/
static int mob_delayspawn(int tid, unsigned int tick, int m, int n)
{
- mob_spawn(m);
+ struct block_list *bl = map_id2bl(m);
+ if (bl && bl->type == BL_MOB)
+ mob_spawn((TBL_MOB*)bl);
return 0;
}
@@ -987,37 +619,16 @@ static int mob_delayspawn(int tid, unsigned int tick, int m, int n)
* spawn timing calculation
*------------------------------------------
*/
-int mob_setdelayspawn(int id)
+int mob_setdelayspawn(struct mob_data *md)
{
unsigned int spawntime, spawntime1, spawntime2, spawntime3;
- struct mob_data *md;
- struct block_list *bl;
- if ((bl = map_id2bl(id)) == NULL || bl->type != BL_MOB)
- return -1;
- nullpo_retr(-1, md = (struct mob_data*)bl);
- // Processing of MOB which is not revitalized
- if (md->spawndelay1 == -1 && md->spawndelay2 == -1 && md->n == 0) {
- if (md->lootitem) {
- aFree(md->lootitem);
- md->lootitem = NULL;
- }
- if (md->guardian_data)
- {
- if (md->guardian_data->number < MAX_GUARDIANS)
- md->guardian_data->castle->guardian[md->guardian_data->number].id = 0;
- aFree (md->guardian_data);
- md->guardian_data = NULL;
- }
- map_deliddb(&md->bl);
- map_delblock(bl); //In case it wasn't done before invoking the function.
- map_freeblock(bl);
- return 0;
- }
+ if (!md->spawn) //Doesn't has respawn data!
+ return unit_free(&md->bl);
- spawntime1 = md->last_spawntime + md->spawndelay1;
- spawntime2 = md->last_deadtime + md->spawndelay2;
+ spawntime1 = md->last_spawntime + md->spawn->delay1;
+ spawntime2 = md->last_deadtime + md->spawn->delay2;
spawntime3 = gettick() + 5000 + rand()%5000; //Lupus
// spawntime = max(spawntime1,spawntime2,spawntime3);
if (DIFF_TICK(spawntime1, spawntime2) > 0)
@@ -1027,7 +638,7 @@ int mob_setdelayspawn(int id)
if (DIFF_TICK(spawntime3, spawntime) > 0)
spawntime = spawntime3;
- add_timer(spawntime, mob_delayspawn, id, 0);
+ add_timer(spawntime, mob_delayspawn, md->bl.id, 0);
return 0;
}
@@ -1040,75 +651,73 @@ static int mob_count_sub(struct block_list *bl,va_list ap)
* Mob spawning. Initialization is also variously here.
*------------------------------------------
*/
-int mob_spawn (int id)
+int mob_spawn (struct mob_data *md)
{
- int x, y, i = 0;
+ int i=0;
unsigned int c =0, tick = gettick();
- struct mob_data *md;
- struct block_list *bl;
-
- if ((bl = map_id2bl(id)) == NULL || bl->type != BL_MOB)
- return -1;
- nullpo_retr(-1, md = (struct mob_data*)bl);
md->last_spawntime = tick;
if (md->bl.prev != NULL)
- map_delblock(&md->bl);
- else {
- if(md->class_ != md->base_class){ // ƒNƒ‰ƒXƒ`ƒFƒ“ƒW‚µ‚½Mob
- md->class_ = md->base_class;
- md->db = mob_db(md->base_class);
+ unit_remove_map(&md->bl,2);
+ else if (md->spawn && md->class_ != md->spawn->class_) {
+ md->class_ = md->spawn->class_;
+ md->db = mob_db(md->class_);
+ md->speed=md->db->speed;
+ if (md->spawn)
+ memcpy(md->name,md->spawn->name,NAME_LENGTH);
+ else
memcpy(md->name,md->db->jname,NAME_LENGTH);
- md->speed=md->db->speed;
- }
}
- md->bl.m = md->m;
- while (i < 50) {
- if (md->x0 == 0 && md->y0 == 0) {
- x = rand()%(map[md->bl.m].xs-2)+1;
- y = rand()%(map[md->bl.m].ys-2)+1;
- } else {
- x = md->x0+rand()%(md->xs+1)-md->xs/2;
- y = md->y0+rand()%(md->ys+1)-md->ys/2;
- }
- i++;
- if (map_getcell(md->bl.m,x,y,CELL_CHKNOPASS))
- continue;
+ if (md->spawn) { //Respawn data
+ md->bl.m = md->spawn->m;
- //Avoid spawning on the view-range of players. [Skotlex]
- if (battle_config.no_spawn_on_player &&
- !(md->spawndelay1 == -1 && md->spawndelay2 == -1) &&
- c++ < battle_config.no_spawn_on_player &&
- map_foreachinarea(mob_count_sub, md->m,
- x-AREA_SIZE, y-AREA_SIZE, x+AREA_SIZE, y+AREA_SIZE, BL_PC)
- )
- continue;
- //Found a spot.
- break;
- }
+ if ((md->spawn->x == 0 && md->spawn->y == 0) || md->spawn->xs || md->spawn->ys)
+ { //Monster can be spawned on an area.
+ int x, y;
+ while (i < 50) {
+ if (md->spawn->x == 0 && md->spawn->y == 0) {
+ x = rand()%(map[md->bl.m].xs-2)+1;
+ y = rand()%(map[md->bl.m].ys-2)+1;
+ } else {
+ x = md->spawn->x+rand()%(md->spawn->xs+1)-md->spawn->xs/2;
+ y = md->spawn->y+rand()%(md->spawn->ys+1)-md->spawn->ys/2;
+ }
+ i++;
+ if (map_getcell(md->bl.m,x,y,CELL_CHKNOPASS))
+ continue;
- if (i >= 50) {
- if (md->spawndelay1 != -1 || md->spawndelay2 == -1)
- // retry again later
- add_timer(tick+5000,mob_delayspawn,id,0);
- return 1;
+ //Avoid spawning on the view-range of players. [Skotlex]
+ if (battle_config.no_spawn_on_player &&
+ c++ < battle_config.no_spawn_on_player &&
+ map_foreachinarea(mob_count_sub, md->bl.m,
+ x-AREA_SIZE, y-AREA_SIZE, x+AREA_SIZE, y+AREA_SIZE, BL_PC)
+ )
+ continue;
+ //Found a spot.
+ break;
+ }
+ if (i >= 50) {
+ // retry again later
+ add_timer(tick+5000,mob_delayspawn,md->bl.id,0);
+ return 1;
+ }
+ md->bl.x = x;
+ md->bl.y = y;
+ } else {
+ md->bl.x = md->spawn->x;
+ md->bl.y = md->spawn->y;
+ }
}
-
- md->to_x = md->bl.x = x;
- md->to_y = md->bl.y = y;
- md->dir = 0;
- md->target_dir = 0;
-
memset(&md->state, 0, sizeof(md->state));
+
md->attacked_id = 0;
+ md->attacked_players = 0;
md->attacked_count = 0;
md->target_id = 0;
md->mode = 0;
md->move_fail_count = 0;
- if (!md->speed)
- md->speed = md->db->speed;
md->def_ele = md->db->element;
if (!md->level) // [Valaris]
@@ -1117,14 +726,10 @@ int mob_spawn (int id)
md->master_id = 0;
md->master_dist = 0;
- md->state.state = MS_IDLE;
md->state.skillstate = MSS_IDLE;
- md->timer = -1;
- md->last_thinktime = tick;
- md->next_walktime = tick+rand()%50+5000;
- md->attackabletime = tick;
- md->canmove_tick = tick;
+ md->next_walktime = tick+rand()%5000+1000;
md->last_linktime = tick;
+ unit_dataset(&md->bl);
/* Guardians should be spawned using mob_spawn_guardian! [Skotlex]
* and the Emperium is spawned using mob_once_spawn.
@@ -1136,13 +741,8 @@ int mob_spawn (int id)
}
*/
- md->deletetimer = -1;
-
- md->skilltimer = -1;
for (i = 0, c = tick-1000*3600*10; i < MAX_MOBSKILL; i++)
md->skilldelay[i] = c;
- md->skillid = 0;
- md->skilllv = 0;
memset(md->dmglog, 0, sizeof(md->dmglog));
md->tdmg = 0;
@@ -1150,16 +750,6 @@ int mob_spawn (int id)
memset(md->lootitem, 0, sizeof(md->lootitem));
md->lootitem_count = 0;
- for (i = 0; i < MAX_MOBSKILLTIMERSKILL; i++)
- md->skilltimerskill[i].timer = -1;
-
- for (i = 0; i < MAX_STATUSCHANGE; i++) {
- md->sc.data[i].timer = -1;
- md->sc.data[i].val1 = md->sc.data[i].val2 = md->sc.data[i].val3 = md->sc.data[i].val4 = 0;
- }
- md->sc.count = 0;
- md->sc.opt1 = md->sc.opt2 = md->sc.opt3 = md->sc.option = 0;
-
if(md->db->option){ // Added for carts, falcons and pecos for cloned monsters. [Valaris]
if(md->db->option & 0x0008)
md->sc.option |= 0x0008;
@@ -1177,9 +767,6 @@ int mob_spawn (int id)
md->sc.option |= OPTION_RIDING;
}
- memset(md->skillunit, 0, sizeof(md->skillunit));
- memset(md->skillunittick, 0, sizeof(md->skillunittick));
-
md->max_hp = md->db->max_hp;
if(md->special_state.size==1) // change for sized monsters [Valaris]
md->max_hp/=2;
@@ -1197,62 +784,16 @@ int mob_spawn (int id)
}
/*==========================================
- * The stop of MOB's attack
- *------------------------------------------
- */
-int mob_stopattack(struct mob_data *md)
-{
- md->target_id = 0;
- md->state.targettype = NONE_ATTACKABLE;
- md->attacked_id = 0;
- md->attacked_count = 0;
- return 0;
-}
-/*==========================================
- * The stop of MOB's walking
- *------------------------------------------
- */
-int mob_stop_walking(struct mob_data *md,int type)
-{
- nullpo_retr(0, md);
-
- if(md->state.state == MS_WALK || md->state.state == MS_IDLE) {
- int dx=0,dy=0;
-
- md->walkpath.path_len=0;
- if(type&2 && mob_can_move(md)){
- dx=md->to_x-md->bl.x;
- if(dx<0)
- dx=-1;
- else if(dx>0)
- dx=1;
- dy=md->to_y-md->bl.y;
- if(dy<0)
- dy=-1;
- else if(dy>0)
- dy=1;
- }
- md->to_x=md->bl.x+dx;
- md->to_y=md->bl.y+dy;
- if(dx!=0 || dy!=0){
- mob_walktoxy_sub(md);
- return 0;
- }
- mob_changestate(md,MS_IDLE,0);
- }
- if(type&0x01)
- clif_fixmobpos(md);
-
- return 0;
-}
-
-
-/*==========================================
* Determines if the mob can change target. [Skotlex]
*------------------------------------------
*/
static int mob_can_changetarget(struct mob_data* md, struct block_list* target, int mode)
{
+ // if the monster was provoked ignore the above rule [celest]
+ if(md->state.provoke_flag && md->state.provoke_flag != target->id &&
+ !battle_config.mob_ai&4)
+ return 0;
+
switch (md->state.skillstate) {
case MSS_BERSERK: //Only Assist, Angry or Aggressive+CastSensor mobs can change target while attacking.
if (mode&(MD_ASSIST|MD_ANGRY) || (mode&(MD_AGGRESSIVE|MD_CASTSENSOR)) == (MD_AGGRESSIVE|MD_CASTSENSOR))
@@ -1282,20 +823,14 @@ int mob_target(struct mob_data *md,struct block_list *bl,int dist)
nullpo_retr(0, bl);
// Nothing will be carried out if there is no mind of changing TAGE by TAGE ending.
- if((md->target_id > 0 && md->state.targettype == ATTACKABLE) && !mob_can_changetarget(md, bl, status_get_mode(&md->bl)) &&
- // if the monster was provoked ignore the above rule [celest]
- !(md->state.provoke_flag && md->state.provoke_flag == bl->id))
+ if(md->target_id && !mob_can_changetarget(md, bl, status_get_mode(&md->bl)))
return 0;
if(!status_check_skilluse(&md->bl, bl, 0, 0))
return 0;
md->target_id = bl->id; // Since there was no disturbance, it locks on to target.
- if(bl->type == BL_PC || bl->type == BL_MOB)
- md->state.targettype = ATTACKABLE;
- else
- md->state.targettype = NONE_ATTACKABLE;
- if (md->state.provoke_flag)
+ if (md->state.provoke_flag && bl->id != md->state.provoke_flag)
md->state.provoke_flag = 0;
md->min_chase=dist+md->db->range2;
if(md->min_chase>MAX_MINCHASE)
@@ -1335,7 +870,6 @@ static int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap)
) {
(*target) = bl;
md->target_id=bl->id;
- md->state.targettype = ATTACKABLE;
md->state.aggressive = (status_get_mode(&md->bl)&MD_ANGRY)?1:0;
md->min_chase= md->db->range3;
return 1;
@@ -1372,7 +906,6 @@ static int mob_ai_sub_hard_changechase(struct block_list *bl,va_list ap)
) {
(*target) = bl;
md->target_id=bl->id;
- md->state.targettype = ATTACKABLE;
md->state.aggressive = (status_get_mode(&md->bl)&MD_ANGRY)?1:0;
md->min_chase= md->db->range3;
return 1;
@@ -1404,7 +937,6 @@ static int mob_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap)
mob_can_reach(md,bl,dist, MSS_LOOT) && rand()%1000<1000/(++(*itc)))
{ // It is made a probability, such as within the limits PC.
md->target_id=bl->id;
- md->state.targettype = NONE_ATTACKABLE;
md->min_chase=md->db->range3;
md->next_walktime = gettick() + 500; //So that the mob may go after the item inmediately.
}
@@ -1426,7 +958,7 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick)
if (!bl || status_isdead(bl)) { //Žå‚ªŽ€–S‚µ‚Ä‚¢‚é‚©Œ©‚‚©‚ç‚È‚¢
if(md->special_state.ai>0)
- mob_timer_delete(0, 0, md->bl.id, 0);
+ unit_remove_map(&md->bl, 1);
else
mob_damage(NULL,md,md->hp,0);
return 0;
@@ -1437,7 +969,7 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick)
if(bl->m != md->bl.m || md->master_dist > 30)
{ // Since it is not in the same map (or is way to far), just warp it
- mob_warp(md,bl->m,bl->x,bl->y,3);
+ unit_warp(&md->bl,bl->m,bl->x,bl->y,3);
return 0;
}
@@ -1447,15 +979,16 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick)
// Since the master was in near immediately before, teleport is carried out and it pursues.
if(old_dist<10 && md->master_dist>18){
- mob_warp(md,-1,bl->x,bl->y,3);
+ unit_warp(&md->bl,-1,bl->x,bl->y,3);
return 0;
}
// Approach master if within view range, chase back to Master's area also if standing on top of the master.
- if(md->master_dist<md->db->range3 && (md->master_dist>MOB_SLAVEDISTANCE || md->master_dist == 0) &&
- mob_can_move(md) && md->state.state == MS_IDLE)
+ if(md->master_dist<md->db->range3 &&
+ (md->master_dist>MOB_SLAVEDISTANCE || md->master_dist == 0) &&
+ unit_can_move(&md->bl))
{
- int i=0,dx,dy,ret;
+ int i=0,dx,dy;
do {
if(i<=5){
dx=bl->x - md->bl.x;
@@ -1467,66 +1000,44 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick)
else if(dy>0) dy-=rand()%MOB_SLAVEDISTANCE +1;
}else{
- ret = MOB_SLAVEDISTANCE*2+1;
- dx=bl->x - md->bl.x + rand()%ret - MOB_SLAVEDISTANCE;
- dy=bl->y - md->bl.y + rand()%ret - MOB_SLAVEDISTANCE;
+ old_dist = MOB_SLAVEDISTANCE*2+1;
+ dx=bl->x - md->bl.x + rand()%old_dist - MOB_SLAVEDISTANCE;
+ dy=bl->y - md->bl.y + rand()%old_dist - MOB_SLAVEDISTANCE;
}
-
- ret=mob_walktoxy(md,md->bl.x+dx,md->bl.y+dy,0);
- i++;
- } while(ret && i<10);
+ } while(!unit_walktoxy(&md->bl,md->bl.x+dx,md->bl.y+dy,0)&& ++i<10);
}
} else if (bl->m != md->bl.m && map_flag_gvg(md->bl.m)) {
//Delete the summoned mob if it's in a gvg ground and the master is elsewhere. [Skotlex]
if(md->special_state.ai>0)
- mob_timer_delete(0, 0, md->bl.id, 0);
+ unit_remove_map(&md->bl, 1);
else
mob_damage(NULL,md,md->hp,0);
return 0;
}
//Avoid attempting to lock the master's target too often to avoid unnecessary overload. [Skotlex]
- if (DIFF_TICK(md->last_linktime, tick) < MIN_MOBLINKTIME && (!md->target_id || md->state.targettype == NONE_ATTACKABLE)) {
+ if (DIFF_TICK(md->last_linktime, tick) < MIN_MOBLINKTIME && !md->target_id) {
+ struct unit_data *ud = unit_bl2ud(bl);
md->last_linktime = tick;
- switch (bl->type) {
- case BL_MOB:
- {
- struct mob_data *mmd= (struct mob_data*)bl;
- struct block_list *tbl;
- if(mmd->target_id>0 && mmd->state.targettype == ATTACKABLE &&
- (tbl=map_id2bl(mmd->target_id)) && status_check_skilluse(&md->bl, tbl, 0, 0)
- ) {
- md->target_id=tbl->id;
- md->state.targettype = ATTACKABLE;
- md->state.aggressive = (status_get_mode(&md->bl)&MD_ANGRY)?1:0;
- md->min_chase=md->db->range2+distance_bl(&md->bl, tbl);
- if(md->min_chase>MAX_MINCHASE)
- md->min_chase=MAX_MINCHASE;
- }
- }
- break;
- case BL_PC:
- {
- struct map_session_data *msd = (struct map_session_data*)bl;
- struct block_list *tbl = NULL;
- if(msd->attacktarget)
- tbl = map_id2bl(msd->attacktarget);
- else if (msd->skilltarget) {
- tbl = map_id2bl(msd->skilltarget);
- if (tbl && battle_check_target(&md->bl, tbl, BCT_ENEMY) <= 0)
- tbl = NULL; //Required check as skilltarget is not always an enemy. [Skotlex]
- }
- if(tbl && status_check_skilluse(&md->bl, tbl, 0, 0)) {
- md->target_id=tbl->id;
- md->state.targettype = ATTACKABLE;
- md->state.aggressive = (status_get_mode(&md->bl)&MD_ANGRY)?1:0;
- md->min_chase=md->db->range2+distance_bl(&md->bl, tbl);
- if(md->min_chase>MAX_MINCHASE)
- md->min_chase=MAX_MINCHASE;
- }
- }
- break;
- }
+
+ if (ud) {
+ struct block_list *tbl=NULL;
+ if (ud->attacktarget && ud->attacktimer != -1)
+ tbl=map_id2bl(ud->attacktarget);
+ else if (ud->skilltarget) {
+ tbl = map_id2bl(ud->skilltarget);
+ //Required check as skilltarget is not always an enemy. [Skotlex]
+ if (tbl && battle_check_target(&md->bl, tbl, BCT_ENEMY) <= 0)
+ tbl = NULL;
+ }
+ if (tbl && status_check_skilluse(&md->bl, tbl, 0, 0)) {
+ md->target_id=tbl->id;
+ md->state.aggressive = (status_get_mode(&md->bl)&MD_ANGRY)?1:0;
+ md->min_chase=md->db->range2+distance_bl(&md->bl, tbl);
+ if(md->min_chase>MAX_MINCHASE)
+ md->min_chase=MAX_MINCHASE;
+ }
+ }
}
return 0;
}
@@ -1540,9 +1051,9 @@ int mob_unlocktarget(struct mob_data *md,int tick)
nullpo_retr(0, md);
md->target_id=0;
- md->state.targettype = NONE_ATTACKABLE;
md->state.skillstate=MSS_IDLE;
md->next_walktime=tick+rand()%3000+3000;
+ mob_stop_attack(md);
return 0;
}
/*==========================================
@@ -1559,38 +1070,30 @@ int mob_randomwalk(struct mob_data *md,int tick)
speed=status_get_speed(&md->bl);
if(DIFF_TICK(md->next_walktime,tick)<0){
int i,x,y,c,d=12-md->move_fail_count;
- int mask[8][2] = {{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1}};
if(d<5) d=5;
for(i=0;i<retrycount;i++){ // Search of a movable place
int r=rand();
x=r%(d*2+1)-d;
y=r/(d*2+1)%(d*2+1)-d;
- if (md->target_dir){
- if (x<0) x=0-x;
- if (y<0) y=0-y;
- x *= mask[md->target_dir-1][0];
- y *= mask[md->target_dir-1][1];
- }
x+=md->bl.x;
y+=md->bl.y;
- if((map_getcell(md->bl.m,x,y,CELL_CHKPASS)) && mob_walktoxy(md,x,y,1)==0){
+ if((map_getcell(md->bl.m,x,y,CELL_CHKPASS)) && unit_walktoxy(&md->bl,x,y,1)){
md->move_fail_count=0;
break;
}
if(i+1>=retrycount){
md->move_fail_count++;
- md->target_dir = 0;
if(md->move_fail_count>1000){
if(battle_config.error_log)
ShowWarning("MOB cant move. random spawn %d, class = %d\n",md->bl.id,md->class_);
md->move_fail_count=0;
- mob_spawn(md->bl.id);
+ mob_spawn(md);
}
}
}
- for(i=c=0;i<md->walkpath.path_len;i++){ // The next walk start time is calculated.
- if(md->walkpath.path[i]&1)
+ for(i=c=0;i<md->ud.walkpath.path_len;i++){ // The next walk start time is calculated.
+ if(md->ud.walkpath.path[i]&1)
c+=speed*14/10;
else
c+=speed;
@@ -1612,48 +1115,47 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
struct block_list *tbl = NULL, *abl = NULL;
unsigned int tick;
int i, j, dx, dy, dist;
- int attack_type = 0;
int mode;
- int search_size = AREA_SIZE*2;
- int blind_flag = 0;
-
- nullpo_retr(0, bl);
- nullpo_retr(0, ap);
+ int search_size;
+ int view_range, can_move;
md = (struct mob_data*)bl;
tick = va_arg(ap, unsigned int);
- if(md->bl.prev == NULL || md->state.state == MS_DEAD)
+ if(md->bl.prev == NULL || md->hp <= 0)
return 1;
if (DIFF_TICK(tick, md->last_thinktime) < MIN_MOBTHINKTIME)
return 0;
md->last_thinktime = tick;
- if (md->skilltimer != -1){ // Casting skill, or has died
- if (DIFF_TICK (tick, md->next_walktime) > MIN_MOBTHINKTIME)
- md->next_walktime = tick;
+ if (md->ud.skilltimer != -1)
return 0;
- }
+
+ if( md->ud.walktimer != -1 && md->ud.walkpath.path_pos <= 3)
+ return 0; //Prevent ai when it just started walking.
// Abnormalities
- if((md->sc.opt1 > 0 && md->sc.opt1 != OPT1_STONEWAIT) || md->state.state == MS_DELAY || md->sc.data[SC_BLADESTOP].timer != -1)
+ if((md->sc.opt1 > 0 && md->sc.opt1 != OPT1_STONEWAIT) || md->sc.data[SC_BLADESTOP].timer != -1)
return 0;
if (md->sc.count && md->sc.data[SC_BLIND].timer != -1)
- blind_flag = 1;
-
+ view_range = 1;
+ else
+ view_range = md->db->range2;
mode = status_get_mode(&md->bl);
+ can_move = (mode&MD_CANMOVE) && unit_can_move(&md->bl);
if (md->target_id)
{ //Check validity of current target. [Skotlex]
tbl = map_id2bl(md->target_id);
- if (!tbl || tbl->m != md->bl.m || !status_check_skilluse(&md->bl, tbl, 0, 0) || (
+ if (!tbl || tbl->m != md->bl.m ||
+ (md->ud.attacktimer == -1 && !status_check_skilluse(&md->bl, tbl, 0, 0)) || (
tbl->type == BL_PC && !(mode&MD_BOSS) &&
((struct map_session_data*)tbl)->state.gangsterparadise
)) { //Unlock current target.
- if (md->state.state == MS_WALK && (battle_config.mob_ai&8 || !tbl)) //Inmediately stop chasing.
- mob_stop_walking(md, 2);
+ if (md->ud.walktimer != -1 && (battle_config.mob_ai&8 || !tbl)) //Inmediately stop chasing.
+ mob_stop_walking(md,2);
mob_unlocktarget(md, tick-(battle_config.mob_ai&8?3000:0)); //Imediately do random walk.
tbl = NULL;
}
@@ -1675,28 +1177,23 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
)
) { //Can't attack back
if (md->attacked_count++ > 3) {
- if (mobskill_use(md, tick, MSC_RUDEATTACKED) == 0 &&
- mode&MD_CANMOVE && mob_can_move(md))
+ if (mobskill_use(md, tick, MSC_RUDEATTACKED) == 0 && can_move)
{
int dist = rand() % 10 + 1;//Œã‘Þ‚·‚é‹——£
int dir = map_calc_dir(abl, bl->x, bl->y);
int mask[8][2] = {{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1}};
- mob_walktoxy(md, md->bl.x + dist * mask[dir][0], md->bl.y + dist * mask[dir][1], 0);
- md->next_walktime = tick + 500;
+ unit_walktoxy(&md->bl, md->bl.x + dist * mask[dir][0], md->bl.y + dist * mask[dir][1], 0);
}
}
} else if (!(battle_config.mob_ai&2) && !status_check_skilluse(bl, abl, 0, 0)) {
//Can't attack back, but didn't invoke a rude attacked skill...
md->attacked_id = 0; //Simply unlock, shouldn't attempt to run away when in dumb_ai mode.
- } else if (blind_flag && dist > 2 && DIFF_TICK(tick,md->next_walktime) < 0) { //Blinded, but can reach
- if (!md->target_id)
- { //Attempt to follow new target
- if (mode&MD_CANMOVE && mob_can_move(md)) { // why is it moving to the target when the mob can't see the player? o.o
- dx = abl->x - md->bl.x;
- dy = abl->y - md->bl.y;
- md->next_walktime = tick + 1000;
- mob_walktoxy(md, md->bl.x+dx, md->bl.y+dy, 0);
- }
+ } else if (dist > view_range) { //Out of view range, but can reach
+ //Attempt to follow new target
+ if (!md->target_id && can_move) { // why is it moving to the target when the mob can't see the player? o.o
+ dx = abl->x - md->bl.x -1;
+ dy = abl->y - md->bl.y -1;
+ unit_walktoxy(&md->bl, md->bl.x+dx, md->bl.y+dy, 0);
}
} else { //Attackable
if (!tbl || dist < md->db->range || !check_distance_bl(&md->bl, tbl, dist)
@@ -1704,9 +1201,7 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
{ //Change if the new target is closer than the actual one
//or if the previous target is not attacking the mob. [Skotlex]
md->target_id = md->attacked_id; // set target
- md->state.targettype = ATTACKABLE;
md->state.aggressive = 0; //Retaliating.
- attack_type = 1;
md->attacked_count = 0;
md->min_chase = dist+md->db->range2;
if(md->min_chase>MAX_MINCHASE)
@@ -1716,12 +1211,17 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
}
}
}
+
if (md->attacked_id) {
if (md->state.aggressive && md->attacked_id == md->target_id)
md->state.aggressive = 0; //No longer aggressive, change to retaliate AI.
+ md->attacked_players = 0;
md->attacked_id = 0; //Clear it since it's been checked for already.
}
+ if (md->ud.attacktimer != -1 && tbl && md->ud.attacktarget == tbl->id)
+ return 0; //Already attacking the current target.
+
// Processing of slave monster, is it needed when there's a target to deal with?
if (md->master_id > 0 && !tbl)
mob_ai_sub_hard_slavemob(md, tick);
@@ -1730,23 +1230,18 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
if ((mode&MD_AGGRESSIVE && battle_config.monster_active_enable && !tbl) ||
(mode&MD_ANGRY && md->state.skillstate == MSS_FOLLOW)
) {
- search_size = (blind_flag) ? 3 : md->db->range2;
map_foreachinrange (mob_ai_sub_hard_activesearch, &md->bl,
- search_size, md->special_state.ai?BL_CHAR:BL_PC, md, &tbl);
+ view_range, md->special_state.ai?BL_CHAR:BL_PC, md, &tbl);
} else if (mode&MD_CHANGECHASE && (md->state.skillstate == MSS_RUSH || md->state.skillstate == MSS_FOLLOW)) {
- search_size = (blind_flag && md->db->range>3) ? 3 : md->db->range;
+ search_size = view_range<md->db->range ? view_range:md->db->range;
map_foreachinrange (mob_ai_sub_hard_changechase, &md->bl,
- search_size, md->special_state.ai?BL_CHAR:BL_PC, md, &tbl);
- }
-
- // Scan area for items to loot, avoid trying to loot of the mob is full and can't consume the items.
- if (!md->target_id && mode&MD_LOOTER && md->lootitem &&
+ search_size, (md->special_state.ai?BL_CHAR:BL_PC), md, &tbl);
+ } else if (!tbl && mode&MD_LOOTER && md->lootitem &&
(md->lootitem_count < LOOTITEM_SIZE || battle_config.monster_loot_type != 1))
- {
+ { // Scan area for items to loot, avoid trying to loot of the mob is full and can't consume the items.
i = 0;
- search_size = (blind_flag) ? 3 : md->db->range2;
map_foreachinrange (mob_ai_sub_hard_lootsearch, &md->bl,
- search_size, BL_ITEM, md, &i);
+ view_range, BL_ITEM, md, &i);
}
if (tbl)
@@ -1754,42 +1249,39 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
if (tbl->type != BL_ITEM)
{ //Attempt to attack.
//At this point we know the target is attackable, we just gotta check if the range matches.
- if (blind_flag && DIFF_TICK(tick,md->next_walktime) < 0 && !check_distance_bl(&md->bl, tbl, 1))
+ if (!check_distance_bl(&md->bl, tbl, view_range))
{ //Run towards the enemy when out of range?
- md->target_id = 0;
- md->state.targettype = NONE_ATTACKABLE;
- if (!(mode & MD_CANMOVE) || !mob_can_move(md))
+ if (!can_move) {
+ mob_unlocktarget(md, tick);
return 0;
- dx = tbl->x - md->bl.x;
- dy = tbl->y - md->bl.y;
- md->next_walktime = tick + 1000;
- mob_walktoxy(md, md->bl.x+dx, md->bl.y+dy, 0);
+ }
+ dx = tbl->x - md->bl.x -1;
+ dy = tbl->y - md->bl.y -1;
+ unit_walktoxy(&md->bl, md->bl.x+dx, md->bl.y+dy, 0);
return 0;
}
if (!battle_check_range (&md->bl, tbl, md->db->range))
{ //Out of range...
+ mob_stop_attack(md);
if (!(mode&MD_CANMOVE))
{ //Can't chase. Attempt to use a ranged skill at least?
if (mobskill_use(md, tick, MSC_LONGRANGEATTACKED) == 0)
md->attacked_count++; //Increase rude-attacked count as it can't attack back.
-
mob_unlocktarget(md,tick);
return 0;
}
- if (!mob_can_move(md)) //Wait until you can move?
+ if (!can_move) //Wait until you can move?
return 0;
//Follow up
md->state.skillstate = md->state.aggressive?MSS_FOLLOW:MSS_RUSH;
mobskill_use (md, tick, -1);
- if (md->timer != -1 && md->state.state != MS_ATTACK &&
- (DIFF_TICK (md->next_walktime, tick) < 0 ||
- !(battle_config.mob_ai&1) ||
- check_distance_blxy(tbl, md->to_x, md->to_y, md->db->range)) //Current target tile is still within attack range.
+ if (md->ud.walktimer != -1 &&
+ (!battle_config.mob_ai&1 ||
+ check_distance_blxy(tbl, md->ud.to_x, md->ud.to_y, md->db->range)) //Current target tile is still within attack range.
) {
return 0; //No need to follow, already doing it?
}
- search_size = blind_flag?3: md->min_chase;
- if (!mob_can_reach(md, tbl, search_size, MSS_RUSH))
+ if (!mob_can_reach(md, tbl, md->min_chase, MSS_RUSH))
{ //Can't reach
mob_unlocktarget(md,tick);
return 0;
@@ -1802,7 +1294,7 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
else if (dx > 0) dx=1;
if (dy < 0) dy=-1;
else if (dy > 0) dy=1;
- if(mob_walktoxy(md, tbl->x -dx, tbl->y -dy, 0)) {
+ if(!unit_walktoxy(&md->bl, tbl->x -dx, tbl->y -dy, 0)) {
j = (dy+1) + 3*(dx+1);
for (i = j+1; i%9 != j; i++) {
dx = -1+(i%9)/3;
@@ -1811,7 +1303,7 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
if (map_getcell(md->bl.m, tbl->x-dx, tbl->y-dy, CELL_CHKSTACK))
continue;
#endif
- if (!mob_walktoxy(md, tbl->x-dx, tbl->y-dy, 0))
+ if (unit_walktoxy(&md->bl, tbl->x-dx, tbl->y-dy, 0))
break;
}
#ifdef CELL_NOSTACK
@@ -1822,8 +1314,8 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
dy = 2*(-1+(i%3));
if (map_getcell(md->bl.m, tbl->x-dx, tbl->y-dy, CELL_CHKSTACK))
continue;
- if (!mob_walktoxy(md, tbl->x-dx, tbl->y-dy, 0)) {
- md->next_walktime = tick + 1000;
+ if (unit_walktoxy(md, tbl->x-dx, tbl->y-dy, 0)) {
+ unit_set_walkdelay(&md->bl, tick, 1000, 1);
break;
}
}
@@ -1832,18 +1324,17 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
{
//On stacked mode, it is much more likely that you just can't reach the target. So unlock it
mob_unlocktarget(md, tick);
- md->next_walktime = tick + 1000;
+ unit_set_walkdelay(&md->bl, tick, 1000, 1);
return 0;
}
#else
if (i%9 == j)
- { //Failed? Try going away from the target before retrying.
+ { //Failed? Try going to the other side of the target before retrying.
if (dx < 0) dx = 2;
else if (dx > 0) dx = -2;
if (dy < 0) dy = 2;
else if (dy > 0) dy = -2;
- mob_walktoxy (md, tbl->x+dx, tbl->y+dy, 0);
- md->next_walktime = tick + 500;
+ unit_walktoxy (&md->bl, tbl->x+dx, tbl->y+dy, 0);
}
#endif
}
@@ -1851,51 +1342,44 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
}
//Target within range, engage
md->state.skillstate = md->state.aggressive?MSS_ANGRY:MSS_BERSERK;
- if (md->state.state == MS_WALK)
- mob_stop_walking (md, 1);
- else if (md->state.state == MS_ATTACK)
- return 0; //Ah, we are already attacking.
- mob_changestate(md, MS_ATTACK, attack_type);
+ mob_stop_walking(md,1);
+ unit_attack(&md->bl,tbl->id,1);
return 0;
} else { //Target is BL_ITEM, attempt loot.
struct flooritem_data *fitem;
- if ((dist = distance_bl(&md->bl, tbl)) >= md->min_chase || (blind_flag && dist >= 4) || md->lootitem == NULL)
+ if (md->lootitem == NULL)
{ //Can't loot...
mob_unlocktarget (md, tick);
- if (md->state.state == MS_WALK)
- mob_stop_walking(md,0);
+ mob_stop_walking(md,0);
return 0;
}
- if (dist)
+ if (!check_distance_bl(&md->bl, tbl, 1))
{ //Still not within loot range.
- if (!(mode & MD_CANMOVE))
+ if (!(mode&MD_CANMOVE))
{ //A looter that can't move? Real smart.
mob_unlocktarget(md,tick);
return 0;
}
- if (!mob_can_move(md)) // “®‚¯‚È‚¢ó‘Ô‚É‚ ‚é
+ if (!can_move) // “®‚¯‚È‚¢ó‘Ô‚É‚ ‚é
return 0;
md->state.skillstate = MSS_LOOT; // ƒ‹[ƒgŽžƒXƒLƒ‹Žg—p
mobskill_use(md, tick, -1);
- if (md->timer != -1 && md->state.state != MS_ATTACK &&
- (DIFF_TICK(md->next_walktime,tick) < 0 ||
- check_distance_blxy(tbl, md->to_x, md->to_y, 0)))
+ if (md->ud.walktimer != -1 &&
+ check_distance_blxy(tbl, md->ud.to_x, md->ud.to_y, 0))
{ //Already on the way to looting.
return 0;
}
- md->next_walktime = tick + 500;
dx = tbl->x - md->bl.x;
dy = tbl->y - md->bl.y;
- if (mob_walktoxy(md, md->bl.x+dx, md->bl.y+dy, 0))
+ if (!unit_walktoxy(&md->bl, md->bl.x+dx, md->bl.y+dy, 0))
mob_unlocktarget(md, tick); //Can't loot...
return 0;
}
//Within looting range.
- if (md->state.state == MS_ATTACK)
+ if (md->ud.attacktimer != -1)
return 0; //Busy attacking?
- if (md->state.state == MS_WALK)
- mob_stop_walking(md,0);
+ mob_stop_walking(md,0);
fitem = (struct flooritem_data *)tbl;
if (md->lootitem_count < LOOTITEM_SIZE) {
@@ -1920,24 +1404,22 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
}
// When there's no target, it is idling.
+ md->state.skillstate = MSS_IDLE;
if (mobskill_use(md, tick, -1))
return 0;
// Nothing else to do... except random walking.
// Slaves do not random walk! [Skotlex]
- if (mode&MD_CANMOVE && mob_can_move(md) && !md->master_id)
+ if (can_move && !md->master_id)
{
if (DIFF_TICK(md->next_walktime, tick) > 7000 &&
- (md->walkpath.path_len == 0 || md->walkpath.path_pos >= md->walkpath.path_len))
+ (md->ud.walkpath.path_len == 0 || md->ud.walkpath.path_pos >= md->ud.walkpath.path_len))
md->next_walktime = tick + 3000 + rand() % 2000;
// Random movement
if (mob_randomwalk(md,tick))
return 0;
}
- // Since he has finished walking, it stands by.
- if (md->walkpath.path_len == 0 || md->walkpath.path_pos >= md->walkpath.path_len)
- md->state.skillstate = MSS_IDLE;
return 0;
}
@@ -1948,9 +1430,6 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
static int mob_ai_sub_foreachclient(struct map_session_data *sd,va_list ap)
{
unsigned int tick;
- nullpo_retr(0, sd);
- nullpo_retr(0, ap);
-
tick=va_arg(ap,unsigned int);
map_foreachinrange(mob_ai_sub_hard,&sd->bl, AREA_SIZE*2, BL_MOB,tick);
@@ -1983,26 +1462,21 @@ static int mob_ai_sub_lazy(DBKey key,void * data,va_list app)
if(DIFF_TICK(tick,md->last_thinktime)<MIN_MOBTHINKTIME*10)
return 0;
+
md->last_thinktime=tick;
- if (md->bl.prev==NULL || md->state.state == MS_DEAD)
+ if (md->bl.prev==NULL || md->hp <= 0)
return 1;
- if(md->skilltimer!=-1){
- if(DIFF_TICK(tick,md->next_walktime)>MIN_MOBTHINKTIME*10)
- md->next_walktime=tick;
- return 0;
- }
-
// Žæ‚芪‚«ƒ‚ƒ“ƒXƒ^[‚̈—iŒÄ‚Ñ–ß‚µ‚³‚ꂽŽžj
- if (md->master_id > 0) {
+ if (md->master_id) {
mob_ai_sub_hard_slavemob (md,tick);
return 0;
}
mode = status_get_mode(&md->bl);
if(DIFF_TICK(md->next_walktime,tick)<0 &&
- (mode&MD_CANMOVE) && mob_can_move(md) ){
+ (mode&MD_CANMOVE) && unit_can_move(&md->bl) ){
if( map[md->bl.m].users>0 ){
// Since PC is in the same map, somewhat better negligent processing is carried out.
@@ -2010,19 +1484,21 @@ static int mob_ai_sub_lazy(DBKey key,void * data,va_list app)
// It sometimes moves.
if(rand()%1000<MOB_LAZYMOVEPERC)
mob_randomwalk(md,tick);
- // MOB which is not not the summons MOB but BOSS, either sometimes reboils.
- else if( rand()%1000<MOB_LAZYWARPPERC && md->x0<=0 && md->master_id!=0 &&
- !(mode&MD_BOSS))
- mob_spawn(md->bl.id);
else if(rand()%1000<MOB_LAZYSKILLPERC) //Chance to do a mob's idle skill.
mobskill_use(md, tick, -1);
+ // MOB which is not not the summons MOB but BOSS, either sometimes reboils.
+ else if( rand()%1000<MOB_LAZYWARPPERC
+ && (md->spawn && !md->spawn->x && !md->spawn->y)
+ && !md->target_id && !(mode&MD_BOSS))
+ mob_spawn(md);
}else{
// Since PC is not even in the same map, suitable processing is carried out even if it takes.
// MOB which is not BOSS which is not Summons MOB, either -- a case -- sometimes -- leaping
- if( rand()%1000<MOB_LAZYWARPPERC && md->x0<=0 && md->master_id!=0 &&
- !(mode&MD_BOSS))
- mob_warp(md,-1,-1,-1,-1);
+ if( rand()%1000<MOB_LAZYWARPPERC
+ && (md->spawn && !md->spawn->x && !md->spawn->y)
+ && !(mode&MD_BOSS))
+ unit_warp(&md->bl,-1,-1,-1,0);
}
md->next_walktime = tick+rand()%10000+5000;
@@ -2154,59 +1630,14 @@ static void mob_item_drop(struct mob_data *md, unsigned int tick, struct delay_i
add_timer(tick, mob_delay_item_drop, (int)ditem, 0);
}
-/*==========================================
- * mob data is erased.
- *------------------------------------------
- */
-void mob_unload(struct mob_data *md)
-{
- nullpo_retv(md);
- mob_remove_map(md, 0);
- map_deliddb(&md->bl);
- map_freeblock((struct block_list*)md);
-}
-
-int mob_remove_map(struct mob_data *md, int type)
-{
- nullpo_retr(1, md);
-
- if(md->bl.prev == NULL)
- return 1;
- mob_changestate(md,MS_DEAD,0);
- clif_clearchar_area(&md->bl,type);
- map_delblock(&md->bl);
- if (md->lootitem){
- aFree(md->lootitem);
- md->lootitem = NULL;
- }
- if (md->guardian_data)
- {
- aFree(md->guardian_data);
- md->guardian_data = NULL;
- }
- return 0;
-}
-int mob_delete(struct mob_data *md)
-{
- nullpo_retr(1, md);
-
- mob_remove_map(md, 1);
- if(pcdb_checkid(mob_get_viewclass(md->class_))) //Player mobs are not removed automatically by the client.
- clif_clearchar_delay(gettick()+3000,&md->bl,0);
- if(mob_is_clone(md->class_))
- mob_clone_delete(md->class_);
- mob_deleteslave(md);
- mob_setdelayspawn(md->bl.id);
- return 0;
-}
int mob_timer_delete(int tid, unsigned int tick, int id, int data)
{
- struct mob_data *md=(struct mob_data *)map_id2bl(id);
- nullpo_retr(0, md);
-
+ struct block_list *bl=map_id2bl(id);
+ nullpo_retr(0, bl);
+ if (bl->type != BL_MOB)
+ return 0; //??
//for Alchemist CANNIBALIZE [Lupus]
- mob_remove_map(md, 3);
- mob_setdelayspawn(md->bl.id);
+ unit_remove_map(bl, 3);
return 0;
}
@@ -2246,18 +1677,14 @@ int mob_respawn(int tid, unsigned int tick, int id,int data )
if (!md || md->bl.type != BL_MOB)
return 0;
//Mob must be dead and not in a map to respawn!
- if (md->bl.prev != NULL || md->state.state != MS_DEAD)
+ if (md->bl.prev != NULL || md->hp)
return 0;
- md->state.state = MS_IDLE;
md->state.skillstate = MSS_IDLE;
- md->timer = -1;
md->last_thinktime = tick;
md->next_walktime = tick+rand()%50+5000;
- md->attackabletime = tick;
- md->canmove_tick = tick;
md->last_linktime = tick;
-
+ unit_dataset(&md->bl);
map_addblock(&md->bl);
mob_heal(md,data*status_get_max_hp(&md->bl)/100);
skill_unit_move(&md->bl,tick,1);
@@ -2317,14 +1744,9 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
return 0;
}
- if(md->state.state==MS_DEAD || md->hp<=0) {
- if(md->bl.prev != NULL) {
- mob_changestate(md,MS_DEAD,0);
- mobskill_use(md,tick,-1); // It is skill at the time of death.
- clif_clearchar_area(&md->bl,1);
- map_delblock(&md->bl);
- mob_setdelayspawn(md->bl.id);
- }
+ if(md->hp<=0) {
+ if(md->bl.prev != NULL)
+ unit_remove_map(&md->bl, 0);
return 0;
}
@@ -2346,7 +1768,7 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
switch (src->type) {
case BL_PC:
id = sd->status.char_id;
- if(md->attacked_id <= 0)
+ if(rand()%1000 < 1000/++(md->attacked_players))
md->attacked_id = sd->bl.id;
break;
case BL_PET:
@@ -2357,7 +1779,7 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
damage=(damage*battle_config.pet_attack_exp_rate)/100; //Modify logged damage accordingly.
}
//Let mobs retaliate against the pet's master [Skotlex]
- if(md->attacked_id <= 0)
+ if(rand()%1000 < 1000/++(md->attacked_players))
md->attacked_id = pd->msd->bl.id;
break;
}
@@ -2368,7 +1790,7 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
struct map_session_data* msd = map_id2sd(md2->master_id);
if (msd) id = msd->status.char_id;
}
- if(md->attacked_id <= 0)
+ if(rand()%1000 < 1000/++(md->attacked_players))
{ //Let players decide whether to retaliate versus the master or the mob. [Skotlex]
if (md2->master_id && battle_config.retaliate_to_master)
md->attacked_id = md2->master_id;
@@ -2414,7 +1836,6 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
src && md->master_id == src->id)
{
md->state.alchemist = 1;
- md->target_dir = map_calc_dir(src,md->bl.x,md->bl.y)+1;
mobskill_use(md, tick, MSC_ALCHEMIST);
}
@@ -2438,15 +1859,15 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
if (md->sc.data[SC_KAIZEL].timer != -1) {
//Revive in a bit.
max_hp = 10*md->sc.data[SC_KAIZEL].val1; //% of life to rebirth with
- mob_changestate(md,MS_DEAD,0);
clif_clearchar_area(&md->bl,1);
+ mob_unlocktarget(md,tick);
+ mob_stop_walking(md, 0);
map_delblock(&md->bl);
add_timer(gettick()+3000, mob_respawn, md->bl.id, max_hp);
return damage;
}
map_freeblock_lock();
- mob_changestate(md,MS_DEAD,0);
memset(tmpsd,0,sizeof(tmpsd));
memset(pt,0,sizeof(pt));
@@ -2461,7 +1882,7 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
int sp = 0, hp = 0;
if (sd->state.attack_type == BF_MAGIC)
base_drop_delay = 500;
- if (sd->state.attack_type == BF_MAGIC && sd->skilltarget == md->bl.id && (i=pc_checkskill(sd,HW_SOULDRAIN))>0)
+ if (sd->state.attack_type == BF_MAGIC && sd->ud.skilltarget == md->bl.id && (i=pc_checkskill(sd,HW_SOULDRAIN))>0)
{ //Soul Drain should only work on targetted spells [Skotlex]
if (pc_issit(sd)) pc_setstand(sd); //Character stuck in attacking animation while 'sitting' fix. [Skotlex]
clif_skill_nodamage(src,&md->bl,HW_SOULDRAIN,i,1);
@@ -2555,14 +1976,13 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
per *= 1.15; // pk_mode additional exp if monster >20 levels [Valaris]
//SG additional exp from Blessings [Komurka] - probably can be optimalized ^^;;
- if (tmpsd[i]->sc.data[SC_MIRACLE].timer!=-1)
+ //
+ if(md->class_ == tmpsd[i]->hate_mob[2] && (battle_config.allow_skill_without_day || is_day_of_star() || tmpsd[i]->sc.data[SC_MIRACLE].timer!=-1))
per += per*20*pc_checkskill(tmpsd[i],SG_STAR_BLESS)/100.;
- else if(md->class_ == tmpsd[i]->hate_mob[0] && (battle_config.allow_skill_without_day || is_day_of_sun()))
- per += per*10*pc_checkskill(tmpsd[i],SG_SUN_BLESS)/100.;
else if(md->class_ == tmpsd[i]->hate_mob[1] && (battle_config.allow_skill_without_day || is_day_of_moon()))
per += per*10*pc_checkskill(tmpsd[i],SG_MOON_BLESS)/100.;
- else if(md->class_ == tmpsd[i]->hate_mob[2] && (battle_config.allow_skill_without_day || is_day_of_star()))
- per += per*20*pc_checkskill(tmpsd[i],SG_STAR_BLESS)/100.;
+ else if(md->class_ == tmpsd[i]->hate_mob[0] && (battle_config.allow_skill_without_day || is_day_of_sun()))
+ per += per*10*pc_checkskill(tmpsd[i],SG_SUN_BLESS)/100.;
if(md->special_state.size==1) // change experience for different sized monsters [Valaris]
per /=2.;
@@ -2596,12 +2016,13 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
else
job_exp = (unsigned int)(job_exp*per);
- if (base_exp < 1) base_exp = 1;
- if (job_exp < 1) job_exp = 1;
-
//mapflags: noexp check [Lorky]
if (map[md->bl.m].flag.nobaseexp == 1) base_exp=0;
+ else if (base_exp < 1) base_exp = 1;
+
if (map[md->bl.m].flag.nojobexp == 1) job_exp=0;
+ else if (job_exp < 1) job_exp = 1;
+
//end added Lorky
if((pid=tmpsd[i]->status.party_id)>0){ // ƒp[ƒeƒB‚É“ü‚Á‚Ä‚¢‚é
int j;
@@ -2869,19 +2290,9 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
}
}
}
-//[lordalfa]
- (battle_config.mob_clear_delay) ? clif_clearchar_delay(tick+battle_config.mob_clear_delay,&md->bl,1) : clif_clearchar_area(&md->bl,1);
-// clif_clearchar_area(&md->bl,1); //eh? Why send the same packet twice? [Skotlex]
if(md->level) md->level=0;
- map_delblock(&md->bl);
- if(pcdb_checkid(mob_get_viewclass(md->class_)))
- clif_clearchar_delay(tick+3000,&md->bl,0);
- if(mob_is_clone(md->class_))
- mob_clone_delete(md->class_);
- mob_deleteslave(md);
- mob_setdelayspawn(md->bl.id);
map_freeblock_unlock();
-
+ unit_remove_map(&md->bl, 1);
return damage;
}
@@ -2910,7 +2321,7 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap)
guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
guild_castledatasave(md->guardian_data->castle->castle_id, 18+md->guardian_data->number,0);
}
- mob_delete(md); //Remove guardian.
+ unit_free(&md->bl); //Remove guardian.
}
return 0;
}
@@ -2922,7 +2333,7 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap)
md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0;
guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
guild_castledatasave(md->guardian_data->castle->castle_id, 18+md->guardian_data->number,0);
- mob_delete(md);
+ unit_free(&md->bl);
return 0;
}
@@ -2988,32 +2399,27 @@ int mob_class_change (struct mob_data *md, int class_)
memcpy(md->name,md->db->jname,NAME_LENGTH-1);
memset(&md->state,0,sizeof(md->state));
md->attacked_id = 0;
+ md->attacked_players = 0;
md->target_id = 0;
md->move_fail_count = 0;
md->speed = md->db->speed;
md->def_ele = md->db->element;
- mob_changestate(md,MS_IDLE,0);
- skill_castcancel(&md->bl,0);
md->state.skillstate = MSS_IDLE;
md->last_thinktime = tick;
md->next_walktime = tick+rand()%50+5000;
- md->attackabletime = tick;
- md->canmove_tick = tick;
md->last_linktime = tick;
-
+ mob_stop_attack(md);
+ mob_stop_walking(md, 0);
+ unit_skillcastcancel(&md->bl, 0);
+ unit_dataset(&md->bl);
for(i=0,c=tick-1000*3600*10;i<MAX_MOBSKILL;i++)
md->skilldelay[i] = c;
- md->skillid=0;
- md->skilllv=0;
if(md->lootitem == NULL && md->db->mode&MD_LOOTER)
md->lootitem=(struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item));
- skill_clear_unitgroup(&md->bl);
- skill_cleartimerskill(&md->bl);
-
clif_clearchar_area(&md->bl,0);
clif_spawnmob(md);
@@ -3074,9 +2480,9 @@ int mob_warpslave_sub(struct block_list *bl,va_list ap)
} while (map_getcell(master->m,x,y,CELL_CHKNOPASS) && i<25);
if (i == 100)
- mob_warp(md, master->m, master->x, master->y,2);
+ unit_warp(&md->bl, master->m, master->x, master->y,2);
else
- mob_warp(md, master->m, x, y,2);
+ unit_warp(&md->bl, master->m, x, y,2);
return 1;
}
@@ -3096,96 +2502,6 @@ int mob_warpslave(struct block_list *bl, int range)
}
/*==========================================
- * mobƒ[ƒv
- *------------------------------------------
- */
-int mob_warp(struct mob_data *md,int m,int x,int y,int type)
-{
- int i=0,xs=0,ys=0,bx=x,by=y;
- int tick = gettick();
-
- nullpo_retr(0, md);
-
- if( md->bl.prev==NULL )
- return 0;
-
- if( m<0 ) m=md->bl.m;
-
- if(type >= 0) {
- if(map[md->bl.m].flag.monster_noteleport)
- return 0;
- if(md->sc.count) { //Clear a few status changes (taken directly from pc_setpos). [Skotlex]
- if(md->sc.data[SC_TRICKDEAD].timer != -1)
- status_change_end(&md->bl, SC_TRICKDEAD, -1);
- if(md->sc.data[SC_BLADESTOP].timer!=-1)
- status_change_end(&md->bl,SC_BLADESTOP,-1);
- if(md->sc.data[SC_RUN].timer!=-1)
- status_change_end(&md->bl,SC_RUN,-1);
- if(md->sc.data[SC_DANCING].timer!=-1)
- skill_stop_dancing(&md->bl);
- if (md->sc.data[SC_DEVOTION].timer!=-1)
- status_change_end(&md->bl,SC_DEVOTION,-1);
- if (md->sc.data[SC_CLOSECONFINE].timer!=-1)
- status_change_end(&md->bl,SC_CLOSECONFINE,-1);
- if (md->sc.data[SC_CLOSECONFINE2].timer!=-1)
- status_change_end(&md->bl,SC_CLOSECONFINE2,-1);
- if (md->sc.data[SC_RUN].timer!=-1)
- status_change_end(&md->bl,SC_RUN,-1);
- }
- clif_clearchar_area(&md->bl,type);
- }
- skill_unit_move(&md->bl,tick,4);
- map_delblock(&md->bl);
-
- if(bx>0 && by>0){ // ˆÊ’uŽw’è‚ÌꇎüˆÍ‚XƒZƒ‹‚ð’Tõ
- xs=ys=9;
- }
-
- while( ( x<0 || y<0 || map_getcell(m,x,y,CELL_CHKNOPASS)) && (i++)<1000 ){
- if( xs>0 && ys>0 && i<250 ){ // Žw’èˆÊ’u•t‹ß‚Ì’Tõ
- x=bx+rand()%xs-xs/2;
- y=by+rand()%ys-ys/2;
- }else{ // Š®‘Sƒ‰ƒ“ƒ_ƒ€’Tõ
- x=rand()%(map[m].xs-2)+1;
- y=rand()%(map[m].ys-2)+1;
- }
- }
- md->dir=0;
- if(i<1000){
- md->bl.x=md->to_x=x;
- md->bl.y=md->to_y=y;
- md->bl.m=m;
- }else {
- m=md->bl.m;
- if(battle_config.error_log==1)
- ShowWarning("MOB %d warp failed, class = %d\n",md->bl.id,md->class_);
- }
-
- md->target_id=0; // ƒ^ƒQ‚ð‰ðœ‚·‚é
- md->state.targettype=NONE_ATTACKABLE;
- md->attacked_id=0;
- if (md->master_id)
- md->master_dist = 0; //Assume mob warped to leader. [Skotlex]
- md->state.skillstate=MSS_IDLE;
- mob_changestate(md,MS_IDLE,0);
-
- if(type>0 && i==1000) {
- if(battle_config.battle_log)
- ShowInfo("MOB %d warp to (%d,%d), class = %d\n",md->bl.id,x,y,md->class_);
- }
-
- map_addblock(&md->bl);
- skill_unit_move(&md->bl,tick,1);
- if(type>0)
- {
- clif_spawnmob(md);
- mob_warpslave(&md->bl,AREA_SIZE);
- }
-
- return 0;
-}
-
-/*==========================================
* ‰æ–Ê“à‚ÌŽæ‚芪‚«‚Ì”ŒvŽZ—p(foreachinarea)
*------------------------------------------
*/
@@ -3216,14 +2532,19 @@ int mob_countslave(struct block_list *bl)
int mob_summonslave(struct mob_data *md2,int *value,int amount,int skill_id)
{
struct mob_data *md;
- int bx,by,m,count = 0,class_,k=0;
+ struct spawn_data data;
+ int bx,by,count = 0,k=0;
nullpo_retr(0, md2);
nullpo_retr(0, value);
+ memset(&data, 0, sizeof(struct spawn_data));
+ data.m = md2->bl.m;
+ data.x = md2->bl.x;
+ data.y = md2->bl.y;
+
bx=md2->bl.x;
by=md2->bl.y;
- m=md2->bl.m;
if(mobdb_checkid(value[0]) == 0)
return 0;
@@ -3236,16 +2557,11 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,int skill_id)
}
for(;k<amount;k++) {
int x=0,y=0,i=0;
- class_ = value[k%count]; //Summon slaves in round-robin fashion. [Skotlex]
-
- if (mobdb_checkid(class_) == 0)
+ data.class_ = value[k%count]; //Summon slaves in round-robin fashion. [Skotlex]
+ if (mobdb_checkid(data.class_) == 0)
continue;
- md=(struct mob_data *)aCalloc(1,sizeof(struct mob_data));
- if(mob_db(class_)->mode&MD_LOOTER)
- md->lootitem=(struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item));
-
- while((x<=0 || y<=0 || map_getcell(m,x,y,CELL_CHKNOPASS)) && (i++)<100){
+ while((x<=0 || y<=0 || map_getcell(data.m,x,y,CELL_CHKNOPASS)) && (i++)<100){
x=rand()%9-4+bx;
y=rand()%9-4+by;
}
@@ -3253,34 +2569,27 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,int skill_id)
x=bx;
y=by;
}
+ data.x = x;
+ data.y = y;
- mob_spawn_dataset(md,"--ja--",class_);
- md->bl.m=m;
- md->bl.x=x;
- md->bl.y=y;
+ strcpy(data.name, "--ja--"); //These two need to be loaded from the db for each slave.
+ data.level = 0;
+ if (!mob_parse_dataset(&data))
+ continue;
+
+ md= mob_spawn_dataset(&data);
- md->m =m;
- md->x0=x;
- md->y0=y;
- md->xs=0;
- md->ys=0;
if (battle_config.slaves_inherit_speed && md2->db->mode&MD_CANMOVE
&& (skill_id != NPC_METAMORPHOSIS && skill_id != NPC_TRANSFORMATION))
md->speed=md2->speed;
md->special_state.cached= battle_config.dynamic_mobs; //[Skotlex]
- md->spawndelay1=-1; // ˆê“x‚̂݃tƒ‰ƒO
- md->spawndelay2=-1; // ˆê“x‚̂݃tƒ‰ƒO
if (!battle_config.monster_class_change_full_recover &&
(skill_id == NPC_TRANSFORMATION || skill_id == NPC_METAMORPHOSIS))
{ //Scale HP
md->hp = (md->max_hp*md2->hp)/md2->max_hp;
}
-
- memset(md->npc_event,0,sizeof(md->npc_event));
- md->bl.type=BL_MOB;
- map_addiddb(&md->bl);
- mob_spawn(md->bl.id);
+ mob_spawn(md);
clif_skill_nodamage(&md->bl,&md->bl,skill_id,amount,1);
if(skill_id == NPC_SUMMONSLAVE)
@@ -3309,359 +2618,6 @@ int mob_skillid2skillidx(int class_,int skillid)
}
-//
-// MOBƒXƒLƒ‹
-//
-
-/*==========================================
- * ƒXƒLƒ‹Žg—pi‰r¥Š®—¹AIDŽw’èj
- *------------------------------------------
- */
-int mobskill_castend_id( int tid, unsigned int tick, int id,int data )
-{
- struct mob_data* md=NULL;
- struct block_list *bl;
- int inf;
-//Code cleanup. Insert any code that should be executed if the skill fails here.
-#define skill_failed(md) { md->skillid = md->skilllv = -1; }
-
- if((md = (struct mob_data*)map_id2bl(id)) == NULL ) //‰r¥‚µ‚½Mob‚ª‚à‚¤‚¢‚È‚¢‚Æ‚¢‚¤‚Ì‚Í—Ç‚­‚ ‚é³íˆ—
- return 0;
-
- if( md->bl.type!=BL_MOB || md->bl.prev==NULL )
- return 0;
-
- if( md->skilltimer != tid ) {
- if (battle_config.error_log)
- ShowError("mobskill_castend_id: Timer mismatch %d!=%d\n", md->skilltimer, tid);
- md->skilltimer = -1;
- return 0;
- }
-
- md->skilltimer=-1;
-
- if((bl = map_id2bl(md->skilltarget)) == NULL || bl->prev==NULL || md->bl.m != bl->m) {
- skill_failed(md);
- return 0;
- }
-
- if(md->skillid != NPC_EMOTION)
- //Set afterskill delay.
- md->last_thinktime=tick + (tid==-1?status_get_adelay(&md->bl):status_get_amotion(&md->bl));
-
- if(md->skillid == RG_BACKSTAP) {
- int dir = map_calc_dir(&md->bl,bl->x,bl->y),t_dir = status_get_dir(bl);
- if(bl->type != BL_SKILL && (check_distance_bl(&md->bl, bl, 0) || map_check_dir(dir,t_dir))) {
- skill_failed(md);
- return 0;
- }
- }
-
- inf = skill_get_inf(md->skillid);
- if((inf&INF_ATTACK_SKILL ||
- (inf&INF_SELF_SKILL && md->bl.id != bl->id && !(skill_get_nk(md->skillid)&NK_NO_DAMAGE)))
- && battle_check_target(&md->bl,bl, BCT_ENEMY)<=0 ) {
- skill_failed(md);
- return 0;
- }
-
- if(tid != -1)
- {
- if (md->skillid == -1 ||!status_check_skilluse(&md->bl, bl, md->skillid, 1)) {
- skill_failed(md);
- return 0;
- }
- if(!check_distance_bl(&md->bl, bl, skill_get_range2(&md->bl, md->skillid,md->skilllv) + battle_config.mob_skill_add_range)) {
- skill_failed(md);
- return 0;
- }
- }
- md->skilldelay[md->skillidx]=tick;
-
- if(battle_config.mob_skill_log)
- ShowInfo("MOB skill castend skill=%d, class = %d\n",md->skillid,md->class_);
-// mob_stop_wShowInfo(md,0);
-
-
- if (skill_get_casttype(md->skillid) == CAST_NODAMAGE)
- skill_castend_nodamage_id(&md->bl,bl,md->skillid,md->skilllv,tick,0);
- else
- skill_castend_damage_id(&md->bl,bl,md->skillid,md->skilllv,tick,0);
-
- if (md->sc.count && md->sc.data[SC_MAGICPOWER].timer != -1 && md->skillid != HW_MAGICPOWER && md->skillid != WZ_WATERBALL)
- status_change_end(&md->bl, SC_MAGICPOWER, -1);
-
- if (md->db->skill[md->skillidx].emotion >= 0)
- clif_emotion(&md->bl, md->db->skill[md->skillidx].emotion);
-
- //TODO: This value is used for the "afterskill" mob condition, what could one do to clean it other than
- //to use a "previous skill" struct variable?
- //md->skillid = md->skilllv = -1; //Clean up skill-data for battle_getcurrentskill references. [Skotlex]
- return 0;
-}
-
-/*==========================================
- * ƒXƒLƒ‹Žg—pi‰r¥Š®—¹Aꊎw’èj
- *------------------------------------------
- */
-int mobskill_castend_pos( int tid, unsigned int tick, int id,int data )
-{
- struct mob_data* md=NULL;
- int maxcount;
-
-//Code cleanup. Insert any code that should be executed if the skill fails here.
-#define skill_failed(md) { md->skillid = md->skilllv = -1; }
-
- nullpo_retr(0, md=(struct mob_data *)map_id2bl(id));
-
- if( md->bl.type!=BL_MOB || md->bl.prev==NULL )
- return 0;
-
- if( md->skilltimer != tid ) {
- if (battle_config.error_log)
- ShowError("mobskill_castend_pos: Timer mismatch %d!=%d\n", md->skilltimer, tid);
- md->skilltimer = -1;
- return 0;
- }
-
- md->skilltimer=-1;
-
- if (tid != -1)
- { //Avoid unnecessary checks for instant-cast skills. [Skotlex]
- if (md->skillid == -1 || !status_check_skilluse(&md->bl, NULL, md->skillid, 1)) {
- skill_failed(md);
- return 0;
- }
- if(!check_distance_blxy(&md->bl, md->skillx, md->skilly, skill_get_range2(&md->bl, md->skillid,md->skilllv) + battle_config.mob_skill_add_range)) {
- skill_failed(md);
- return 0;
- }
- }
-
- if (!battle_config.monster_skill_reiteration &&
- skill_get_unit_flag (md->skillid) & UF_NOREITERATION &&
- skill_check_unit_range (md->bl.m, md->skillx, md->skilly, md->skillid, md->skilllv)) {
- skill_failed(md);
- return 0;
- }
-
- if(battle_config.monster_skill_nofootset &&
- skill_get_unit_flag (md->skillid) & UF_NOFOOTSET &&
- skill_check_unit_range2(&md->bl, md->bl.m, md->skillx, md->skilly, md->skillid, md->skilllv)) {
- skill_failed(md);
- return 0;
- }
- if(battle_config.monster_land_skill_limit) {
- maxcount = skill_get_maxcount(md->skillid);
- if(maxcount > 0) {
- int i,c;
- for(i=c=0;i<MAX_MOBSKILLUNITGROUP;i++) {
- if(md->skillunit[i].alive_count > 0 && md->skillunit[i].skill_id == md->skillid)
- c++;
- }
- if(c >= maxcount) {
- skill_failed(md);
- return 0;
- }
- }
- }
-
- md->skilldelay[md->skillidx]=tick;
-
- //Set afterskill delay.
- md->last_thinktime=tick + (tid==-1?status_get_adelay(&md->bl):status_get_amotion(&md->bl));
-
- if(battle_config.mob_skill_log)
- ShowInfo("MOB skill castend skill=%d, class = %d\n",md->skillid,md->class_);
-// mob_stop_walking(md,0);
-
- skill_castend_pos2(&md->bl,md->skillx,md->skilly,md->skillid,md->skilllv,tick,0);
-
- if (md->db->skill[md->skillidx].emotion >= 0)
- clif_emotion(&md->bl, md->db->skill[md->skillidx].emotion);
-
- //TODO: This value is used for the "afterskill" mob condition, what could one do to clean it other than
- //to use a "previous skill" struct variable?
- //md->skillid = md->skilllv = -1; //Clean up skill data for future references to battle_getcurrentskill [Skotlex]
- return 0;
-}
-
-/*==========================================
- * Skill use (an aria start, ID specification)
- *------------------------------------------
- */
-int mobskill_use_id(struct mob_data *md,struct block_list *target,int skill_idx)
-{
- int casttime;
- struct mob_skill *ms;
- int skill_id, skill_lv, forcecast = 0;
- int selfdestruct_flag = 0;
-
- nullpo_retr(0, md);
- nullpo_retr(0, ms=&md->db->skill[skill_idx]);
-
- if( target==NULL && (target=map_id2bl(md->target_id))==NULL )
- return 0;
-
- if( target->prev==NULL || md->bl.prev==NULL )
- return 0;
-
- skill_id=ms->skill_id;
- skill_lv=ms->skill_lv;
-
- if(map_flag_gvg(md->bl.m) && skill_db[skill_id].nocast & 4)
- return 0;
- if(skill_get_inf2(skill_id)&INF2_NO_TARGET_SELF && md->bl.id == target->id)
- return 0;
-
- if(!status_check_skilluse(&md->bl, target, skill_id, 0))
- return 0;
-
- if(md->sc.count && md->sc.data[SC_WINKCHARM].timer != -1 && target->type == BL_PC) {
- clif_emotion(&md->bl, 3);
- return 0;
- }
-
- // ŽË’ö‚ÆáŠQ•¨ƒ`ƒFƒbƒN
- if(!battle_check_range(&md->bl,target,skill_get_range2(&md->bl,skill_id,skill_lv)))
- return 0;
-
-// delay=skill_delayfix(&md->bl, skill_id, skill_lv, 0);
-
- casttime=skill_castfix(&md->bl, skill_id, skill_lv, ms->casttime);
- md->state.skillcastcancel=ms->cancel;
- md->skilldelay[skill_idx]=gettick();
-
- switch(skill_id){ /* ‰½‚©“ÁŽê‚Ȉ—‚ª•K—v */
- case ALL_RESURRECTION: /* ƒŠƒUƒŒƒNƒVƒ‡ƒ“ */
- if(battle_check_undead(status_get_race(target),status_get_elem_type(target))){ /* “G‚ªƒAƒ“ƒfƒbƒh‚È‚ç */
- forcecast=1; /* ƒ^[ƒ“ƒAƒ“ƒfƒbƒg‚Æ“¯‚¶‰r¥ŽžŠÔ */
- casttime=skill_castfix(&md->bl, PR_TURNUNDEAD,skill_lv, 0);
- }
- break;
- case MO_EXTREMITYFIST: /*ˆ¢C—…”e–PŒ*/
- case SA_MAGICROD:
- case SA_SPELLBREAKER:
- forcecast=1;
- break;
- case NPC_SUMMONSLAVE:
- case NPC_SUMMONMONSTER:
- if(md->master_id!=0)
- return 0;
- break;
- case NPC_SELFDESTRUCTION:
- if (casttime == 0 && md->special_state.ai == 2) {
- casttime = skill_get_time(skill_id,skill_lv);
- selfdestruct_flag = 1;
- }
- break;
- }
-
- if(battle_config.mob_skill_log)
- ShowInfo("MOB skill use target_id=%d skill=%d lv=%d cast=%d, class = %d\n",target->id,skill_id,skill_lv,casttime,md->class_);
-
- if (casttime || forcecast) { // ‰r¥‚ª•K—v
- if (!selfdestruct_flag)
- mob_stop_walking(md,1); // •às’âŽ~
- clif_skillcasting(&md->bl, md->bl.id, target->id, 0,0, skill_id, casttime);
- }
-
- if (casttime <= 0) // ‰r¥‚Ì–³‚¢‚à‚̂̓Lƒƒƒ“ƒZƒ‹‚³‚ê‚È‚¢
- md->state.skillcastcancel = 0;
-
- md->skilltarget = target->id;
- md->skillx = 0;
- md->skilly = 0;
- md->skillid = skill_id;
- md->skilllv = skill_lv;
- md->skillidx = skill_idx;
-
- if(!(battle_config.monster_cloak_check_type&2) && md->sc.data[SC_CLOAKING].timer != -1 && md->skillid != AS_CLOAKING)
- status_change_end(&md->bl,SC_CLOAKING,-1);
-
- if( casttime>0 ){
- md->skilltimer =
- add_timer( gettick()+casttime, mobskill_castend_id, md->bl.id, 0 );
- }else{
- md->skilltimer = -1;
- mobskill_castend_id(md->skilltimer,gettick(),md->bl.id, 0);
- }
-
- return 1;
-}
-/*==========================================
- * ƒXƒLƒ‹Žg—piꊎw’èj
- *------------------------------------------
- */
-int mobskill_use_pos( struct mob_data *md,
- int skill_x, int skill_y, int skill_idx)
-{
- int casttime=0;
- struct mob_skill *ms;
- struct block_list bl;
- int skill_id, skill_lv;
-
- nullpo_retr(0, md);
- nullpo_retr(0, ms=&md->db->skill[skill_idx]);
-
- if( md->bl.prev==NULL )
- return 0;
-
- skill_id=ms->skill_id;
- skill_lv=ms->skill_lv;
-
- if(map_flag_gvg(md->bl.m) && skill_db[skill_id].nocast & 4)
- return 0;
- if(!status_check_skilluse(&md->bl, NULL, skill_id, 0))
- return 0;
-
- // ŽË’ö‚ÆáŠQ•¨ƒ`ƒFƒbƒN
- bl.type = BL_NUL;
- bl.m = md->bl.m;
- bl.x = skill_x;
- bl.y = skill_y;
- if(!battle_check_range(&md->bl,&bl,skill_get_range2(&md->bl,skill_id,skill_lv)))
- return 0;
-
-// delay=skill_delayfix(&md->bl, skill_id, skill_lv, 0);
- casttime=skill_castfix(&md->bl,skill_id, skill_lv, ms->casttime);
- md->skilldelay[skill_idx]=gettick();
- md->state.skillcastcancel=ms->cancel;
-
- if(battle_config.mob_skill_log)
- ShowInfo("MOB skill use target_pos=(%d,%d) skill=%d lv=%d cast=%d, class = %d\n",
- skill_x,skill_y,skill_id,skill_lv,casttime,md->class_);
-
- if( casttime>0 ) { // A cast time is required.
- mob_stop_walking(md,1); // •às’âŽ~
- clif_skillcasting( &md->bl,
- md->bl.id, 0, skill_x,skill_y, skill_id,casttime);
- }
-
- if( casttime<=0 ) // A skill without a cast time wont be cancelled.
- md->state.skillcastcancel=0;
-
-
- md->skillx = skill_x;
- md->skilly = skill_y;
- md->skilltarget = 0;
- md->skillid = skill_id;
- md->skilllv = skill_lv;
- md->skillidx = skill_idx;
- if(!(battle_config.monster_cloak_check_type&2) && md->sc.data[SC_CLOAKING].timer != -1)
- status_change_end(&md->bl,SC_CLOAKING,-1);
- if( casttime>0 ){
- md->skilltimer =
- add_timer( gettick()+casttime, mobskill_castend_pos, md->bl.id, 0 );
- }else{
- md->skilltimer = -1;
- mobskill_castend_pos(md->skilltimer,gettick(),md->bl.id, 0);
- }
-
- return 1;
-}
-
-
/*==========================================
* Friendly Mob whose HP is decreasing by a nearby MOB is looked for.
*------------------------------------------
@@ -3780,9 +2736,12 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event)
nullpo_retr (0, md);
nullpo_retr (0, ms = md->db->skill);
- if (battle_config.mob_skill_rate == 0 || md->skilltimer != -1)
+ if (battle_config.mob_skill_rate == 0 || md->ud.skilltimer != -1)
return 0;
+ if (event < 0 && DIFF_TICK(md->ud.canact_tick, tick) > 0)
+ return 0; //Skill act delay only affects non-event skills.
+
for (i = 0; i < md->db->maxskill; i++) {
int c2 = ms[i].cond2, flag = 0;
@@ -3791,7 +2750,7 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event)
continue;
// ó‘Ô”»’è
- if (ms[i].state >= 0 && ms[i].state != md->state.skillstate)
+ if (ms[i].state != MSS_ANY && ms[i].state != md->state.skillstate)
continue;
if (rand() % 10000 > ms[i].permillage) //Lupus (max value = 10000)
@@ -3837,13 +2796,13 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event)
case MSC_SLAVELT: // slave < num
flag = (mob_countslave(&md->bl) < c2 ); break;
case MSC_ATTACKPCGT: // attack pc > num
- flag = (battle_counttargeted(&md->bl, NULL, 0) > c2); break;
+ flag = (unit_counttargeted(&md->bl, 0) > c2); break;
case MSC_SLAVELE: // slave <= num
flag = (mob_countslave(&md->bl) <= c2 ); break;
case MSC_ATTACKPCGE: // attack pc >= num
- flag = (battle_counttargeted(&md->bl, NULL, 0) >= c2); break;
+ flag = (unit_counttargeted(&md->bl, 0) >= c2); break;
case MSC_AFTERSKILL:
- flag = (md->skillid == c2); break;
+ flag = (md->ud.skillid == c2); break;
case MSC_SKILLUSED: // specificated skill used
flag = ((event & 0xffff) == MSC_SKILLUSED && ((event >> 16) == c2 || c2 == 0)); break;
case MSC_RUDEATTACKED:
@@ -3853,7 +2812,7 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event)
case MSC_MASTERHPLTMAXRATE:
flag = ((fbl = mob_getmasterhpltmaxrate(md, ms[i].cond2)) != NULL); break;
case MSC_MASTERATTACKED:
- flag = (md->master_id > 0 && battle_counttargeted(map_id2bl(md->master_id), NULL, 0) > 0); break;
+ flag = (md->master_id > 0 && unit_counttargeted(map_id2bl(md->master_id), 0) > 0); break;
case MSC_ALCHEMIST:
flag = (md->state.alchemist);
break;
@@ -3925,8 +2884,8 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event)
x = bx; y = by;
}
}
- if (!mobskill_use_pos(md, x, y, i))
- return 0;
+ return unit_skilluse_pos2(&md->bl, x, y, ms[i].skill_id, ms[i].skill_lv,
+ skill_castfix(&md->bl,ms[i].skill_id, ms[i].skill_lv, ms[i].casttime), ms[i].cancel);
} else {
// IDŽw’è
if (ms[i].target <= MST_MASTER) {
@@ -3953,8 +2912,8 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event)
bl = &md->bl;
break;
}
- if (bl && !mobskill_use_id(md, bl, i))
- return 0;
+ return (bl && unit_skilluse_id2(&md->bl, bl->id, ms[i].skill_id, ms[i].skill_lv,
+ skill_castfix(&md->bl,ms[i].skill_id, ms[i].skill_lv, ms[i].casttime), ms[i].cancel));
} else {
if (battle_config.error_log)
ShowWarning("Wrong mob skill target 'around' for non-ground skill %d (%s). Mob %d - %s\n",
@@ -3998,31 +2957,14 @@ int mobskill_event(struct mob_data *md, struct block_list *src, unsigned int tic
return res;
}
-/*==========================================
- * ƒXƒLƒ‹—pƒ^ƒCƒ}[íœ
- *------------------------------------------
- */
-int mobskill_deltimer(struct mob_data *md )
-{
- nullpo_retr(0, md);
-
- if( md->skilltimer!=-1 ){
- if( skill_get_inf( md->skillid )& INF_GROUND_SKILL )
- delete_timer( md->skilltimer, mobskill_castend_pos );
- else
- delete_timer( md->skilltimer, mobskill_castend_id );
- md->skilltimer=-1;
- }
- return 0;
-}
-
// Player cloned mobs. [Valaris]
int mob_is_clone(int class_)
{
- if(class_ >= MOB_CLONE_START && class_ <= MOB_CLONE_END)
- return 1;
-
- return 0;
+ if(class_ < MOB_CLONE_START || class_ > MOB_CLONE_END)
+ return 0;
+ if (mob_db(class_) == mob_dummy)
+ return 0;
+ return class_;
}
//Flag values:
@@ -4245,13 +3187,11 @@ int mob_clone_spawn(struct map_session_data *sd, char *map, int x, int y, const
int mob_clone_delete(int class_)
{
- int i;
- for(i=MOB_CLONE_START; i<MOB_CLONE_END; i++){
- if(i==class_ && mob_db_data[i]!=NULL){
- aFree(mob_db_data[i]);
- mob_db_data[i]=NULL;
- break;
- }
+ if (class_ >= MOB_CLONE_START && class_ < MOB_CLONE_END
+ && mob_db_data[class_]!=NULL) {
+ aFree(mob_db_data[class_]);
+ mob_db_data[class_]=NULL;
+ return 1;
}
return 0;
}
@@ -4703,7 +3643,7 @@ static int mob_readskilldb(void)
{ "hiding", SC_HIDING },
{ "sight", SC_SIGHT },
}, state[] = {
- { "any", -1 },
+ { "any", MSS_ANY },
{ "idle", MSS_IDLE },
{ "walk", MSS_WALK },
{ "loot", MSS_LOOT },
@@ -4736,6 +3676,7 @@ static int mob_readskilldb(void)
return 0;
}
for(x=0;x<2;x++){
+ int last_mob_id = 0;
count = 0;
sprintf(line, "%s/%s", db_path, filename[x]);
fp=fopen(line,"r");
@@ -4768,7 +3709,10 @@ static int mob_readskilldb(void)
}
if (mob_id > 0 && mob_db(mob_id) == mob_dummy)
{
- ShowError("mob_skill: Invalid mob id %d at %s, line %d\n", mob_id, filename[x], count);
+ if (mob_id != last_mob_id) {
+ ShowWarning("mob_skill: Non existant Mob id %d at %s, line %d\n", mob_id, filename[x], count);
+ last_mob_id = mob_id;
+ }
continue;
}
if( strcmp(sp[1],"clear")==0 ){
@@ -4788,8 +3732,11 @@ static int mob_readskilldb(void)
if( (ms=&mob_db_data[mob_id]->skill[i])->skill_id == 0)
break;
if(i==MAX_MOBSKILL){
- ShowWarning("mob_skill: readdb: too many skill ! [%s] in %d[%s]\n",
- sp[1],mob_id,mob_db_data[mob_id]->jname);
+ if (mob_id != last_mob_id) {
+ ShowWarning("mob_skill: readdb: too many skill! Line %d in %d[%s]\n",
+ count,mob_id,mob_db_data[mob_id]->jname);
+ last_mob_id = mob_id;
+ }
continue;
}
}
@@ -5197,13 +4144,10 @@ int do_init_mob(void)
mob_readskilldb();
mob_readdb_race();
- add_timer_func_list(mob_timer,"mob_timer");
add_timer_func_list(mob_delayspawn,"mob_delayspawn");
add_timer_func_list(mob_delay_item_drop,"mob_delay_item_drop");
add_timer_func_list(mob_ai_hard,"mob_ai_hard");
add_timer_func_list(mob_ai_lazy,"mob_ai_lazy");
- add_timer_func_list(mobskill_castend_id,"mobskill_castend_id");
- add_timer_func_list(mobskill_castend_pos,"mobskill_castend_pos");
add_timer_func_list(mob_timer_delete,"mob_timer_delete");
add_timer_func_list(mob_spawn_guardian_sub,"mob_spawn_guardian_sub");
add_timer_func_list(mob_respawn,"mob_respawn");
diff --git a/src/map/mob.h b/src/map/mob.h
index 2e12114ec..e7e3eb07e 100644
--- a/src/map/mob.h
+++ b/src/map/mob.h
@@ -4,6 +4,8 @@
#ifndef _MOB_H_
#define _MOB_H_
+#include "unit.h"
+
#define MAX_RANDOMMONSTER 3
#define MAX_MOB_RACE_DB 6
#define MAX_MOB_DB 10000
@@ -11,6 +13,9 @@
a larger mob database. Be sure to note that IDs 4001 to 4048 are reserved for advanced/baby/expanded classes.
*/
+//Min time before mobs do a check to call nearby friends for help (or for slaves to support their master)
+#define MIN_MOBLINKTIME 1000
+
// These define the range of available IDs for clones. [Valaris]
#define MOB_CLONE_START 9001
#define MOB_CLONE_END 10000
@@ -92,6 +97,7 @@ enum {
//Mob skill states.
enum {
+ MSS_ANY = -1,
MSS_IDLE,
MSS_WALK,
MSS_LOOT,
@@ -116,20 +122,19 @@ int mob_spawn_guardian(struct map_session_data *sd,char *mapname, // Spawning Gu
int x,int y,const char *mobname,int class_,int amount,const char *event,int guardian); // Spawning Guardians [Valaris]
int mob_guardian_guildchange(struct block_list *bl,va_list ap); //Change Guardian's ownership. [Skotlex]
-int mob_walktoxy(struct mob_data *md,int x,int y,int easy);
int mob_randomwalk(struct mob_data *md,int tick);
-int mob_can_move(struct mob_data *md);
int mob_target(struct mob_data *md,struct block_list *bl,int dist);
int mob_unlocktarget(struct mob_data *md,int tick);
-int mob_stop_walking(struct mob_data *md,int type);
-int mob_stopattack(struct mob_data *);
-int mob_spawn(int);
-int mob_setdelayspawn(int);
+struct mob_data* mob_spawn_dataset(struct spawn_data *data);
+int mob_spawn(struct mob_data *md);
+int mob_setdelayspawn(struct mob_data *md);
+int mob_parse_dataset(struct spawn_data *data);
int mob_damage(struct block_list *,struct mob_data*,int,int);
-int mob_changestate(struct mob_data *md,int state,int type);
int mob_heal(struct mob_data*,int);
+#define mob_stop_walking(md, type) { if (md->ud.walktimer != -1) unit_stop_walking(&md->bl, type); }
+#define mob_stop_attack(md) { if (md->ud.attacktimer != -1) unit_stop_attack(&md->bl); }
//Defines to speed up search.
#define mob_get_viewclass(class_) mob_db(class_)->view_class
#define mob_get_sex(class_) mob_db(class_)->sex
@@ -146,9 +151,6 @@ int mob_heal(struct mob_data*,int);
int do_init_mob(void);
int do_final_mob(void);
-void mob_unload(struct mob_data *md);
-int mob_remove_map(struct mob_data *md, int type);
-int mob_delete(struct mob_data *md);
int mob_timer_delete(int tid, unsigned int tick, int id, int data);
int mob_deleteslave(struct mob_data *md);
@@ -157,8 +159,8 @@ int mob_deleteslave(struct mob_data *md);
int mob_random_class (int *value, size_t count);
int mob_get_random_id(int type, int flag, int lv);
int mob_class_change(struct mob_data *md,int class_);
-int mob_warp(struct mob_data *md,int m,int x,int y,int type);
int mob_warpslave(struct block_list *bl, int range);
+int mob_linksearch(struct block_list *bl,va_list ap);
int mobskill_use(struct mob_data *md,unsigned int tick,int event);
int mobskill_event(struct mob_data *md,struct block_list *src,unsigned int tick, int flag);
diff --git a/src/map/npc.c b/src/map/npc.c
index a91892238..ccf634cf7 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -27,6 +27,7 @@
#include "pet.h"
#include "battle.h"
#include "skill.h"
+#include "unit.h"
#ifdef _WIN32
#undef isspace
@@ -61,8 +62,6 @@ struct event_data {
static struct tm ev_tm_b; // ŽžŒvƒCƒxƒ“ƒg—p
static struct eri *timer_event_ers; //For the npc timer data. [Skotlex]
-static int npc_walktimer(int,unsigned int,int,int); // [Valaris]
-static int npc_walktoxy_sub(struct npc_data *nd); // [Valaris]
/*==========================================
* NPC‚Ì–³Œø‰»/—LŒø‰»
@@ -1258,227 +1257,6 @@ int npc_selllist(struct map_session_data *sd,int n,unsigned short *item_list)
}
-// [Valaris] NPC Walking
-
-/*==========================================
- * Time calculation concerning one step next to npc
- *------------------------------------------
- */
-static int calc_next_walk_step(struct npc_data *nd)
-{
- nullpo_retr(0, nd);
-
- if(nd->walkpath.path_pos>=nd->walkpath.path_len)
- return -1;
- if(nd->walkpath.path[nd->walkpath.path_pos]&1)
- return status_get_speed(&nd->bl)*14/10;
- return status_get_speed(&nd->bl);
-}
-
-
-/*==========================================
- * npc Walk processing
- *------------------------------------------
- */
-static int npc_walk(struct npc_data *nd,unsigned int tick,int data)
-{
- int i;
- static int dirx[8]={0,-1,-1,-1,0,1,1,1};
- static int diry[8]={1,1,0,-1,-1,-1,0,1};
- int x,y,dx,dy;
-
- nullpo_retr(0, nd);
-
- nd->state.state=MS_IDLE;
- if(nd->walkpath.path_pos>=nd->walkpath.path_len || nd->walkpath.path_pos!=data)
- return 0;
-
- nd->walkpath.path_half ^= 1;
- if(nd->walkpath.path_half==0){
- nd->walkpath.path_pos++;
- if(nd->state.change_walk_target){
- npc_walktoxy_sub(nd);
- return 0;
- }
- }
- else {
- if(nd->walkpath.path[nd->walkpath.path_pos]>=8)
- return 1;
-
- x = nd->bl.x;
- y = nd->bl.y;
- if(map_getcell(nd->bl.m,x,y,CELL_CHKNOPASS)) {
- npc_stop_walking(nd,1);
- return 0;
- }
- nd->dir=nd->walkpath.path[nd->walkpath.path_pos];
- dx = dirx[nd->dir];
- dy = diry[nd->dir];
-
- if(map_getcell(nd->bl.m,x+dx,y+dy,CELL_CHKNOPASS)) {
- npc_walktoxy_sub(nd);
- return 0;
- }
-
- nd->state.state=MS_WALK;
- map_foreachinmovearea(clif_npcoutsight,nd->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_PC,nd);
-
- x += dx;
- y += dy;
- map_moveblock(&nd->bl, x, y, tick);
-
- map_foreachinmovearea(clif_npcinsight,nd->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,-dx,-dy,BL_PC,nd);
- nd->state.state=MS_IDLE;
- }
- if((i=calc_next_walk_step(nd))>0){
- i = i>>1;
- if(i < 1 && nd->walkpath.path_half == 0)
- i = 1;
- nd->walktimer=add_timer(tick+i,npc_walktimer,nd->bl.id,nd->walkpath.path_pos);
- nd->state.state=MS_WALK;
-
- if(nd->walkpath.path_pos>=nd->walkpath.path_len)
- clif_fixnpcpos(nd); // When npc stops, retransmission current of a position.
-
- }
- return 0;
-}
-
-int npc_changestate(struct npc_data *nd,int state,int type)
-{
- int i;
-
- nullpo_retr(0, nd);
-
- if(nd->walktimer != -1)
- delete_timer(nd->walktimer,npc_walktimer);
- nd->walktimer=-1;
- nd->state.state=state;
-
- switch(state){
- case MS_WALK:
- if((i=calc_next_walk_step(nd))>0){
- i = i>>2;
- nd->walktimer=add_timer(gettick()+i,npc_walktimer,nd->bl.id,0);
- }
- else
- nd->state.state=MS_IDLE;
- break;
- case MS_DELAY:
- nd->walktimer=add_timer(gettick()+type,npc_walktimer,nd->bl.id,0);
- break;
-
- }
-
- return 0;
-}
-
-static int npc_walktimer(int tid,unsigned int tick,int id,int data)
-{
- struct npc_data *nd;
-
- nd=(struct npc_data*)map_id2bl(id);
- if(nd == NULL || nd->bl.type != BL_NPC)
- return 1;
-
- if(nd->walktimer != tid){
- return 0;
- }
-
- nd->walktimer=-1;
-
- if(nd->bl.prev == NULL)
- return 1;
-
- switch(nd->state.state){
- case MS_WALK:
- npc_walk(nd,tick,data);
- break;
- case MS_DELAY:
- npc_changestate(nd,MS_IDLE,0);
- break;
- default:
- break;
- }
- return 0;
-}
-
-
-static int npc_walktoxy_sub(struct npc_data *nd)
-{
- struct walkpath_data wpd;
-
- nullpo_retr(0, nd);
-
- if(path_search(&wpd,nd->bl.m,nd->bl.x,nd->bl.y,nd->to_x,nd->to_y,nd->state.walk_easy))
- return 1;
- memcpy(&nd->walkpath,&wpd,sizeof(wpd));
-
- nd->state.change_walk_target=0;
- npc_changestate(nd,MS_WALK,0);
-
- clif_movenpc(nd);
-
- return 0;
-}
-
-int npc_walktoxy(struct npc_data *nd,int x,int y,int easy)
-{
- struct walkpath_data wpd;
-
- nullpo_retr(0, nd);
-
- if(nd->state.state == MS_WALK && path_search(&wpd,nd->bl.m,nd->bl.x,nd->bl.y,x,y,0) )
- return 1;
-
- nd->state.walk_easy = easy;
- nd->to_x=x;
- nd->to_y=y;
- if(nd->state.state == MS_WALK) {
- nd->state.change_walk_target=1;
- } else {
- return npc_walktoxy_sub(nd);
- }
-
- return 0;
-}
-
-int npc_stop_walking(struct npc_data *nd,int type)
-{
- nullpo_retr(0, nd);
-
- if(nd->state.state == MS_WALK || nd->state.state == MS_IDLE) {
- int dx=0,dy=0;
-
- nd->walkpath.path_len=0;
- if(type&4){
- dx=nd->to_x-nd->bl.x;
- if(dx<0)
- dx=-1;
- else if(dx>0)
- dx=1;
- dy=nd->to_y-nd->bl.y;
- if(dy<0)
- dy=-1;
- else if(dy>0)
- dy=1;
- }
- nd->to_x=nd->bl.x+dx;
- nd->to_y=nd->bl.y+dy;
- if(dx!=0 || dy!=0){
- npc_walktoxy_sub(nd);
- return 0;
- }
- npc_changestate(nd,MS_IDLE,0);
- }
- if(type&0x01)
- clif_fixnpcpos(nd);
- if(type&0x02)
- battle_set_walkdelay(&nd->bl, gettick(), status_get_dmotion(&nd->bl), 1);
-
- return 0;
-}
-
int npc_remove_map (struct npc_data *nd)
{
int m,i;
@@ -1775,7 +1553,6 @@ static int npc_parse_shop (char *w1, char *w2, char *w3, char *w4)
nd->bl.x = x;
nd->bl.y = y;
nd->bl.id = npc_get_new_npc_id();
- nd->dir = dir;
nd->flag = 0;
memcpy(nd->name, w3, NAME_LENGTH-1);
nd->name[NAME_LENGTH-1] = '\0';
@@ -1788,6 +1565,8 @@ static int npc_parse_shop (char *w1, char *w2, char *w3, char *w4)
npc_shop++;
nd->bl.type = BL_NPC;
nd->bl.subtype = SHOP;
+ unit_dataset(&nd->bl);
+ nd->ud.dir = dir;
if (m >= 0) {
nd->n = map_addnpc(m,nd);
map_addblock(&nd->bl);
@@ -2077,26 +1856,18 @@ static int npc_parse_script (char *w1,char *w2,char *w3,char *w4,char *first_lin
nd->bl.x = x;
nd->bl.y = y;
nd->bl.id = npc_get_new_npc_id();
- nd->dir = dir;
// nd->flag = 0;
nd->class_ = class_;
nd->speed = 200;
nd->u.scr.script = script;
nd->u.scr.src_id = src_id;
-/* Cleaned up above with memset...
- nd->chat_id = 0;
- nd->sc.option = 0;
- nd->sc.opt1 = 0;
- nd->sc.opt2 = 0;
- nd->sc.opt3 = 0;
-*/
- nd->walktimer = -1;
npc_script++;
nd->bl.type = BL_NPC;
nd->bl.subtype = SCRIPT;
-// Cleaned up above...
-// memset (nd->eventqueue, 0, sizeof(nd->eventqueue));
+ unit_dataset(&nd->bl);
+ nd->ud.dir = dir;
+
for (i = 0; i < MAX_EVENTTIMER; i++)
nd->eventtimer[i] = -1;
if (m >= 0) {
@@ -2266,111 +2037,80 @@ static int npc_parse_function (char *w1, char *w2, char *w3, char *w4, char *fir
* Parse Mob 2 - Actually Spawns Mob
* [Wizputer]
* If cached =1, it is a dynamic cached mob
+ * index points to the index in the mob_list of the map_data cache.
+ * -1 indicates that it is not stored on the map.
*------------------------------------------
*/
-int npc_parse_mob2 (struct mob_list *mob, int cached)
+int npc_parse_mob2 (struct spawn_data *mob, int index)
{
int i;
struct mob_data *md;
for (i = 0; i < mob->num; i++) {
- md = (struct mob_data *) aCalloc (1, sizeof(struct mob_data));
-
- md->bl.prev = NULL;
- md->bl.next = NULL;
- md->bl.m = mob->m;
- md->bl.x = mob->x;
- md->bl.y = mob->y;
- md->level = mob->level;
- memcpy(md->name, mob->mobname, NAME_LENGTH-1);
- md->n = i;
- //FIXME: This implementation is not stable, npc scripts will stop working once MAX_MOB_DB changes value! [Skotlex]
- if(mob->class_ > 2*MAX_MOB_DB){ // large/tiny mobs [Valaris]
- md->special_state.size=2;
- md->base_class = md->class_ = mob->class_-2*MAX_MOB_DB;
- } else if (mob->class_ > MAX_MOB_DB) {
- md->special_state.size=1;
- md->base_class = md->class_ = mob->class_-MAX_MOB_DB;
- } else
- md->base_class = md->class_ = mob->class_;
- md->bl.id = npc_get_new_npc_id();
- md->db = mob_db(mob->class_);
- md->m = mob->m;
- md->x0 = mob->x;
- md->y0 = mob->y;
- md->xs = mob->xs;
- md->ys = mob->ys;
- md->spawndelay1 = mob->delay1;
- md->spawndelay2 = mob->delay2;
-
- md->special_state.cached = cached; //If cached, mob is dynamically removed
- md->timer = -1;
- md->speed = mob_db(mob->class_)->speed;
-
- if (mob_db(mob->class_)->mode & MD_LOOTER)
- md->lootitem = (struct item *)aCalloc(LOOTITEM_SIZE, sizeof(struct item));
- else
- md->lootitem = NULL;
-
- if (strlen(mob->eventname) >= 4) {
- memcpy(md->npc_event, mob->eventname, NAME_LENGTH-1);
- } else if (strlen(mob->eventname) <= 2) { //Portable monster big/small implementation. [Skotlex]
- int size = atoi(mob->eventname);
- if (size & 2)
- md->special_state.size=1;
- else if (size & 4)
- md->special_state.size=2;
- if (size & 8)
- md->special_state.ai=1;
- }
-
- md->bl.type = BL_MOB;
- map_addiddb(&md->bl);
- mob_spawn(md->bl.id);
+ md = mob_spawn_dataset(mob);
+ md->spawn = mob;
+ md->spawn_n = index;
+ md->special_state.cached = (index>=0); //If mob is cached on map, it is dynamically removed
+ mob_spawn(md);
}
- return 0;
+ return 1;
}
int npc_parse_mob (char *w1, char *w2, char *w3, char *w4)
{
- int level, mode;
+ int level, num, class_, mode, x,y,xs,ys;
char mapname[MAP_NAME_LENGTH];
char mobname[NAME_LENGTH];
- struct mob_list mob;
+ struct spawn_data mob, *data;
- memset(&mob, 0, sizeof(struct mob_list));
+ memset(&mob, 0, sizeof(struct spawn_data));
// ˆø”‚̌”ƒ`ƒFƒbƒN
- if (sscanf(w1, "%15[^,],%d,%d,%d,%d", mapname, &mob.x, &mob.y, &mob.xs, &mob.ys) < 3 ||
- sscanf(w4, "%d,%d,%d,%d,%23s", &mob.class_, &mob.num, &mob.delay1, &mob.delay2, mob.eventname) < 2 ) {
+ if (sscanf(w1, "%15[^,],%d,%d,%d,%d", mapname, &x, &y, &xs, &ys) < 3 ||
+ sscanf(w4, "%d,%d,%u,%u,%23s", &class_, &num, &mob.delay1, &mob.delay2, mob.eventname) < 2 ) {
ShowError("bad monster line : %s %s %s (file %s)\n", w1, w3, w4, current_file);
return 1;
}
-
- mob.m = map_mapname2mapid(mapname);
- if (mob.m < 0) {
+ if (!mapindex_name2id(mapname)) {
ShowError("wrong map name : %s %s (file %s)\n", w1,w3, current_file);
return 1;
}
+ mode = map_mapname2mapid(mapname);
+ if (mode < 0) //Not loaded on this map-server instance.
+ return 1;
+ mob.m = (unsigned short)mode;
+
+ if (x < 0 || map[mob.m].xs <= x || y < 0 || map[mob.m].ys <= y) {
+ ShowError("Out of range spawn coordinates: %s (%d,%d), map size is (%d,%d) - %s %s (file %s)\n", map[mob.m].name, x, y, map[mob.m].xs-1, map[mob.m].ys-1, w1,w3, current_file);
+ return 1;
+ }
// check monster ID if exists!
- if (mobdb_checkid(mob.class_)==0) {
+ if (mobdb_checkid(class_)==0) {
ShowError("bad monster ID : %s %s (file %s)\n", w3, w4, current_file);
return 1;
}
- if (mob.num < 1 || mob.num>1000 ) {
+ if (num < 1 || num>1000 ) {
ShowError("wrong number of monsters : %s %s (file %s)\n", w3, w4, current_file);
return 1;
}
+
+ mob.num = (unsigned short)num;
+ mob.class_ = (short) class_;
+ mob.x = (unsigned short)x;
+ mob.y = (unsigned short)y;
+ mob.xs = (unsigned short)xs;
+ mob.ys = (unsigned short)ys;
+
if (mob.num > 1 && battle_config.mob_count_rate != 100) {
if ((mob.num = mob.num * battle_config.mob_count_rate / 100) < 1)
mob.num = 1;
}
//Apply the spawn delay fix [Skotlex]
- mode = mob_db(mob.class_)->mode;
+ mode = mob_db(class_)->mode;
if (mode & MD_BOSS) { //Bosses
if (battle_config.boss_spawn_delay != 100)
{
@@ -2393,35 +2133,38 @@ int npc_parse_mob (char *w1, char *w2, char *w3, char *w4)
if (sscanf(w3, "%23[^,],%d", mobname, &level) > 1)
mob.level = level;
- if (strcmp(mobname, "--en--") == 0)
- memcpy(mob.mobname, mob_db(mob.class_)->name, NAME_LENGTH-1);
- else if (strcmp(mobname, "--ja--") == 0)
- memcpy(mob.mobname, mob_db(mob.class_)->jname, NAME_LENGTH-1);
- else memcpy(mob.mobname, mobname, NAME_LENGTH-1);
-
if( mob.delay1<0 || mob.delay2<0 || mob.delay1>0xfffffff || mob.delay2>0xfffffff) {
ShowError("wrong monsters spawn delays : %s %s (file %s)\n", w3, w4, current_file);
return 1;
}
+ strncpy(mob.name, mobname, NAME_LENGTH-1);
+ if (!mob_parse_dataset(&mob)) //Verify dataset.
+ return 1;
+
+ //Now that all has been validated. We allocate the actual memory
+ //that the re-spawn data will use.
+ data = aMalloc(sizeof(struct spawn_data));
+ memcpy(data, &mob, sizeof(struct spawn_data));
+
if( !battle_config.dynamic_mobs || mob.delay1 || mob.delay2 ) {
- npc_parse_mob2(&mob,0);
+ npc_parse_mob2(data,-1);
npc_delay_mob += mob.num;
} else {
- struct mob_list *dynmob = map_addmobtolist(mob.m);
- if( dynmob ) {
- memcpy(dynmob, &mob, sizeof(struct mob_list));
+ int index = map_addmobtolist(data->m, data);
+ if( index >= 0 ) {
// check if target map has players
// (usually shouldn't occur when map server is just starting,
// but not the case when we do @reloadscript
if (map[mob.m].users > 0)
- npc_parse_mob2(&mob,1);
+ npc_parse_mob2(data,index);
npc_cache_mob += mob.num;
} else {
// mobcache is full
// create them as delayed with one second
mob.delay1 = 1000;
- npc_parse_mob2(&mob,0);
+ mob.delay2 = 1000;
+ npc_parse_mob2(data,-1);
npc_delay_mob += mob.num;
}
}
@@ -2789,7 +2532,7 @@ static int npc_cleanup_sub (struct block_list *bl, va_list ap) {
npc_unload((struct npc_data *)bl);
break;
case BL_MOB:
- mob_unload((struct mob_data *)bl);
+ unit_free(bl);
break;
}
@@ -2954,7 +2697,6 @@ int do_init_npc(void)
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);
- add_timer_func_list(npc_walktimer,"npc_walktimer"); // [Valaris]
add_timer_func_list(npc_event_timer,"npc_event_timer");
add_timer_func_list(npc_event_do_clock,"npc_event_do_clock");
add_timer_func_list(npc_timerevent,"npc_timerevent");
diff --git a/src/map/npc.h b/src/map/npc.h
index 5d41c87a0..8f659eb46 100644
--- a/src/map/npc.h
+++ b/src/map/npc.h
@@ -32,7 +32,7 @@ int npc_buysellsel(struct map_session_data *,int,int);
int npc_buylist(struct map_session_data *,int,unsigned short *);
int npc_selllist(struct map_session_data *,int,unsigned short *);
int npc_parse_mob(char *w1,char *w2,char *w3,char *w4);
-int npc_parse_mob2 (struct mob_list *, int cached); // [Wizputer]
+int npc_parse_mob2 (struct spawn_data*, int index); // [Wizputer]
int npc_parse_warp(char *w1,char *w2,char *w3,char *w4);
int npc_globalmessage(const char *name,char *mes);
@@ -40,8 +40,6 @@ int npc_enable(const char *name,int flag);
int npc_changename(const char *name, const char *newname, short look); // [Lance]
struct npc_data* npc_name2id(const char *name);
-int npc_walktoxy(struct npc_data *nd,int x,int y,int easy); // npc walking [Valaris]
-int npc_stop_walking(struct npc_data *nd,int type);
int npc_changestate(struct npc_data *nd,int state,int type);
int npc_get_new_npc_id(void);
diff --git a/src/map/pc.c b/src/map/pc.c
index 46357f59a..4a93dbea0 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -8,10 +8,13 @@
#include <time.h>
#include <limits.h>
-#include "socket.h" // [Valaris]
-#include "timer.h"
+#include "../common/socket.h" // [Valaris]
+#include "../common/timer.h"
+#include "../common/nullpo.h"
+#include "../common/showmsg.h"
+#include "../common/malloc.h"
+#include "../common/core.h"
-#include "malloc.h"
#include "map.h"
#include "chrif.h"
#include "clif.h"
@@ -31,11 +34,8 @@
#include "trade.h"
#include "storage.h"
#include "vending.h"
-#include "nullpo.h"
#include "atcommand.h"
#include "log.h"
-#include "showmsg.h"
-#include "core.h"
#ifndef TXT_ONLY // mail system [Valaris]
#include "mail.h"
@@ -350,46 +350,6 @@ int pc_setrestartvalue(struct map_session_data *sd,int type) {
}
/*==========================================
- * Determines if the player can move based on status changes. [Skotlex]
- *------------------------------------------
- */
-int pc_can_move(struct map_session_data *sd)
-{
-
- if (sd->sc.opt1 > 0 && sd->sc.opt1 != OPT1_STONEWAIT)
- return 0;
-
- if ((sd->sc.option & OPTION_HIDE) && pc_checkskill(sd, RG_TUNNELDRIVE) <= 0)
- return 0;
-
- if (sd->skilltimer != -1 && pc_checkskill(sd, SA_FREECAST) <= 0)
- return 0;
-
- if (pc_issit(sd))
- return 0; //Can't move while sitting...
-
- if (DIFF_TICK(sd->canmove_tick, gettick()) > 0)
- return 0;
-
- if (sd->sc.count && (
- sd->sc.data[SC_ANKLE].timer != -1 ||
- sd->sc.data[SC_AUTOCOUNTER].timer !=-1 ||
- sd->sc.data[SC_TRICKDEAD].timer !=-1 ||
- sd->sc.data[SC_BLADESTOP].timer !=-1 ||
- sd->sc.data[SC_SPIDERWEB].timer !=-1 ||
- (sd->sc.data[SC_DANCING].timer !=-1 && sd->sc.data[SC_DANCING].val4 && sd->sc.data[SC_LONGING].timer == -1) ||
- (sd->sc.data[SC_DANCING].timer !=-1 && sd->sc.data[SC_DANCING].val1 == CG_HERMODE) || //cannot move while Hermod is active.
- (sd->sc.data[SC_GOSPEL].timer !=-1 && sd->sc.data[SC_GOSPEL].val4 == BCT_SELF) || // cannot move while gospel is in effect
- sd->sc.data[SC_STOP].timer != -1 ||
- sd->sc.data[SC_CLOSECONFINE].timer != -1 ||
- sd->sc.data[SC_CLOSECONFINE2].timer != -1
- ))
- return 0;
-
- return 1;
-}
-
-/*==========================================
Determines if the GM can give / drop / trade / vend items [Lupus]
Args: GM Level (current player GM level)
* Returns
@@ -403,12 +363,6 @@ int pc_can_give_items(int level) {
}
/*==========================================
- * ƒ?ƒJƒ‹ƒvƒƒgƒ^ƒCƒv錾 (•K—v‚È•¨‚Ì‚Ý)
- *------------------------------------------
- */
-static int pc_walktoxy_sub(struct map_session_data *);
-
-/*==========================================
* save‚É•K—v‚ȃXƒe?ƒ^ƒXC³‚ðs‚È‚¤
*------------------------------------------
*/
@@ -463,8 +417,8 @@ int pc_setnewpc(struct map_session_data *sd, int account_id, int char_id, int lo
sd->sex = sex;
sd->state.auth = 0;
sd->bl.type = BL_PC;
- sd->canact_tick = sd->canmove_tick = gettick();
sd->canlog_tick = gettick();
+ unit_dataset(&sd->bl);
sd->state.waitingdisconnect = 0;
return 0;
@@ -689,25 +643,16 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t
sd->view_class = sd->status.class_;
sd->speed = DEFAULT_WALK_SPEED;
- sd->walktimer = -1;
- sd->attacktimer = -1;
sd->followtimer = -1; // [MouseJstr]
- sd->skilltimer = -1;
sd->skillitem = -1;
sd->skillitemlv = -1;
sd->invincible_timer = -1;
- sd->canact_tick = tick;
- sd->canmove_tick = tick;
sd->canregen_tick = tick;
- sd->attackabletime = tick;
sd->canuseitem_tick = tick;
for(i = 0; i < MAX_SKILL_LEVEL; i++)
sd->spirit_timer[i] = -1;
- for(i = 0; i < MAX_SKILLTIMERSKILL; i++)
- sd->skilltimerskill[i].timer = -1;
-
if (battle_config.item_auto_get)
sd->state.autoloot = 10000;
@@ -2532,7 +2477,7 @@ int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem)
nullpo_retr(0, sd);
nullpo_retr(0, fitem);
- if(!check_distance_bl(&fitem->bl, &sd->bl, 2) && sd->skillid!=BS_GREED)
+ if(!check_distance_bl(&fitem->bl, &sd->bl, 2) && sd->ud.skillid!=BS_GREED)
return 0; // ‹——£‚ª‰“‚¢
if (sd->status.party_id)
@@ -2583,14 +2528,13 @@ int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem)
}
//Display pickup animation.
- if(sd->attacktimer != -1)
- pc_stopattack(sd);
+ pc_stop_attack(sd);
clif_takeitem(&sd->bl,&fitem->bl);
- map_clearflooritem(fitem->bl.id);
if(itemdb_autoequip(fitem->item_data.nameid) != 0){
pc_equipitem(sd, fitem->item_data.nameid, fitem->item_data.equip);
}
+ map_clearflooritem(fitem->bl.id);
return 0;
}
@@ -3049,65 +2993,16 @@ int pc_setpos(struct map_session_data *sd,unsigned short mapindex,int x,int y,in
ShowInfo("pc_setpos failed: Attempted to relocate player %s (%d:%d) while it is still between maps.\n", sd->status.name, sd->status.account_id, sd->status.char_id);
return 3;
}
- if(sd->chatID) // ƒ`ƒƒƒbƒg‚©‚ço‚é
- chat_leavechat(sd);
- if(sd->trade_partner) // Žæˆø‚ð’†?‚·‚é
- trade_tradecancel(sd);
- if(sd->vender_id)
- vending_closevending(sd);
- if(sd->state.storage_flag == 1)
- storage_storage_quit(sd,0); // ‘qŒÉ‚ðŠJ‚¢‚Ä‚é‚È‚ç•Û‘¶‚·‚é
- else if (sd->state.storage_flag == 2)
- storage_guild_storage_quit(sd,0);
-
- if(sd->party_invite>0) // ƒp?ƒeƒB?—U‚ð‹‘”Û‚·‚é
- party_reply_invite(sd,sd->party_invite_account,0);
- if(sd->guild_invite>0) // ƒMƒ‹ƒh?—U‚ð‹‘”Û‚·‚é
- guild_reply_invite(sd,sd->guild_invite,0);
- if(sd->guild_alliance>0) // ƒMƒ‹ƒh“¯–¿?—U‚ð‹‘”Û‚·‚é
- guild_reply_reqalliance(sd,sd->guild_alliance_account,0);
-
- // Delete timer before the player moved to hise repawn point
- if (sd->pvp_timer != -1 && !battle_config.pk_mode) {
- delete_timer(sd->pvp_timer, pc_calc_pvprank_timer);
- sd->pvp_timer = -1;
- }
-
- skill_castcancel(&sd->bl,0); // ‰r¥’†?
- pc_stop_walking(sd,0); // ?s’†?
- pc_stopattack(sd); // U?’†?
-
- if(pc_issit(sd)) {
- pc_setstand(sd);
- skill_gangsterparadise(sd,0);
- }
m=map_mapindex2mapid(mapindex);
- if (sd->sc.count) {
- if (sd->sc.data[SC_TRICKDEAD].timer != -1)
- status_change_end(&sd->bl, SC_TRICKDEAD, -1);
- if (sd->sc.data[SC_BLADESTOP].timer!=-1)
- status_change_end(&sd->bl,SC_BLADESTOP,-1);
- if (sd->sc.data[SC_RUN].timer!=-1)
- status_change_end(&sd->bl,SC_RUN,-1);
- if (sd->sc.data[SC_DANCING].timer!=-1) // clear dance effect when warping [Valaris]
- skill_stop_dancing(&sd->bl);
- if (sd->sc.data[SC_DEVOTION].timer!=-1)
- status_change_end(&sd->bl,SC_DEVOTION,-1);
- if (sd->sc.data[SC_CLOSECONFINE].timer!=-1)
- status_change_end(&sd->bl,SC_CLOSECONFINE,-1);
- if (sd->sc.data[SC_CLOSECONFINE2].timer!=-1)
- status_change_end(&sd->bl,SC_CLOSECONFINE2,-1);
- if (sd->sc.data[SC_RUN].timer!=-1)
- status_change_end(&sd->bl,SC_RUN,-1);
- if (sd->sc.data[SC_HIDING].timer!=-1)
- status_change_end(&sd->bl, SC_HIDING, -1);
- if (sd->sc.data[SC_CLOAKING].timer!=-1)
- status_change_end(&sd->bl, SC_CLOAKING, -1);
- if (sd->sc.data[SC_CHASEWALK].timer!=-1)
- status_change_end(&sd->bl, SC_CHASEWALK, -1);
- if (sd->bl.m != m) { //Cancel some map related stuff.
+ if (sd->mapindex != mapindex)
+ { //Misc map-changing settings
+ party_send_dot_remove(sd); //minimap dot fix [Kevin]
+ guild_send_dot_remove(sd);
+ skill_clear_element_field(&sd->bl);
+ if (sd->sc.count)
+ { //Cancel some map related stuff.
if (sd->sc.data[SC_WARM].timer != -1)
status_change_end(&sd->bl,SC_WARM,-1);
if (sd->sc.data[SC_SUN_COMFORT].timer != -1)
@@ -3119,61 +3014,21 @@ int pc_setpos(struct map_session_data *sd,unsigned short mapindex,int x,int y,in
}
}
- if (sd->mapindex != mapindex)
- { //Misc map-changing settings
- party_send_dot_remove(sd); //minimap dot fix [Kevin]
- guild_send_dot_remove(sd);
- skill_clear_element_field(&sd->bl);
- }
-
- if(sd->status.pet_id > 0 && sd->pd && sd->pet.intimate > 0) {
- pet_stopattack(sd->pd);
- pet_changestate(sd->pd,MS_IDLE,0);
- }
-
if(m<0){
if(sd->mapindex){
int ip,port;
if(map_mapname2ipport(mapindex,&ip,&port)==0){
-
- skill_stop_dancing(&sd->bl);
- skill_unit_move(&sd->bl,gettick(),4);
- clif_clearchar_area(&sd->bl,clrtype&0xffff);
- skill_gangsterparadise(sd,0);
- map_delblock(&sd->bl);
- if(sd->status.pet_id > 0 && sd->pd) {
- if(sd->pd->bl.m != m && sd->pet.intimate <= 0) {
- pet_remove_map(sd);
- intif_delete_petdata(sd->status.pet_id);
- sd->status.pet_id = 0;
- sd->pd = NULL;
- sd->petDB = NULL;
- if(battle_config.pet_status_support)
- status_calc_pc(sd,2);
- }
- else if(sd->pet.intimate > 0) {
- pet_stopattack(sd->pd);
- pet_changestate(sd->pd,MS_IDLE,0);
- clif_clearchar_area(&sd->pd->bl,clrtype&0xffff);
- map_delblock(&sd->pd->bl);
- }
- }
+ unit_remove_map(&sd->bl,0);
sd->mapindex = mapindex;
sd->bl.x=x;
sd->bl.y=y;
sd->state.waitingdisconnect=1;
pc_clean_skilltree(sd);
-
- if(sd->status.pet_id > 0 && sd->pd)
+ if(sd->status.pet_id > 0 && sd->pd) {
+ unit_remove_map(&sd->pd->bl, 0);
intif_save_petdata(sd->status.account_id,&sd->pet);
- //The storage close routines save the char data. [Skotlex]
- if (!sd->state.storage_flag)
- chrif_save(sd,1);
- else if (sd->state.storage_flag == 1) {
- storage_storage_quit(sd,1);
- } else if (sd->state.storage_flag == 2)
- storage_guild_storage_quit(sd,1);
-
+ }
+ chrif_save(sd,1);
chrif_changemapserver(sd, mapindex, x, y, ip, (short)port);
return 0;
}
@@ -3202,52 +3057,22 @@ int pc_setpos(struct map_session_data *sd,unsigned short mapindex,int x,int y,in
}
if(sd->mapindex && sd->bl.prev != NULL){
- skill_unit_move(&sd->bl,gettick(),4);
- clif_clearchar_area(&sd->bl,clrtype&0xffff);
- skill_gangsterparadise(sd,0);
-
- map_delblock(&sd->bl);
- // pet
- if(sd->status.pet_id > 0 && sd->pd) {
- if(sd->pd->bl.m != m && sd->pet.intimate <= 0) {
- pet_remove_map(sd);
- intif_delete_petdata(sd->status.pet_id);
- sd->status.pet_id = 0;
- sd->pd = NULL;
- sd->petDB = NULL;
- if(battle_config.pet_status_support)
- status_calc_pc(sd,2);
- }
- else if(sd->pet.intimate > 0) {
- pet_stopattack(sd->pd);
- pet_changestate(sd->pd,MS_IDLE,0);
- clif_clearchar_area(&sd->pd->bl,clrtype&0xffff);
- map_delblock(&sd->pd->bl);
- }
- }
- if (sd->state.storage_flag == 1)
- storage_storageclose(sd);
- else if (sd->state.storage_flag == 2)
- storage_guild_storageclose(sd);
-
+ unit_remove_map(&sd->bl, 0);
+ if(sd->status.pet_id > 0 && sd->pd)
+ unit_remove_map(&sd->pd->bl, 0);
clif_changemap(sd,map[m].index,x,y); // [MouseJstr]
}
sd->mapindex = mapindex;
sd->bl.m = m;
- sd->to_x = x;
- sd->to_y = y;
-
- // moved and changed dance effect stopping
-
- sd->bl.x = x;
- sd->bl.y = y;
+ sd->bl.x = sd->ud.to_x = x;
+ sd->bl.y = sd->ud.to_y = y;
if(sd->status.pet_id > 0 && sd->pd && sd->pet.intimate > 0) {
sd->pd->bl.m = m;
- sd->pd->bl.x = sd->pd->to_x = x;
- sd->pd->bl.y = sd->pd->to_y = y;
- sd->pd->dir = sd->dir;
+ sd->pd->bl.x = sd->pd->ud.to_x = x;
+ sd->pd->bl.y = sd->pd->ud.to_y = y;
+ sd->pd->ud.dir = sd->ud.dir;
}
return 0;
@@ -3274,7 +3099,7 @@ int pc_randomwarp(struct map_session_data *sd, int type) {
}while(map_getcell(m,x,y,CELL_CHKNOPASS) && (i++)<1000 );
if (i < 1000)
- pc_setpos(sd,map[sd->bl.m].index,x,y,type);
+ return pc_setpos(sd,map[sd->bl.m].index,x,y,type);
return 0;
}
@@ -3340,7 +3165,7 @@ int pc_run(struct map_session_data *sd, int skilllv, int dir)
nullpo_retr(0, sd);
- if (!pc_can_move(sd)) {
+ if (!unit_can_move(&sd->bl)) {
if(sd->sc.data[SC_RUN].timer!=-1)
status_change_end(&sd->bl,SC_RUN,-1);
return 0;
@@ -3366,7 +3191,7 @@ int pc_run(struct map_session_data *sd, int skilllv, int dir)
status_change_end(&sd->bl,SC_RUN,-1);
return 0;
}
- pc_walktoxy(sd, to_x, to_y);
+ unit_walktoxy(&sd->bl, to_x, to_y, 1);
return 1;
}
/*==========================================
@@ -3381,321 +3206,22 @@ int pc_walktodir(struct map_session_data *sd,int step)
to_x = sd->bl.x;
to_y = sd->bl.y;
- dir_x = dirx[(int)sd->dir];
- dir_y = diry[(int)sd->dir];
+ dir_x = dirx[(int)sd->ud.dir];
+ dir_y = diry[(int)sd->ud.dir];
for(i=0;i<step;i++)
{
if(map_getcell(sd->bl.m,to_x+dir_x,to_y+dir_y,CELL_CHKNOPASS))
break;
- if(map_getcell(sd->bl.m,to_x+dir_x,to_y+dir_y,CELL_CHKPASS))
- {
- to_x += dir_x;
- to_y += dir_y;
- continue;
- }
- break;
+ to_x += dir_x;
+ to_y += dir_y;
}
- pc_walktoxy(sd, sd->to_x, sd->to_y);
+ unit_walktoxy(&sd->bl, sd->to_x, sd->to_y, 1);
return 1;
}
-/*==========================================
- *
- *------------------------------------------
- */
-int pc_can_reach(struct map_session_data *sd,int x,int y)
-{
- struct walkpath_data wpd;
-
- nullpo_retr(0, sd);
-
- if( sd->bl.x==x && sd->bl.y==y ) // “¯‚¶ƒ}ƒX
- return 1;
-
- // áŠQ•¨”»’è
- wpd.path_len=0;
- wpd.path_pos=0;
- wpd.path_half=0;
- return (path_search_real(&wpd,sd->bl.m,sd->bl.x,sd->bl.y,x,y,0,CELL_CHKNOREACH)!=-1)?1:0;
-}
-
-//
-// ? s•¨
-//
-/*==========================================
- * ŽŸ‚Ì1?‚É‚©‚©‚éŽjÔ‚ðŒvŽZ
- *------------------------------------------
- */
-static int calc_next_walk_step(struct map_session_data *sd)
-{
- nullpo_retr(0, sd);
-
- if(sd->walkpath.path_pos>=sd->walkpath.path_len)
- return -1;
- if(sd->walkpath.path[sd->walkpath.path_pos]&1)
- return sd->speed*14/10;
-
- return sd->speed;
-}
-
-/*==========================================
- * ”¼?i‚Þ(timer??)
- *------------------------------------------
- */
-static int pc_walk(int tid,unsigned int tick,int id,int data)
-{
- struct map_session_data *sd;
- int i, x, y, dx, dy;
-
- if ((sd = map_id2sd(id)) == NULL)
- return 0;
-
- if(sd->walktimer != tid){
- if(battle_config.error_log)
- ShowError("pc_walk %d != %d\n", sd->walktimer, tid);
- return 0;
- }
-
- sd->walktimer = -1;
-
- if (sd->walkpath.path_pos >= sd->walkpath.path_len ||
- sd->walkpath.path_pos != data)
- return 0;
-
- //?‚¢‚½‚Ì‚Å‘§‚̃^ƒCƒ}?‚ð‰Šú‰»
- sd->inchealspirithptick = 0;
- sd->inchealspiritsptick = 0;
-
- sd->walkpath.path_half ^= 1;
- if (sd->walkpath.path_half == 0) { // ƒ}ƒX–Ú’†S‚Ö“r
- sd->walkpath.path_pos++;
- if (sd->state.change_walk_target) {
- pc_walktoxy_sub(sd);
- return 0;
- }
- } else { // ƒ}ƒX–Ú‹«ŠE‚Ö“r
- if (sd->walkpath.path[sd->walkpath.path_pos] >= 8)
- return 1;
- x = sd->bl.x;
- y = sd->bl.y;
-#ifndef CELL_NOSTACK
- if (map_getcell(sd->bl.m,x,y,CELL_CHKNOPASS)) {
- pc_stop_walking(sd,1);
- return 0;
- }
-#endif
- sd->dir = sd->head_dir = sd->walkpath.path[sd->walkpath.path_pos];
- dx = dirx[(int)sd->dir];
- dy = diry[(int)sd->dir];
- if (map_getcell(sd->bl.m,x+dx,y+dy,CELL_CHKNOPASS)) {
- pc_walktoxy_sub(sd);
- return 0;
- }
- sd->walktimer = 1; // temporarily set (so that in clif_set007x the player will still appear as walking)
- map_foreachinmovearea(clif_pcoutsight, sd->bl.m,
- x-AREA_SIZE, y-AREA_SIZE, x+AREA_SIZE, y+AREA_SIZE,
- dx, dy, BL_ALL, sd);
-
- sd->walktimer = -1; // set back so not to disturb future pc_stop_walking calls
- x += dx;
- y += dy;
- map_moveblock(&sd->bl, x, y, tick);
- sd->walktimer = 1; // temporarily set (so that in clif_set007x the player will still appear as walking)
-
- map_foreachinmovearea (clif_pcinsight, sd->bl.m,
- x-AREA_SIZE, y-AREA_SIZE, x+AREA_SIZE, y+AREA_SIZE,
- -dx, -dy, BL_ALL, sd);
- sd->walktimer = -1; // set back so not to disturb future pc_stop_walking calls
-
- if (map_getcell(sd->bl.m,x,y,CELL_CHKNPC))
- npc_touch_areanpc(sd,sd->bl.m,x,y);
- else
- sd->areanpc_id = 0;
- }
-
- if ((i = calc_next_walk_step(sd)) > 0) {
- i = i>>1;
- if (i < 1 && sd->walkpath.path_half == 0)
- i = 1;
- sd->walktimer = add_timer (tick+i, pc_walk, id, sd->walkpath.path_pos);
- }
- else if(sd->sc.data[SC_RUN].timer!=-1) //Keep trying to run.
- pc_run(sd, sd->sc.data[SC_RUN].val1, sd->sc.data[SC_RUN].val2);
- else { //Stopped walking. Update to_x and to_y to current location [Skotlex]
- sd->to_x = sd->bl.x;
- sd->to_y = sd->bl.y;
- }
- return 0;
-}
-
-/*==========================================
- * ˆÚ“®‰Â”\‚©Šm”F‚µ‚ÄA‰Â”\‚È‚ç?sŠJŽn
- *------------------------------------------
- */
-static int pc_walktoxy_sub (struct map_session_data *sd)
-{
- struct walkpath_data wpd;
- int i;
-
- nullpo_retr(1, sd);
-
- if(path_search(&wpd, sd->bl.m, sd->bl.x, sd->bl.y, sd->to_x, sd->to_y, 0))
- return 1;
-
- memcpy(&sd->walkpath, &wpd, sizeof(wpd));
-
- clif_walkok(sd);
- sd->state.change_walk_target = 0;
-
- if ((i = calc_next_walk_step(sd)) > 0){
- i = i >> 2;
- sd->walktimer = add_timer(gettick()+i, pc_walk, sd->bl.id, 0);
- }
- clif_movechar(sd);
-
- return 0;
-}
-
-/*==========================================
- * pc? s—v‹
- *------------------------------------------
- */
-int pc_walktoxy (struct map_session_data *sd, int x, int y)
-{
- nullpo_retr(0, sd);
-
- sd->to_x = x;
- sd->to_y = y;
- if (sd->sc.data[SC_CONFUSION].timer != -1) //Randomize the target position
- map_random_dir(&sd->bl, &sd->to_x, &sd->to_y);
-
- if (sd->walktimer != -1)
- { //There was a timer-mismatch here. pc_walktoxy_sub does not clears previous pc_walk timers! [Skotlex]
- sd->state.change_walk_target = 1;
- } else {
- pc_walktoxy_sub(sd);
- }
-
- if (sd->state.gmaster_flag) {
- struct guild *g = sd->state.gmaster_flag;
- int skill, guildflag = 0;
- if ((skill = guild_checkskill(g, GD_LEADERSHIP)) > 0) guildflag |= skill<<12;
- if ((skill = guild_checkskill(g, GD_GLORYWOUNDS)) > 0) guildflag |= skill<<8;
- if ((skill = guild_checkskill(g, GD_SOULCOLD)) > 0) guildflag |= skill<<4;
- if ((skill = guild_checkskill(g, GD_HAWKEYES)) > 0) guildflag |= skill;
- if (guildflag)
- map_foreachinrange(skill_guildaura_sub, &sd->bl,2, BL_PC,
- sd->bl.id, sd->status.guild_id, &guildflag);
- }
- //SG_MIRACLE [Komurka]
- if (sd->sc.data && sd->sc.data[SC_MIRACLE].timer==-1 && ((sd->status.class_==JOB_STAR_GLADIATOR) || (sd->status.class_==JOB_STAR_GLADIATOR2)) && (rand()%10000 < battle_config.sg_miracle_skill_ratio) )
- {
- clif_displaymessage(sd->fd,"[Miracle of the Sun, Moon and Stars]");
- sc_start(&sd->bl,SC_MIRACLE,100,1,battle_config.sg_miracle_skill_duration);
- }
-
- return 0;
-}
-
-/*==========================================
- * ? s’âŽ~
- *------------------------------------------
- */
-int pc_stop_walking (struct map_session_data *sd, int type)
-{
- nullpo_retr(0, sd);
-
- if (sd->walktimer != -1) {
- if(type&2 && pc_can_move(sd)){
- int dx, dy;
- dx=sd->to_x-sd->bl.x;
- if(dx<0)
- dx=-1;
- else if(dx>0)
- dx=1;
- dy=sd->to_y-sd->bl.y;
- if(dy<0)
- dy=-1;
- else if(dy>0)
- dy=1;
- if(dx!=0 || dy!=0){
- sd->to_x=sd->bl.x+dx;
- sd->to_y=sd->bl.y+dy;
- sd->state.change_walk_target = 1;
- return 0;
- }
- }
- delete_timer(sd->walktimer, pc_walk);
- sd->walktimer = -1;
- }
- sd->walkpath.path_len = 0;
- sd->to_x = sd->bl.x;
- sd->to_y = sd->bl.y;
- if (type & 0x01 && !pc_issit(sd)) //Trying to fixpos while sitting makes you seem standing. [Skotlex]
- clif_fixpos(&sd->bl);
- if (sd->sc.data[SC_RUN].timer != -1)
- status_change_end(&sd->bl, SC_RUN, -1);
- return 0;
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-int pc_movepos(struct map_session_data *sd,int dst_x,int dst_y,int checkpath)
-{
- int dx,dy;
-
- struct walkpath_data wpd;
-
- nullpo_retr(0, sd);
-
- if(checkpath && path_search(&wpd,sd->bl.m,sd->bl.x,sd->bl.y,dst_x,dst_y,0))
- return 1;
-
- sd->dir = sd->head_dir = map_calc_dir(&sd->bl, dst_x,dst_y);
-
- dx = dst_x - sd->bl.x;
- dy = dst_y - sd->bl.y;
-
- map_foreachinmovearea(clif_pcoutsight,sd->bl.m,sd->bl.x-AREA_SIZE,sd->bl.y-AREA_SIZE,sd->bl.x+AREA_SIZE,sd->bl.y+AREA_SIZE,dx,dy,BL_ALL,sd);
-
- map_moveblock(&sd->bl, dst_x, dst_y, gettick());
-
- map_foreachinmovearea(clif_pcinsight,sd->bl.m,sd->bl.x-AREA_SIZE,sd->bl.y-AREA_SIZE,sd->bl.x+AREA_SIZE,sd->bl.y+AREA_SIZE,-dx,-dy,BL_ALL,sd);
-
- if(sd->status.pet_id > 0 && sd->pd && sd->pet.intimate > 0) {
- struct pet_data *pd = sd->pd;
- int flag = 0;
-
- //Check if pet needs to be teleported. [Skotlex]
- if (!checkpath && path_search(&wpd,pd->bl.m,pd->bl.x,pd->bl.y,dst_x,dst_y,0))
- flag = 1;
- else if (!check_distance_bl(&sd->bl, &pd->bl, AREA_SIZE)) //Too far, teleport.
- flag = 2;
- if (flag) {
- pet_stopattack(pd);
- pet_changestate(pd,MS_IDLE,0);
- if (flag == 2) clif_clearchar_area(&pd->bl,3);
- map_moveblock(&pd->bl, dst_x, dst_y, gettick());
- pd->dir = sd->dir;
- pd->to_x = dst_x;
- pd->to_y = dst_y;
- if (flag == 2) clif_fixpos(&pd->bl);
-
- else clif_slide(&pd->bl,pd->bl.x,pd->bl.y);
- }
- }
- 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;
- return 0;
-}
-
//
// •Ší??
//
@@ -4251,167 +3777,6 @@ char * job_name(int class_) {
}
}
-/*==========================================
- * PC‚ÌU? (timer??)
- *------------------------------------------
- */
-int pc_attack_timer(int tid,unsigned int tick,int id,int data)
-{
- struct map_session_data *sd;
- struct block_list *bl;
- int skill,range;
-
- sd=map_id2sd(id);
- if(sd == NULL)
- return 0;
-
- //Should we disable this line? Ctrl+click and then going away "IS" idling... [Skotlex]
- sd->idletime = last_tick;
-
- if(sd->attacktimer != tid){
- if(battle_config.error_log)
- ShowError("pc_attack_timer %d != %d\n",sd->attacktimer,tid);
- return 0;
- }
- sd->attacktimer=-1;
-
- if(sd->bl.prev == NULL)
- return 0;
-
- bl=map_id2bl(sd->attacktarget);
- if(bl==NULL || bl->prev == NULL)
- return 0;
-
- // “¯‚¶map‚Å‚È‚¢‚È‚çU?‚µ‚È‚¢
- // PC‚ªŽ€‚ñ‚Å‚Ä‚àU?‚µ‚È‚¢
- if(sd->bl.m != bl->m)
- return 0;
-
- if(!status_check_skilluse(&sd->bl, bl, 0, 0))
- return 0;
-
- if(sd->skilltimer != -1 && pc_checkskill(sd,SA_FREECAST) <= 0)
- return 0;
-
- if(!battle_config.sdelay_attack_enable && DIFF_TICK(sd->canact_tick,tick) > 0 && pc_checkskill(sd,SA_FREECAST) <= 0)
- {
- if (tid == -1) { //player requested attack.
- clif_skill_fail(sd,1,4,0);
- return 0;
- }
- //Otherwise, we are in a combo-attack, delay this until your canact time is over. [Skotlex]
- if(sd->state.attack_continue) {
- sd->attackabletime = sd->canact_tick;
- sd->attacktimer=add_timer(sd->attackabletime,pc_attack_timer,sd->bl.id,0);
- }
- return 0;
- }
-
- if((sd->status.weapon == 11 || sd->status.weapon == 17 || sd->status.weapon == 18
- || sd->status.weapon == 19 || sd->status.weapon == 20 || sd->status.weapon == 21)&& sd->equip_index[10] < 0)
- {
- clif_arrow_fail(sd,0);
- return 0;
- }
-
- range = sd->attackrange;
- if(sd->status.weapon != 11) range++;
- if(battle_iswalking(bl)) range++;
- if(!battle_check_range(&sd->bl,bl,range) ) {
- if(pc_can_reach(sd,bl->x,bl->y))
- clif_movetoattack(sd,bl);
- return 0;
- }
-
- if(battle_config.pc_attack_direction_change)
- sd->dir=sd->head_dir=map_calc_dir(&sd->bl, bl->x,bl->y ); // Œü‚«Ý’è
-
- if(sd->walktimer != -1)
- pc_stop_walking(sd,1);
-
- if(DIFF_TICK(sd->attackabletime,tick) <= 0) {
- map_freeblock_lock();
- sd->attacktarget_lv = battle_weapon_attack(&sd->bl,bl,tick,0);
-
- if(!(battle_config.pc_cloak_check_type&2) && sd->sc.data[SC_CLOAKING].timer != -1)
- status_change_end(&sd->bl,SC_CLOAKING,-1);
-
- if(sd->status.pet_id > 0 && sd->pd && sd->petDB && battle_config.pet_attack_support)
- pet_target_check(sd,bl,0);
-
- map_freeblock_unlock();
-
- if(sd->skilltimer != -1 && (skill = pc_checkskill(sd,SA_FREECAST)) > 0 ) // ƒtƒŠ?ƒLƒƒƒXƒg
- sd->attackabletime = tick + ((sd->aspd<<1)*(150 - skill*5)/100);
- else
- sd->attackabletime = tick + (sd->aspd<<1);
- }
-
- if(sd->state.attack_continue)
- sd->attacktimer=add_timer(sd->attackabletime,pc_attack_timer,sd->bl.id,0);
-
- return 0;
-}
-
-/*==========================================
- * U?—v‹
- * type‚ª1‚È‚ç??U?
- *------------------------------------------
- */
-int pc_attack(struct map_session_data *sd,int target_id,int type)
-{
- struct block_list *bl;
-
- nullpo_retr(0, sd);
-
- bl=map_id2bl(target_id);
- if(bl==NULL)
- return 1;
-
- if(bl->type==BL_NPC) { // monster npcs [Valaris]
- npc_click(sd,target_id); // submitted by leinsirk10 [Celest]
- return 0;
- }
-
- if(battle_check_target(&sd->bl,bl,BCT_ENEMY) <= 0 || !status_check_skilluse(&sd->bl, bl, 0, 0))
- return 1;
- if(sd->attacktimer != -1)
- { //Just change target/type. [Skotlex]
- sd->attacktarget=target_id;
- sd->state.attack_continue=type;
- return 0;
- }
-
- sd->attacktarget=target_id;
- sd->state.attack_continue=type;
-
- if(sd->attackabletime > gettick()){ //Do attack next time it is possible. [Skotlex]
- sd->attacktimer=add_timer(sd->attackabletime,pc_attack_timer,sd->bl.id,0);
- } else { //Attack NOW.
- pc_attack_timer(-1,gettick(),sd->bl.id,0);
- }
-
- return 0;
-}
-
-/*==========================================
- * ??U?’âŽ~
- *------------------------------------------
- */
-int pc_stopattack(struct map_session_data *sd)
-{
- nullpo_retr(0, sd);
-
- if(sd->attacktimer != -1) {
- delete_timer(sd->attacktimer,pc_attack_timer);
- sd->attacktimer=-1;
- }
- sd->attacktarget=0;
- sd->state.attack_continue=0;
-
- return 0;
-}
-
int pc_follow_timer(int tid,unsigned int tick,int id,int data)
{
struct map_session_data *sd, *tsd;
@@ -4438,11 +3803,11 @@ int pc_follow_timer(int tid,unsigned int tick,int id,int data)
// either player or target is currently detached from map blocks (could be teleporting),
// but still connected to this map, so we'll just increment the timer and check back later
if (sd->bl.prev != NULL && tsd->bl.prev != NULL &&
- sd->skilltimer == -1 && sd->attacktimer == -1 && sd->walktimer == -1)
+ sd->ud.skilltimer == -1 && sd->ud.attacktimer == -1 && sd->ud.walktimer == -1)
{
- if((sd->bl.m == tsd->bl.m) && pc_can_reach(sd,tsd->bl.x,tsd->bl.y)) {
- if (!check_distance_bl(&sd->bl, &tsd->bl, 5) && pc_can_move(sd))
- pc_walktoxy(sd,tsd->bl.x,tsd->bl.y);
+ if((sd->bl.m == tsd->bl.m) && unit_can_reach(&sd->bl,tsd->bl.x,tsd->bl.y)) {
+ if (!check_distance_bl(&sd->bl, &tsd->bl, 5) && unit_can_move(&sd->bl))
+ unit_walktoxy(&sd->bl,tsd->bl.x,tsd->bl.y, 0);
} else
pc_setpos(sd, tsd->mapindex, tsd->bl.x, tsd->bl.y, 3);
}
@@ -5218,6 +4583,7 @@ int pc_damage(struct block_list *src,struct map_session_data *sd,int damage)
if(pc_issit(sd)) {
pc_setstand(sd);
skill_gangsterparadise(sd,0);
+ skill_rest(sd,0);
}
// ? ‚¢‚Ä‚¢‚½‚ç‘«‚ðŽ~‚ß‚é
@@ -5289,9 +4655,9 @@ int pc_damage(struct block_list *src,struct map_session_data *sd,int damage)
duel_reject(sd->duel_invite, sd);
}
- pc_stopattack(sd);
+ pc_stop_attack(sd);
pc_stop_walking(sd,0);
- skill_castcancel(&sd->bl,0); // ‰r¥‚Ì’†Ž~
+ unit_skillcastcancel(&sd->bl,0);
skill_stop_dancing(&sd->bl); //You should stop dancing when dead... [Skotlex]
if (sd->sc.data[SC_GOSPEL].timer != -1 && sd->sc.data[SC_GOSPEL].val4 == BCT_SELF)
{ //Remove Gospel [Skotlex]
@@ -5461,11 +4827,11 @@ int pc_damage(struct block_list *src,struct map_session_data *sd,int damage)
}
if(src && src->type==BL_MOB) {
struct mob_data *md=(struct mob_data *)src;
- if(md && md->target_id != 0 && md->target_id==sd->bl.id) { // reset target id when player dies
- md->target_id=0;
- mob_changestate(md,MS_WALK,0);
+ if(md && md->target_id != 0 && md->target_id==sd->bl.id) {
+ // reset target id when player dies
+ mob_unlocktarget(md,gettick());
}
- if(battle_config.mobs_level_up && md && md->state.state!=MS_DEAD &&
+ if(battle_config.mobs_level_up && md && md->hp &&
md->level < pc_maxbaselv(sd) &&
!md->guardian_data && !md->special_state.ai// Guardians/summons should not level. [Skotlex]
) { // monster level up [Valaris]
@@ -7451,9 +6817,9 @@ static int pc_natural_heal_hp(struct map_session_data *sd)
}
bhp=sd->status.hp;
- hp_flag = (pc_checkskill(sd,SM_MOVINGRECOVERY) > 0 && sd->walktimer != -1);
+ hp_flag = (pc_checkskill(sd,SM_MOVINGRECOVERY) > 0 && sd->ud.walktimer != -1);
- if(sd->walktimer == -1) {
+ if(sd->ud.walktimer == -1) {
inc_num = pc_hpheal(sd);
if(sd->sc.data[SC_TENSIONRELAX].timer!=-1 ){ // ƒeƒ“ƒVƒ‡ƒ“ƒŠƒ‰ƒbƒNƒX
sd->hp_sub += 2*inc_num;
@@ -7533,7 +6899,7 @@ static int pc_natural_heal_sp(struct map_session_data *sd)
inc_num = pc_spheal(sd);
if(sd->sc.data[SC_EXPLOSIONSPIRITS].timer == -1 || (sd->sc.data[SC_SPIRIT].timer!=-1 && sd->sc.data[SC_SPIRIT].val2 == SL_MONK))
sd->sp_sub += inc_num;
- if(sd->walktimer == -1)
+ if(sd->ud.walktimer == -1)
sd->inchealsptick += natural_heal_diff_tick;
else sd->inchealsptick = 0;
@@ -8243,8 +7609,6 @@ int do_init_pc(void) {
pc_readdb();
pc_read_motd(); // Read MOTD [Valaris]
- add_timer_func_list(pc_walk, "pc_walk");
- add_timer_func_list(pc_attack_timer, "pc_attack_timer");
add_timer_func_list(pc_natural_heal, "pc_natural_heal");
add_timer_func_list(pc_invincible_timer, "pc_invincible_timer");
add_timer_func_list(pc_eventtimer, "pc_eventtimer");
diff --git a/src/map/pc.h b/src/map/pc.h
index 66591adc8..a6e65a3b5 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -5,6 +5,7 @@
#define _PC_H_
#include "map.h"
+#include "unit.h"
#define OPTION_MASK 0xd7b8
#define CART_MASK 0x788
@@ -16,7 +17,7 @@
#define pc_setsit(sd) ((sd)->state.dead_sit = 2)
#define pc_isdead(sd) ((sd)->state.dead_sit == 1)
#define pc_issit(sd) ((sd)->state.dead_sit == 2)
-#define pc_setdir(sd,b,h) ((sd)->dir = (b) ,(sd)->head_dir = (h) )
+#define pc_setdir(sd,b,h) ((sd)->ud.dir = (b) ,(sd)->head_dir = (h) )
#define pc_setchatid(sd,n) ((sd)->chatID = n)
#define pc_ishiding(sd) ((sd)->sc.option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK))
#define pc_iscloaking(sd) (!((sd)->sc.option&OPTION_CHASEWALK) && ((sd)->sc.option&OPTION_CLOAK))
@@ -28,13 +29,16 @@
#define pc_is50overweight(sd) (sd->weight*2 >= sd->max_weight)
#define pc_is90overweight(sd) (sd->weight*10 >= sd->max_weight*9)
#define pc_maxparameter(sd) ((sd->class_&JOBL_BABY) ? battle_config.max_baby_parameter : battle_config.max_parameter)
+
+#define pc_stop_attack(sd) { if (sd->ud.attacktimer!=-1) unit_stop_attack(&sd->bl); }
+#define pc_stop_walking(sd, type) { if (sd->ud.walktimer!=-1) unit_stop_walking(&sd->bl, type); }
+
//Checks if the given class value corresponds to a player class. [Skotlex]
#define pcdb_checkid(class_) ((class_ >= JOB_NOVICE && class_ <= JOB_XMAS) || (class_ >= JOB_NOVICE_HIGH && class_ <= JOB_SOUL_LINKER))
int pc_isGM(struct map_session_data *sd);
int pc_iskiller(struct map_session_data *src, struct map_session_data *target); // [MouseJstr]
int pc_getrefinebonus(int lv,int type);
-int pc_can_move(struct map_session_data *sd); //[Skotlex]
int pc_can_give_items(int level); //[Lupus]
int pc_setrestartvalue(struct map_session_data *sd,int type);
@@ -58,10 +62,6 @@ int pc_clean_skilltree(struct map_session_data *sd);
int pc_checkoverhp(struct map_session_data*);
int pc_checkoversp(struct map_session_data*);
-int pc_can_reach(struct map_session_data*,int,int);
-int pc_walktoxy(struct map_session_data*,int,int);
-int pc_stop_walking(struct map_session_data*,int);
-int pc_movepos(struct map_session_data*,int,int,int);
int pc_setpos(struct map_session_data*,unsigned short,int,int,int);
int pc_setsavepoint(struct map_session_data*,short,int,int);
int pc_randomwarp(struct map_session_data *sd,int type);
@@ -102,9 +102,6 @@ int pc_steal_coin(struct map_session_data *sd,struct block_list *bl);
int pc_modifybuyvalue(struct map_session_data*,int);
int pc_modifysellvalue(struct map_session_data*,int);
-int pc_attack(struct map_session_data*,int,int);
-int pc_stopattack(struct map_session_data*);
-
int pc_follow(struct map_session_data*, int); // [MouseJstr]
int pc_stop_following(struct map_session_data*);
diff --git a/src/map/pet.c b/src/map/pet.c
index 306f21ff2..e578e97d6 100644
--- a/src/map/pet.c
+++ b/src/map/pet.c
@@ -32,22 +32,6 @@ struct pet_db pet_db[MAX_PET_DB];
static int dirx[8]={0,-1,-1,-1,0,1,1,1};
static int diry[8]={1,1,0,-1,-1,-1,0,1};
-static int pet_timer(int tid,unsigned int tick,int id,int data);
-static int pet_walktoxy_sub(struct pet_data *pd);
-
-static int calc_next_walk_step(struct pet_data *pd)
-{
- nullpo_retr(0, pd);
-
- Assert((pd->msd == 0) || (pd->msd->pd == pd));
-
- if(pd->walkpath.path_pos>=pd->walkpath.path_len)
- return -1;
- if(pd->walkpath.path[pd->walkpath.path_pos]&1)
- return pd->speed*14/10;
- return pd->speed;
-}
-
static int pet_performance_val(struct map_session_data *sd)
{
nullpo_retr(0, sd);
@@ -80,346 +64,95 @@ int pet_hungry_val(struct map_session_data *sd)
return 0;
}
-static int pet_can_reach(struct pet_data *pd,int x,int y)
-{
- struct walkpath_data wpd;
-
- nullpo_retr(0, pd);
-
- Assert((pd->msd == 0) || (pd->msd->pd == pd));
-
- if( pd->bl.x==x && pd->bl.y==y ) // “¯‚¶ƒ}ƒX
- return 1;
-
- // áŠQ•¨”»’è
- wpd.path_len=0;
- wpd.path_pos=0;
- wpd.path_half=0;
- return (path_search_real(&wpd,pd->bl.m,pd->bl.x,pd->bl.y,x,y,0,CELL_CHKNOREACH)!=-1)?1:0;
-}
-
static int pet_calc_pos(struct pet_data *pd,int tx,int ty,int dir)
{
int x,y,dx,dy;
- int i,j=0,k;
+ int i,k;
nullpo_retr(0, pd);
- Assert((pd->msd == 0) || (pd->msd->pd == pd));
+ pd->ud.to_x = tx;
+ pd->ud.to_y = ty;
- pd->to_x = tx;
- pd->to_y = ty;
-
- if(dir >= 0 && dir < 8) {
- dx = -dirx[dir]*2;
- dy = -diry[dir]*2;
- x = tx + dx;
- y = ty + dy;
- if(!(j=pet_can_reach(pd,x,y))) {
- if(dx > 0) x--;
- else if(dx < 0) x++;
- if(dy > 0) y--;
- else if(dy < 0) y++;
- if(!(j=pet_can_reach(pd,x,y))) {
- for(i=0;i<12;i++) {
- k = rand()%8;
- dx = -dirx[k]*2;
- dy = -diry[k]*2;
- x = tx + dx;
- y = ty + dy;
- if((j=pet_can_reach(pd,x,y)))
+ if(dir < 0 || dir >= 8)
+ return 1;
+
+ dx = -dirx[dir]*2;
+ dy = -diry[dir]*2;
+ x = tx + dx;
+ y = ty + dy;
+ if(!unit_can_reach(&pd->bl,x,y)) {
+ if(dx > 0) x--;
+ else if(dx < 0) x++;
+ if(dy > 0) y--;
+ else if(dy < 0) y++;
+ if(!unit_can_reach(&pd->bl,x,y)) {
+ for(i=0;i<12;i++) {
+ k = rand()%8;
+ dx = -dirx[k]*2;
+ dy = -diry[k]*2;
+ x = tx + dx;
+ y = ty + dy;
+ if(unit_can_reach(&pd->bl,x,y))
+ break;
+ else {
+ if(dx > 0) x--;
+ else if(dx < 0) x++;
+ if(dy > 0) y--;
+ else if(dy < 0) y++;
+ if(unit_can_reach(&pd->bl,x,y))
break;
- else {
- if(dx > 0) x--;
- else if(dx < 0) x++;
- if(dy > 0) y--;
- else if(dy < 0) y++;
- if((j=pet_can_reach(pd,x,y)))
- break;
- }
- }
- if(!j) {
- x = tx;
- y = ty;
- if(!pet_can_reach(pd,x,y))
- return 1;
}
}
+ if(i>=12) {
+ x = tx;
+ y = ty;
+ if(!unit_can_reach(&pd->bl,x,y))
+ return 1;
+ }
}
}
- else
- return 1;
-
- pd->to_x = x;
- pd->to_y = y;
+ pd->ud.to_x = x;
+ pd->ud.to_y = y;
return 0;
}
-static int pet_unlocktarget(struct pet_data *pd)
+int pet_unlocktarget(struct pet_data *pd)
{
nullpo_retr(0, pd);
pd->target_id=0;
-
+ pet_stop_attack(pd);
return 0;
}
-static int pet_attack(struct pet_data *pd,unsigned int tick,int data)
-{
- struct block_list *target;
-
- short range;
-
- nullpo_retr(0, pd);
-
- Assert((pd->msd == 0) || (pd->msd->pd == pd));
-
- target= map_id2bl(pd->target_id);
-
- if(target == NULL || pd->bl.m != target->m || target->prev == NULL ||
- !check_distance_bl(&pd->bl, target, pd->db->range3))
- {
- pet_unlocktarget(pd);
- return 0;
- }
-
- if(!status_check_skilluse(&pd->bl, target, 0, 0))
- return 0;
-
- range = pd->db->range;
- if (battle_iswalking(&pd->bl)) range++;
- if (battle_iswalking(target)) range++;
- if(!check_distance_bl(&pd->bl, target, range))
- return 0;
- if(battle_config.monster_attack_direction_change)
- pd->dir=map_calc_dir(&pd->bl, target->x,target->y );
-
- clif_fixpetpos(pd);
-
- pd->target_lv = battle_weapon_attack(&pd->bl,target,tick,0);
-
- pd->attackabletime = tick + status_get_adelay(&pd->bl);
-
- pd->timer=add_timer(pd->attackabletime,pet_timer,pd->bl.id,0);
- pd->state.state=MS_ATTACK;
- return 0;
-}
-
-static int petskill_castend(struct pet_data *pd,unsigned int tick,int data);
-static int petskill_castend2(struct pet_data *pd, struct block_list *target, unsigned int tick);
-
/*==========================================
* Pet Attack Skill [Skotlex]
*------------------------------------------
*/
-static int pet_attackskill(struct pet_data *pd, unsigned int tick, int data)
+int pet_attackskill(struct pet_data *pd, int target_id)
{
-
struct block_list *bl;
-
- nullpo_retr(0, pd);
- Assert((pd->msd == 0) || (pd->msd->pd == pd));
- bl=map_id2bl(pd->target_id);
- if(bl == NULL || pd->bl.m != bl->m || bl->prev == NULL ||
- !check_distance_bl(&pd->bl, bl, pd->db->range3))
- {
- pet_unlocktarget(pd);
+ if (!battle_config.pet_status_support || !pd->a_skill ||
+ (battle_config.pet_equip_required && !pd->equip))
return 0;
- }
-
- petskill_use(pd, bl, pd->a_skill->id, pd->a_skill->lv, tick);
- return 0;
-}
-/*==========================================
- * Pet Skill Use [Skotlex]
- *------------------------------------------
- */
-int petskill_use(struct pet_data *pd, struct block_list *target, short skill_id, short skill_lv, unsigned int tick)
-{
- int casttime;
-
- nullpo_retr(0, pd);
- Assert((pd->msd == 0) || (pd->msd->pd == pd));
-
- if(pd->state.casting_flag)
- return 1; //Will not interrupt an already casting skill.
-
- if(!status_check_skilluse(&pd->bl, target, skill_id, 0))
- return 0; //Cannot target....
-
- if(pd->timer != -1) //Cancel whatever else the pet is doing.
- delete_timer(pd->timer, pet_timer);
-
- if(battle_config.monster_attack_direction_change)
- pd->dir=map_calc_dir(&pd->bl, target->x, target->y );
- clif_fixpetpos(pd);
-
- //Casting time
- casttime=skill_castfix(&pd->bl, skill_id, skill_lv, 0);
-
- pet_stop_walking(pd,1);
- pd->attackabletime = tick;
- pd->state.state=MS_ATTACK;
-
- pd->skilltarget = target->id;
- pd->skillid = skill_id;
- pd->skilllv = skill_lv;
- pd->skillx = target->x;
- pd->skilly = target->y;
- if (casttime > 0)
- {
- pd->attackabletime += casttime;
- pd->state.casting_flag = 1;
- if (skill_get_inf(skill_id) & INF_GROUND_SKILL)
- clif_skillcasting( &pd->bl, pd->bl.id, 0, pd->skillx, pd->skilly, skill_id,casttime);
- else
- clif_skillcasting( &pd->bl, pd->bl.id, target->id, 0,0, skill_id,casttime);
-
- pd->timer = add_timer(pd->attackabletime,pet_timer,pd->bl.id,0);
- } else {
- petskill_castend2(pd, target, tick);
- }
- return 0;
-}
-
-/*==========================================
- * Pet Attack Cast End [Skotlex]
- *------------------------------------------
- */
-static int petskill_castend(struct pet_data *pd,unsigned int tick,int data)
-{
- struct block_list *target = map_id2bl(pd->skilltarget);
- pd->state.casting_flag = 0;
- pd->skilltarget = 0;
- petskill_castend2(pd, target, tick);
- return 0;
-}
-
-/*==========================================
- * Pet Attack Cast End2 [Skotlex]
- *------------------------------------------
- */
-static int petskill_castend2(struct pet_data *pd, struct block_list *target, unsigned int tick)
-{ //Invoked after the casting time has passed.
- int delaytime =0;
- int skill_id = pd->skillid, skill_lv = pd->skilllv;
-
- pd->state.state=MS_IDLE;
-
- if (skill_get_inf(skill_id)&INF_GROUND_SKILL)
- { //Area skill
- skill_castend_pos2(&pd->bl, pd->skillx, pd->skilly, pd->skillid, pd->skilllv, tick,0);
- pd->skillx = pd->skilly = 0;
- } else { //Targeted Skill
- if (!target)
+ if (rand()%100 < (pd->a_skill->rate +pd->msd->pet.intimate*pd->a_skill->bonusrate/1000))
+ { //Skotlex: Use pet's skill
+ bl=map_id2bl(target_id);
+ if(bl == NULL || pd->bl.m != bl->m || bl->prev == NULL || status_isdead(bl) ||
+ !check_distance_bl(&pd->bl, bl, pd->db->range3))
return 0;
- if(!skill_get_inf(skill_id)&INF_SELF_SKILL && //No range check for self skills.
- !check_distance_bl(&pd->bl, target,
- skill_get_range2(&pd->bl, skill_id, skill_lv)))
- return 0;
-
- if (!status_check_skilluse(&pd->bl, target, skill_id, 1))
- return 0;
- if (skill_get_casttype(skill_id) == CAST_NODAMAGE)
- skill_castend_nodamage_id(&pd->bl, target, skill_id, skill_lv, tick, 0);
+ if (skill_get_inf(pd->a_skill->id) & INF_GROUND_SKILL)
+ unit_skilluse_pos(&pd->bl, bl->x, bl->y, pd->a_skill->id, pd->a_skill->lv);
else
- skill_castend_damage_id(&pd->bl, target, skill_id, skill_lv, tick,0);
- }
-
- if (pd->timer != -1) //The above skill casting could had changed the state (Abracadabra?)
- return 0;
-
- pd->skillid = pd->skilllv = 0;
- delaytime = skill_delayfix(&pd->bl,skill_id, skill_lv, 0);
- if (delaytime < MIN_PETTHINKTIME)
- delaytime = status_get_adelay(&pd->bl);
- pd->attackabletime = tick + delaytime;
- if (pd->target_id)
- { //Resume attacking
- pd->state.state=MS_ATTACK;
- pd->timer=add_timer(pd->attackabletime,pet_timer,pd->bl.id,0);
- }
-
- return 0;
-}
-
-/*==========================================
- *
- *------------------------------------------
- */
-static int pet_walk(struct pet_data *pd,unsigned int tick,int data)
-{
- int i;
- int x,y,dx,dy;
-
- nullpo_retr(0, pd);
-
- pd->state.state=MS_IDLE;
- if(pd->walkpath.path_pos >= pd->walkpath.path_len || pd->walkpath.path_pos != data)
- return 0;
-
- pd->walkpath.path_half ^= 1;
- if(pd->walkpath.path_half==0){
- pd->walkpath.path_pos++;
- if(pd->state.change_walk_target){
- pet_walktoxy_sub(pd);
- return 0;
- }
- }
- else {
- if(pd->walkpath.path[pd->walkpath.path_pos] >= 8)
- return 1;
-
- x = pd->bl.x;
- y = pd->bl.y;
-
- pd->dir=pd->walkpath.path[pd->walkpath.path_pos];
- dx = dirx[pd->dir];
- dy = diry[pd->dir];
-
- if(map_getcell(pd->bl.m,x+dx,y+dy,CELL_CHKNOPASS)){
- pet_walktoxy_sub(pd);
- return 0;
- }
-
- pd->state.state=MS_WALK;
- map_foreachinmovearea(clif_petoutsight,pd->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_PC,pd);
-
- x += dx;
- y += dy;
- map_moveblock(&pd->bl, x, y, tick);
-
- map_foreachinmovearea(clif_petinsight,pd->bl.m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,-dx,-dy,BL_PC,pd);
- pd->state.state=MS_IDLE;
- }
- if((i=calc_next_walk_step(pd))>0){
- i = i>>1;
- if(i < 1 && pd->walkpath.path_half == 0)
- i = 1;
- pd->timer=add_timer(tick+i,pet_timer,pd->bl.id,pd->walkpath.path_pos);
- pd->state.state=MS_WALK;
-
- if(pd->walkpath.path_pos >= pd->walkpath.path_len)
- clif_fixpetpos(pd);
+ unit_skilluse_id(&pd->bl, bl->id, pd->a_skill->id, pd->a_skill->lv);
+ return 1; //Skill invoked.
}
return 0;
}
-int pet_stopattack(struct pet_data *pd)
-{
- nullpo_retr(0, pd);
-
- Assert((pd->msd == 0) || (pd->msd->pd == pd));
-
- pd->target_id=0;
- if(pd->state.state == MS_ATTACK)
- pet_changestate(pd,MS_IDLE,0);
-
- return 0;
-}
-
int pet_target_check(struct map_session_data *sd,struct block_list *bl,int type)
{
struct pet_data *pd;
@@ -432,8 +165,7 @@ int pet_target_check(struct map_session_data *sd,struct block_list *bl,int type)
if(bl == NULL || bl->type != BL_MOB || bl->prev == NULL ||
sd->pet.intimate < battle_config.pet_support_min_friendly ||
sd->pet.hungry < 1 ||
- pd->class_ == status_get_class(bl) ||
- pd->state.state == MS_DELAY)
+ pd->class_ == status_get_class(bl))
return 0;
if(pd->bl.m != bl->m ||
@@ -485,171 +217,6 @@ int pet_sc_check(struct map_session_data *sd, int type)
return 0;
}
-int pet_changestate(struct pet_data *pd,int state,int type)
-{
- unsigned int tick;
- int i;
-
- nullpo_retr(0, pd);
-
- Assert((pd->msd == 0) || (pd->msd->pd == pd));
-
- if (pd->state.casting_flag)
- skill_castcancel(&pd->bl, 0);
- if(pd->timer != -1)
- delete_timer(pd->timer,pet_timer);
- pd->timer=-1;
- pd->state.state=state;
-
- switch(state) {
- case MS_WALK:
- if((i=calc_next_walk_step(pd)) > 0){
- i = i>>2;
- pd->timer=add_timer(gettick()+i,pet_timer,pd->bl.id,0);
- } else
- pd->state.state=MS_IDLE;
- break;
- case MS_ATTACK:
- tick = gettick();
- i=DIFF_TICK(pd->attackabletime,tick);
- if(i>0 && i<2000)
- pd->timer=add_timer(pd->attackabletime,pet_timer,pd->bl.id,0);
- else
- pd->timer=add_timer(tick+1,pet_timer,pd->bl.id,0);
- break;
- case MS_DELAY:
- pd->timer=add_timer(gettick()+type,pet_timer,pd->bl.id,0);
- break;
- }
-
- return 0;
-}
-
-static int pet_timer(int tid,unsigned int tick,int id,int data)
-{
- struct pet_data *pd;
-
- pd=(struct pet_data*)map_id2bl(id);
- if(pd == NULL || pd->bl.type != BL_PET)
- return 1;
-
- Assert((pd->msd == 0) || (pd->msd->pd == pd));
-
- if(pd->timer != tid){
- if(battle_config.error_log)
- ShowError("pet_timer %d != %d\n",pd->timer,tid);
- return 0;
- }
- pd->timer=-1;
-
- if(pd->bl.prev == NULL)
- return 1;
-
- switch(pd->state.state){
- case MS_WALK:
- pet_walk(pd,tick,data);
- break;
- case MS_ATTACK:
- if (pd->msd == NULL) //Is this even possible?
- break;
- if (pc_isdead(pd->msd))
- { //Stop attacking when master died.
- pet_stopattack(pd);
- break;
- }
- if (pd->state.casting_flag)
- { //There is a skill being cast.
- petskill_castend(pd, tick, data);
- break;
- }
- if (battle_config.pet_status_support &&
- pd->a_skill &&
- (!battle_config.pet_equip_required || pd->equip > 0) &&
- (rand()%100 < (pd->a_skill->rate +pd->msd->pet.intimate*pd->a_skill->bonusrate/1000))
- )
- { //Skotlex: Use pet's skill
- pet_attackskill(pd,tick,data);
- break;
- }
- pet_attack(pd,tick,data);
- break;
- case MS_DELAY:
- pet_changestate(pd,MS_IDLE,0);
- break;
- default:
- if(battle_config.error_log)
- ShowError("pet_timer : %d ?\n",pd->state.state);
- break;
- }
-
- return 0;
-}
-
-static int pet_walktoxy_sub(struct pet_data *pd)
-{
- struct walkpath_data wpd;
-
- nullpo_retr(0, pd);
-
- Assert((pd->msd == 0) || (pd->msd->pd == pd));
-
- if(path_search(&wpd,pd->bl.m,pd->bl.x,pd->bl.y,pd->to_x,pd->to_y,0))
- return 1;
- memcpy(&pd->walkpath,&wpd,sizeof(wpd));
-
- pd->state.change_walk_target=0;
- pet_changestate(pd,MS_WALK,0);
- clif_movepet(pd);
-// if(battle_config.etc_log)
-// printf("walkstart\n");
-
- return 0;
-}
-
-int pet_walktoxy(struct pet_data *pd,int x,int y)
-{
- struct walkpath_data wpd;
-
- nullpo_retr(0, pd);
-
- Assert((pd->msd == 0) || (pd->msd->pd == pd));
-
- if(pd->state.state == MS_WALK && path_search(&wpd,pd->bl.m,pd->bl.x,pd->bl.y,x,y,0))
- return 1;
-
- pd->to_x=x;
- pd->to_y=y;
-
- if(pd->state.state == MS_WALK) {
- pd->state.change_walk_target=1;
- } else {
- return pet_walktoxy_sub(pd);
- }
-
- return 0;
-}
-
-int pet_stop_walking(struct pet_data *pd,int type)
-{
- nullpo_retr(0, pd);
-
- Assert((pd->msd == 0) || (pd->msd->pd == pd));
-
- if(pd->state.state == MS_WALK || pd->state.state == MS_IDLE) {
- pd->walkpath.path_len=0;
- pd->to_x=pd->bl.x;
- pd->to_y=pd->bl.y;
- }
- if(type&0x01)
- clif_fixpetpos(pd);
- if(type&~0xff)
- pet_changestate(pd,MS_DELAY,type>>8);
- else
- pet_changestate(pd,MS_IDLE,0);
-
- return 0;
-}
-
static int pet_hungry(int tid,unsigned int tick,int id,int data)
{
struct map_session_data *sd;
@@ -671,15 +238,18 @@ static int pet_hungry(int tid,unsigned int tick,int id,int data)
if(!sd->status.pet_id || !sd->pd || !sd->petDB)
return 1;
+ if (sd->pet.intimate <= 0)
+ return 1; //You lost the pet already, the rest is irrelevant.
+
sd->pet.hungry--;
t = sd->pet.intimate;
if(sd->pet.hungry < 0) {
- if(sd->pd->target_id > 0)
- pet_stopattack(sd->pd);
+ pet_stop_attack(sd->pd);
sd->pet.hungry = 0;
sd->pet.intimate -= battle_config.pet_hungry_friendly_decrease;
if(sd->pet.intimate <= 0) {
sd->pet.intimate = 0;
+ sd->pd->speed = sd->pd->db->speed;
if(battle_config.pet_status_support && t > 0) {
if(sd->bl.prev != NULL)
status_calc_pc(sd,0);
@@ -750,76 +320,6 @@ int pet_hungry_timer_delete(struct map_session_data *sd)
return 0;
}
-int pet_remove_map(struct map_session_data *sd)
-{
- nullpo_retr(0, sd);
-
- Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd);
-
- if(sd->status.pet_id && sd->pd) {
-
- struct pet_data *pd=sd->pd; // [Valaris]
- skill_cleartimerskill(&pd->bl); //Just in case pets get a timer-based skill.
- //[Skotlex] clear bonus data
- if (pd->status)
- {
- aFree(pd->status);
- pd->status = NULL;
- }
- if (pd->a_skill)
- {
- aFree(pd->a_skill);
- pd->a_skill = NULL;
- }
- if (pd->s_skill)
- {
- if (pd->s_skill->timer != -1)
- {
- if (sd->pd->s_skill->id)
- delete_timer(sd->pd->s_skill->timer, pet_skill_support_timer);
- else
- delete_timer(sd->pd->s_skill->timer, pet_heal_timer);
- }
- aFree(pd->s_skill);
- pd->s_skill = NULL;
- }
- if(pd->recovery)
- {
- if(pd->recovery->timer != -1)
- delete_timer(pd->recovery->timer, pet_recovery_timer);
- aFree(pd->recovery);
- pd->recovery = NULL;
- }
- if(pd->bonus)
- {
- if (pd->bonus->timer != -1)
- delete_timer(pd->bonus->timer, pet_skill_bonus_timer);
- aFree(pd->bonus);
- pd->bonus = NULL;
- }
- if (pd->loot)
- {
- if (pd->loot->item)
- aFree(pd->loot->item);
- // if (pd->loot->timer != -1)
- // delete_timer(pd->loot->timer, pet_loot_timer);
- aFree (pd->loot);
- pd->loot = NULL;
- }
- pd->state.skillbonus=-1;
- if(sd->state.perfect_hiding) sd->state.perfect_hiding=0; // end additions
-
- pet_changestate(sd->pd,MS_IDLE,0);
- if(sd->pet_hungry_timer != -1)
- pet_hungry_timer_delete(sd);
- clif_clearchar_area(&sd->pd->bl,0);
- map_delblock(&sd->pd->bl);
- map_deliddb(&sd->pd->bl);
- aFree(sd->pd);
- sd->pd = NULL;
- }
- return 0;
-}
struct delay_item_drop {
int m,x,y;
int nameid,amount;
@@ -861,10 +361,7 @@ int pet_return_egg(struct map_session_data *sd)
if(sd->status.pet_id && sd->pd) {
// ƒ‹[ƒg‚µ‚½Item‚ð—Ž‚Æ‚³‚¹‚é
pet_lootitem_drop(sd->pd,sd);
- pet_remove_map(sd);
- sd->status.pet_id = 0;
- sd->pd = NULL;
-
+ unit_free(&sd->pd->bl);
if(sd->petDB == NULL)
return 1;
memset(&tmp_item,0,sizeof(tmp_item));
@@ -879,17 +376,17 @@ int pet_return_egg(struct map_session_data *sd)
map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,NULL,NULL,NULL,0);
}
sd->pet.incuvate = 1;
+ sd->pet.pet_id = 0;
+ sd->pet.rename_flag = 0; //Prevents future captured pets from starting as "beloved" [Skotlex]
if(battle_config.pet_status_support && sd->pet.intimate > 0) {
if(sd->bl.prev != NULL)
status_calc_pc(sd,0);
else
status_calc_pc(sd,2);
}
-
intif_save_petdata(sd->status.account_id,&sd->pet);
chrif_save(sd,0); //FIXME: Do we really need to save the char when returning to pet? Seems like a waste, and unexploitable as the pet data is just moved to an item in the inventory. [Skotlex]
- sd->pet.rename_flag = 0; //Prevents future captured pets from starting as "beloved" [Skotlex]
sd->petDB = NULL;
}
@@ -919,24 +416,22 @@ int pet_data_init(struct map_session_data *sd)
sd->petDB = &pet_db[i];
sd->pd = pd = (struct pet_data *)aCalloc(1,sizeof(struct pet_data));
pd->bl.m = sd->bl.m;
- pd->bl.x = pd->to_x = sd->bl.x;
- pd->bl.y = pd->to_y = sd->bl.y;
- pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->dir);
- pd->bl.x = pd->to_x;
- pd->bl.y = pd->to_y;
+ pd->bl.x = sd->bl.x;
+ pd->bl.y = sd->bl.y;
+ pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->ud.dir);
+ pd->bl.x = pd->ud.to_x;
+ pd->bl.y = pd->ud.to_y;
pd->bl.id = npc_get_new_npc_id();
memcpy(pd->name, sd->pet.name, NAME_LENGTH-1);
pd->class_ = sd->pet.class_;
pd->db = mob_db(pd->class_);
pd->equip = sd->pet.equip;
- pd->dir = sd->dir;
pd->speed = sd->petDB->speed;
pd->bl.subtype = MONS;
pd->bl.type = BL_PET;
- pd->state.state = MS_IDLE;
- pd->timer = -1;
- pd->next_walktime = pd->attackabletime = pd->last_thinktime = gettick();
pd->msd = sd;
+ unit_dataset(&sd->pd->bl);
+ pd->ud.dir = sd->ud.dir;
map_addiddb(&pd->bl);
@@ -950,9 +445,6 @@ int pet_data_init(struct map_session_data *sd)
if (battle_config.pet_status_support) //Skotlex
run_script(pet_db[i].script,0,sd->bl.id,0);
- for(i=0;i<MAX_MOBSKILLTIMERSKILL;i++)
- pd->skilltimerskill[i].timer = -1;
-
if(sd->pet_hungry_timer != -1)
pet_hungry_timer_delete(sd);
if(battle_config.pet_hungry_delay_rate != 100)
@@ -1132,8 +624,7 @@ int pet_catch_process2(struct map_session_data *sd,int target_id)
pet_catch_rate = (pet_catch_rate*battle_config.pet_catch_rate)/100;
if(rand()%10000 < pet_catch_rate) {
- mob_remove_map(md,0);
- mob_setdelayspawn(md->bl.id);
+ unit_remove_map(&md->bl,0);
clif_pet_rulet(sd,1);
// if(battle_config.etc_log)
// printf("rulet success %d\n",target_id);
@@ -1323,8 +814,6 @@ int pet_food(struct map_session_data *sd)
nullpo_retr(1, sd);
- Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd);
-
if(sd->petDB == NULL)
return 1;
i=pc_search_inventory(sd,sd->petDB->FoodID);
@@ -1355,6 +844,9 @@ int pet_food(struct map_session_data *sd)
}
if(sd->pet.intimate <= 0) {
sd->pet.intimate = 0;
+ pet_stop_attack(sd->pd);
+ sd->pd->speed = sd->pd->db->speed;
+
if(battle_config.pet_status_support && t > 0) {
if(sd->bl.prev != NULL)
status_calc_pc(sd,0);
@@ -1376,7 +868,7 @@ int pet_food(struct map_session_data *sd)
return 0;
}
-static int pet_randomwalk(struct pet_data *pd,int tick)
+static int pet_randomwalk(struct pet_data *pd,unsigned int tick)
{
const int retrycount=20;
int speed;
@@ -1394,7 +886,7 @@ static int pet_randomwalk(struct pet_data *pd,int tick)
int r=rand();
x=pd->bl.x+r%(d*2+1)-d;
y=pd->bl.y+r/(d*2+1)%(d*2+1)-d;
- if((map_getcell(pd->bl.m,x,y,CELL_CHKPASS))&&( pet_walktoxy(pd,x,y)==0)){
+ if(map_getcell(pd->bl.m,x,y,CELL_CHKPASS) && unit_walktoxy(&pd->bl,x,y,0)){
pd->move_fail_count=0;
break;
}
@@ -1404,13 +896,13 @@ static int pet_randomwalk(struct pet_data *pd,int tick)
if(battle_config.error_log)
ShowWarning("PET cant move. hold position %d, class = %d\n",pd->bl.id,pd->class_);
pd->move_fail_count=0;
- pet_changestate(pd,MS_DELAY,60000);
+ pd->ud.canmove_tick = tick + 60000;
return 0;
}
}
}
- for(i=c=0;i<pd->walkpath.path_len;i++){
- if(pd->walkpath.path[i]&1)
+ for(i=c=0;i<pd->ud.walkpath.path_len;i++){
+ if(pd->ud.walkpath.path[i]&1)
c+=speed*14/10;
else
c+=speed;
@@ -1424,12 +916,9 @@ static int pet_randomwalk(struct pet_data *pd,int tick)
static int pet_ai_sub_hard(struct pet_data *pd,unsigned int tick)
{
- struct map_session_data *sd = pd->msd;
- struct block_list *bl = NULL;
- int dist,i=0,dx,dy,ret;
- int mode,race;
-
- nullpo_retr(0, pd);
+ struct map_session_data *sd;
+ struct block_list *target = NULL;
+ int i=0,dx,dy;
sd = pd->msd;
@@ -1442,142 +931,136 @@ static int pet_ai_sub_hard(struct pet_data *pd,unsigned int tick)
return 0;
pd->last_thinktime=tick;
- if(pd->state.state == MS_DELAY || pd->bl.m != sd->bl.m)
+ if(pd->ud.attacktimer != -1 || pd->ud.skilltimer != -1 || pd->bl.m != sd->bl.m)
+ return 0;
+
+ if(pd->ud.walktimer != -1 && pd->ud.walkpath.path_pos <= 3)
+ return 0; //No thinking when you just started to walk.
+
+ if(sd->pet.intimate <= 0) {
+ //Pet should just... well, random walk.
+ pet_randomwalk(pd,tick);
+ return 0;
+ }
+
+ if (!check_distance_bl(&sd->bl, &pd->bl, pd->db->range2)) {
+ //Master too far, chase.
+ if(pd->target_id)
+ pet_unlocktarget(pd);
+ if(pd->ud.walktimer != -1 && check_distance_blxy(&sd->bl, pd->ud.to_x,pd->ud.to_y, 3))
+ return 0; //Already walking to him
+
+ pd->speed = (sd->speed>>1);
+ if(pd->speed <= 0)
+ pd->speed = 1;
+ pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->ud.dir);
+ if(!unit_walktoxy(&pd->bl,pd->ud.to_x,pd->ud.to_y,0))
+ pet_randomwalk(pd,tick);
return 0;
+ }
+
+ //Return speed to normal.
+ if (pd->speed == 1 || pd->speed == sd->speed>>1);
+ pd->speed = status_get_speed(&pd->bl);
+
+ if (pd->target_id) {
+ target= map_id2bl(pd->target_id);
+ if (!target || pd->bl.m != target->m || target->prev == NULL ||
+ !check_distance_bl(&pd->bl, target, pd->db->range3))
+ pet_unlocktarget(pd);
+ }
+
// ƒyƒbƒg‚É‚æ‚郋[ƒg
- if(!pd->target_id && pd->loot && pd->loot->count < pd->loot->max && DIFF_TICK(gettick(),pd->loot->timer)>0)
+ if(!pd->target_id && pd->loot && pd->loot->count < pd->loot->max && DIFF_TICK(tick,pd->ud.canact_tick)>0)
//Use half the pet's range of sight.
map_foreachinrange(pet_ai_sub_hard_lootsearch,&pd->bl,
pd->db->range2/2, BL_ITEM,pd,&i);
- if(sd->pet.intimate > 0) {
- dist = distance_bl(&sd->bl, &pd->bl);
- if(dist > 12) {
- if(pd->target_id > 0)
- pet_unlocktarget(pd);
- if(pd->timer != -1 && pd->state.state == MS_WALK && check_distance_blxy(&sd->bl, pd->to_x, pd->to_y, 3))
- return 0;
- pd->speed = (sd->speed>>1);
- if(pd->speed <= 0)
- pd->speed = 1;
- pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->dir);
- if(pet_walktoxy(pd,pd->to_x,pd->to_y))
- pet_randomwalk(pd,tick);
- }
- else if(pd->target_id - MAX_FLOORITEM > 0) { //Mob targeted
- mode=pd->db->mode;
- race=pd->db->race;
- bl= map_id2bl(pd->target_id);
- if(bl == NULL || pd->bl.m != bl->m || bl->prev == NULL ||
- !check_distance_bl(&pd->bl, bl, pd->db->range3))
- pet_unlocktarget(pd);
- else if(!battle_check_range(&pd->bl,bl,pd->db->range) && !pd->state.casting_flag){ //Skotlex Don't interrupt a casting spell when targed moved
- if(pd->timer != -1 && pd->state.state == MS_WALK && check_distance_blxy(bl, pd->to_x, pd->to_y, 2))
- return 0;
- if(!pet_can_reach(pd, bl->x, bl->y))
- pet_unlocktarget(pd);
- else {
- i=0;
- pd->speed = status_get_speed(&pd->bl);
- do {
- if(i==0) { // ʼn‚ÍAEGIS‚Æ“¯‚¶•û–@‚ÅŒŸõ
- dx=bl->x - pd->bl.x;
- dy=bl->y - pd->bl.y;
- if(dx<0) dx++;
- else if(dx>0) dx--;
- if(dy<0) dy++;
- else if(dy>0) dy--;
- }
- else { // ‚¾‚ß‚È‚çAthenaŽ®(ƒ‰ƒ“ƒ_ƒ€)
- dx=bl->x - pd->bl.x + rand()%3 - 1;
- dy=bl->y - pd->bl.y + rand()%3 - 1;
- }
- ret=pet_walktoxy(pd,pd->bl.x+dx,pd->bl.y+dy);
- i++;
- } while(ret && i<5);
-
- if(ret) { // ˆÚ“®•s‰Â”\‚ÈŠ‚©‚ç‚ÌUŒ‚‚È‚ç2•à‰º‚é
- if(dx<0) dx=2;
- else if(dx>0) dx=-2;
- if(dy<0) dy=2;
- else if(dy>0) dy=-2;
- pet_walktoxy(pd,pd->bl.x+dx,pd->bl.y+dy);
- }
- }
- }
- else {
- if(pd->state.state==MS_WALK)
- pet_stop_walking(pd,1);
- if(pd->state.state==MS_ATTACK)
- return 0;
- pet_changestate(pd,MS_ATTACK,0);
- }
- }
- else if(pd->target_id > 0 && pd->loot){ //Item Targeted, attempt loot
- struct block_list *bl_item;
- struct flooritem_data *fitem;
-
- bl_item = map_id2bl(pd->target_id);
- if(bl_item == NULL || bl_item->type != BL_ITEM ||bl_item->m != pd->bl.m ||
- (dist=distance_bl(&pd->bl, bl_item))>=5){
- // ‰“‚·‚¬‚é‚©ƒAƒCƒeƒ€‚ª‚È‚­‚È‚Á‚½
- pet_unlocktarget(pd);
- }
- else if(dist){
- if(pd->timer != -1 && pd->state.state!=MS_ATTACK && (DIFF_TICK(pd->next_walktime,tick)<0 || !check_distance_blxy(bl_item, pd->to_x, pd->to_y, 0)))
- return 0; // Šù‚Ɉړ®’†
+ if (!target) {
+ //Just walk around.
+ if (check_distance_bl(&sd->bl, &pd->bl, 3))
+ return 0; //Already next to master.
+
+ if(pd->ud.walktimer != -1 && check_distance_blxy(&sd->bl, pd->ud.to_x,pd->ud.to_y, 3))
+ return 0; //Already walking to him
- pd->next_walktime=tick+500;
- dx=bl_item->x - pd->bl.x;
- dy=bl_item->y - pd->bl.y;
+ pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->ud.dir);
+ if(!unit_walktoxy(&pd->bl,pd->ud.to_x,pd->ud.to_y,0))
+ pet_randomwalk(pd,tick);
- ret=pet_walktoxy(pd,pd->bl.x+dx,pd->bl.y+dy);
+ return 0;
+ }
+
+ if (target->type != BL_ITEM)
+ { //enemy targetted
+ if(!battle_check_range(&pd->bl,target,pd->db->range))
+ { //Chase
+ if(pd->ud.walktimer != -1 && check_distance_blxy(target, pd->ud.to_x,pd->ud.to_y, pd->db->range))
+ return 0;
+
+ if(!unit_can_reach(&pd->bl, target->x, target->y))
+ { //Unreachable target.
+ pet_unlocktarget(pd);
+ return 0;
}
- else{ // ƒAƒCƒeƒ€‚Ü‚Å‚½‚Ç‚è’…‚¢‚½
- fitem = (struct flooritem_data *)bl_item;
- if(pd->state.state==MS_ATTACK)
- return 0; // UŒ‚’†
- if(pd->state.state==MS_WALK){ // •às’†‚È‚ç’âŽ~
- pet_stop_walking(pd,1);
+ i=0;
+ do {
+ if(i==0) { // ʼn‚ÍAEGIS‚Æ“¯‚¶•û–@‚ÅŒŸõ
+ dx=target->x - pd->bl.x;
+ dy=target->y - pd->bl.y;
+ if(dx<0) dx++;
+ else if(dx>0) dx--;
+ if(dy<0) dy++;
+ else if(dy>0) dy--;
}
- if(pd->loot->count < pd->loot->max){
- memcpy(&pd->loot->item[pd->loot->count++],&fitem->item_data,sizeof(pd->loot->item[0]));
- pd->loot->weight += itemdb_search(fitem->item_data.nameid)->weight*fitem->item_data.amount;
- map_clearflooritem(bl_item->id);
- pet_unlocktarget(pd);
- }
- else { //Maxed out on carried items
- pet_unlocktarget(pd);
- return 0;
+ else { // ‚¾‚ß‚È‚çAthenaŽ®(ƒ‰ƒ“ƒ_ƒ€)
+ dx=target->x - pd->bl.x + rand()%3 - 1;
+ dy=target->y - pd->bl.y + rand()%3 - 1;
}
+ } while(!unit_walktoxy(&pd->bl,pd->bl.x+dx,pd->bl.y+dy,0) && ++i<5);
+
+ if(i>=5) {
+ if(dx<0) dx=2;
+ else if(dx>0) dx=-2;
+ if(dy<0) dy=2;
+ else if(dy>0) dy=-2;
+ unit_walktoxy(&pd->bl,pd->bl.x+dx,pd->bl.y+dy,0);
}
- }
- else {
- if(dist <= 3 || pd->state.casting_flag || (pd->timer != -1 && pd->state.state == MS_WALK && check_distance_blxy(&sd->bl, pd->to_x,pd->to_y, 3)))
+ return 0;
+ } //End Chase
+ pet_stop_walking(pd,1);
+ //Continuous attack.
+ unit_attack(&pd->bl, pd->target_id, 1);
+ } else { //Item Targeted, attempt loot
+ if (!check_distance_bl(&pd->bl, target, 1))
+ { //Out of range
+ if(pd->ud.walktimer != -1 && check_distance_blxy(target, pd->ud.to_x, pd->ud.to_y, 0))
+ return 0; // Šù‚Ɉړ®’†
+
+ if(!unit_can_reach(&pd->bl, target->x, target->y))
+ { //Unreachable target.
+ pet_unlocktarget(pd);
return 0;
- pd->speed = status_get_speed(&pd->bl);
- pet_calc_pos(pd,sd->bl.x,sd->bl.y,sd->dir);
- if(pet_walktoxy(pd,pd->to_x,pd->to_y))
- pet_randomwalk(pd,tick);
+ }
+ unit_walktoxy(&pd->bl, target->x, target->y, 1);
+ } else{ // ƒAƒCƒeƒ€‚Ü‚Å‚½‚Ç‚è’…‚¢‚½
+ struct flooritem_data *fitem = (struct flooritem_data *)target;
+ pet_stop_walking(pd,1);
+ if(pd->loot->count < pd->loot->max){
+ memcpy(&pd->loot->item[pd->loot->count++],&fitem->item_data,sizeof(pd->loot->item[0]));
+ pd->loot->weight += itemdb_search(fitem->item_data.nameid)->weight*fitem->item_data.amount;
+ map_clearflooritem(target->id);
+ }
+ //Target is unlocked regardless of whether it was picked or not.
+ pet_unlocktarget(pd);
}
}
- else {
- pd->speed = status_get_speed(&pd->bl);
- if(pd->state.state == MS_ATTACK)
- pet_stopattack(pd);
- pet_randomwalk(pd,tick);
- }
-
return 0;
}
static int pet_ai_sub_foreachclient(struct map_session_data *sd,va_list ap)
{
unsigned int tick;
-
- nullpo_retr(0, sd);
- nullpo_retr(0, ap);
-
tick=va_arg(ap,unsigned int);
if(sd->status.pet_id && sd->pd && sd->petDB)
pet_ai_sub_hard(sd->pd,tick);
@@ -1595,68 +1078,60 @@ static int pet_ai_hard(int tid,unsigned int tick,int id,int data)
int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap)
{
struct pet_data* pd;
+ struct flooritem_data *fitem = (struct flooritem_data *)bl;
+ struct map_session_data *sd = NULL;
int *itc;
- nullpo_retr(0, bl);
- nullpo_retr(0, ap);
- nullpo_retr(0, pd=va_arg(ap,struct pet_data *));
- nullpo_retr(0, itc=va_arg(ap,int *));
-
- if(!pd->target_id){
- struct flooritem_data *fitem = (struct flooritem_data *)bl;
- struct map_session_data *sd = NULL;
- // ƒ‹[ƒgŒ –³‚µ
- if(fitem && fitem->first_get_id>0)
- sd = map_id2sd(fitem->first_get_id);
- // Removed [Valaris]
- //if((pd->lootitem_weight + (itemdb_search(fitem->item_data.))->weight * fitem->item_data.amount) > battle_config.pet_weight)
- // return 0;
-
- if(pd->loot == NULL || pd->loot->item == NULL || (pd->loot->count >= pd->loot->max) || (sd && sd->pd != pd))
- return 0;
- if(bl->m == pd->bl.m && check_distance_bl(&pd->bl, bl, 5)){
- if( pet_can_reach(pd,bl->x,bl->y) // “ž’B‰Â”\«”»’è
- && rand()%1000<1000/(++(*itc)) ){ // ”͈͓àPC‚Å“™Šm—¦‚É‚·‚é
- pd->target_id=bl->id;
- }
- }
- }
+ pd=va_arg(ap,struct pet_data *);
+ itc=va_arg(ap,int *);
+
+ // ƒ‹[ƒgŒ –³‚µ
+ if(fitem && fitem->first_get_id)
+ sd = map_id2sd(fitem->first_get_id);
+ // Removed [Valaris]
+ //if((pd->lootitem_weight + (itemdb_search(fitem->item_data.))->weight * fitem->item_data.amount) > battle_config.pet_weight)
+ // return 0;
+
+ if(pd->loot == NULL || pd->loot->item == NULL || (pd->loot->count >= pd->loot->max) || (sd && sd->pd != pd))
+ return 0;
+ if(bl->m == pd->bl.m && check_distance_bl(&pd->bl, bl, pd->db->range2) &&
+ unit_can_reach(&pd->bl,bl->x,bl->y) && rand()%1000<1000/(++(*itc)))
+ pd->target_id=bl->id;
return 0;
}
+
int pet_lootitem_drop(struct pet_data *pd,struct map_session_data *sd)
{
int i,flag=0;
-
- if(pd){
- if(pd->loot) {
- for(i=0;i<pd->loot->count;i++) {
- struct delay_item_drop2 *ditem;
-
- ditem=(struct delay_item_drop2 *)aCalloc(1,sizeof(struct delay_item_drop2));
- memcpy(&ditem->item_data,&pd->loot->item[i],sizeof(pd->loot->item[0]));
- ditem->m = pd->bl.m;
- ditem->x = pd->bl.x;
- ditem->y = pd->bl.y;
- ditem->first_sd = 0;
- ditem->second_sd = 0;
- ditem->third_sd = 0;
- // —Ž‚Æ‚³‚È‚¢‚Å’¼ÚPC‚ÌItem—“‚Ö
- if(sd){
- if((flag = pc_additem(sd,&ditem->item_data,ditem->item_data.amount))){
- clif_additem(sd,0,0,flag);
- map_addflooritem(&ditem->item_data,ditem->item_data.amount,ditem->m,ditem->x,ditem->y,ditem->first_sd,ditem->second_sd,ditem->third_sd,0);
- }
- aFree(ditem);
+ struct delay_item_drop2 *ditem_floor, ditem;
+ if(pd && pd->loot && pd->loot->count) {
+ memset(&ditem, 0, sizeof(struct delay_item_drop2));
+ ditem.m = pd->bl.m;
+ ditem.x = pd->bl.x;
+ ditem.y = pd->bl.y;
+ ditem.first_sd = 0;
+ ditem.second_sd = 0;
+ ditem.third_sd = 0;
+ for(i=0;i<pd->loot->count;i++) {
+ memcpy(&ditem.item_data,&pd->loot->item[i],sizeof(pd->loot->item[0]));
+ // —Ž‚Æ‚³‚È‚¢‚Å’¼ÚPC‚ÌItem—“‚Ö
+ if(sd){
+ if((flag = pc_additem(sd,&ditem.item_data,ditem.item_data.amount))){
+ clif_additem(sd,0,0,flag);
+ map_addflooritem(&ditem.item_data,ditem.item_data.amount,ditem.m,ditem.x,ditem.y,ditem.first_sd,ditem.second_sd,ditem.third_sd,0);
}
- else
- add_timer(gettick()+540+i,pet_delay_item_drop2,(int)ditem,0);
}
- //The smart thing to do is use pd->loot->max (thanks for pointing it out, Shinomori)
- memset(pd->loot->item,0,pd->loot->max * sizeof(struct item));
- pd->loot->count = 0;
- pd->loot->weight = 0;
- pd->loot->timer = gettick()+10000; // 10*1000ms‚ÌŠÔE‚í‚È‚¢
+ else {
+ ditem_floor=(struct delay_item_drop2 *)aCalloc(1,sizeof(struct delay_item_drop2));
+ memcpy(ditem_floor, &ditem, sizeof(struct delay_item_drop2));
+ add_timer(gettick()+540+i,pet_delay_item_drop2,(int)ditem_floor,0);
+ }
}
+ //The smart thing to do is use pd->loot->max (thanks for pointing it out, Shinomori)
+ memset(pd->loot->item,0,pd->loot->max * sizeof(struct item));
+ pd->loot->count = 0;
+ pd->loot->weight = 0;
+ pd->ud.canact_tick = gettick()+10000; // 10*1000ms‚ÌŠÔE‚í‚È‚¢
}
return 1;
}
@@ -1725,7 +1200,7 @@ int pet_skill_bonus_timer(int tid,unsigned int tick,int id,int data)
*/
int pet_recovery_timer(int tid,unsigned int tick,int id,int data)
{
- struct map_session_data *sd=(struct map_session_data*)map_id2bl(id);
+ struct map_session_data *sd=map_id2sd(id);
struct pet_data *pd;
if(sd==NULL || sd->pd == NULL || sd->pd->recovery == NULL)
@@ -1733,14 +1208,9 @@ int pet_recovery_timer(int tid,unsigned int tick,int id,int data)
pd=sd->pd;
- if(pd->recovery == NULL || pd->recovery->timer != tid) {
+ if(pd->recovery->timer != tid) {
if(battle_config.error_log)
- {
- if (pd->recovery)
- ShowError("pet_recovery_timer %d != %d\n",pd->recovery->timer,tid);
- else
- ShowError("pet_recovery_timer called with no recovery skill defined (tid=%d)\n",tid);
- }
+ ShowError("pet_recovery_timer %d != %d\n",pd->recovery->timer,tid);
return 0;
}
@@ -1759,43 +1229,34 @@ int pet_recovery_timer(int tid,unsigned int tick,int id,int data)
int pet_heal_timer(int tid,unsigned int tick,int id,int data)
{
- struct map_session_data *sd=(struct map_session_data*)map_id2bl(id);
+ struct map_session_data *sd=map_id2sd(id);
struct pet_data *pd;
short rate = 100;
- if(sd==NULL || sd->bl.type!=BL_PC || sd->pd == NULL)
+ if(sd==NULL || sd->pd == NULL || sd->pd->s_skill == NULL)
return 1;
pd=sd->pd;
- if(pd->s_skill == NULL || pd->s_skill->timer != tid) {
+ if(pd->s_skill->timer != tid) {
if(battle_config.error_log)
- {
- if (pd->s_skill)
- ShowError("pet_heal_timer %d != %d\n",pd->s_skill->timer,tid);
- else
- ShowError("pet_heal_timer called with no support skill defined (tid=%d)\n",tid);
- }
+ ShowError("pet_heal_timer %d != %d\n",pd->s_skill->timer,tid);
return 0;
}
if(pc_isdead(sd) ||
(rate = sd->status.sp*100/sd->status.max_sp) > pd->s_skill->sp ||
(rate = sd->status.hp*100/sd->status.max_hp) > pd->s_skill->hp ||
- (rate = pd->state.casting_flag) || //Another skill is in effect
- (rate = pd->state.state) == MS_WALK) //Better wait until the pet stops moving (MS_WALK is 2)
- { //Wait (how long? 1 sec for every 10% of remaining)
+ (rate = (pd->ud.skilltimer != -1)) //Another skill is in effect
+ ) { //Wait (how long? 1 sec for every 10% of remaining)
pd->s_skill->timer=add_timer(gettick()+(rate>10?rate:10)*100,pet_heal_timer,sd->bl.id,0);
return 0;
}
-
- if (pd->state.state == MS_ATTACK)
- pet_stopattack(pd);
+ pet_stop_attack(pd);
+ pet_stop_walking(pd,1);
clif_skill_nodamage(&pd->bl,&sd->bl,AL_HEAL,pd->s_skill->lv,1);
pc_heal(sd,pd->s_skill->lv,0);
-
pd->s_skill->timer=add_timer(tick+pd->s_skill->delay*1000,pet_heal_timer,sd->bl.id,0);
-
return 0;
}
@@ -1805,41 +1266,38 @@ int pet_heal_timer(int tid,unsigned int tick,int id,int data)
*/
int pet_skill_support_timer(int tid,unsigned int tick,int id,int data)
{
- struct map_session_data *sd=(struct map_session_data*)map_id2bl(id);
+ struct map_session_data *sd=map_id2sd(id);
struct pet_data *pd;
short rate = 100;
- if(sd==NULL || sd->bl.type!=BL_PC || sd->pd == NULL)
+ if(sd==NULL || sd->pd == NULL || sd->pd->s_skill == NULL)
return 1;
pd=sd->pd;
- if(pd->s_skill == NULL || pd->s_skill->timer != tid) {
+ if(pd->s_skill->timer != tid) {
if(battle_config.error_log)
- {
- if (pd->s_skill)
- ShowError("pet_skill_support_timer %d != %d\n",pd->s_skill->timer,tid);
- else
- ShowError("pet_skill_support_timer called with no support skill defined (tid=%d)\n",tid);
- }
+ ShowError("pet_skill_support_timer %d != %d\n",pd->s_skill->timer,tid);
return 0;
}
if(pc_isdead(sd) ||
(rate = sd->status.sp*100/sd->status.max_sp) > pd->s_skill->sp ||
(rate = sd->status.hp*100/sd->status.max_hp) > pd->s_skill->hp ||
- (rate = pd->state.casting_flag) || //Another skill is in effect
- (rate = pd->state.state) == MS_WALK) //Better wait until the pet stops moving (MS_WALK is 2)
- { //Wait (how long? 1 sec for every 10% of remaining)
+ (rate = (pd->ud.skilltimer != -1)) //Another skill is in effect
+ ) { //Wait (how long? 1 sec for every 10% of remaining)
pd->s_skill->timer=add_timer(gettick()+(rate>10?rate:10)*100,pet_skill_support_timer,sd->bl.id,0);
return 0;
}
- if (pd->state.state == MS_ATTACK)
- pet_stopattack(pd);
- petskill_use(pd, &sd->bl, pd->s_skill->id, pd->s_skill->lv, tick);
+ pet_stop_attack(pd);
+ pet_stop_walking(pd,1);
+
+ if (skill_get_inf(pd->s_skill->id) & INF_GROUND_SKILL)
+ unit_skilluse_pos(&pd->bl, sd->bl.x, sd->bl.y, pd->s_skill->id, pd->s_skill->lv);
+ else
+ unit_skilluse_id(&pd->bl, sd->bl.id, pd->s_skill->id, pd->s_skill->lv);
pd->s_skill->timer=add_timer(tick+pd->s_skill->delay*1000,pet_skill_support_timer,sd->bl.id,0);
-
return 0;
}
@@ -1944,7 +1402,6 @@ int do_init_pet(void)
memset(pet_db,0,sizeof(pet_db));
read_petdb();
- add_timer_func_list(pet_timer,"pet_timer");
add_timer_func_list(pet_hungry,"pet_hungry");
add_timer_func_list(pet_ai_hard,"pet_ai_hard");
add_timer_func_list(pet_skill_bonus_timer,"pet_skill_bonus_timer"); // [Valaris]
diff --git a/src/map/pet.h b/src/map/pet.h
index feadafdf3..5e4541de0 100644
--- a/src/map/pet.h
+++ b/src/map/pet.h
@@ -35,14 +35,10 @@ enum { PET_CLASS,PET_CATCH,PET_EGG,PET_EQUIP,PET_FOOD };
int pet_hungry_val(struct map_session_data *sd);
int pet_target_check(struct map_session_data *sd,struct block_list *bl,int type);
+int pet_unlocktarget(struct pet_data *pd);
int pet_sc_check(struct map_session_data *sd, int type); //Skotlex
-int pet_stopattack(struct pet_data *pd);
-int pet_changestate(struct pet_data *pd,int state,int type);
-int pet_walktoxy(struct pet_data *pd,int x,int y);
-int pet_stop_walking(struct pet_data *pd,int type);
int search_petDB_index(int key,int type);
int pet_hungry_timer_delete(struct map_session_data *sd);
-int pet_remove_map(struct map_session_data *sd);
int pet_data_init(struct map_session_data *sd);
int pet_birth_process(struct map_session_data *sd);
int pet_recv_petdata(int account_id,struct s_pet *p,int flag);
@@ -58,12 +54,14 @@ int pet_food(struct map_session_data *sd);
int pet_lootitem_drop(struct pet_data *pd,struct map_session_data *sd);
int pet_delay_item_drop2(int tid,unsigned int tick,int id,int data);
int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap);
-int petskill_use(struct pet_data *pd, struct block_list *target, short skill_id, short skill_lv, unsigned int tick); // [Skotlex]
+int pet_attackskill(struct pet_data *pd, int target_id);
int pet_skill_support_timer(int tid, unsigned int tick, int id, int data); // [Skotlex]
int pet_skill_bonus_timer(int tid,unsigned int tick,int id,int data); // [Valaris]
int pet_recovery_timer(int tid,unsigned int tick,int id,int data); // [Valaris]
int pet_heal_timer(int tid,unsigned int tick,int id,int data); // [Valaris]
-int pet_skillsupport_timer(int tid,unsigned int tick,int id,int data); // [Skotlex]
+
+#define pet_stop_walking(pd, type) { if((pd)->ud.walktimer != -1) unit_stop_walking(&(pd)->bl, type); }
+#define pet_stop_attack(pd) { if((pd)->ud.attacktimer != -1) unit_stop_attack(&(pd)->bl); }
int read_petdb(void);
int do_init_pet(void);
diff --git a/src/map/script.c b/src/map/script.c
index 0dff1f7fc..3226a6b2f 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -22,6 +22,7 @@
#include "../common/malloc.h"
#include "../common/lock.h"
#include "../common/nullpo.h"
+#include "../common/showmsg.h"
#include "map.h"
#include "clif.h"
@@ -43,7 +44,8 @@
#include "atcommand.h"
#include "charcommand.h"
#include "log.h"
-#include "showmsg.h"
+#include "unit.h"
+
#if !defined(TXT_ONLY) && defined(MAPREGSQL)
#include "strlib.h"
#endif
@@ -5336,7 +5338,7 @@ int buildin_itemskill(struct script_state *st)
str=conv_str(st,& (st->stack->stack_data[st->start+4]));
// ‰r¥’†‚ɃXƒLƒ‹ƒAƒCƒeƒ€‚ÍŽg—p‚Å‚«‚È‚¢
- if(sd->skilltimer != -1)
+ if(sd->ud.skilltimer != -1)
return 0;
sd->skillitem=id;
@@ -5500,16 +5502,17 @@ int buildin_areamonster(struct script_state *st)
*/
int buildin_killmonster_sub(struct block_list *bl,va_list ap)
{
+ TBL_MOB* md = (TBL_MOB*)bl;
char *event=va_arg(ap,char *);
int allflag=va_arg(ap,int);
if(!allflag){
- if(strcmp(event,((struct mob_data *)bl)->npc_event)==0)
- mob_delete((struct mob_data *)bl);
+ if(strcmp(event,md->npc_event)==0)
+ unit_remove_map(bl,1);
return 0;
- }else if(allflag){
- if(((struct mob_data *)bl)->spawndelay1==-1 && ((struct mob_data *)bl)->spawndelay2==-1)
- mob_delete((struct mob_data *)bl);
+ }else{
+ if(!md->spawn)
+ unit_remove_map(bl,1);
return 0;
}
return 0;
@@ -5531,7 +5534,7 @@ int buildin_killmonster(struct script_state *st)
int buildin_killmonsterall_sub(struct block_list *bl,va_list ap)
{
- mob_delete((struct mob_data *)bl);
+ unit_remove_map(bl,1);
return 0;
}
int buildin_killmonsterall(struct script_state *st)
@@ -7044,7 +7047,7 @@ int buildin_maprespawnguildid_sub(struct block_list *bl,va_list ap)
}
if(md && flag&4){
if(!md->guardian_data && md->class_ != MOBID_EMPERIUM)
- mob_delete(md);
+ unit_remove_map(bl,1);
}
return 0;
}
@@ -7961,7 +7964,6 @@ int buildin_petloot(struct script_state *st)
pd->loot->max=max;
pd->loot->count = 0;
pd->loot->weight = 0;
- pd->loot->timer = gettick();
return 0;
}
@@ -8783,7 +8785,7 @@ int buildin_npcwalkto(struct script_state *st)
y=conv_num(st,& (st->stack->stack_data[st->start+3]));
if(nd) {
- npc_walktoxy(nd,x,y,0);
+ unit_walktoxy(&nd->bl,x,y,0);
}
return 0;
@@ -8794,8 +8796,7 @@ int buildin_npcstop(struct script_state *st)
struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
if(nd) {
- if(nd->state.state==MS_WALK)
- npc_stop_walking(nd,1);
+ unit_stop_walking(&nd->bl,1);
}
return 0;
@@ -9046,7 +9047,8 @@ int buildin_skilluseid (struct script_state *st)
skid=conv_num(st,& (st->stack->stack_data[st->start+2]));
sklv=conv_num(st,& (st->stack->stack_data[st->start+3]));
sd=script_rid2sd(st);
- skill_use_id(sd,sd->status.account_id,skid,sklv);
+ if (sd)
+ unit_skilluse_id(&sd->bl,sd->bl.id,skid,sklv);
return 0;
}
@@ -9066,7 +9068,8 @@ int buildin_skillusepos(struct script_state *st)
y=conv_num(st,& (st->stack->stack_data[st->start+5]));
sd=script_rid2sd(st);
- skill_use_pos(sd,x,y,skid,sklv);
+ if (sd)
+ unit_skilluse_pos(&sd->bl,x,y,skid,sklv);
return 0;
}
@@ -9961,7 +9964,7 @@ int buildin_pcwalkxy(struct script_state *st){
sd = script_rid2sd(st);
if(sd)
- pc_walktoxy(sd, x, y);
+ unit_walktoxy(&sd->bl, x, y, 0);
return 0;
}
@@ -10097,27 +10100,29 @@ int buildin_spawnmob(struct script_state *st){
int buildin_removemob(struct script_state *st) {
int id;
- struct mob_data *md = NULL;
+ struct block_list *bl = NULL;
id = conv_num(st, & (st->stack->stack_data[st->start+2]));
- md = (struct mob_data *)map_id2bl(id);
- if(md)
- mob_delete(md);
+ bl = map_id2bl(id);
+ if (bl && bl->type == BL_MOB)
+ unit_free(bl);
return 0;
}
int buildin_mobwalk(struct script_state *st){
int id,x,y;
- struct mob_data *md = NULL;
+ struct block_list *bl = NULL;
id = conv_num(st, & (st->stack->stack_data[st->start+2]));
x = conv_num(st, & (st->stack->stack_data[st->start+3]));
y = conv_num(st, & (st->stack->stack_data[st->start+4]));
- md = (struct mob_data *)map_id2bl(id);
- if(md)
- push_val(st->stack,C_INT,mob_walktoxy(md,x,y,0)); // We'll use harder calculations.
+ bl = map_id2bl(id);
+ if(bl && bl->type == BL_MOB)
+ push_val(st->stack,C_INT,unit_walktoxy(bl,x,y,0)); // We'll use harder calculations.
+ else
+ push_val(st->stack,C_INT,0);
return 0;
}
@@ -10142,21 +10147,20 @@ int buildin_getmobdata(struct script_state *st) {
setd_sub(map_id2sd(st->rid),name,7,(void *)(int)md->bl.y);
setd_sub(map_id2sd(st->rid),name,8,(void *)(int)md->speed);
setd_sub(map_id2sd(st->rid),name,9,(void *)(int)md->mode);
- setd_sub(map_id2sd(st->rid),name,10,(void *)(int)md->state.state);
- setd_sub(map_id2sd(st->rid),name,11,(void *)(int)md->special_state.ai);
- setd_sub(map_id2sd(st->rid),name,12,(void *)(int)md->db->option);
- setd_sub(map_id2sd(st->rid),name,13,(void *)(int)md->db->sex);
- setd_sub(map_id2sd(st->rid),name,14,(void *)(int)md->db->view_class);
- setd_sub(map_id2sd(st->rid),name,15,(void *)(int)md->db->hair);
- setd_sub(map_id2sd(st->rid),name,16,(void *)(int)md->db->hair_color);
- setd_sub(map_id2sd(st->rid),name,17,(void *)(int)md->db->head_buttom);
- setd_sub(map_id2sd(st->rid),name,18,(void *)(int)md->db->head_mid);
- setd_sub(map_id2sd(st->rid),name,19,(void *)(int)md->db->head_top);
- setd_sub(map_id2sd(st->rid),name,20,(void *)(int)md->db->clothes_color);
- setd_sub(map_id2sd(st->rid),name,21,(void *)(int)md->db->equip);
- setd_sub(map_id2sd(st->rid),name,22,(void *)(int)md->db->weapon);
- setd_sub(map_id2sd(st->rid),name,23,(void *)(int)md->db->shield);
- setd_sub(map_id2sd(st->rid),name,24,(void *)(int)md->dir);
+ setd_sub(map_id2sd(st->rid),name,10,(void *)(int)md->special_state.ai);
+ setd_sub(map_id2sd(st->rid),name,11,(void *)(int)md->db->option);
+ setd_sub(map_id2sd(st->rid),name,12,(void *)(int)md->db->sex);
+ setd_sub(map_id2sd(st->rid),name,13,(void *)(int)md->db->view_class);
+ setd_sub(map_id2sd(st->rid),name,14,(void *)(int)md->db->hair);
+ setd_sub(map_id2sd(st->rid),name,15,(void *)(int)md->db->hair_color);
+ setd_sub(map_id2sd(st->rid),name,16,(void *)(int)md->db->head_buttom);
+ setd_sub(map_id2sd(st->rid),name,17,(void *)(int)md->db->head_mid);
+ setd_sub(map_id2sd(st->rid),name,18,(void *)(int)md->db->head_top);
+ setd_sub(map_id2sd(st->rid),name,19,(void *)(int)md->db->clothes_color);
+ setd_sub(map_id2sd(st->rid),name,20,(void *)(int)md->db->equip);
+ setd_sub(map_id2sd(st->rid),name,21,(void *)(int)md->db->weapon);
+ setd_sub(map_id2sd(st->rid),name,22,(void *)(int)md->db->shield);
+ setd_sub(map_id2sd(st->rid),name,23,(void *)(int)md->ud.dir);
}
return 0;
}
@@ -10201,49 +10205,46 @@ int buildin_setmobdata(struct script_state *st){
md->mode = (short)value;
break;
case 10:
- md->state.state = (unsigned int)value;
- break;
- case 11:
md->special_state.ai = (unsigned int)value;
break;
- case 12:
+ case 11:
md->db->option = (short)value;
break;
- case 13:
+ case 12:
md->db->sex = value;
break;
- case 14:
+ case 13:
md->db->view_class = value;
break;
- case 15:
+ case 14:
md->db->hair = (short)value;
break;
- case 16:
+ case 15:
md->db->hair_color = (short)value;
break;
- case 17:
+ case 16:
md->db->head_buttom = (short)value;
break;
- case 18:
+ case 17:
md->db->head_mid = (short)value;
break;
- case 19:
+ case 18:
md->db->head_top = (short)value;
break;
- case 20:
+ case 19:
md->db->clothes_color = (short)value;
break;
- case 21:
+ case 20:
md->db->equip = value;
break;
- case 22:
+ case 21:
md->db->weapon = (short)value;
break;
- case 23:
+ case 22:
md->db->shield = (short)value;
break;
- case 24:
- md->dir = (short)value;
+ case 23:
+ md->ud.dir = (short)value;
break;
default:
ShowError("buildin_setmobdata: argument id is not identified.");
@@ -10264,24 +10265,12 @@ int buildin_mobattack(struct script_state *st) {
target = conv_str(st, & (st->stack->stack_data[st->start+3]));
if((sd = map_nick2sd(target)) != NULL || (bl = map_id2bl(atoi(target))) != NULL) {
- if(sd) {
- md = (struct mob_data *)map_id2bl(id);
- if(md) {
- md->target_id = sd->bl.id;
- md->state.targettype = ATTACKABLE;
- md->special_state.ai = 1;
- md->min_chase = distance_bl(bl,&md->bl) + md->db->range2;
- }
- } else {
- if(bl->type == BL_MOB || bl->type == BL_PC) {
- md = (struct mob_data *)map_id2bl(id);
- if(md) {
- md->target_id = bl->id;
- md->state.targettype = ATTACKABLE;
- md->special_state.ai = 1;
- md->min_chase = distance_bl(bl,&md->bl) + md->db->range2;
- }
- }
+ if (sd) bl = &sd->bl;
+ md = (struct mob_data *)map_id2bl(id);
+ if (md && md->bl.type == BL_MOB) {
+ md->target_id = sd->bl.id;
+ md->special_state.ai = 1;
+ md->min_chase = distance_bl(bl,&md->bl) + md->db->range2;
}
}
@@ -10290,15 +10279,15 @@ int buildin_mobattack(struct script_state *st) {
int buildin_mobstop(struct script_state *st) {
int id;
- struct mob_data *md = NULL;
+ struct block_list *bl = NULL;
id = conv_num(st, & (st->stack->stack_data[st->start+2]));
- md = (struct mob_data *)map_id2bl(id);
- if(md){
- mob_stopattack(md);
- mob_stop_walking(md,0);
- md->master_id = md->bl.id; // Quick hack to stop random walking.
+ bl = map_id2bl(id);
+ if(bl && bl->type == BL_MOB){
+ unit_stop_attack(bl);
+ unit_stop_walking(bl,0);
+ ((TBL_MOB*)bl)->master_id = bl->id; // Quick hack to stop random walking.
}
return 0;
@@ -10309,25 +10298,25 @@ int buildin_mobassist(struct script_state *st) {
char *target;
struct mob_data *md = NULL;
struct block_list *bl = NULL;
-
+ struct unit_data *ud;
+
id = conv_num(st, & (st->stack->stack_data[st->start+2]));
target = conv_str(st, & (st->stack->stack_data[st->start+3]));
if((bl =&(map_nick2sd(target)->bl)) || (bl = map_id2bl(atoi(target)))) {
md = (struct mob_data *)map_id2bl(id);
- if(md) {
+ if(md && md->bl.type == BL_MOB) {
+ ud = unit_bl2ud(bl);
md->master_id = bl->id;
- if(bl->type == BL_PC)
- md->target_id = map_id2sd(bl->id)->attacktarget;
- else if(bl->type == BL_MOB)
- md->target_id = ((struct mob_data *)bl)->target_id;
- if(map_id2bl(md->target_id)){
- md->state.targettype = ATTACKABLE;
+ if (ud) {
+ if (ud->attacktarget)
+ md->target_id = ud->attacktarget;
+ else if (ud->skilltarget)
+ md->target_id = ud->skilltarget;
md->min_chase = distance_bl(&md->bl,map_id2bl(md->target_id)) + md->db->range2;
}
}
}
-
return 0;
}
@@ -10343,7 +10332,7 @@ int buildin_mobtalk(struct script_state *st)
str=conv_str(st,& (st->stack->stack_data[st->start+3]));
md = (struct mob_data *)map_id2bl(id);
- if(md) {
+ if(md && md->bl.type == BL_MOB) {
memcpy(message, md->name, NAME_LENGTH);
strcat(message," : ");
strncat(message,str, 254); //Prevent overflow possibility. [Skotlex]
@@ -10358,7 +10347,7 @@ int buildin_mobemote(struct script_state *st) {
struct mob_data *md = NULL;
id = conv_num(st, & (st->stack->stack_data[st->start+2]));
emo = conv_num(st, & (st->stack->stack_data[st->start+3]));
- if((md = (struct mob_data *)map_id2bl(id)))
+ if((md = (struct mob_data *)map_id2bl(id)) && md->bl.type == BL_MOB)
clif_emotion(&md->bl,emo);
return 0;
}
@@ -10367,7 +10356,7 @@ int buildin_mobattach(struct script_state *st){
int id;
struct mob_data *md = NULL;
id = conv_num(st, & (st->stack->stack_data[st->start+2]));
- if((md = (struct mob_data *)map_id2bl(id)))
+ if((md = (struct mob_data *)map_id2bl(id)) && md->bl.type == BL_MOB)
md->nd = (struct npc_data *)map_id2bl(st->oid);
return 0;
}
diff --git a/src/map/skill.c b/src/map/skill.c
index ef835eba4..333db383c 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -28,6 +28,7 @@
#include "chrif.h"
#include "guild.h"
#include "date.h"
+#include "unit.h"
#define SKILLUNITTIMER_INVERVAL 100
//Guild Skills are shifted to these to make them stick into the skill array.
@@ -691,7 +692,6 @@ int skill_tree_get_max(int id, int b_class){
}
/* ƒvƒ?ƒgƒ^ƒCƒv */
-int skill_check_condition( struct map_session_data *sd,int type);
int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag );
int skill_frostjoke_scream(struct block_list *bl,va_list ap);
int status_change_timer_sub(struct block_list *bl, va_list ap);
@@ -708,7 +708,6 @@ static int skill_unit_onplace(struct skill_unit *src,struct block_list *bl,unsig
static int skill_unit_onleft(int skill_id, struct block_list *bl,unsigned int tick);
int skill_unit_effect(struct block_list *bl,va_list ap);
static void skill_moonlit(struct block_list* src, struct block_list* partner, int skilllv);
-static int skill_check_pc_partner(struct map_session_data *sd, int skill_id, int* skill_lv, int range, int cast_flag);
int enchant_eff[5] = { 10, 14, 17, 19, 20 };
int deluge_eff[5] = { 5, 9, 12, 14, 15 };
@@ -813,7 +812,7 @@ int skillnotok(int skillid, struct map_session_data *sd)
case WZ_ICEWALL:
// noicewall flag [Valaris]
if (map[sd->bl.m].flag.noicewall) {
- clif_skill_fail(sd,sd->skillid,0,0);
+ clif_skill_fail(sd,skillid,0,0);
return 1;
}
default:
@@ -1573,7 +1572,7 @@ int skill_blown( struct block_list *src, struct block_list *target,int count)
if (count&0xf00000)
dir = (count>>20)&0xf;
else if (count&0x10000 || (target->x==src->x && target->y==src->y))
- dir = status_get_dir(target);
+ dir = unit_getdir(target);
else if (count&0x40000) //Flag for random pushing.
dir = rand()%8;
else
@@ -1587,7 +1586,7 @@ int skill_blown( struct block_list *src, struct block_list *target,int count)
nx=ret>>16;
ny=ret&0xffff;
- battle_stopwalking(target,0);
+ unit_stop_walking(target,0);
dx = nx - x;
dy = ny - y;
@@ -1739,7 +1738,7 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds
else //‰ñ•œSP+Œ»Ý‚ÌSP‚ªMSP‚æ‚謂³‚¢ê‡‚͉ñ•œSP‚ð‰ÁŽZ
tsd->status.sp += sp;
clif_heal(tsd->fd,SP_SP,sp); //SP‰ñ•œƒGƒtƒFƒNƒg‚Ì•\Ž¦
- tsd->canact_tick = tick + skill_delayfix(bl, SA_MAGICROD, sc->data[SC_MAGICROD].val1, 0);
+ tsd->ud.canact_tick = tick + skill_delayfix(bl, SA_MAGICROD, sc->data[SC_MAGICROD].val1, skill_get_delay(SA_MAGICROD, sc->data[SC_MAGICROD].val1));
}
clif_skill_nodamage(bl,bl,SA_MAGICROD,sc->data[SC_MAGICROD].val1,1); //ƒ}ƒWƒbƒNƒƒbƒhƒGƒtƒFƒNƒg‚ð•\Ž¦
}
@@ -1780,8 +1779,8 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds
pc_checkskill(sd, MO_CHAINCOMBO) > 0)
delay += 300 * battle_config.combo_delay_rate / 100;
sc_start4(src,SC_COMBO,100,MO_TRIPLEATTACK,skilllv,0,0,delay);
- sd->attackabletime = tick + delay;
- battle_set_walkdelay(src, tick, delay, 1);
+ sd->ud.attackabletime = tick + delay;
+ unit_set_walkdelay(src, tick, delay, 1);
clif_combo_delay(src, delay);
if (sd->status.party_id>0) //bonus from SG_FRIEND [Komurka]
@@ -1795,8 +1794,8 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds
(pc_checkskill(sd, MO_COMBOFINISH) > 0 && sd->spiritball > 0))
delay += 300 * battle_config.combo_delay_rate /100;
sc_start4(src,SC_COMBO,100,MO_CHAINCOMBO,skilllv,0,0,delay);
- sd->attackabletime = tick + delay;
- battle_set_walkdelay(src, tick, delay, 1);
+ sd->ud.attackabletime = tick + delay;
+ unit_set_walkdelay(src, tick, delay, 1);
clif_combo_delay(src,delay);
break;
}
@@ -1811,8 +1810,8 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds
))
delay += 300 * battle_config.combo_delay_rate /100;
sc_start4(src,SC_COMBO,100,MO_COMBOFINISH,skilllv,0,0,delay);
- sd->attackabletime = tick + delay;
- battle_set_walkdelay(src, tick, delay, 1);
+ sd->ud.attackabletime = tick + delay;
+ unit_set_walkdelay(src, tick, delay, 1);
clif_combo_delay(src,delay);
break;
}
@@ -1826,8 +1825,8 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds
))
delay += 300 * battle_config.combo_delay_rate /100;
sc_start4(src,SC_COMBO,100,CH_TIGERFIST,skilllv,0,0,delay);
- sd->attackabletime = tick + delay;
- battle_set_walkdelay(src, tick, delay, 1);
+ sd->ud.attackabletime = tick + delay;
+ unit_set_walkdelay(src, tick, delay, 1);
clif_combo_delay(src,delay);
break;
}
@@ -1837,8 +1836,8 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds
if(damage < status_get_hp(bl))
delay += 300 * battle_config.combo_delay_rate /100;
sc_start4(src,SC_COMBO,100,CH_CHAINCRUSH,skilllv,0,0,delay);
- sd->attackabletime = tick + delay;
- battle_set_walkdelay(src, tick, delay, 1);
+ sd->ud.attackabletime = tick + delay;
+ unit_set_walkdelay(src, tick, delay, 1);
clif_combo_delay(src,delay);
break;
}
@@ -2248,38 +2247,17 @@ int skill_count_water(struct block_list *src,int range)
*/
static int skill_timerskill(int tid, unsigned int tick, int id,int data )
{
- struct map_session_data *sd = NULL;
- struct mob_data *md = NULL;
- struct pet_data *pd = NULL;
struct block_list *src = map_id2bl(id),*target;
+ struct unit_data *ud = unit_bl2ud(src);
struct skill_timerskill *skl = NULL;
int range;
nullpo_retr(0, src);
-
- if(src->type == BL_PC) {
- sd = (struct map_session_data *)src;
- skl = &sd->skilltimerskill[data];
- }
- else if(src->type == BL_MOB) {
- md = (struct mob_data *)src;
- skl = &md->skilltimerskill[data];
- }
- else if(src->type == BL_PET) { // [Valaris]
- pd = (struct pet_data *)src;
- skl = &pd->skilltimerskill[data];
- }
- else
- return 0;
-
+ nullpo_retr(0, ud);
+ skl = &ud->skilltimerskill[data];
nullpo_retr(0, skl);
-
skl->timer = -1;
- if (sd) {
- sd->timerskill_count--;
- }
-
//Check moved here because otherwise the timer is not reset to -1 and later on we'll see problems when clearing. [Skotlex]
if(src->prev == NULL)
return 0;
@@ -2309,50 +2287,23 @@ static int skill_timerskill(int tid, unsigned int tick, int id,int data )
switch(skl->skill_id) {
case RG_INTIMIDATE:
- if(sd && !map[src->m].flag.noteleport) {
+ if (unit_warp(src,-1,-1,-1,3) == 0) {
int x,y,i,j;
- pc_randomwarp(sd,3);
- for(i=0;i<16;i++) {
- j = rand()%8;
- x = sd->bl.x + dirx[j];
- y = sd->bl.y + diry[j];
- if(map_getcell(sd->bl.m,x,y,CELL_CHKPASS))
- break;
- }
- if(i >= 16) {
- x = sd->bl.x;
- y = sd->bl.y;
- }
- if(target->prev != NULL) {
- if(target->type == BL_PC && !pc_isdead((struct map_session_data *)target))
- pc_setpos((struct map_session_data *)target,map[sd->bl.m].index,x,y,3);
- else if(target->type == BL_MOB)
- mob_warp((struct mob_data *)target,-1,x,y,3);
- }
- }
- else if(md && !map[src->m].flag.monster_noteleport) {
- int x,y,i,j;
- mob_warp(md,-1,-1,-1,3);
for(i=0;i<16;i++) {
j = rand()%8;
- x = md->bl.x + dirx[j];
- y = md->bl.y + diry[j];
- if(map_getcell(md->bl.m,x,y,CELL_CHKPASS))
+ x = src->x + dirx[j];
+ y = src->y + diry[j];
+ if(map_getcell(src->m,x,y,CELL_CHKPASS))
break;
}
if(i >= 16) {
- x = md->bl.x;
- y = md->bl.y;
- }
- if(target->prev != NULL) {
- if(target->type == BL_PC && !pc_isdead((struct map_session_data *)target))
- pc_setpos((struct map_session_data *)target,map[md->bl.m].index,x,y,3);
- else if(target->type == BL_MOB)
- mob_warp((struct mob_data *)target,-1,x,y,3);
+ x = src->x;
+ y = src->y;
}
+ if (!status_isdead(target))
+ unit_warp(target, -1, x, y, 3);
}
break;
-
case BA_FROSTJOKE: /* Š¦‚¢ƒWƒ‡?ƒN */
case DC_SCREAM: /* ƒXƒNƒŠ?ƒ€ */
range= skill_get_splash(skl->skill_id, skl->skill_lv);
@@ -2402,42 +2353,25 @@ static int skill_timerskill(int tid, unsigned int tick, int id,int data )
*/
int skill_addtimerskill(struct block_list *src,unsigned int tick,int target,int x,int y,int skill_id,int skill_lv,int type,int flag)
{
- int i, max;
- unsigned short *count=NULL;
- struct skill_timerskill *sts = NULL;
+ int i;
+ struct unit_data *ud;
nullpo_retr(1, src);
- switch (src->type) {
- case BL_PC:
- sts = ((struct map_session_data *)src)->skilltimerskill;
- max = MAX_SKILLTIMERSKILL;
- count = &((struct map_session_data *)src)->timerskill_count;
- break;
- case BL_MOB:
- sts = ((struct mob_data *)src)->skilltimerskill;
- max = MAX_MOBSKILLTIMERSKILL;
- break;
- case BL_PET:
- sts = ((struct pet_data *)src)->skilltimerskill;
- max = MAX_MOBSKILLTIMERSKILL;
- break;
- default:
- return 1;
- }
- for(i=0;i<max && sts[i].timer != -1;i++);
- if (i>=max) return 1;
-
- sts[i].timer = add_timer(tick, skill_timerskill, src->id, i);
- sts[i].src_id = src->id;
- sts[i].target_id = target;
- sts[i].skill_id = skill_id;
- sts[i].skill_lv = skill_lv;
- sts[i].map = src->m;
- sts[i].x = x;
- sts[i].y = y;
- sts[i].type = type;
- sts[i].flag = flag;
- if (count)
- (*count)++;
+ ud = unit_bl2ud(src);
+ nullpo_retr(1, ud);
+
+ for(i=0;i<MAX_SKILLTIMERSKILL && ud->skilltimerskill[i].timer != -1;i++);
+ if (i>=MAX_SKILLTIMERSKILL) return 1;
+
+ ud->skilltimerskill[i].timer = add_timer(tick, skill_timerskill, src->id, i);
+ ud->skilltimerskill[i].src_id = src->id;
+ ud->skilltimerskill[i].target_id = target;
+ ud->skilltimerskill[i].skill_id = skill_id;
+ ud->skilltimerskill[i].skill_lv = skill_lv;
+ ud->skilltimerskill[i].map = src->m;
+ ud->skilltimerskill[i].x = x;
+ ud->skilltimerskill[i].y = y;
+ ud->skilltimerskill[i].type = type;
+ ud->skilltimerskill[i].flag = flag;
return 0;
}
@@ -2447,46 +2381,19 @@ int skill_addtimerskill(struct block_list *src,unsigned int tick,int target,int
*/
int skill_cleartimerskill(struct block_list *src)
{
- int i, max;
- unsigned short *count=NULL;
- struct skill_timerskill *sts = NULL;
-
+ int i;
+ struct unit_data *ud;
nullpo_retr(0, src);
- switch (src->type) {
- case BL_PC:
- sts = ((struct map_session_data *)src)->skilltimerskill;
- max = MAX_SKILLTIMERSKILL;
- count = &((struct map_session_data *)src)->timerskill_count;
- break;
- case BL_MOB:
- sts = ((struct mob_data *)src)->skilltimerskill;
- max = MAX_MOBSKILLTIMERSKILL;
- break;
- case BL_PET:
- sts = ((struct pet_data *)src)->skilltimerskill;
- max = MAX_MOBSKILLTIMERSKILL;
- break;
- default:
- return 0;
- }
+ ud = unit_bl2ud(src);
+ nullpo_retr(0, ud);
- if (count) {
- for(i=0;i<max && *count > 0;i++) {
- if(sts[i].timer != -1) {
- delete_timer(sts[i].timer, skill_timerskill);
- sts[i].timer = -1;
- (*count)--;
- }
- }
- } else {
- for(i=0;i<max;i++) {
- if(sts[i].timer != -1) {
- delete_timer(sts[i].timer, skill_timerskill);
- sts[i].timer = -1;
- }
+ for(i=0;i<MAX_SKILLTIMERSKILL;i++) {
+ if(ud->skilltimerskill[i].timer != -1) {
+ delete_timer(ud->skilltimerskill[i].timer, skill_timerskill);
+ ud->skilltimerskill[i].timer = -1;
}
}
- return 0;
+ return 1;
}
/*==========================================
@@ -2628,14 +2535,11 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl,int s
BF_WEAPON, src, src, skillid, skilllv, tick, flag, BCT_ENEMY);
break;
case TK_JUMPKICK:
- if (sd && !pc_can_move(sd)) {
- map_freeblock_unlock();
- return 1;
- }
+ if (!unit_can_move(src))
+ break;
skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
- if (sd) pc_movepos(sd,bl->x,bl->y,0);
- else map_moveblock(src, bl->y, bl->y, tick);
- clif_slide(src,bl->x,bl->y);
+ if (unit_movepos(src, bl->x, bl->y, 0, 0))
+ clif_slide(src,bl->x,bl->y);
break;
case ASC_BREAKER: /* ƒ\ƒEƒ‹ƒuƒŒ?ƒJ? */ // [DracoRPG]
// Separate weapon and magic attacks
@@ -2658,18 +2562,13 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl,int s
case RG_BACKSTAP: /* ƒoƒbƒNƒXƒ^ƒu */
{
- int dir = map_calc_dir(src, bl->x, bl->y), t_dir = status_get_dir(bl);
+ int dir = map_calc_dir(src, bl->x, bl->y), t_dir = unit_getdir(bl);
if ((!check_distance_bl(src, bl, 0) && !map_check_dir(dir, t_dir)) || bl->type == BL_SKILL) {
if (sc && sc->data[SC_HIDING].timer != -1)
status_change_end(src, SC_HIDING, -1); // ƒnƒCƒfƒBƒ“ƒO‰ð?œ
skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick, flag);
dir = dir < 4 ? dir+4 : dir-4; // change direction [Celest]
- if (tsd)
- tsd->dir = dir;
- else if (bl->type == BL_MOB) {
- struct mob_data *tmd = (struct mob_data *)bl;
- if (tmd) tmd->dir = dir;
- }
+ unit_setdir(bl,dir);
clif_changed_dir(bl);
}
else if (sd)
@@ -2702,63 +2601,57 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl,int s
case KN_CHARGEATK:
case MO_EXTREMITYFIST: /* ˆ¢?C—…”e–PŒ? */
{
- if(sd && !check_distance_bl(src, bl, 1)) { //Need to move to target.
- struct walkpath_data wpd;
- int dx,dy,speed;
+ if (skillid == MO_EXTREMITYFIST && sc && sc->count)
+ {
+ if (sc->data[SC_EXPLOSIONSPIRITS].timer != -1)
+ status_change_end(src, SC_EXPLOSIONSPIRITS, -1);
+ if (sc->data[SC_BLADESTOP].timer != -1)
+ status_change_end(src,SC_BLADESTOP,-1);
+ if (sc->data[SC_COMBO].timer != -1) //This is one is here to make combo end even if skill failed.
+ status_change_end(src,SC_COMBO,-1);
+ }
+ if(!check_distance_bl(src, bl, 1)) { //Need to move to target.
+ struct unit_data *ud;
+ int dx,dy;
- if (!pc_can_move(sd)) { //You need to be able to move to attack/reach target.
- clif_skill_fail(sd,skillid,0,0);
+ if (!unit_can_move(src)) { //You need to be able to move to attack/reach target.
+ if (sd) clif_skill_fail(sd,skillid,0,0);
break;
}
- dx = bl->x - sd->bl.x;
- dy = bl->y - sd->bl.y;
+ dx = bl->x - src->x;
+ dy = bl->y - src->y;
if(dx > 0) dx++;
else if(dx < 0) dx--;
if (dy > 0) dy++;
else if(dy < 0) dy--;
- if(dx == 0 && dy == 0) dx++;
- if (path_search(&wpd,src->m,sd->bl.x,sd->bl.y,sd->bl.x+dx,sd->bl.y+dy,1) == -1) {
- dx = bl->x - sd->bl.x;
- dy = bl->y - sd->bl.y;
- if(path_search(&wpd,src->m,sd->bl.x,sd->bl.y,sd->bl.x+dx,sd->bl.y+dy,1) == -1) {
- clif_skill_fail(sd,skillid,0,0);
- break;
- }
- }
- sd->to_x = sd->bl.x + dx;
- sd->to_y = sd->bl.y + dy;
+
if (skillid == KN_CHARGEATK) //Store distance in flag [Skotlex]
- flag = wpd.path_len; //Path_len is a pretty good approximate of the distance.
+ flag = distance_bl(src, bl);
+
+ if (!unit_movepos(src, src->x+dx, src->y+dy, 1, 1)) {
+ if (sd) clif_skill_fail(sd,skillid,0,0);
+ break;
+ }
+ clif_slide(src,src->x,src->y);
if (skillid != MO_EXTREMITYFIST || battle_check_target(src, bl, BCT_ENEMY) > 0) //Check must be done here because EF should be broken this way.. [Skotlex]
skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
- else
+ else if (sd)
clif_skill_fail(sd,skillid,0,0);
- speed = sd->speed;
- sd->speed = 20; //Simulate ultra fast walk speed. [Skotlex]
-// clif_updatestatus(sd, SP_SPEED); //Not sure yet if this is needed.
- clif_walkok(sd);
- clif_movechar(sd);
- if(dx < 0) dx = -dx;
- if(dy < 0) dy = -dy;
- sd->attackabletime = tick + 100 + sd->speed * ((dx > dy)? dx:dy);
- battle_set_walkdelay(src, tick, 100 + sd->speed * ((dx > dy)? dx:dy), 1);
- if(sd->canact_tick < sd->canmove_tick)
- sd->canact_tick = sd->canmove_tick;
- sd->speed = speed;
-// clif_updatestatus(sd, SP_SPEED);
- pc_movepos(sd,sd->to_x,sd->to_y,1);
+
+ ud = unit_bl2ud(src);
+ if (ud) {
+ if(dx < 0) dx = -dx;
+ if(dy < 0) dy = -dy;
+ if(dy > dx) dx = dy;
+ dy = status_get_speed(src);
+ ud->attackabletime = tick + 100 + dy*dx;
+ unit_set_walkdelay(src, tick, 100 + dy*dx, 1);
+ if(DIFF_TICK(ud->canact_tick,ud->canmove_tick)<0)
+ ud->canact_tick = ud->canmove_tick;
+ }
}
else //Assume minimum distance of 1 for Charge.
skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,skillid == KN_CHARGEATK?1:flag);
- if (skillid == MO_EXTREMITYFIST && sc && sc->count)
- {
- if (sc->data[SC_EXPLOSIONSPIRITS].timer != -1)
- status_change_end(src, SC_EXPLOSIONSPIRITS, -1);
- if (sc->data[SC_BLADESTOP].timer != -1)
- status_change_end(src,SC_BLADESTOP,-1);
- if (sc->data[SC_COMBO].timer != -1) //This is one is here to make combo end even if skill failed.
- status_change_end(src,SC_COMBO,-1);
- }
}
break;
@@ -3480,21 +3373,44 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
} while (abra_skillid == 0);
abra_skilllv = skill_get_max(abra_skillid) > skilllv ? skilllv : skill_get_max(abra_skillid);
clif_skill_nodamage (src, bl, skillid, skilllv, 1);
+
if (sd)
{ //Crash-protection against Abracadabra casting pets
sd->skillitem = abra_skillid;
sd->skillitemlv = abra_skilllv;
sd->state.abra_flag = 1;
clif_item_skill (sd, abra_skillid, abra_skilllv, "Abracadabra");
- } else if(src->type == BL_PET)
+ } else
{ // [Skotlex]
- struct pet_data *pd = (struct pet_data *)src;
+ struct unit_data *ud = unit_bl2ud(src);
int inf = skill_get_inf(abra_skillid);
+ int target_id = 0;
+ if (!ud) break;
if (inf&INF_SELF_SKILL || inf&INF_SUPPORT_SKILL) {
- nullpo_retr(1,(struct map_session_data *)pd->msd);
- petskill_use(pd, &pd->msd->bl, abra_skillid, abra_skilllv, tick);
- } else //Assume offensive skills
- petskill_use(pd, bl, abra_skillid, abra_skilllv, tick);
+ if (src->type == BL_PET)
+ bl = (struct block_list*)((TBL_PET*)src)->msd;
+ if (!bl) bl = src;
+ unit_skilluse_id(src, bl->id, abra_skillid, abra_skilllv);
+ } else { //Assume offensive skills
+ if (ud->attacktarget)
+ target_id = ud->attacktarget;
+ else switch (src->type) {
+ case BL_MOB:
+ target_id = ((TBL_MOB*)src)->target_id;
+ break;
+ case BL_PET:
+ target_id = ((TBL_PET*)src)->target_id;
+ break;
+ }
+ if (!target_id)
+ break;
+ if (skill_get_casttype(abra_skillid) == CAST_GROUND) {
+ bl = map_id2bl(target_id);
+ if (!bl) bl = src;
+ unit_skilluse_pos(src, bl->x, bl->y, abra_skillid, abra_skilllv);
+ } else
+ unit_skilluse_id(src, target_id, abra_skillid, abra_skilllv);
+ }
}
}
break;
@@ -3871,11 +3787,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
map_freeblock_unlock();
return 0;
}
- if(dstmd && dstmd->skilltimer!=-1 && dstmd->state.skillcastcancel) // ‰r?¥–WŠQ
- skill_castcancel(bl,0);
- if(dstsd && dstsd->skilltimer!=-1 && (!dstsd->special_state.no_castcancel || map_flag_gvg(bl->m))
- && dstsd->state.skillcastcancel && !dstsd->special_state.no_castcancel2)
- skill_castcancel(bl,0);
+ unit_skillcastcancel(bl, 2);
if(tsc && tsc->count){
if(tsc->data[SC_FREEZE].timer!=-1)
@@ -4191,7 +4103,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
if (tsc && tsc->data[type].timer != -1)
i = status_change_end(bl, type, -1);
else
- i = sc_start4(bl,type,100,skilllv,status_get_dir(bl),0,0,0);
+ i = sc_start4(bl,type,100,skilllv,unit_getdir(bl),0,0,0);
clif_skill_nodamage(src,bl,skillid,skilllv,i);
break;
case AS_CLOAKING: /* ƒNƒ??ƒLƒ“ƒO */
@@ -4232,7 +4144,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case CG_HERMODE: // Wand of Hermod
{
struct skill_unit_group *sg;
- battle_stopwalking(src,1);
+ unit_stop_walking(src,1);
skill_clear_unitgroup(src);
sg = skill_unitsetting(src,skillid,skilllv,src->x,src->y,0);
if(skillid == CG_HERMODE)
@@ -4399,7 +4311,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
if(dstmd){
dstmd->attacked_id=0;
dstmd->target_id=0;
- dstmd->state.targettype = NONE_ATTACKABLE;
dstmd->state.skillstate=MSS_IDLE;
dstmd->next_walktime=tick+rand()%3000+3000;
}
@@ -4434,7 +4345,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
if ( pc_can_give_items(pc_isGM(sd)) )
clif_skill_fail(sd,skillid,0,0);
else
- clif_openvendingreq(sd,2+sd->skilllv);
+ clif_openvendingreq(sd,2+skilllv);
}
break;
@@ -4452,20 +4363,20 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
if(skilllv == 1) {
// possibility to skip menu [LuzZza]
if(!battle_config.skip_teleport_lv1_menu &&
- sd->skillid == AL_TELEPORT) //If skillid is not teleport, this was auto-casted! [Skotlex]
+ sd->skillitem != AL_TELEPORT) //If skillid is not teleport, this was auto-casted! [Skotlex]
clif_skill_warppoint(sd,skillid,skilllv,"Random","","","");
else
pc_randomwarp(sd,3);
} else {
- if (sd->skillid == AL_TELEPORT)
+ if (sd->skillitem != AL_TELEPORT)
clif_skill_warppoint(sd,skillid,skilllv,"Random",
mapindex_id2name(sd->status.save_point.map),"","");
else //Autocasted Teleport level 2??
pc_setpos(sd,sd->status.save_point.map,
sd->status.save_point.x,sd->status.save_point.y,3);
}
- } else if(dstmd && !map[bl->m].flag.monster_noteleport)
- mob_warp(dstmd,-1,-1,-1,3);
+ } else
+ unit_warp(bl,-1,-1,-1,3);
break;
case AL_HOLYWATER: /* ƒAƒNƒAƒxƒlƒfƒBƒNƒ^ */
@@ -4727,9 +4638,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case TK_HIGHJUMP:
{
- int x,y, dir = status_get_dir(src);
+ int x,y, dir = unit_getdir(src);
- if (md && !mob_can_move(md)) {
+ if (!unit_can_move(src)) {
map_freeblock_unlock();
return 1;
}
@@ -4737,10 +4648,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
x = src->x + dirx[dir]*skilllv*2;
y = src->y + diry[dir]*skilllv*2;
+
clif_skill_nodamage(src,bl,TK_HIGHJUMP,skilllv,1);
if(map_getcell(src->m,x,y,CELL_CHKPASS)) {
- if (sd) pc_movepos(sd,x,y,0);
- if (md) mob_warp(md, src->m, x, y, 0);
+ unit_movepos(src, x, y, 1, 0);
clif_slide(src,x,y);
}
}
@@ -4748,7 +4659,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case SA_CASTCANCEL:
clif_skill_nodamage(src,bl,skillid,skilllv,1);
- skill_castcancel(src,1);
+ unit_skillcastcancel(src,1);
if(sd) {
int sp = skill_get_sp(sd->skillid_old,sd->skilllv_old);
sp = sp * (90 - (skilllv-1)*20) / 100;
@@ -4774,32 +4685,23 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
pc_heal(sd,0,-sp);
}
} else {
+ struct unit_data *ud = unit_bl2ud(bl);
int bl_skillid=0,bl_skilllv=0,hp = 0;
- if(dstsd && dstsd->skilltimer != -1) {
- bl_skillid = dstsd->skillid;
- bl_skilllv = dstsd->skilllv;
- if (map_flag_vs(bl->m))
- hp = status_get_max_hp(bl)/50; //Recover 2% HP [Skotlex]
- }
- else if(dstmd && dstmd->skilltimer != -1) {
- if (status_get_mode(bl) & MD_BOSS)
- { //Only 10% success chance against bosses. [Skotlex]
- if (rand()%100 < 90)
- {
- if (sd) clif_skill_fail(sd,skillid,0,0);
- break;
- }
- } else
- hp = status_get_max_hp(bl)/50; //Recover 2% HP [Skotlex]
- bl_skillid = dstmd->skillid;
- bl_skilllv = dstmd->skilllv;
- }
- if(!bl_skillid) {
- if(sd) clif_skill_fail(sd,skillid,0,0);
- break;
- }
+ if (!ud || ud->skilltimer == -1) break; //Nothing to cancel.
+ bl_skillid = ud->skillid;
+ bl_skilllv = ud->skilllv;
+ if (status_get_mode(bl) & MD_BOSS)
+ { //Only 10% success chance against bosses. [Skotlex]
+ if (rand()%100 < 90)
+ {
+ if (sd) clif_skill_fail(sd,skillid,0,0);
+ break;
+ }
+ } else if (!dstsd || map_flag_vs(bl->m)) //HP damage only on pvp-maps when against players.
+ hp = status_get_max_hp(bl)/50; //Recover 2% HP [Skotlex]
+
clif_skill_nodamage(src,bl,skillid,skilllv,1);
- skill_castcancel(bl,0);
+ unit_skillcastcancel(bl,0);
sp = skill_get_sp(bl_skillid,bl_skilllv);
battle_heal(NULL, bl, -hp, -sp, 0);
if(sd && sp) {
@@ -4809,7 +4711,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
clif_heal(sd->fd,SP_SP,pc_heal(sd, 0, sp));
}
if (hp && skilllv >= 5)
- { //Recover half damaged HP at levels 6-10 [Skotlex]
+ { //Recover half damaged HP at level 5 [Skotlex]
hp = battle_heal(bl, src, hp/2, 0, 0);
if (sd && sd->fd)
clif_heal(sd->fd,SP_HP,hp);
@@ -4907,12 +4809,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case NPC_BARRIER:
{
int skill_time = skill_get_time(skillid,skilllv);
- clif_skill_nodamage(src,bl,skillid,skilllv,
- sc_start(bl,type,100,skilllv,skill_time));
- if (md)
- mob_changestate(md,MS_DELAY,skill_time);
- else
- battle_set_walkdelay(bl, tick, skill_time, 1);
+ struct unit_data *ud = unit_bl2ud(bl);
+ if (clif_skill_nodamage(src,bl,skillid,skilllv,
+ sc_start(bl,type,100,skilllv,skill_time))
+ && ud) { //Disable attacking/acting/moving for skill's duration.
+ ud->attackabletime =
+ ud->canact_tick =
+ ud->canmove_tick = tick + skill_time;
+ }
}
break;
@@ -4984,17 +4888,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
break;
case NPC_RUN: //Œã‘Þ
- if(md) {
- int dist = skilllv; //Run skillv tiles.
- int dir = (bl == src)?md->dir:map_calc_dir(src,bl->x,bl->y); //If cast on self, run forward, else run away.
- int mask[8][2] = {{0,-1},{1,-1},{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1}};
-
- md->attacked_id = 0;
- md->attacked_count = 0;
- md->target_id = 0;
- md->state.targettype = NONE_ATTACKABLE;
- md->state.skillstate = MSS_IDLE;
- mob_walktoxy(md, md->bl.x + dist * mask[dir][0], md->bl.y + dist * mask[dir][1], 0);
+ {
+ const int mask[8][2] = {{0,-1},{1,-1},{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1}};
+ int dir = (bl == src)?unit_getdir(src):map_calc_dir(src,bl->x,bl->y); //If cast on self, run forward, else run away.
+ unit_stop_attack(src);
+ //Run skillv tiles.
+ unit_walktoxy(src, bl->x + skilllv * mask[dir][0], bl->y + skilllv * mask[dir][1], 0);
}
break;
@@ -5004,7 +4903,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
if (skilllv > 1)
{ //Multiply skilllv times, the original instance must be silently killed. [Skotlex]
mob_summonslave(md,md->db->skill[md->skillidx].val,skilllv,skillid);
- mob_delete(md);
+ unit_free(src);
}
else
{ //Transform into another class.
@@ -5016,7 +4915,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case NPC_EMOTION_ON:
case NPC_EMOTION:
- if(md)
+ if(md && md->skillidx >= 0)
{
clif_emotion(&md->bl,md->db->skill[md->skillidx].val[0]);
if(!md->special_state.ai && (md->db->skill[md->skillidx].val[1] || md->db->skill[md->skillidx].val[2]))
@@ -5038,7 +4937,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
if (md->mode == md->db->mode)
md->mode = 0; //Fallback to the db's mode.
//Since mode changed, reset their state.
- mob_stopattack(md);
+ mob_stop_attack(md);
mob_stop_walking(md,0);
}
}
@@ -5192,7 +5091,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case BD_ENCORE: /* ƒAƒ“ƒR?ƒ‹ */
clif_skill_nodamage(src,bl,skillid,skilllv,1);
if(sd)
- skill_use_id(sd,src->id,sd->skillid_dance,sd->skilllv_dance);
+ unit_skilluse_id(src,src->id,sd->skillid_dance,sd->skilllv_dance);
break;
case AS_SPLASHER: /* ƒxƒiƒ€ƒXƒvƒ‰ƒbƒVƒƒ? */
@@ -5223,11 +5122,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
return 0;
}
- if(dstmd && dstmd->skilltimer!=-1 && dstmd->state.skillcastcancel) // ‰r?¥–WŠQ
- skill_castcancel(bl,0);
- if(dstsd && dstsd->skilltimer!=-1 && (!dstsd->special_state.no_castcancel || map_flag_gvg(bl->m))
- && dstsd->state.skillcastcancel && !dstsd->special_state.no_castcancel2)
- skill_castcancel(bl,0);
+ unit_skillcastcancel(bl,0);
if(tsc && tsc->count){
if(tsc->data[SC_FREEZE].timer!=-1)
@@ -5368,8 +5263,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
break;
case 5: // 2000HP heal, random teleported
battle_heal(src, src, 2000, 0, 0);
- if(sd && !map[src->m].flag.noteleport) pc_setpos(sd,sd->mapindex,-1,-1,3);
- else if(md && !map[src->m].flag.monster_noteleport) mob_warp(md,-1,-1,-1,3);
+ unit_warp(src, -1,-1,-1, 3);
break;
case 6: // random 2 other effects
if (count == -1)
@@ -5665,244 +5559,254 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
map_freeblock_unlock();
return 0;
}
-
/*==========================================
- * ƒXƒLƒ‹Žg—p?i‰r?¥Š®—¹?AIDŽw’è?j
+ * ƒXƒLƒ‹Žg—pi‰r¥Š®—¹AIDŽw’èj
*------------------------------------------
*/
int skill_castend_id( int tid, unsigned int tick, int id,int data )
{
- struct map_session_data* sd = map_id2sd(id)/*,*target_sd=NULL*/;
- struct block_list *bl;
+ struct block_list *target, *src = map_id2bl(id);
+ struct map_session_data* sd = NULL;
+ struct mob_data* md = NULL;
+ struct unit_data* ud = unit_bl2ud(src);
+ struct status_change *sc;
int inf2;
- nullpo_retr(0, sd);
-
-//Code cleanup.
-#define skill_failed(sd) { sd->skillid = sd->skilllv = sd->skillitem = sd->skillitemlv = -1; sd->canact_tick = tick; sd->skilltarget = 0; }
+ nullpo_retr(0, ud);
- if(sd->skillid != SA_CASTCANCEL && sd->skilltimer != tid )
- { /* ƒ^ƒCƒ}ID‚ÌŠm”F */
- ShowError("skill_castend_id: Timer mismatch %d!=%d!\n", sd->skilltimer, tid);
- sd->skilltimer = -1;
- return 0;
- }
+ BL_CAST( BL_PC, src, sd);
+ BL_CAST( BL_MOB, src, md);
- if( sd->bl.prev == NULL || sd->skillid == -1 || sd->skilllv == -1)
- { //Finished casting between maps, or the skill has failed after starting casting{
- sd->skilltimer = -1;
- skill_failed(sd);
+ if( src->prev == NULL ) {
+ ud->skilltimer = -1;
return 0;
}
- if(sd->skillid != SA_CASTCANCEL && sd->skilltimer != -1 && (inf2 = pc_checkskill(sd,SA_FREECAST) > 0)) //Hope ya don't mind me borrowing inf2 :X
- status_quick_recalc_speed(sd, SA_FREECAST, inf2, 0);
-
- if(sd->skillid != SA_CASTCANCEL)
- sd->skilltimer=-1;
- if((bl=map_id2bl(sd->skilltarget))==NULL ||
- bl->prev==NULL || sd->bl.m != bl->m) {
- skill_failed(sd);
- return 0;
- }
-
- if(sd->skillid == RG_BACKSTAP) {
- int dir = map_calc_dir(&sd->bl,bl->x,bl->y),t_dir = status_get_dir(bl);
- if(bl->type != BL_SKILL && (check_distance_bl(&sd->bl, bl, 0) || map_check_dir(dir,t_dir))) {
- clif_skill_fail(sd,sd->skillid,0,0);
- skill_failed(sd);
+ if(ud->skillid != SA_CASTCANCEL ) {
+ if( ud->skilltimer != tid ) {
+ ShowError("skill_castend_id: Timer mismatch %d!=%d!\n", ud->skilltimer, tid);
+ ud->skilltimer = -1;
return 0;
}
+ if( sd && ud->skilltimer != -1 && (inf2 = pc_checkskill(sd,SA_FREECAST)) > 0)
+ status_quick_recalc_speed(sd, SA_FREECAST, inf2, 0);
+ ud->skilltimer=-1;
}
- if (sd->skillid == PR_LEXDIVINA)
- {
- struct status_change *sc = status_get_sc(bl);
- if (battle_check_target(&sd->bl,bl, BCT_ENEMY)<=0 &&
- (!sc || sc->data[SC_SILENCE].timer == -1)) //If it's not an enemy, and not silenced, you can't use the skill on them. [Skotlex]
- {
- clif_skill_nodamage (&sd->bl, bl, sd->skillid, sd->skilllv, 0);
- skill_failed(sd);
- return 0;
+ if (ud->skilltarget == id)
+ target = src;
+ else
+ target = map_id2bl(ud->skilltarget);
+
+ // Use a do so that you can break out of it when the skill fails.
+ do {
+ if(!target || target->prev==NULL) break;
+
+ if(src->m != target->m || status_isdead(src)) break;
+
+ if(ud->skillid == RG_BACKSTAP) {
+ int dir = map_calc_dir(src,target->x,target->y),t_dir = unit_getdir(target);
+ if(check_distance_bl(src, target, 0) || map_check_dir(dir,t_dir)) {
+ break;
+ }
}
- } else {
- inf2 = skill_get_inf(sd->skillid);
- if((inf2&INF_ATTACK_SKILL ||
- (inf2&INF_SELF_SKILL && sd->bl.id != bl->id && !(skill_get_nk(sd->skillid)&NK_NO_DAMAGE))) //Self skills that cause damage (EF, Combo Skills, etc)
- && battle_check_target(&sd->bl,bl, BCT_ENEMY)<=0
- ) {
- skill_failed(sd);
- return 0;
+ if (ud->skillid == PR_LEXDIVINA)
+ {
+ sc = status_get_sc(target);
+ if (battle_check_target(src,target, BCT_ENEMY)<=0 &&
+ (!sc || sc->data[SC_SILENCE].timer == -1))
+ { //If it's not an enemy, and not silenced, you can't use the skill on them. [Skotlex]
+ clif_skill_nodamage (src, target, ud->skillid, ud->skilllv, 0);
+ break;
+ }
+ } else {
+ inf2 = skill_get_inf(ud->skillid);
+ if((inf2&INF_ATTACK_SKILL ||
+ (inf2&INF_SELF_SKILL && skill_get_inf2(ud->skillid)&INF2_NO_TARGET_SELF)) //Combo skills
+ && battle_check_target(src, target, BCT_ENEMY)<=0
+ )
+ break;
}
- }
- if (tid != -1 && !status_check_skilluse(&sd->bl, bl, sd->skillid, 1))
- { //Avoid doing double checks for instant-cast skills.
- if(sd->skillid == PR_LEXAETERNA) //Eh.. assuming skill failed due to opponent frozen/stone-cursed. [Skotlex]
- clif_skill_fail(sd,sd->skillid,0,0);
- skill_failed(sd);
- return 0;
- }
-
- inf2 = skill_get_inf2(sd->skillid);
- if(inf2 & (INF2_PARTY_ONLY|INF2_GUILD_ONLY) && sd->bl.id != bl->id) {
- int fail_flag = 1;
- if(inf2 & INF2_PARTY_ONLY && battle_check_target(&sd->bl,bl, BCT_PARTY) > 0)
- fail_flag = 0;
- else if(inf2 & INF2_GUILD_ONLY && battle_check_target(&sd->bl,bl, BCT_GUILD) > 0)
- fail_flag = 0;
- if (sd->skillid == PF_SOULCHANGE && map_flag_vs(sd->bl.m))
- //Soul Change overrides this restriction during pvp/gvg [Skotlex]
- fail_flag = 0;
-
- if(fail_flag) {
- clif_skill_fail(sd,sd->skillid,0,0);
- skill_failed(sd);
- return 0;
- }
- }
+ //Avoid doing double checks for instant-cast skills.
+ if (tid != -1 && !status_check_skilluse(src, target, ud->skillid, 1))
+ break;
- if(!check_distance_bl(&sd->bl, bl, skill_get_range2(&sd->bl,sd->skillid,sd->skilllv)+battle_config.pc_skill_add_range))
- {
- clif_skill_fail(sd,sd->skillid,0,0);
- if(battle_config.skill_out_range_consume) //Consume items anyway. [Skotlex]
- skill_check_condition(sd,1);
+ //’¾–Ù‚âó‘ÔˆÙí‚È‚Ç
+ if(md) {
+ if(ud->skillid != NPC_EMOTION)//Set afterskill delay.
+ md->last_thinktime=tick + (tid==-1?status_get_adelay(src):status_get_amotion(src));
+ if(md->skillidx >= 0) {
+ md->skilldelay[md->skillidx]=tick;
+ if (md->db->skill[md->skillidx].emotion >= 0)
+ clif_emotion(src, md->db->skill[md->skillidx].emotion);
+ }
+ }
+
+ inf2 = skill_get_inf2(ud->skillid);
+ if(inf2 & (INF2_PARTY_ONLY|INF2_GUILD_ONLY) && src != target) {
+ int fail_flag = 1;
+ if(inf2 & INF2_PARTY_ONLY && battle_check_target(src, target, BCT_PARTY) > 0)
+ fail_flag = 0;
+ else if(inf2 & INF2_GUILD_ONLY && battle_check_target(src, target, BCT_GUILD) > 0)
+ fail_flag = 0;
- skill_failed(sd);
- return 0;
- }
-
- if(!skill_check_condition(sd,1)) { /* Žg—p?Œ?ƒ`ƒFƒbƒN */
- skill_failed(sd);
- return 0;
- }
+ if (ud->skillid == PF_SOULCHANGE && map_flag_vs(target->m))
+ //Soul Change overrides this restriction during pvp/gvg [Skotlex]
+ fail_flag = 0;
+
+ if(fail_flag)
+ break;
+ }
- if(battle_config.pc_skill_log)
- ShowInfo("PC %d skill castend skill=%d\n",sd->bl.id,sd->skillid);
- pc_stop_walking(sd,0);
+ if(src != target && !check_distance_bl(src, target, skill_get_range2(src,ud->skillid,ud->skilllv)+battle_config.skill_add_range))
+ {
+ if (sd) {
+ clif_skill_fail(sd,ud->skillid,0,0);
+ if(battle_config.skill_out_range_consume) //Consume items anyway. [Skotlex]
+ skill_check_condition(sd,ud->skillid, ud->skilllv,1);
+ }
+ break;
+ }
- if (sd->skillid == SA_MAGICROD)
- sd->canact_tick = tick;
- else
- sd->canact_tick = tick + skill_delayfix(&sd->bl, sd->skillid, sd->skilllv, 0);
- battle_set_walkdelay(&sd->bl, tick, skill_get_walkdelay(sd->skillid, sd->skilllv), 1);
- if (skill_get_casttype(sd->skillid) == CAST_NODAMAGE)
- skill_castend_nodamage_id(&sd->bl,bl,sd->skillid,sd->skilllv,tick,0);
- else
- skill_castend_damage_id(&sd->bl,bl,sd->skillid,sd->skilllv,tick,0);
+ if(sd && !skill_check_condition(sd,ud->skillid, ud->skilllv,1)) /* Žg—pðŒƒ`ƒFƒbƒN */
+ break;
+
+ unit_stop_walking(src,0);
+
+ if (ud->skillid == SA_MAGICROD)
+ ud->canact_tick = tick;
+ else
+ ud->canact_tick = tick + skill_delayfix(src, ud->skillid, ud->skilllv, skill_get_delay(ud->skillid, ud->skilllv));
+ unit_set_walkdelay(src, tick, skill_get_walkdelay(ud->skillid, ud->skilllv), 1);
+
+ if(battle_config.skill_log && battle_config.skill_log&src->type)
+ ShowInfo("Type %d, ID %d skill castend id [id =%d, lv=%d, target ID %d)\n",
+ src->type, src->id, ud->skillid, ud->skilllv, target->id);
+ if (skill_get_casttype(ud->skillid) == CAST_NODAMAGE)
+ skill_castend_nodamage_id(src,target,ud->skillid,ud->skilllv,tick,0);
+ else
+ skill_castend_damage_id(src,target,ud->skillid,ud->skilllv,tick,0);
- if(sd->sc.count && sd->sc.data[SC_MAGICPOWER].timer != -1 && sd->skillid != HW_MAGICPOWER && sd->skillid != WZ_WATERBALL)
- status_change_end(&sd->bl,SC_MAGICPOWER,-1);
+ sc = status_get_sc(src);
+ if(sc && sc->count && sc->data[SC_MAGICPOWER].timer != -1 && ud->skillid != HW_MAGICPOWER && ud->skillid != WZ_WATERBALL)
+ status_change_end(src,SC_MAGICPOWER,-1);
- //Clean this up for future references to battle_getcurrentskill. [Skotlex]
- if (sd->skilltimer == -1) {
- sd->skillid = sd->skilllv = -1;
- sd->skilltarget = 0;
- }
+ if (ud->skilltimer == -1) {
+ if(md) md->skillidx = -1;
+ else ud->skillid = 0; //Non mobs can't clear this one as it is used for skill condition 'afterskill'
+ ud->skilllv = ud->skilltarget = 0;
+ }
+ return 1;
+ } while(0);
+ //Skill failed.
+ ud->skillid = ud->skilllv = ud->skilltarget = 0;
+ ud->canact_tick = tick;
+ if(sd) sd->skillitem = sd->skillitemlv = -1;
+ if(md) md->skillidx = -1;
return 0;
-#undef skill_failed
}
-/*---------------------------------------------------------------------------- */
-
/*==========================================
- * ƒXƒLƒ‹Žg—p?i‰r?¥Š®—¹?A?ê?ŠŽw’è?j
+ * ƒXƒLƒ‹Žg—pi‰r¥Š®—¹Aꊎw’èj
*------------------------------------------
*/
int skill_castend_pos( int tid, unsigned int tick, int id,int data )
{
- struct map_session_data* sd=map_id2sd(id)/*,*target_sd=NULL*/;
+ struct block_list* src = map_id2bl(id);
int maxcount;
+ struct map_session_data *sd = NULL;
+ struct unit_data *ud = unit_bl2ud(src);
+ struct mob_data *md = NULL;
- nullpo_retr(0, sd);
+ nullpo_retr(0, ud);
-//Code cleanup.
-#define skill_failed(sd) { sd->skillid = sd->skilllv = sd->skillitem = sd->skillitemlv = -1; sd->canact_tick = tick; }
+ BL_CAST( BL_PC , src, sd);
+ BL_CAST( BL_MOB, src, md);
- if( sd->skilltimer != tid )
- { /* ƒ^ƒCƒ}ID‚ÌŠm”F */
- ShowError("skill_castend_pos: Timer mismatch %d!=%d\n", sd->skilltimer, tid);
- sd->skilltimer = -1;
+ if( src->prev == NULL ) {
+ ud->skilltimer = -1;
+ return 0;
+ }
+
+ if( ud->skilltimer != tid ) /* ƒ^ƒCƒ}ID‚ÌŠm”F */
+ {
+ ShowError("skill_castend_pos: Timer mismatch %d!=%d\n", ud->skilltimer, tid);
+ ud->skilltimer = -1;
return 0;
}
- if(sd->skillid != SA_CASTCANCEL && sd->skilltimer != -1 && (maxcount = pc_checkskill(sd,SA_FREECAST) > 0)) //Hope ya don't mind me borrowing maxcount :X
+ if(sd && ud->skilltimer != -1 && (maxcount = pc_checkskill(sd,SA_FREECAST) > 0))
status_quick_recalc_speed(sd, SA_FREECAST, maxcount, 0);
- sd->skilltimer=-1;
- if (sd->bl.prev == NULL || sd->skillid == -1 || sd->skilllv <= 0)
- { // skill has failed after starting casting
- return 0;
- }
+ ud->skilltimer=-1;
+ do {
+ if(status_isdead(src)) break;
- if (!battle_config.pc_skill_reiteration &&
- skill_get_unit_flag(sd->skillid)&UF_NOREITERATION &&
- skill_check_unit_range(sd->bl.m,sd->skillx,sd->skilly,sd->skillid,sd->skilllv)) {
- clif_skill_fail(sd,sd->skillid,0,0);
- skill_failed(sd);
- return 0;
- }
+ if (!(battle_config.skill_reiteration && src->type&battle_config.skill_reiteration) &&
+ skill_get_unit_flag(ud->skillid)&UF_NOREITERATION &&
+ skill_check_unit_range(src->m,ud->skillx,ud->skilly,ud->skillid,ud->skilllv)
+ )
+ break;
- if (battle_config.pc_skill_nofootset &&
- skill_get_unit_flag(sd->skillid)&UF_NOFOOTSET &&
- skill_check_unit_range2(&sd->bl,sd->bl.m,sd->skillx,sd->skilly,sd->skillid,sd->skilllv)) {
- clif_skill_fail(sd,sd->skillid,0,0);
- skill_failed(sd);
- return 0;
- }
- if(battle_config.pc_land_skill_limit) {
- maxcount = skill_get_maxcount(sd->skillid);
- if(maxcount > 0) {
- int i,c;
- for(i=c=0;i<MAX_SKILLUNITGROUP;i++) {
- if(sd->skillunit[i].alive_count > 0 && sd->skillunit[i].skill_id == sd->skillid)
- c++;
- }
- if(c >= maxcount) {
- clif_skill_fail(sd,sd->skillid,0,0);
- skill_failed(sd);
- return 0;
+ if (battle_config.skill_nofootset && src->type&battle_config.skill_nofootset &&
+ skill_get_unit_flag(ud->skillid)&UF_NOFOOTSET &&
+ skill_check_unit_range2(src, src->m,ud->skillx,ud->skilly,ud->skillid,ud->skilllv)
+ )
+ break;
+
+ if(battle_config.land_skill_limit && src->type&battle_config.land_skill_limit &&
+ (maxcount = skill_get_maxcount(ud->skillid)) > 0
+ ) {
+ int i;
+ for(i=0;i<MAX_SKILLUNITGROUP && maxcount;i++) {
+ if(ud->skillunit[i].alive_count > 0 && ud->skillunit[i].skill_id == ud->skillid)
+ maxcount--;
}
+ if(!maxcount)
+ break;
}
- }
- if(tid != -1)
- { //Avoid double checks on instant cast skills. [Skotlex]
- if (!status_check_skilluse(&sd->bl, NULL, sd->skillid, 1))
- {
- skill_failed(sd);
- return 0;
+ if(tid != -1)
+ { //Avoid double checks on instant cast skills. [Skotlex]
+ if (!status_check_skilluse(src, NULL, ud->skillid, 1))
+ break;
+ if(!check_distance_blxy(src, ud->skillx, ud->skilly, skill_get_range2(src,ud->skillid,ud->skilllv)+battle_config.skill_add_range)) {
+ if (sd && battle_config.skill_out_range_consume) //Consume items anyway.
+ skill_check_condition(sd,ud->skillid, ud->skilllv,1);
+ break;
+ }
}
- if(!check_distance_blxy(&sd->bl, sd->skillx, sd->skilly, skill_get_range2(&sd->bl,sd->skillid,sd->skilllv)+battle_config.pc_skill_add_range)) {
- clif_skill_fail(sd,sd->skillid,0,0);
- if(battle_config.skill_out_range_consume) //Consume items anyway.
- skill_check_condition(sd,1);
- skill_failed(sd);
- return 0;
- }
- }
-
- if(!skill_check_condition(sd,1)) { /* Žg—p?Œ?ƒ`ƒFƒbƒN */
- skill_failed(sd);
- return 0;
- }
- if(battle_config.pc_skill_log)
- ShowInfo("PC %d skill castend skill=%d\n",sd->bl.id,sd->skillid);
- pc_stop_walking(sd,0);
+ if(sd && !skill_check_condition(sd,ud->skillid, ud->skilllv, 1)) /* Žg—pðŒƒ`ƒFƒbƒN */
+ break;
- sd->canact_tick = tick + skill_delayfix(&sd->bl, sd->skillid, sd->skilllv, 0);
- battle_set_walkdelay(&sd->bl, tick, skill_get_walkdelay(sd->skillid, sd->skilllv), 1);
+ if(battle_config.skill_log && battle_config.skill_log&src->type)
+ ShowInfo("Type %d, ID %d skill castend pos [id =%d, lv=%d, (%d,%d)]\n",
+ src->type, src->id, ud->skillid, ud->skilllv, ud->skillx, ud->skilly);
+ unit_stop_walking(src,0);
+ ud->canact_tick = tick + skill_delayfix(src, ud->skillid, ud->skilllv, skill_get_delay(ud->skillid, ud->skilllv));
+ unit_set_walkdelay(src, tick, skill_get_walkdelay(ud->skillid, ud->skilllv), 1);
+ skill_castend_pos2(src,ud->skillx,ud->skilly,ud->skillid,ud->skilllv,tick,0);
- skill_castend_pos2(&sd->bl,sd->skillx,sd->skilly,sd->skillid,sd->skilllv,tick,0);
+ if (ud->skilltimer == -1) {
+ if (md) md->skillidx = -1;
+ else ud->skillid = 0; //Non mobs can't clear this one as it is used for skill condition 'afterskill'
+ ud->skilllv = ud->skillx = ud->skilly = 0;
+ }
+ return 1;
+ } while(0);
- //Clean this up for future references to battle_getcurrentskill. [Skotlex]
- if (sd->skilltimer == -1) {
- sd->skillid = sd->skilllv = -1;
+ ud->canact_tick = tick;
+ ud->skillid = ud->skilllv = 0;
+ if(sd) {
+ clif_skill_fail(sd,ud->skillid,0,0);
+ sd->skillitem = sd->skillitemlv = -1;
}
+ if(md) md->skillidx = -1;
return 0;
-#undef skill_failed
+
}
/*==========================================
@@ -6057,20 +5961,16 @@ int skill_castend_pos2( struct block_list *src, int x,int y,int skillid,int skil
case AL_WARP: /* ƒ??ƒvƒ|?ƒ^ƒ‹ */
if(sd) {
clif_skill_warppoint(sd,skillid,skilllv,mapindex_id2name(sd->status.save_point.map),
- (sd->skilllv>1)?mapindex_id2name(sd->status.memo_point[0].map):"",
- (sd->skilllv>2)?mapindex_id2name(sd->status.memo_point[1].map):"",
- (sd->skilllv>3)?mapindex_id2name(sd->status.memo_point[2].map):"");
+ (skilllv>1)?mapindex_id2name(sd->status.memo_point[0].map):"",
+ (skilllv>2)?mapindex_id2name(sd->status.memo_point[1].map):"",
+ (skilllv>3)?mapindex_id2name(sd->status.memo_point[2].map):"");
}
break;
case MO_BODYRELOCATION:
- if (sd) {
- pc_movepos(sd, x, y, 1);
- skill_blockpc_start (sd, MO_EXTREMITYFIST, 2000);
- } else if (src->type == BL_MOB) {
- struct mob_data *md = (struct mob_data *)src;
- mob_warp(md, -1, x, y, 0);
- clif_spawnmob(md);
+ if (unit_movepos(src, x, y, 1, 1)) {
+ clif_slide(src, x, y);
+ if (sd) skill_blockpc_start (sd, MO_EXTREMITYFIST, 2000);
}
break;
case AM_CANNIBALIZE: // ƒoƒCƒIƒvƒ‰ƒ“ƒg
@@ -6253,11 +6153,11 @@ int skill_castend_map( struct map_session_data *sd,int skill_num, const char *ma
return 0;
}
- pc_stopattack(sd);
+ pc_stop_attack(sd);
+ pc_stop_walking(sd,0);
- if(battle_config.pc_skill_log)
+ if(battle_config.skill_log && battle_config.skill_log&BL_PC)
ShowInfo("PC %d skill castend skill =%d map=%s\n",sd->bl.id,skill_num,map);
- pc_stop_walking(sd,0);
if(strcmp(map,"cancel")==0) {
skill_failed(sd);
@@ -6292,12 +6192,11 @@ int skill_castend_map( struct map_session_data *sd,int skill_num, const char *ma
p[3] = &sd->status.memo_point[2];
if((maxcount = skill_get_maxcount(skill_num)) > 0) {
- int c;
- for(i=c=0;i<MAX_SKILLUNITGROUP;i++) {
- if(sd->skillunit[i].alive_count > 0 && sd->skillunit[i].skill_id == skill_num)
- c++;
+ for(i=0;i<MAX_SKILLUNITGROUP && maxcount;i++) {
+ if(sd->ud.skillunit[i].alive_count > 0 && sd->ud.skillunit[i].skill_id == skill_num)
+ maxcount--;
}
- if(c >= maxcount) {
+ if(!maxcount) {
clif_skill_fail(sd,skill_num,0,0);
skill_failed(sd);
return 0;
@@ -6318,27 +6217,18 @@ int skill_castend_map( struct map_session_data *sd,int skill_num, const char *ma
}
//FIXME: What about when you use another ground skill? skillx
//and skilly are messed up already... [Skotlex]
- i = sd->skillid;
- lv = sd->skilllv;
- sd->skillid = sd->menuskill_id;
- sd->skilllv = sd->menuskill_lv;
- if(!skill_check_condition(sd,3)) //This checks versus skillid/skilllv...
+ if(!skill_check_condition(sd, sd->menuskill_id, sd->menuskill_lv,3)) //This checks versus skillid/skilllv...
{
- sd->skillid = i;
- sd->skilllv = lv;
skill_failed(sd);
return 0;
}
- sd->skillid = i;
- sd->skilllv = lv;
- lv = sd->menuskill_lv;
- if(skill_check_unit_range2(&sd->bl,sd->bl.m,sd->skillx,sd->skilly,skill_num,lv) > 0) {
+ if(skill_check_unit_range2(&sd->bl,sd->bl.m,sd->ud.skillx,sd->ud.skilly,skill_num,lv) > 0) {
clif_skill_fail(sd,0,0,0);
skill_failed(sd);
return 0;
}
- if((group=skill_unitsetting(&sd->bl,skill_num,lv,sd->skillx,sd->skilly,0))==NULL) {
+ if((group=skill_unitsetting(&sd->bl,skill_num,lv,sd->ud.skillx,sd->ud.skilly,0))==NULL) {
skill_failed(sd);
return 0;
}
@@ -6418,7 +6308,7 @@ struct skill_unit_group *skill_unitsetting( struct block_list *src, int skillid,
case WZ_QUAGMIRE: //The target changes to "all" if used in a gvg map. [Skotlex]
case AM_DEMONSTRATION:
if (map_flag_vs(src->m) && battle_config.vs_traps_bctall
- && src->type != BL_MOB)
+ && (src->type&battle_config.vs_traps_bctall))
target = BCT_ALL;
break;
case HT_SHOCKWAVE: /* ƒVƒ‡ƒbƒNƒEƒF?ƒuƒgƒ‰ƒbƒv */
@@ -6436,8 +6326,7 @@ struct skill_unit_group *skill_unitsetting( struct block_list *src, int skillid,
if (map_flag_gvg(src->m))
limit *= 4; // longer trap times in WOE [celest]
if (battle_config.vs_traps_bctall && map_flag_vs(src->m)
- && src->type != BL_MOB)
- //Change target to all with the exception of mob traps [Skotlex]
+ && (src->type&battle_config.vs_traps_bctall))
target = BCT_ALL;
break;
@@ -6713,10 +6602,8 @@ int skill_unit_onplace(struct skill_unit *src,struct block_list *bl,unsigned int
skill_delunitgroup(sg);
}
}
- } else if(bl->type==BL_MOB && battle_config.mob_warpportal){
- int m = map_mapindex2mapid(sg->val3);
- mob_warp((struct mob_data *)bl,m,sg->val2>>16,sg->val2&0xffff,3);
- }
+ } else if(battle_config.mob_warpportal)
+ unit_warp(bl,map_mapindex2mapid(sg->val3),sg->val2>>16,sg->val2&0xffff,3);
break;
case UNT_QUAGMIRE:
@@ -7484,7 +7371,7 @@ static int skill_check_condition_char_sub (struct block_list *bl, va_list ap)
case PR_BENEDICTIO: /* ?¹??~•Ÿ */
{
int dir = map_calc_dir(&sd->bl,tsd->bl.x,tsd->bl.y);
- dir = (status_get_dir(&sd->bl) + dir)%8; //This adjusts dir to account for the direction the sd is facing.
+ dir = (unit_getdir(&sd->bl) + dir)%8; //This adjusts dir to account for the direction the sd is facing.
if ((tsd->class_&MAPID_BASEMASK) == MAPID_ACOLYTE && (dir == 2 || dir == 6) //Must be standing to the left/right of Priest.
&& sd->status.sp >= 10)
p_sd[(*c)++]=tsd->bl.id;
@@ -7493,7 +7380,7 @@ static int skill_check_condition_char_sub (struct block_list *bl, va_list ap)
default: //Warning: Assuming Ensemble Dance/Songs for code speed. [Skotlex]
{
int skilllv;
- if(pc_issit(tsd) || !pc_can_move(tsd))
+ if(pc_issit(tsd) || !unit_can_move(&tsd->bl))
return 0;
if (sd->status.sex != tsd->status.sex &&
(tsd->class_&MAPID_UPPERMASK) == MAPID_BARDDANCER &&
@@ -7518,7 +7405,7 @@ static int skill_check_condition_char_sub (struct block_list *bl, va_list ap)
* Checks and stores partners for ensemble skills [Skotlex]
*------------------------------------------
*/
-static int skill_check_pc_partner(struct map_session_data *sd, int skill_id, int* skill_lv, int range, int cast_flag)
+int skill_check_pc_partner(struct map_session_data *sd, int skill_id, int* skill_lv, int range, int cast_flag)
{
static int c=0;
static int p_sd[2] = { 0, 0 };
@@ -7540,8 +7427,8 @@ static int skill_check_pc_partner(struct map_session_data *sd, int skill_id, int
{
clif_skill_nodamage(&tsd->bl, &sd->bl, skill_id, *skill_lv, 1);
skill_moonlit(&sd->bl, &tsd->bl, *skill_lv);
- tsd->skillid_dance = tsd->skillid = skill_id;
- tsd->skilllv_dance = tsd->skilllv = *skill_lv;
+ tsd->skillid_dance = skill_id;
+ tsd->skilllv_dance = *skill_lv;
}
return c;
default: //Warning: Assuming Ensemble skills here (for speed)
@@ -7550,8 +7437,8 @@ static int skill_check_pc_partner(struct map_session_data *sd, int skill_id, int
sd->sc.data[SC_DANCING].val4= tsd->bl.id;
sc_start4(&tsd->bl,SC_DANCING,100,skill_id,sd->sc.data[SC_DANCING].val2,0,sd->bl.id,skill_get_time(skill_id,*skill_lv)+1000);
clif_skill_nodamage(&tsd->bl, &sd->bl, skill_id, *skill_lv, 1);
- tsd->skillid_dance = tsd->skillid = skill_id;
- tsd->skilllv_dance = tsd->skilllv = *skill_lv;
+ tsd->skillid_dance = skill_id;
+ tsd->skilllv_dance = *skill_lv;
}
return c;
}
@@ -7603,9 +7490,9 @@ static int skill_check_condition_hermod_sub(struct block_list *bl,va_list ap)
* ƒXƒLƒ‹Žg—p?Œ??i?‚ÅŽg—pŽ¸”s?j
*------------------------------------------
*/
-int skill_check_condition(struct map_session_data *sd,int type)
+int skill_check_condition(struct map_session_data *sd,int skill, int lv, int type)
{
- int i,hp,sp,hp_rate,sp_rate,zeny,weapon,state,spiritball,skill,lv,mhp;
+ int i,j,hp,sp,hp_rate,sp_rate,zeny,weapon,state,spiritball,mhp;
int index[10],itemid[10],amount[10];
int arrow_flag = 0;
int force_gem_flag = 0;
@@ -7613,21 +7500,23 @@ int skill_check_condition(struct map_session_data *sd,int type)
nullpo_retr(0, sd);
+ if (lv <= 0) return 0;
+
if( battle_config.gm_skilluncond &&
pc_isGM(sd)>= battle_config.gm_skilluncond &&
- sd->skillitem != sd->skillid)
+ sd->skillitem != skill)
{ //GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex]
sd->skillitem = sd->skillitemlv = -1;
return 1;
}
if( sd->sc.opt1 ) {
- clif_skill_fail(sd,sd->skillid,0,0);
+ clif_skill_fail(sd,skill,0,0);
sd->skillitem = sd->skillitemlv = -1;
return 0;
}
if(pc_is90overweight(sd)) {
- clif_skill_fail(sd,sd->skillid,9,0);
+ clif_skill_fail(sd,skill,9,0);
sd->skillitem = sd->skillitemlv = -1;
return 0;
}
@@ -7640,14 +7529,14 @@ int skill_check_condition(struct map_session_data *sd,int type)
}
if (sd->menuskill_id == AM_PHARMACY &&
- (sd->skillid == AM_PHARMACY || sd->skillid == AC_MAKINGARROW || sd->skillid == BS_REPAIRWEAPON ||
- sd->skillid == AM_TWILIGHT1 || sd->skillid == AM_TWILIGHT2 || sd->skillid == AM_TWILIGHT3
+ (skill == AM_PHARMACY || skill == AC_MAKINGARROW || skill == BS_REPAIRWEAPON ||
+ skill == AM_TWILIGHT1 || skill == AM_TWILIGHT2 || skill == AM_TWILIGHT3
)) {
sd->skillitem = sd->skillitemlv = -1;
return 0;
}
- if(sd->skillitem == sd->skillid) { /* ƒAƒCƒeƒ€‚Ì?ê?‡–³?Œ??¬Œ÷ */
+ if(sd->skillitem == skill) { /* ƒAƒCƒeƒ€‚Ì?ê?‡–³?Œ??¬Œ÷ */
if(!type) //When a target was selected
{ //Consume items that were skipped in pc_use_item [Skotlex]
if((i = sd->itemindex) == -1 ||
@@ -7662,7 +7551,7 @@ int skill_check_condition(struct map_session_data *sd,int type)
}
//Consume
sd->itemid = sd->itemindex = -1;
- if(sd->skillid == WZ_EARTHSPIKE
+ if(skill == WZ_EARTHSPIKE
&& sd->sc.data[SC_TKDORI].timer != -1 && rand()%100 > sd->sc.data[SC_TKDORI].val2) // [marquis007]
; //Do not consume item.
else
@@ -7672,51 +7561,31 @@ int skill_check_condition(struct map_session_data *sd,int type)
sd->skillitem = sd->skillitemlv = -1;
return 1;
}
- /* These two are part of status_check_skilluse now.
- if( sd->sc.opt1 ){
- clif_skill_fail(sd,sd->skillid,0,0);
- return 0;
- }
- if(sd->sc.count){
- if( sd->sc.data[SC_SILENCE].timer!=-1 ||
- sd->sc.data[SC_ROKISWEIL].timer!=-1 ||
- (sd->sc.data[SC_AUTOCOUNTER].timer != -1 && sd->skillid != KN_AUTOCOUNTER) ||
- sd->sc.data[SC_STEELBODY].timer != -1 ||
- sd->sc.data[SC_BERSERK].timer != -1 ||
- (sd->sc.data[SC_MARIONETTE].timer != -1 && sd->skillid != CG_MARIONETTE)){
- clif_skill_fail(sd,sd->skillid,0,0);
- return 0;
- }
- }
- */
- skill = sd->skillid;
- lv = sd->skilllv;
- if (lv <= 0) return 0;
// for the guild skills [celest]
if (skill >= GD_SKILLBASE)
- skill = GD_SKILLRANGEMIN + skill - GD_SKILLBASE;
- if (skill < 0 || skill >= MAX_SKILL_DB)
+ j = GD_SKILLRANGEMIN + skill - GD_SKILLBASE;
+ else
+ j = skill;
+ if (j < 0 || j >= MAX_SKILL_DB)
return 0;
//Code speedup, rather than using skill_get_* over and over again.
if (lv < 1 || lv > MAX_SKILL_LEVEL)
return 0;
- hp = skill_db[skill].hp[lv-1]; /* ?Á”ïHP */
- sp = skill_db[skill].sp[lv-1]; /* ?Á”ïSP */
+ hp = skill_db[j].hp[lv-1]; /* ?Á”ïHP */
+ sp = skill_db[j].sp[lv-1]; /* ?Á”ïSP */
if((sd->skillid_old == BD_ENCORE) && skill == sd->skillid_dance)
sp=sp/2; //ƒAƒ“ƒR?ƒ‹Žž‚ÍSP?Á””¼•ª
- hp_rate = skill_db[skill].hp_rate[lv-1];
- sp_rate = skill_db[skill].sp_rate[lv-1];
- zeny = skill_db[skill].zeny[lv-1];
- weapon = skill_db[skill].weapon;
- state = skill_db[skill].state;
- spiritball = skill_db[skill].spiritball[lv-1];
- mhp = skill_db[skill].mhp[lv-1]; /* ?Á”ïHP */
+ hp_rate = skill_db[j].hp_rate[lv-1];
+ sp_rate = skill_db[j].sp_rate[lv-1];
+ zeny = skill_db[j].zeny[lv-1];
+ weapon = skill_db[j].weapon;
+ state = skill_db[j].state;
+ spiritball = skill_db[j].spiritball[lv-1];
+ mhp = skill_db[j].mhp[lv-1]; /* ?Á”ïHP */
for(i = 0; i < 10; i++) {
- itemid[i] = skill_db[skill].itemid[i];
- amount[i] = skill_db[skill].amount[i];
+ itemid[i] = skill_db[j].itemid[i];
+ amount[i] = skill_db[j].amount[i];
}
- if (skill != sd->skillid)
- skill = sd->skillid; //Restore skillid for guild skills.
if(mhp > 0)
hp += (sd->status.max_hp * mhp)/100;
if(hp_rate > 0)
@@ -7768,7 +7637,7 @@ int skill_check_condition(struct map_session_data *sd,int type)
switch(skill) {
case SA_CASTCANCEL:
- if(sd->skilltimer == -1) {
+ if(sd->ud.skilltimer == -1) {
clif_skill_fail(sd,skill,0,0);
return 0;
}
@@ -7930,7 +7799,7 @@ int skill_check_condition(struct map_session_data *sd,int type)
int summons[5] = { 1020, 1068, 1118, 1500, 1368 };
int maxcount = (skill==AM_CANNIBALIZE)? 6-lv : skill_get_maxcount(skill);
int mob_class = (skill==AM_CANNIBALIZE)? summons[lv-1] :1142;
- if(battle_config.pc_land_skill_limit && maxcount>0) {
+ if(battle_config.land_skill_limit && maxcount>0 && (battle_config.land_skill_limit&BL_PC)) {
map_foreachinmap(skill_check_condition_mob_master_sub ,sd->bl.m, BL_MOB, sd->bl.id, mob_class,&c );
if(c >= maxcount){
clif_skill_fail(sd,skill,0,0);
@@ -7939,42 +7808,9 @@ int skill_check_condition(struct map_session_data *sd,int type)
}
}
break;
- case MG_FIREWALL: /* ƒtƒ@ƒCƒA?ƒEƒH?ƒ‹ */
- case WZ_QUAGMIRE:
- case PF_FOGWALL:
- /* ??§ŒÀ */
- if(battle_config.pc_land_skill_limit) {
- int maxcount = skill_get_maxcount(skill);
- if(maxcount > 0) {
- int i,c;
- for(i=c=0;i<MAX_SKILLUNITGROUP;i++) {
- if(sd->skillunit[i].alive_count > 0 && sd->skillunit[i].skill_id == skill)
- c++;
- }
- if(c >= maxcount) {
- clif_skill_fail(sd,skill,0,0);
- return 0;
- }
- }
- }
- break;
case WZ_FIREPILLAR: // celest
if (lv <= 5) // no gems required at level 1-5
itemid[0] = 0;
- if(battle_config.pc_land_skill_limit) {
- int maxcount = skill_get_maxcount(skill);
- if(maxcount > 0) {
- int i,c;
- for(i=c=0;i<MAX_SKILLUNITGROUP;i++) {
- if(sd->skillunit[i].alive_count > 0 && sd->skillunit[i].skill_id == skill)
- c++;
- }
- if(c >= maxcount) {
- clif_skill_fail(sd,skill,0,0);
- return 0;
- }
- }
- }
break;
case SL_SMA:
if(type) break; //Only do the combo check when the target is selected (type == 0)
@@ -8306,16 +8142,9 @@ int skill_check_condition(struct map_session_data *sd,int type)
}
break;
case ST_MOVE_ENABLE:
- {
- struct walkpath_data wpd;
- if(!pc_can_move(sd)) {
- clif_skill_fail(sd,skill,0,0);
- return 0;
- }
- if (skill_get_inf(skill)&INF_GROUND_SKILL && path_search(&wpd,sd->bl.m,sd->bl.x,sd->bl.y,sd->skillx,sd->skilly,1)==-1) {
- clif_skill_fail(sd,skill,0,0);
- return 0;
- }
+ if(!unit_can_move(&sd->bl)) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
}
break;
case ST_WATER:
@@ -8402,15 +8231,12 @@ int skill_castfix( struct block_list *bl, int skill_id, int skill_lv, int time)
nullpo_retr(0, bl);
- if (!time && bl->type != BL_MOB)
- time = skill_get_cast(skill_id, skill_lv);
-
if (bl->type == BL_PC){
struct map_session_data *sd = (struct map_session_data*)bl;
nullpo_retr(0, sd);
// calculate base cast time (reduced by dex)
- if (!skill_get_castnodex(sd->skillid, sd->skilllv) > 0) {
+ if (!skill_get_castnodex(skill_id, skill_lv) > 0) {
int scale = battle_config.castrate_dex_scale - status_get_dex(bl);
if (scale > 0) // not instant cast
time = time * scale / battle_config.castrate_dex_scale;
@@ -8460,9 +8286,6 @@ int skill_delayfix( struct block_list *bl, int skill_id, int skill_lv, int time
nullpo_retr(0, bl);
- if (!time && bl->type != BL_MOB)
- time = skill_get_delay(skill_id, skill_lv);
-
if (bl->type == BL_PC){
struct map_session_data *sd = (struct map_session_data*)bl;
nullpo_retr(0, sd);
@@ -8474,7 +8297,7 @@ int skill_delayfix( struct block_list *bl, int skill_id, int skill_lv, int time
else
time = 300; // default delay, according to official servers
} else if (time < 0)
- time = abs(time) + status_get_amotion(bl); // if set to <0, the attack motion is added.
+ time = -time + status_get_amotion(bl); // if set to <0, the attack motion is added.
if (battle_config.delay_dependon_dex && /* dex‚̉e‹¿‚ðŒvŽZ‚·‚é */
!skill_get_delaynodex(skill_id, skill_lv)) // if skill casttime is allowed to be reduced by dex
@@ -8516,446 +8339,6 @@ int skill_delayfix( struct block_list *bl, int skill_id, int skill_lv, int time
return (time > 0) ? time : 0;
}
-/*==========================================
- * ƒXƒLƒ‹Žg—p?iIDŽw’è?j
- *------------------------------------------
- */
-int skill_use_id (struct map_session_data *sd, int target_id, int skill_num, int skill_lv)
-{
- struct map_session_data* tsd = NULL;
- struct block_list *bl = NULL;
- struct status_change *sc;
- int casttime, forcecast = 0;
- unsigned int tick = gettick();
-
- nullpo_retr(0, sd);
-
- if (skill_lv <= 0)
- return 0;
-
- sc = sd->sc.count?&sd->sc:NULL;
-
- //casttime is reused as a combo-skill checker (needed to invoke battle_stopattack) [Skotlex]
- casttime = (target_id == sd->bl.id
- && skill_get_inf(skill_num)&INF_SELF_SKILL
- && skill_get_inf2(skill_num)&INF2_NO_TARGET_SELF);
- if (casttime)
- target_id = sd->attacktarget; //Auto-select skills. [Skotlex]
- switch(skill_num)
- { //Check for skills that auto-select target
- case MO_CHAINCOMBO:
- if (sc && sc->data[SC_BLADESTOP].timer != -1){
- if ((bl=(struct block_list *)sc->data[SC_BLADESTOP].val4) == NULL) //ƒ^?ƒQƒbƒg‚ª‚¢‚È‚¢H
- return 0;
- target_id = bl->id;
- }
- break;
- case TK_JUMPKICK:
- case TK_COUNTER:
- case HT_POWER:
- if (sc && sc->data[SC_COMBO].timer != -1 && sc->data[SC_COMBO].val1 == skill_num)
- target_id = sc->data[SC_COMBO].val2;
- break;
- case WE_MALE:
- case WE_FEMALE:
- if (!sd->status.partner_id)
- return 0;
- tsd = map_charid2sd(sd->status.partner_id);
- bl = (struct block_list *)tsd;
- if (bl)
- target_id = bl->id;
- else
- {
- clif_skill_fail(sd,skill_num,0,0);
- return 0;
- }
- break;
- }
- if (bl == NULL && (bl = map_id2bl(target_id)) == NULL)
- return 0;
-
- if (bl->type == BL_PC)
- tsd = (struct map_session_data*)bl;
-
- if (bl->prev == NULL) //Prevent targeting enemies that are not in the map. [Skotlex]
- return 0;
-
- if(sd->bl.m != bl->m)
- return 0;
-
- if(sd->skilltimer != -1 && skill_num != SA_CASTCANCEL) //Normally not needed because clif.c checks for it, but the at/char/script commands don't! [Skotlex]
- return 0;
-
- if(skillnotok(skill_num, sd)) // [MouseJstr]
- return 0;
-
- if(skill_get_inf2(skill_num)&INF2_NO_TARGET_SELF && sd->bl.id == target_id)
- return 0;
-
- if(!status_check_skilluse(&sd->bl, bl, skill_num, 0))
- {
- if(skill_num == PR_LEXAETERNA) //Eh.. assuming skill failed due to opponent frozen/stone-cursed. [Skotlex]
- clif_skill_fail(sd,skill_num,0,0);
- return 0;
- }
-
- //’¼‘O‚̃XƒLƒ‹‚ª‰½‚©?‚¦‚é•K—v‚Ì‚ ‚éƒXƒLƒ‹
- switch (skill_num) {
- case SA_CASTCANCEL:
- if (sd->skillid != skill_num){ //ƒLƒƒƒXƒgƒLƒƒƒ“ƒZƒ‹Ž©?‚Í?‚¦‚È‚¢
- sd->skillid_old = sd->skillid;
- sd->skilllv_old = sd->skilllv;
- }
- break;
-
- case BD_ENCORE: /* ƒAƒ“ƒR?ƒ‹ */
- if (!sd->skillid_dance || pc_checkskill(sd, sd->skillid_dance) <= 0) { //Prevent using the dance skill if you no longer have the skill in your tree.
- clif_skill_fail(sd,skill_num,0,0);
- return 0;
- }
- sd->skillid_old = skill_num;
- break;
-
- case GD_BATTLEORDER:
- case GD_REGENERATION:
- case GD_RESTORE:
- case GD_EMERGENCYCALL:
- if (sd->state.gmaster_flag)
- skill_lv = guild_checkskill(sd->state.gmaster_flag, skill_num);
- break;
- case BD_LULLABY: /* ŽqŽç‰Ì */
- case BD_RICHMANKIM: /* ƒjƒˆƒ‹ƒh‚̉ƒ */
- case BD_ETERNALCHAOS: /* ‰i‰“‚Ì?¬“× */
- case BD_DRUMBATTLEFIELD: /* ?‘¾ŒÛ‚Ì‹¿‚« */
- case BD_RINGNIBELUNGEN: /* ƒj?ƒxƒ‹ƒ“ƒO‚ÌŽw—Ö */
- case BD_ROKISWEIL: /* ƒ?ƒL‚Ì‹©‚Ñ */
- case BD_INTOABYSS: /* ?[•£‚Ì’†‚É */
- case BD_SIEGFRIED: /* •sŽ€?g‚̃W?ƒNƒtƒŠ?ƒh */
- case CG_MOONLIT: /* ŒŽ–¾‚è‚Ì?ò‚É—Ž‚¿‚é‰Ô‚Ñ‚ç */
- {
- if (battle_config.player_skill_partner_check &&
- (!battle_config.gm_skilluncond || pc_isGM(sd) < battle_config.gm_skilluncond)
- ) {
- if (skill_check_pc_partner(sd, skill_num, &skill_lv, 1, 0) < 1) //Note that skill_lv is automatically updated.
- {
- clif_skill_fail(sd,skill_num,0,0);
- return 0;
- }
- }
- break;
- }
- }
-
- sd->skillid = skill_num;
- sd->skilllv = skill_lv;
- if (!skill_check_condition(sd,0)) return 0;
-
- if(sd->bl.id != target_id){ // Don't check range for self skills, this is useless...
- if(!battle_check_range(&sd->bl,bl,skill_get_range2(&sd->bl, skill_num,skill_lv)
- +(skill_num==RG_CLOSECONFINE?0:1))) //Close confine is expoitable thanks to this extra range "feature" of the client. [Skotlex]
- return 0;
- }
-
- if (!casttime) //Stop attack on non-combo skills [Skotlex]
- pc_stopattack(sd);
- else if(sd->attacktimer != -1) //Elsewise, delay current attack sequence
- sd->attackabletime = tick + status_get_amotion(&sd->bl);
-
- casttime = skill_castfix(&sd->bl, skill_num, skill_lv, 0);
- sd->state.skillcastcancel = skill_get_castcancel(skill_num);
-
- switch (skill_num) { /* ‰½‚©“ÁŽê‚È?—?‚ª•K—v */
- case ALL_RESURRECTION: /* ƒŠƒUƒŒƒNƒVƒ‡ƒ“ */
- if (battle_check_undead(status_get_race(bl),status_get_elem_type(bl))) { /* “G‚ªƒAƒ“ƒfƒbƒh‚È‚ç */
- forcecast = 1; /* ƒ^?ƒ“ƒAƒ“ƒfƒbƒg‚Æ“¯‚¶‰r?¥ŽžŠÔ */
- casttime = skill_castfix(&sd->bl, PR_TURNUNDEAD, skill_lv, 0);
- }
- break;
-
- case MO_FINGEROFFENSIVE: /* Žw? */
- casttime += casttime * ((skill_lv > sd->spiritball) ? sd->spiritball : skill_lv);
- break;
-
-// -- moonsoul (altered to allow proper usage of extremity from new champion combos)
-//
- case MO_EXTREMITYFIST: /*ˆ¢?C—…”e–PŒ?*/
- if (sc && sc->data[SC_COMBO].timer != -1 &&
- (sc->data[SC_COMBO].val1 == MO_COMBOFINISH ||
- sc->data[SC_COMBO].val1 == CH_TIGERFIST ||
- sc->data[SC_COMBO].val1 == CH_CHAINCRUSH))
- casttime = 0;
- forcecast = 1;
- break;
-
- case SA_MAGICROD:
- case SA_SPELLBREAKER:
- forcecast = 1;
- break;
-
- case KN_CHARGEATK:
- casttime *= distance_bl(&sd->bl, bl);
- break;
-
- case HP_BASILICA: /* ƒoƒWƒŠƒJ */
- {
- // cancel Basilica if already in effect
- if (sc && sc->data[SC_BASILICA].timer != -1 && sc->data[SC_BASILICA].val3 == BCT_SELF) {
- status_change_end(&sd->bl,SC_BASILICA,-1);
- return 0;
- }
- }
- break;
- }
-
- //ƒ?ƒ‚ƒ‰ƒCƒY?‘Ô‚È‚çƒLƒƒƒXƒgƒ^ƒCƒ€‚ª1/3
- if (sc && sc->data[SC_MEMORIZE].timer != -1 && casttime > 0) {
- casttime = casttime/2;
- if ((--sc->data[SC_MEMORIZE].val2) <= 0)
- status_change_end(&sd->bl, SC_MEMORIZE, -1);
- }
-
- if (battle_config.pc_skill_log)
- ShowInfo("PC %d skill use target_id=%d skill=%d lv=%d cast=%d\n",
- sd->bl.id, target_id, skill_num, skill_lv, casttime);
-
- if (casttime > 0 || forcecast) {
- struct mob_data *md;
- int mode;
- if(sd->disguise) { // [Valaris]
- clif_skillcasting(&sd->bl,sd->bl.id, target_id, 0,0, skill_num,0);
- clif_skillcasting(&sd->bl,-sd->bl.id, target_id, 0,0, skill_num,casttime);
- }
- else
- clif_skillcasting(&sd->bl,sd->bl.id, target_id, 0,0, skill_num,casttime);
- /* ‰r?¥”½?ƒ‚ƒ“ƒXƒ^? */
- if (bl->type == BL_MOB)
- {
- md = (struct mob_data *)bl;
- mobskill_event(md, &sd->bl, tick, -1); //Cast targetted skill event.
- if ((mode=status_get_mode(bl))&MD_CASTSENSOR &&
- battle_check_target(bl, &sd->bl, BCT_ENEMY) > 0)
- {
- switch (md->state.skillstate) {
- case MSS_ANGRY:
- case MSS_RUSH:
- case MSS_FOLLOW:
- if (!(mode&(MD_AGGRESSIVE|MD_ANGRY)))
- break; //Only Aggressive mobs change target while chasing.
- case MSS_IDLE:
- case MSS_WALK:
- md->target_id = sd->bl.id;
- md->state.targettype = ATTACKABLE;
- md->state.aggressive = (mode&MD_ANGRY)?1:0;
- md->min_chase = md->db->range3;
- }
- }
- }
- }
-
- if (!(battle_config.pc_cloak_check_type&2) &&
- sc && sc->data[SC_CLOAKING].timer != -1 &&
- sd->skillid != AS_CLOAKING)
- status_change_end(&sd->bl,SC_CLOAKING,-1);
-
- sd->skilltarget = target_id;
- sd->skillx = 0;
- sd->skilly = 0;
- sd->canact_tick = tick + casttime + 100;
-
- if (casttime > 0) {
- sd->skilltimer = add_timer (tick + casttime, skill_castend_id, sd->bl.id, 0);
- if ((forcecast = pc_checkskill(sd,SA_FREECAST)) > 0)
- status_quick_recalc_speed (sd, SA_FREECAST, forcecast, 1);
- else
- pc_stop_walking(sd,0);
- } else {
- sd->state.skillcastcancel = 0; /* ‰r?¥‚Ì–³‚¢‚à‚̂̓Lƒƒƒ“ƒZƒ‹‚³‚ê‚È‚¢ */
- if (skill_num != SA_CASTCANCEL)
- sd->skilltimer = -1;
- skill_castend_id(sd->skilltimer,tick,sd->bl.id,0);
- }
-
- return 0;
-}
-
-/*==========================================
- * ƒXƒLƒ‹Žg—p?i?ê?ŠŽw’è?j
- *------------------------------------------
- */
-int skill_use_pos (struct map_session_data *sd, int skill_x, int skill_y, int skill_num, int skill_lv)
-{
- struct block_list bl;
- struct status_change *sc;
- int casttime, skill = 0;
- unsigned int tick = gettick();
-
- nullpo_retr(0, sd);
-
- if (skill_lv <= 0)
- return 0;
- if (sd->skilltimer != -1) //Normally not needed since clif.c checks for it, but at/char/script commands don't! [Skotlex]
- return 0;
- if (skillnotok(skill_num, sd)) // [MouseJstr]
- return 0;
- if (map_getcell(sd->bl.m, skill_x, skill_y, CELL_CHKNOPASS))
- { //prevent casting ground targeted spells on non-walkable areas. [Skotlex]
-
- clif_skill_fail(sd,skill_num,0,0);
- return 0;
- }
-
- sc = sd->sc.count?&sd->sc:NULL;
-
- if (!status_check_skilluse(&sd->bl, NULL, skill_num, 0))
- return 0;
-
- sd->skillid = skill_num;
- sd->skilllv = skill_lv;
- sd->skillx = skill_x;
- sd->skilly = skill_y;
- if (!skill_check_condition(sd,0)) return 0;
-
- /* ŽË’ö‚Æ?áŠQ•¨ƒ`ƒFƒbƒN */
- bl.type = BL_NUL;
- bl.m = sd->bl.m;
- bl.x = skill_x;
- bl.y = skill_y;
-
- if(!battle_check_range(&sd->bl,&bl,skill_get_range2(&sd->bl, skill_num,skill_lv)+1))
- return 0;
-
-/* Previous code body, left here in case we have to rollback. [Skotlex]
- {
- int check_range_flag = 0;
-
- range = skill_get_range(skill_num,skill_lv);
- if(range < 0)
- range = status_get_range(&sd->bl) - (range + 1);
- // be lenient if the skill was cast before we have moved to the correct position [Celest]
- if (sd->walktimer != -1)
- range ++;
- else check_range_flag = 1;
- if(!battle_check_range(&sd->bl,&bl,range)) {
- if (check_range_flag && pc_can_move(sd) && battle_check_range(&sd->bl,&bl,range + 1)) {
- int mask[8][2] = {{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1}};
- int dir = map_calc_dir(&sd->bl,bl.x,bl.y);
- pc_walktoxy (sd, sd->bl.x + mask[dir][0], sd->bl.y + mask[dir][1]);
- } else
- return 0;
- }
- }
-*/
- pc_stopattack(sd);
-
- casttime = skill_castfix(&sd->bl, skill_num, skill_lv, 0);
- sd->state.skillcastcancel = skill_db[skill_num].castcancel;
-
- if (battle_config.pc_skill_log)
- ShowInfo("PC %d skill use target_pos=(%d,%d) skill=%d lv=%d cast=%d\n",
- sd->bl.id, skill_x, skill_y, skill_num, skill_lv, casttime);
-
- //ƒ?ƒ‚ƒ‰ƒCƒY?‘Ô‚È‚çƒLƒƒƒXƒgƒ^ƒCƒ€‚ª1/3
- if (sc && sc->data[SC_MEMORIZE].timer != -1 && casttime > 0){
- casttime = casttime/3;
- if ((--sc->data[SC_MEMORIZE].val2)<=0)
- status_change_end(&sd->bl, SC_MEMORIZE, -1);
- }
-
- if( casttime>0 ) { /* ‰r?¥‚ª•K—v */
- if(sd->disguise) { // [Valaris]
- clif_skillcasting(&sd->bl,sd->bl.id, 0, skill_x,skill_y, skill_num,0);
- clif_skillcasting(&sd->bl,-sd->bl.id, 0, skill_x,skill_y, skill_num,casttime);
- }
- else
- clif_skillcasting(&sd->bl,sd->bl.id, 0, skill_x,skill_y, skill_num,casttime);
- }
-
- if (!(battle_config.pc_cloak_check_type&2) &&
- sc && sc->data[SC_CLOAKING].timer != -1)
- status_change_end(&sd->bl,SC_CLOAKING,-1);
-
- sd->skilltarget = 0;
- sd->canact_tick = tick + casttime + 100;
-
- if (casttime > 0) {
- sd->skilltimer = add_timer(tick + casttime, skill_castend_pos, sd->bl.id, 0);
- if ((skill = pc_checkskill(sd,SA_FREECAST))>0)
- status_quick_recalc_speed (sd, SA_FREECAST, skill, 1);
- else
- pc_stop_walking(sd,0);
- } else {
- sd->state.skillcastcancel = 0; /* ‰r?¥‚Ì–³‚¢‚à‚̂̓Lƒƒƒ“ƒZƒ‹‚³‚ê‚È‚¢ */
- sd->skilltimer = -1;
- skill_castend_pos(sd->skilltimer,tick,sd->bl.id,0);
- }
-
- return 0;
-}
-
-/*==========================================
- * ƒXƒLƒ‹‰r?¥ƒLƒƒƒ“ƒZƒ‹
- *------------------------------------------
- */
-int skill_castcancel (struct block_list *bl, int type)
-{
- int ret = 0;
-
- nullpo_retr(0, bl);
-
- if (bl->type == BL_PC) {
- struct map_session_data *sd = (struct map_session_data *)bl;
- unsigned long tick = gettick();
- nullpo_retr(0, sd);
- if (sd->skilltimer != -1) {
- if ((ret = pc_checkskill(sd,SA_FREECAST)) > 0) {
- status_quick_recalc_speed(sd, SA_FREECAST, ret, 0); //Updated to use calc_speed [Skotlex]
- }
- sd->canact_tick = tick;
- if (!type) {
- if (skill_get_inf( sd->skillid ) & INF_GROUND_SKILL)
- ret = delete_timer( sd->skilltimer, skill_castend_pos );
- else
- ret = delete_timer( sd->skilltimer, skill_castend_id );
- if (ret < 0)
- ShowError("delete timer error : skillid : %d\n", sd->skillid);
- } else {
- if (skill_get_inf( sd->skillid_old ) & INF_GROUND_SKILL)
- ret = delete_timer( sd->skilltimer, skill_castend_pos );
- else
- ret = delete_timer( sd->skilltimer, skill_castend_id );
- if (ret < 0)
- ShowError("delete timer error : (old) skillid : %d\n", sd->skillid_old);
- }
- sd->skillid = sd->skilllv = -1;
- sd->skilltimer = -1;
- clif_skillcastcancel(bl);
- }
- return 0;
- } else if (bl->type == BL_MOB) {
- struct mob_data *md = (struct mob_data *)bl;
- nullpo_retr(0, md);
- if (md->skilltimer != -1) {
- if (skill_get_inf( md->skillid ) & INF_GROUND_SKILL)
- ret = delete_timer( md->skilltimer, mobskill_castend_pos );
- else
- ret = delete_timer( md->skilltimer, mobskill_castend_id );
- md->skillid = md->skilllv = -1;
- md->skilltimer = -1;
- clif_skillcastcancel(bl);
- }
- if (ret < 0)
- ShowError("delete timer error : skillid : %d\n", md->skillid);
- return 0;
- } if (bl->type == BL_PET) {
- ((struct pet_data*)bl)->state.casting_flag = 0;
- clif_skillcastcancel(bl);
- //The timer is not deleted as the pet's attack will be resumed.
- return 0;
- }
-
- return 1;
-}
-
/*=========================================
* ƒuƒ‰ƒ“ƒfƒBƒbƒVƒ…ƒXƒsƒA ?‰Šú”Í?Œˆ’è
*----------------------------------------
@@ -9128,7 +8511,7 @@ void skill_repairweapon(struct map_session_data *sd, int idx)
else
material = materials [2]; // Armors consume 1 Steel
if (pc_search_inventory(sd,material) < 0 ) {
- clif_skill_fail(sd,sd->skillid,0,0);
+ clif_skill_fail(sd,sd->menuskill_id,0,0);
return;
}
item->attribute=0;
@@ -9499,29 +8882,23 @@ int skill_attack_area(struct block_list *bl,va_list ap)
*/
int skill_clear_element_field(struct block_list *bl)
{
- struct skill_unit_group *ug=NULL;
- int i,max,skillid;
+ struct unit_data *ud = unit_bl2ud(bl);
+ int i;
nullpo_retr(0, bl);
-
- if (bl->type==BL_MOB) {
- max = MAX_MOBSKILLUNITGROUP;
- ug = ((struct mob_data *)bl)->skillunit;
- } else if(bl->type==BL_PC) {
- max = MAX_SKILLUNITGROUP;
- ug = ((struct map_session_data *)bl)->skillunit;
- } else if(bl->type==BL_PET) {
- max = MAX_MOBSKILLUNITGROUP;
- ug = ((struct pet_data*)bl)->skillunit;
- } else
- return 0;
-
- for (i=0;i<max;i++) {
- skillid=ug[i].skill_id;
- if(skillid==SA_DELUGE||skillid==SA_VOLCANO||skillid==SA_VIOLENTGALE||skillid==SA_LANDPROTECTOR||skillid==NJ_SUITON)
- skill_delunitgroup(&ug[i]);
+ if (!ud) return 0;
+
+ for (i=0;i<MAX_SKILLUNITGROUP;i++) {
+ switch (ud->skillunit[i].skill_id) {
+ case SA_DELUGE:
+ case SA_VOLCANO:
+ case SA_VIOLENTGALE:
+ case SA_LANDPROTECTOR:
+ case NJ_SUITON:
+ skill_delunitgroup(&ud->skillunit[i]);
+ }
}
- return 0;
+ return 1;
}
/*==========================================
@@ -9530,30 +8907,19 @@ int skill_clear_element_field(struct block_list *bl)
*/
struct skill_unit_group *skill_locate_element_field(struct block_list *bl)
{
- struct mob_data *md=NULL;
- struct map_session_data *sd=NULL;
- int i,max,skillid;
-
+ struct unit_data *ud = unit_bl2ud(bl);
+ int i;
nullpo_retr(0, bl);
+ if (!ud) return NULL;
- if (bl->type==BL_MOB) {
- max = MAX_MOBSKILLUNITGROUP;
- md = (struct mob_data *)bl;
- } else if(bl->type==BL_PC) {
- max = MAX_SKILLUNITGROUP;
- sd = (struct map_session_data *)bl;
- } else
- return NULL;
-
- for (i=0;i<max;i++) {
- if(sd){
- skillid=sd->skillunit[i].skill_id;
- if(skillid==SA_DELUGE||skillid==SA_VOLCANO||skillid==SA_VIOLENTGALE||skillid==SA_LANDPROTECTOR||skillid==NJ_SUITON)
- return &sd->skillunit[i];
- }else if(md){
- skillid=md->skillunit[i].skill_id;
- if(skillid==SA_DELUGE||skillid==SA_VOLCANO||skillid==SA_VIOLENTGALE||skillid==SA_LANDPROTECTOR||skillid==NJ_SUITON)
- return &md->skillunit[i];
+ for (i=0;i<MAX_SKILLUNITGROUP;i++) {
+ switch (ud->skillunit[i].skill_id) {
+ case SA_DELUGE:
+ case SA_VOLCANO:
+ case SA_VIOLENTGALE:
+ case SA_LANDPROTECTOR:
+ case NJ_SUITON:
+ return &ud->skillunit[i];
}
}
return NULL;
@@ -9955,41 +9321,32 @@ static int skill_unit_group_newid = MAX_SKILL_DB;
struct skill_unit_group *skill_initunitgroup(struct block_list *src,
int count,int skillid,int skilllv,int unit_id, int limit, int interval)
{
+ struct unit_data *ud = unit_bl2ud(src);
+ struct skill_unit_group *group=NULL;
int i;
- struct skill_unit_group *group=NULL, *list=NULL;
- int maxsug=0;
if(skilllv <= 0) return 0;
nullpo_retr(NULL, src);
-
- if(src->type==BL_PC){
- list=((struct map_session_data *)src)->skillunit;
- maxsug=MAX_SKILLUNITGROUP;
- }else if(src->type==BL_MOB){
- list=((struct mob_data *)src)->skillunit;
- maxsug=MAX_MOBSKILLUNITGROUP;
- }else if(src->type==BL_PET){
- list=((struct pet_data *)src)->skillunit;
- maxsug=MAX_MOBSKILLUNITGROUP;
- }
- if(list){
- for(i=0;i<maxsug;i++) /* ‹ó‚¢‚Ä‚¢‚é‚à‚Ì??õ */
- if(list[i].group_id==0){
- group=&list[i];
+ nullpo_retr(NULL, ud);
+
+ if(ud->skillunit){
+ for(i=0;i<MAX_SKILLUNITGROUP;i++) /* ‹ó‚¢‚Ä‚¢‚é‚à‚Ì??õ */
+ if(ud->skillunit[i].group_id==0){
+ group=&ud->skillunit[i];
break;
}
if(group==NULL){ /* ‹ó‚¢‚Ä‚È‚¢‚̂Ō¢‚à‚Ì??õ */
int j=0;
unsigned maxdiff=0,x,tick=gettick();
- for(i=0;i<maxsug;i++)
- if((x=DIFF_TICK(tick,list[i].tick))>maxdiff){
+ for(i=0;i<MAX_SKILLUNITGROUP;i++)
+ if((x=DIFF_TICK(tick,ud->skillunit[i].tick))>maxdiff){
maxdiff=x;
j=i;
}
- skill_delunitgroup(&list[j]);
- group=&list[j];
+ skill_delunitgroup(&ud->skillunit[j]);
+ group=&ud->skillunit[j];
}
}
@@ -10100,29 +9457,18 @@ int skill_delunitgroup(struct skill_unit_group *group)
*/
int skill_clear_unitgroup(struct block_list *src)
{
- struct skill_unit_group *group=NULL;
- int maxsug=0;
+ struct unit_data *ud = unit_bl2ud(src);
+ int i;
nullpo_retr(0, src);
+ nullpo_retr(0, ud);
- if(src->type==BL_PC){
- group=((struct map_session_data *)src)->skillunit;
- maxsug=MAX_SKILLUNITGROUP;
- } else if(src->type==BL_MOB){
- group=((struct mob_data *)src)->skillunit;
- maxsug=MAX_MOBSKILLUNITGROUP;
- } else if(src->type==BL_PET){ // [Valaris]
- group=((struct pet_data *)src)->skillunit;
- maxsug=MAX_MOBSKILLUNITGROUP;
- } else
- return 0;
- if(group){
- int i;
- for(i=0;i<maxsug;i++)
- if(group[i].group_id>0 && group[i].src_id == src->id)
- skill_delunitgroup(&group[i]);
- }
- return 0;
+ if(!ud) return 0;
+
+ for(i=0;i<MAX_SKILLUNITGROUP;i++)
+ if(ud->skillunit[i].group_id>0 && ud->skillunit[i].src_id == src->id)
+ skill_delunitgroup(&ud->skillunit[i]);
+ return 1;
}
/*==========================================
@@ -10133,20 +9479,17 @@ struct skill_unit_group_tickset *skill_unitgrouptickset_search(
struct block_list *bl,struct skill_unit_group *group,int tick)
{
int i,j=-1,k,s,id;
+ struct unit_data *ud;
struct skill_unit_group_tickset *set;
nullpo_retr(0, bl);
if (group->interval==-1)
return NULL;
+
+ ud = unit_bl2ud(bl);
+ if (!ud) return NULL;
- if (bl->type == BL_PC)
- set = ((struct map_session_data *)bl)->skillunittick;
- else if (bl->type == BL_MOB)
- set = ((struct mob_data *)bl)->skillunittick;
- else if (bl->type == BL_PET)
- set = ((struct pet_data *)bl)->skillunittick;
- else
- return 0;
+ set = ud->skillunittick;
if (skill_get_unit_flag(group->skill_id)&UF_NOOVERLAP)
id = s = group->skill_id;
@@ -10756,7 +10099,6 @@ int skill_produce_mix( struct map_session_data *sd, int skill_id,
case AM_PHARMACY:
case AM_TWILIGHT1:
case AM_TWILIGHT2:
-
case AM_TWILIGHT3:
flag = battle_config.produce_potion_name_input;
break;
diff --git a/src/map/skill.h b/src/map/skill.h
index bdb545d22..4fb2c9b40 100644
--- a/src/map/skill.h
+++ b/src/map/skill.h
@@ -155,6 +155,7 @@ int skill_get_castdef( int id );
int skill_get_weapontype( int id );
int skill_get_unit_id(int id,int flag);
int skill_get_inf2( int id );
+int skill_get_castcancel( int id );
int skill_get_maxcount( int id );
int skill_get_blewcount( int id ,int lv );
int skill_get_unit_flag( int id );
@@ -162,12 +163,8 @@ int skill_get_unit_target( int id );
int skill_tree_get_max( int id, int b_class ); // Celest
const char* skill_get_name( int id ); // [Skotlex]
-// ƒXƒLƒ‹‚ÌŽg—p
-int skill_use_id( struct map_session_data *sd, int target_id,
- int skill_num,int skill_lv);
-int skill_use_pos( struct map_session_data *sd,
- int skill_x, int skill_y, int skill_num, int skill_lv);
-
+int skill_castend_id( int tid, unsigned int tick, int id,int data );
+int skill_castend_pos( int tid, unsigned int tick, int id,int data );
int skill_castend_map( struct map_session_data *sd,int skill_num, const char *map);
int skill_cleartimerskill(struct block_list *src);
@@ -193,6 +190,8 @@ int skill_unit_ondamaged(struct skill_unit *src,struct block_list *bl,
int skill_castfix( struct block_list *bl, int skill_id, int skill_lv, int time);
int skill_delayfix( struct block_list *bl, int skill_id, int skill_lv, int time);
+int skill_check_condition( struct map_session_data *sd,int skill, int lv, int type);
+int skill_check_pc_partner(struct map_session_data *sd, int skill_id, int* skill_lv, int range, int cast_flag);
int skill_check_unit_range(int m,int x,int y,int skillid, int skilllv);
int skill_check_unit_range2(struct block_list *bl,int m,int x,int y,int skillid, int skilllv);
// -- moonsoul (added skill_check_unit_cell)
diff --git a/src/map/status.c b/src/map/status.c
index 32fd92d98..ba769b15c 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -20,11 +20,12 @@
#include "battle.h"
#include "chrif.h"
#include "status.h"
-
-#include "timer.h"
-#include "nullpo.h"
#include "script.h"
-#include "showmsg.h"
+#include "unit.h"
+
+#include "../common/timer.h"
+#include "../common/nullpo.h"
+#include "../common/showmsg.h"
int SkillStatusChangeTable[MAX_SKILL]; //Stores the status that should be associated to this skill.
int StatusIconChangeTable[SC_MAX]; //Stores the icon that should be associated to this status change.
@@ -408,6 +409,12 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, int
)
return 0;
+ if (sc->data[SC_WINKCHARM].timer != -1 && target && target->type == BL_PC && !flag)
+ { //Prevents skill usage against players?
+ clif_emotion(src, 3);
+ return 0;
+ }
+
if (sc->data[SC_BLADESTOP].timer != -1) {
switch (sc->data[SC_BLADESTOP].val1)
{
@@ -1319,7 +1326,7 @@ int status_calc_pc(struct map_session_data* sd,int first)
sd->speed += sd->speed * (100-16*skill)/100;
if(pc_iscarton(sd) && (skill=pc_checkskill(sd,MC_PUSHCART))>0)
sd->speed += sd->speed * (100-10*skill)/100;
- if(sd->skilltimer != -1 && (skill=pc_checkskill(sd,SA_FREECAST))>0) {
+ if(sd->ud.skilltimer != -1 && (skill=pc_checkskill(sd,SA_FREECAST))>0) {
sd->prev_speed = sd->speed; //Store previous speed to correctly restore it. [Skotlex]
sd->speed += sd->speed * (75-5*skill)/100;
}
@@ -2354,22 +2361,6 @@ int status_get_class(struct block_list *bl)
return 0;
}
/*==========================================
- * ‘ÎÛ‚Ì•ûŒü‚ð•Ô‚·(”Ä—p)
- * –ß‚è‚Í®”‚Å0ˆÈã
- *------------------------------------------
- */
-int status_get_dir(struct block_list *bl)
-{
- nullpo_retr(0, bl);
- if(bl->type==BL_MOB)
- return ((struct mob_data *)bl)->dir;
- if(bl->type==BL_PC)
- return ((struct map_session_data *)bl)->dir;
- if(bl->type==BL_PET)
- return ((struct pet_data *)bl)->dir;
- return 0;
-}
-/*==========================================
* ‘Îۂ̃Œƒxƒ‹‚ð•Ô‚·(”Ä—p)
* –ß‚è‚Í®”‚Å0ˆÈã
*------------------------------------------
@@ -2878,22 +2869,26 @@ int status_get_matk2(struct block_list *bl)
*/
int status_get_def(struct block_list *bl)
{
+ struct unit_data *ud;
int def=0;
nullpo_retr(0, bl);
if(bl->type==BL_PC){
def = ((struct map_session_data *)bl)->def;
- if(((struct map_session_data *)bl)->skilltimer != -1)
- def -= def * skill_get_castdef(((struct map_session_data *)bl)->skillid)/100;
} else if(bl->type==BL_MOB) {
def = ((struct mob_data *)bl)->db->def;
- def -= def * skill_get_castdef(((struct mob_data *)bl)->skillid)/100;
} else if(bl->type==BL_PET)
def = ((struct pet_data *)bl)->db->def;
- def = status_calc_def(bl,def);
+
+ if (bl->type != BL_PC) //Players already had this one done.
+ def = status_calc_def(bl,def);
+
+ ud = unit_bl2ud(bl);
+ if (ud && ud->skilltimer != -1)
+ def -= def * skill_get_castdef(ud->skillid)/100;
+
if(def < 0) def = 0;
-
return def;
}
/*==========================================
@@ -3281,7 +3276,7 @@ int status_isdead(struct block_list *bl)
{
nullpo_retr(0, bl);
if(bl->type == BL_MOB)
- return ((struct mob_data *)bl)->state.state == MS_DEAD;
+ return ((struct mob_data *)bl)->hp <= 0;
if(bl->type==BL_PC)
return pc_isdead((struct map_session_data *)bl);
return 0;
@@ -3977,7 +3972,7 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val
case SC_WEDDING: //Œ‹¥—p(Œ‹¥ˆßÖ‚É‚È‚Á‚Ä?‚­‚Ì‚ª?‚¢‚Æ‚©)
if (sd)
{ //Change look.
- pc_stopattack(sd);
+ pc_stop_attack(sd);
if(type==SC_WEDDING)
sd->view_class = JOB_WEDDING;
else if(type==SC_XMAS)
@@ -4215,12 +4210,14 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val
break;
case SC_GRAVITATION:
- if (sd) {
- if (val3 == BCT_SELF) {
- sd->canmove_tick += tick;
- sd->canact_tick += tick;
- } else calc_flag = 1;
- }
+ if (val3 == BCT_SELF) {
+ struct unit_data *ud = unit_bl2ud(bl);
+ if (ud) {
+ ud->canmove_tick += tick;
+ ud->canact_tick += tick;
+ }
+ } else
+ calc_flag = 1;
break;
case SC_HERMODE:
@@ -4301,24 +4298,27 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val
}
break;
case SC_COMBO:
+ {
+ struct unit_data *ud = unit_bl2ud(bl);
switch (val1) { //Val1 contains the skill id
case TK_STORMKICK:
clif_skill_nodamage(bl,bl,TK_READYSTORM,1,1);
- if (sd) sd->attackabletime = gettick()+tick;
+ if (ud) ud->attackabletime = gettick()+tick;
break;
case TK_DOWNKICK:
clif_skill_nodamage(bl,bl,TK_READYDOWN,1,1);
- if (sd) sd->attackabletime = gettick()+tick;
+ if (ud) ud->attackabletime = gettick()+tick;
break;
case TK_TURNKICK:
clif_skill_nodamage(bl,bl,TK_READYTURN,1,1);
- if (sd) sd->attackabletime = gettick()+tick;
+ if (ud) ud->attackabletime = gettick()+tick;
break;
case TK_COUNTER:
clif_skill_nodamage(bl,bl,TK_READYCOUNTER,1,1);
- if (sd) sd->attackabletime = gettick()+tick;
+ if (ud) ud->attackabletime = gettick()+tick;
break;
}
+ }
break;
case SC_TKDORI:
val2 = 11-val1; //Chance to consume: 11-skilllv%
@@ -4489,11 +4489,11 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val
if (sd && pc_issit(sd)) //Avoid sprite sync problems.
pc_setstand(sd);
case SC_TRICKDEAD:
- battle_stopattack(bl);
+ unit_stop_attack(bl);
skill_stop_dancing(bl); /* ‰‰‘t/ƒ_ƒ“ƒX‚Ì’†? */
// Cancel cast when get status [LuzZza]
if (battle_config.sc_castcancel)
- skill_castcancel(bl, 0);
+ unit_skillcastcancel(bl, 0);
case SC_STOP:
case SC_CONFUSION:
case SC_CLOSECONFINE:
@@ -4501,12 +4501,12 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val
case SC_ANKLE:
case SC_SPIDERWEB:
case SC_MADNESSCANCEL:
- battle_stopwalking(bl,1);
+ unit_stop_walking(bl,1);
break;
case SC_HIDING:
case SC_CLOAKING:
case SC_CHASEWALK:
- battle_stopattack(bl); /* U?’âŽ~ */
+ unit_stop_attack(bl); /* U?’âŽ~ */
break;
}
@@ -4666,9 +4666,9 @@ int status_change_clear(struct block_list *bl,int type)
struct status_change* sc;
int i;
- nullpo_retr(0, sc = status_get_sc(bl));
+ sc = status_get_sc(bl);
- if (sc->count == 0)
+ if (!sc || sc->count == 0)
return 0;
for(i = 0; i < SC_MAX; i++)
{
@@ -4696,7 +4696,7 @@ int status_change_clear(struct block_list *bl,int type)
if(!type || type&2)
clif_changeoption(bl);
- return 0;
+ return 1;
}
/*==========================================
@@ -4849,8 +4849,7 @@ int status_change_end( struct block_list* bl , int type,int tid )
}
break;
case SC_RUN://‹ì‚¯‘«
- if (sd && sd->walktimer != -1)
- pc_stop_walking(sd,1);
+ unit_stop_walking(bl,1);
if (sc->data[type].val1 >= 7 &&
DIFF_TICK(gettick(), sc->data[type].val4) <= 1000 &&
(!sd || (sd->weapontype1 == 0 && sd->weapontype2 == 0))
@@ -5006,14 +5005,12 @@ int status_change_end( struct block_list* bl , int type,int tid )
break;
case SC_GRAVITATION:
- if (sd) {
- if (sc->data[type].val3 == BCT_SELF) {
- unsigned int tick = gettick();
- sd->canmove_tick = tick;
- sd->canact_tick = tick;
- } else calc_flag = 1;
- }
- break;
+ if (sc->data[type].val3 == BCT_SELF) {
+ struct unit_data *ud = unit_bl2ud(bl);
+ if (ud)
+ ud->canmove_tick = ud->canact_tick = gettick();
+ } else
+ calc_flag = 1;
case SC_GOSPEL: //Clear the buffs from other chars.
if(sc->data[type].val4 != BCT_SELF)
@@ -5306,7 +5303,7 @@ int status_change_timer(int tid, unsigned int tick, int id, int data)
if(sc->data[type].val2 != 0) {
sc->data[type].val2 = 0;
sc->data[type].val4 = 0;
- battle_stopwalking(bl,1);
+ unit_stop_walking(bl,1);
sc->opt1 = OPT1_STONE;
clif_changeoption(bl);
sc->data[type].timer=add_timer(1000+tick,status_change_timer, bl->id, data );
@@ -5317,14 +5314,7 @@ int status_change_timer(int tid, unsigned int tick, int id, int data)
if((++sc->data[type].val4)%5 == 0 && status_get_hp(bl) > hp>>2) {
hp = hp/100;
if(hp < 1) hp = 1;
- if(sd)
- pc_heal(sd,-hp,0);
- else if(bl->type == BL_MOB){
- struct mob_data *md;
- if((md=((struct mob_data *)bl)) == NULL)
- break;
- md->hp -= hp;
- }
+ battle_heal(NULL, bl, -hp, 0, 0);
}
sc->data[type].timer=add_timer(1000+tick,status_change_timer, bl->id, data );
return 0;
@@ -5335,16 +5325,8 @@ int status_change_timer(int tid, unsigned int tick, int id, int data)
if (status_get_hp(bl) <= status_get_max_hp(bl)>>2) //Stop damaging after 25% HP left.
break;
case SC_DPOISON:
- if ((--sc->data[type].val3) > 0 && sc->data[SC_SLOWPOISON].timer == -1) {
- if(sd) {
- pc_heal(sd, -sc->data[type].val4, 0);
- } else if (bl->type == BL_MOB) {
- ((struct mob_data*)bl)->hp -= sc->data[type].val4;
- if (battle_config.show_mob_hp)
- clif_charnameack (0, bl);
- } else
- battle_heal(NULL, bl, -sc->data[type].val4, 0, 1);
- }
+ if ((--sc->data[type].val3) > 0 && sc->data[SC_SLOWPOISON].timer == -1)
+ battle_heal(NULL, bl, -sc->data[type].val4, 0, 1);
if (sc->data[type].val3 > 0 && !status_isdead(bl))
{
sc->data[type].timer = add_timer (1000 + tick, status_change_timer, bl->id, data );
@@ -5375,16 +5357,11 @@ int status_change_timer(int tid, unsigned int tick, int id, int data)
// To-do: bleeding effect increases damage taken?
if ((sc->data[type].val4 -= 10000) >= 0) {
int hp = rand()%600 + 200;
- if(sd) {
- pc_heal(sd,-hp,0);
- } else if(bl->type == BL_MOB) {
- struct mob_data *md = (struct mob_data *)bl;
- if (md) md->hp -= hp;
- }
+ battle_heal(NULL,bl,-hp,0,1);
if (!status_isdead(bl)) {
// walking and casting effect is lost
- battle_stopwalking (bl, 1);
- skill_castcancel (bl, 0);
+ unit_stop_walking (bl, 1);
+ unit_skillcastcancel (bl, 2);
sc->data[type].timer = add_timer(10000 + tick, status_change_timer, bl->id, data );
}
return 0;
diff --git a/src/map/status.h b/src/map/status.h
index ccaf54209..58a142a2a 100644
--- a/src/map/status.h
+++ b/src/map/status.h
@@ -442,7 +442,6 @@ enum {
// ƒpƒ‰ƒ[ƒ^Š“¾Œn battle.c ‚æ‚èˆÚ“®
int status_get_class(struct block_list *bl);
-int status_get_dir(struct block_list *bl);
int status_get_lv(struct block_list *bl);
int status_get_range(struct block_list *bl);
int status_get_hp(struct block_list *bl);
diff --git a/src/map/unit.c b/src/map/unit.c
new file mode 100644
index 000000000..a866cdf9e
--- /dev/null
+++ b/src/map/unit.c
@@ -0,0 +1,1680 @@
+// Copyright (c) jAthena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+// Merged originally from jA by Skotlex
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../common/showmsg.h"
+#include "../common/timer.h"
+#include "../common/nullpo.h"
+#include "../common/db.h"
+#include "../common/malloc.h"
+#include "unit.h"
+#include "map.h"
+#include "pc.h"
+#include "mob.h"
+#include "pet.h"
+#include "skill.h"
+#include "clif.h"
+#include "npc.h"
+#include "guild.h"
+#include "status.h"
+#include "battle.h"
+#include "chat.h"
+#include "trade.h"
+#include "vending.h"
+#include "party.h"
+#include "intif.h"
+#include "chrif.h"
+
+static int dirx[8]={0,-1,-1,-1,0,1,1,1};
+static int diry[8]={1,1,0,-1,-1,-1,0,1};
+
+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;
+ if( bl->type == BL_PET) return &((struct pet_data*)bl)->ud;
+ if( bl->type == BL_NPC) return &((struct npc_data*)bl)->ud;
+ return NULL;
+}
+
+static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data);
+
+int unit_walktoxy_sub(struct block_list *bl)
+{
+ int i;
+ struct walkpath_data wpd;
+ struct unit_data *ud = NULL;
+
+ nullpo_retr(1, bl);
+ ud = unit_bl2ud(bl);
+ if(ud == NULL) return 0;
+
+ if(path_search(&wpd,bl->m,bl->x,bl->y,ud->to_x,ud->to_y,ud->state.walk_easy))
+ return 0;
+
+ memcpy(&ud->walkpath,&wpd,sizeof(wpd));
+
+ switch (bl->type) {
+ case BL_PC:
+ clif_walkok((TBL_PC*)bl);
+ clif_movechar((TBL_PC*)bl);
+ break;
+ case BL_MOB:
+ clif_movemob((TBL_MOB*)bl);
+ break;
+ case BL_PET:
+ clif_movepet((TBL_PET*)bl);
+ break;
+ case BL_NPC:
+ clif_movenpc((TBL_NPC*)bl);
+ break;
+ }
+
+ ud->state.change_walk_target=0;
+
+ if(ud->walkpath.path_pos>=ud->walkpath.path_len)
+ i = -1;
+ else if(ud->walkpath.path[ud->walkpath.path_pos]&1)
+ i = status_get_speed(bl)*14/10;
+ else
+ i = status_get_speed(bl);
+ if( i > 0) {
+ i = i>>1;
+ ud->walktimer = add_timer(gettick()+i,unit_walktoxy_timer,bl->id,0);
+ }
+ return 1;
+}
+
+static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data)
+{
+ int i;
+ int x,y,dx,dy,dir;
+ struct block_list *bl;
+ struct map_session_data *sd = NULL;
+ struct mob_data *md = NULL;
+ struct unit_data *ud = NULL;
+
+ bl=map_id2bl(id);
+ if(bl == NULL)
+ return 0;
+ if( BL_CAST( BL_PC, bl, sd ) ) {
+ ud = &sd->ud;
+ } else if( BL_CAST( BL_MOB, bl, md ) ) {
+ ud = &md->ud;
+ } else
+ ud = unit_bl2ud(bl);
+
+ if(ud == NULL) return 0;
+
+ if(ud->walktimer != tid){
+ if(battle_config.error_log)
+ ShowError("unit_walk_timer mismatch %d != %d\n",ud->walktimer,tid);
+ return 0;
+ }
+ ud->walktimer=-1;
+ if( bl->prev == NULL ) return 0; // block_list ‚©‚甲‚¯‚Ä‚¢‚é‚̂ňړ®’âŽ~‚·‚é
+
+ if(ud->walkpath.path_pos>=ud->walkpath.path_len || ud->walkpath.path_pos!=data)
+ return 0;
+
+ //•à‚¢‚½‚Ì‚Å‘§‚̃^ƒCƒ}[‚ð‰Šú‰»
+ if(sd) {
+ sd->inchealspirithptick = 0;
+ sd->inchealspiritsptick = 0;
+ }
+ ud->walkpath.path_half ^= 1;
+ if(ud->walkpath.path_half==0){ // ƒ}ƒX–Ú’†S‚Ö“ž’…
+ ud->walkpath.path_pos++;
+ if(ud->state.change_walk_target) {
+ unit_walktoxy_sub(bl);
+ return 0;
+ }
+ } else { // ƒ}ƒX–Ú‹«ŠE‚Ö“ž’…
+ if(ud->walkpath.path[ud->walkpath.path_pos]>=8)
+ return 1;
+ x = bl->x;
+ y = bl->y;
+
+ dir = ud->walkpath.path[ud->walkpath.path_pos];
+ ud->dir = dir;
+ if (sd)
+ sd->head_dir = dir;
+
+ dx = dirx[(int)dir];
+ dy = diry[(int)dir];
+
+ if(map_getcell(bl->m,x+dx,y+dy,CELL_CHKNOPASS))
+ return unit_walktoxy_sub(bl);
+
+ // ƒoƒVƒŠƒJ”»’è
+
+ ud->walktimer = 1;
+ switch (bl->type) {
+ case BL_PC:
+ map_foreachinmovearea(clif_pcoutsight,bl->m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_ALL,sd);
+ break;
+ case BL_MOB:
+ map_foreachinmovearea(clif_moboutsight,bl->m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_PC,md);
+ break;
+ case BL_PET:
+ map_foreachinmovearea(clif_petoutsight,bl->m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_PC,(TBL_PET*)bl);
+ break;
+ case BL_NPC:
+ map_foreachinmovearea(clif_npcoutsight,bl->m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,dx,dy,BL_PC,(TBL_NPC*)bl);
+ break;
+ }
+ ud->walktimer = -1;
+
+ if(md && md->min_chase > md->db->range2)
+ md->min_chase--;
+
+ x += dx;
+ y += dy;
+ map_moveblock(bl, x, y, tick);
+
+ ud->walktimer = 1;
+ switch (bl->type) {
+ case BL_PC:
+ map_foreachinmovearea(clif_pcinsight,bl->m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,-dx,-dy,BL_ALL,sd);
+ break;
+ case BL_MOB:
+ map_foreachinmovearea(clif_mobinsight,bl->m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,-dx,-dy,BL_PC,md);
+ break;
+ case BL_PET:
+ map_foreachinmovearea(clif_petinsight,bl->m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,-dx,-dy,BL_PC,(TBL_PET*)bl);
+ break;
+ case BL_NPC:
+ map_foreachinmovearea(clif_npcinsight,bl->m,x-AREA_SIZE,y-AREA_SIZE,x+AREA_SIZE,y+AREA_SIZE,-dx,-dy,BL_PC,(TBL_NPC*)bl);
+ break;
+ }
+ ud->walktimer = -1;
+
+ if(sd) {
+ if(map_getcell(bl->m,x,y,CELL_CHKNPC))
+ npc_touch_areanpc(sd,bl->m,x,y);
+ else
+ sd->areanpc_id=0;
+ if (sd->state.gmaster_flag)
+ { //Guild Aura: Likely needs to be recoded, this method seems inefficient.
+ struct guild *g = sd->state.gmaster_flag;
+ int skill, guildflag = 0;
+ if ((skill = guild_checkskill(g, GD_LEADERSHIP)) > 0) guildflag |= skill<<12;
+ if ((skill = guild_checkskill(g, GD_GLORYWOUNDS)) > 0) guildflag |= skill<<8;
+ if ((skill = guild_checkskill(g, GD_SOULCOLD)) > 0) guildflag |= skill<<4;
+ if ((skill = guild_checkskill(g, GD_HAWKEYES)) > 0) guildflag |= skill;
+ if (guildflag)
+ map_foreachinrange(skill_guildaura_sub, bl,2, BL_PC,
+ bl->id, sd->status.guild_id, &guildflag);
+ }
+ if (
+ (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR &&
+ sd->sc.data[SC_MIRACLE].timer==-1 &&
+ rand()%100000 < battle_config.sg_miracle_skill_ratio
+ ) { //SG_MIRACLE [Komurka]
+ clif_displaymessage(sd->fd,"[Miracle of the Sun, Moon and Stars]");
+ sc_start(&sd->bl,SC_MIRACLE,100,1,battle_config.sg_miracle_skill_duration);
+ }
+
+ }
+ }
+
+ if(ud->walkpath.path_pos>=ud->walkpath.path_len)
+ i = -1;
+ else if(ud->walkpath.path[ud->walkpath.path_pos]&1)
+ i = status_get_speed(bl)*14/10;
+ else
+ i = status_get_speed(bl);
+
+ if(i > 0) {
+ i = i>>1;
+// if(i < 1 && ud->walkpath.path_half == 0)
+// i = 1;
+ ud->walktimer = add_timer(tick+i,unit_walktoxy_timer,id,ud->walkpath.path_pos);
+ } else if(sd && sd->sc.count && sd->sc.data[SC_RUN].timer!=-1) //Keep trying to run.
+ pc_run(sd, sd->sc.data[SC_RUN].val1, sd->sc.data[SC_RUN].val2);
+ else
+ { //Stopped walking. Update to_x and to_y to current location [Skotlex]
+ ud->to_x = bl->x;
+ ud->to_y = bl->y;
+ if (bl->type == BL_NPC) //Original eA code had this one only for BL_NPCs
+ clif_fixpos(bl);
+ }
+ return 0;
+}
+
+int unit_walktoxy( struct block_list *bl, int x, int y, int easy) {
+ struct unit_data *ud = NULL;
+ struct status_change *sc = NULL;
+
+ nullpo_retr(0, bl);
+
+ ud = unit_bl2ud(bl);
+
+ if( ud == NULL) return 0;
+
+ // ˆÚ“®o—ˆ‚È‚¢ƒ†ƒjƒbƒg‚Í’e‚­
+ if(!unit_can_move(bl) || !(status_get_mode(bl)&MD_CANMOVE) )
+ return 0;
+
+ ud->state.walk_easy = easy;
+ ud->to_x = x;
+ ud->to_y = y;
+
+ sc = status_get_sc(bl);
+ if (sc && sc->count && sc->data[SC_CONFUSION].timer != -1) //Randomize the target position
+ map_random_dir(bl, &ud->to_x, &ud->to_y);
+
+ if(ud->walktimer != -1) {
+ // Œ»Ý•à‚¢‚Ä‚¢‚éÅ’†‚Ì–Ú“I’n•ÏX‚Ȃ̂Ń}ƒX–Ú‚Ì’†S‚É—ˆ‚½Žž‚É
+ // timerŠÖ”‚©‚çunit_walktoxy_sub‚ðŒÄ‚Ԃ悤‚É‚·‚é
+ ud->state.change_walk_target = 1;
+ return 1;
+ } else {
+ return unit_walktoxy_sub(bl);
+ }
+}
+
+//Instant warp function.
+int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath)
+{
+ int dx,dy,dir;
+ struct unit_data *ud = NULL;
+ struct map_session_data *sd = NULL;
+ struct mob_data *md = NULL;
+ struct walkpath_data wpd;
+
+ nullpo_retr(0, bl);
+ if( BL_CAST( BL_PC, bl, sd ) ) {
+ ud = &sd->ud;
+ } else if( BL_CAST( BL_MOB, bl, md ) ) {
+ ud = &md->ud;
+ } else
+ ud = unit_bl2ud(bl);
+
+ if( ud == NULL) return 0;
+
+ unit_stop_walking(bl,1);
+ unit_stop_attack(bl);
+
+ if(checkpath && (map_getcell(bl->m,bl->x,bl->y, CELL_CHKNOPASS) || path_search_real(&wpd,bl->m,bl->x,bl->y,dst_x,dst_y,easy, CELL_CHKNOREACH)))
+ return 0;
+
+ dir = map_calc_dir(bl, dst_x,dst_y);
+ ud->dir = dir;
+ if(sd) sd->head_dir = dir;
+
+ dx = dst_x - bl->x;
+ dy = dst_y - bl->y;
+
+ switch (bl->type) {
+ case BL_PC:
+ map_foreachinmovearea(clif_pcoutsight,bl->m,bl->x-AREA_SIZE,bl->y-AREA_SIZE,bl->x+AREA_SIZE,bl->y+AREA_SIZE,dx,dy,BL_ALL,sd);
+ break;
+ case BL_MOB:
+ map_foreachinmovearea(clif_moboutsight,bl->m,bl->x-AREA_SIZE,bl->y-AREA_SIZE,bl->x+AREA_SIZE,bl->y+AREA_SIZE,dx,dy,BL_PC,md);
+ break;
+ case BL_PET:
+ map_foreachinmovearea(clif_petoutsight,bl->m,bl->x-AREA_SIZE,bl->y-AREA_SIZE,bl->x+AREA_SIZE,bl->y+AREA_SIZE,dx,dy,BL_PC,(TBL_PET*)bl);
+ break;
+ case BL_NPC:
+ map_foreachinmovearea(clif_petoutsight,bl->m,bl->x-AREA_SIZE,bl->y-AREA_SIZE,bl->x+AREA_SIZE,bl->y+AREA_SIZE,dx,dy,BL_PC,(TBL_NPC*)bl);
+ break;
+ }
+
+ map_moveblock(bl, dst_x, dst_y, gettick());
+ ud->walktimer = 1;
+ switch (bl->type) {
+ case BL_PC:
+ map_foreachinmovearea(clif_pcinsight,bl->m,bl->x-AREA_SIZE,bl->y-AREA_SIZE,bl->x+AREA_SIZE,bl->y+AREA_SIZE,-dx,-dy,BL_ALL,sd);
+ break;
+ case BL_MOB:
+ map_foreachinmovearea(clif_mobinsight,bl->m,bl->x-AREA_SIZE,bl->y-AREA_SIZE,bl->x+AREA_SIZE,bl->y+AREA_SIZE,-dx,-dy,BL_PC,md);
+ break;
+ case BL_PET:
+ map_foreachinmovearea(clif_petinsight,bl->m,bl->x-AREA_SIZE,bl->y-AREA_SIZE,bl->x+AREA_SIZE,bl->y+AREA_SIZE,-dx,-dy,BL_PC,(TBL_PET*)bl);
+ break;
+ case BL_NPC:
+ map_foreachinmovearea(clif_npcinsight,bl->m,bl->x-AREA_SIZE,bl->y-AREA_SIZE,bl->x+AREA_SIZE,bl->y+AREA_SIZE,-dx,-dy,BL_PC,(TBL_NPC*)bl);
+ break;
+ }
+ ud->walktimer = -1;
+
+ if(sd) {
+ 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;
+ if(sd->status.pet_id > 0 && sd->pd && sd->pet.intimate > 0)
+ { //Check if pet needs to be teleported. [Skotlex]
+ int flag = 0;
+ bl = &sd->pd->bl; //Note that bl now points to the pet!
+ if (!checkpath && path_search(&wpd,bl->m,bl->x,bl->y,dst_x,dst_y,0))
+ flag = 1;
+ else if (!check_distance_bl(&sd->bl, bl, AREA_SIZE)) //Too far, teleport.
+ flag = 2;
+ if (flag) {
+ unit_movepos(bl,sd->bl.x,sd->bl.y, 0, 0);
+ clif_slide(bl,bl->x,bl->y);
+ }
+ //If you want to use bl afterwards, uncomment this:
+ //bl = &sd->bl;
+ }
+ }
+ return 1;
+}
+
+int unit_setdir(struct block_list *bl,unsigned short dir)
+{
+ struct unit_data *ud;
+ nullpo_retr( 0, bl );
+ ud = unit_bl2ud(bl);
+ if (!ud) return 0;
+ ud->dir = dir;
+ if (bl->type == BL_PC)
+ ((TBL_PC *)bl)->head_dir = dir;
+ clif_changed_dir(bl);
+ return 0;
+}
+
+int unit_getdir(struct block_list *bl)
+{
+ struct unit_data *ud;
+ nullpo_retr( 0, bl );
+ ud = unit_bl2ud(bl);
+ if (!ud) return 0;
+ return ud->dir;
+}
+
+//Warps a unit/ud to a given map/position.
+//In the case of players, pc_setpos is used.
+//it respects the no warp flags, so it is safe to call this without doing nowarpto/nowarp checks.
+int unit_warp(struct block_list *bl,int m,int x,int y,int type)
+{
+ int i=0,xs=9,ys=9,bx=x,by=y;
+ struct unit_data *ud;
+ nullpo_retr(0, bl);
+ ud = unit_bl2ud(bl);
+
+ if(bl->prev==NULL || !ud)
+ return 1;
+
+ if (type < 0 || type == 1)
+ //Type 1 is invalid, since you shouldn't warp a bl with the "death"
+ //animation, it messes up with unit_remove_map! [Skotlex]
+ return 1;
+
+ if( m<0 ) m=bl->m;
+
+ switch (bl->type) {
+ case BL_MOB:
+ if (map[bl->m].flag.monster_noteleport)
+ return 1;
+ break;
+ case BL_PC:
+ if (map[bl->m].flag.noteleport)
+ return 1;
+ break;
+ }
+
+ if(bx>0 && by>0)
+ xs=ys=9;
+
+ while( ( x<0 || y<0 || map_getcell(m,x,y,CELL_CHKNOPASS)) && (i++)<1000 ){
+ if( xs>0 && ys>0 && i<250 ){
+ x=bx+rand()%xs-xs/2;
+ y=by+rand()%ys-ys/2;
+ }else{
+ x=rand()%(map[m].xs-2)+1;
+ y=rand()%(map[m].ys-2)+1;
+ }
+ }
+
+ if(i>=1000){
+ if(battle_config.error_log)
+ ShowWarning("unit_warp failed. Unit Id:%d/Type:%d, target position map %d (%s) at [%d,%d]\n", bl->id, bl->type, m, map[m].name, bx,by);
+ return 2;
+ }
+
+ if (bl->type == BL_PC) //Use pc_setpos
+ return pc_setpos((TBL_PC*)bl, map[m].index, x, y, type);
+
+ if (!unit_remove_map(bl, type))
+ return 3;
+
+ bl->x=ud->to_x=x;
+ bl->y=ud->to_y=y;
+ bl->m=m;
+
+ map_addblock(bl);
+ switch (bl->type) {
+ case BL_PC:
+ clif_spawnpc((TBL_PC*)bl);
+ break;
+ case BL_MOB:
+ clif_spawnmob((TBL_MOB*)bl);
+ mob_warpslave(bl,AREA_SIZE);
+ break;
+ case BL_PET:
+ clif_spawnpet((TBL_PET*)bl);
+ break;
+ case BL_NPC:
+ clif_spawnnpc((TBL_NPC*)bl);
+ break;
+ }
+ skill_unit_move(bl,gettick(),1);
+ return 0;
+}
+
+/*==========================================
+ * •às’âŽ~
+ *------------------------------------------
+ */
+int unit_stop_walking(struct block_list *bl,int type)
+{
+ struct unit_data *ud;
+ struct status_change *sc;
+ nullpo_retr(0, bl);
+
+ ud = unit_bl2ud(bl);
+ if(!ud || ud->walktimer == -1)
+ return 0;
+
+ sc = status_get_sc(bl);
+ if (sc && sc->count && sc->data[SC_RUN].timer != -1)
+ status_change_end(bl, SC_RUN, -1);
+
+// if(md) { md->state.skillstate = MSS_IDLE; }
+ if(type&0x01) // ˆÊ’u•â³‘—M‚ª•K—v
+ clif_fixpos(bl);
+
+ if(type&0x02 && unit_can_move(bl)) {
+ int dx=ud->to_x-bl->x;
+ int dy=ud->to_y-bl->y;
+ if(dx<0) dx=-1; else if(dx>0) dx=1;
+ if(dy<0) dy=-1; else if(dy>0) dy=1;
+ if(dx || dy) {
+ return unit_walktoxy( bl, bl->x+dx, bl->y+dy, 1);
+ }
+ }
+
+ ud->walkpath.path_len = 0;
+ ud->walkpath.path_pos = 0;
+ ud->to_x = bl->x;
+ ud->to_y = bl->y;
+ delete_timer(ud->walktimer, unit_walktoxy_timer);
+ ud->walktimer = -1;
+ if(bl->type == BL_PET) {
+ if(type&~0xff)
+ ud->canmove_tick = gettick() + (type>>8);
+ }
+ return 1;
+}
+
+int unit_skilluse_id(struct block_list *src, int target_id, int skill_num, int skill_lv) {
+
+ if(skill_num < 0) return 0;
+
+ return unit_skilluse_id2(
+ src, target_id, skill_num, skill_lv,
+ skill_castfix(src, skill_num, skill_lv, skill_get_cast(skill_num, skill_lv)),
+ skill_get_castcancel(skill_num)
+ );
+}
+
+int unit_is_walking(struct block_list *bl)
+{
+ struct unit_data *ud = unit_bl2ud(bl);
+ nullpo_retr(0, bl);
+ if(!ud) return 0;
+ return (ud->walktimer != -1);
+}
+
+/*==========================================
+ * Determines if the bl can move based on status changes. [Skotlex]
+ *------------------------------------------
+ */
+int unit_can_move(struct block_list *bl)
+{
+ struct map_session_data *sd;
+ struct unit_data *ud;
+ struct status_change *sc;
+
+ nullpo_retr(0, bl);
+ ud = unit_bl2ud(bl);
+ sc = status_get_sc(bl);
+ BL_CAST(BL_PC, bl, sd);
+
+ if (!ud)
+ return 0;
+
+ if (ud->skilltimer != -1 && (!sd || pc_checkskill(sd, SA_FREECAST) <= 0))
+ return 0;
+
+ if (DIFF_TICK(ud->canmove_tick, gettick()) > 0)
+ return 0;
+
+ if (sd && (
+ pc_issit(sd) ||
+ sd->state.blockedmove
+ ))
+ return 0; //Can't move
+
+ if (sc) {
+ if (sc->opt1 > 0 && sc->opt1 != OPT1_STONEWAIT)
+ return 0;
+
+ if ((sc->option & OPTION_HIDE) && (!sd || pc_checkskill(sd, RG_TUNNELDRIVE) <= 0))
+ return 0;
+
+ if (sc->count && (
+ sc->data[SC_ANKLE].timer != -1 ||
+ sc->data[SC_AUTOCOUNTER].timer !=-1 ||
+ sc->data[SC_TRICKDEAD].timer !=-1 ||
+ sc->data[SC_BLADESTOP].timer !=-1 ||
+ sc->data[SC_SPIDERWEB].timer !=-1 ||
+ (sc->data[SC_DANCING].timer !=-1 && (
+ (sc->data[SC_DANCING].val4 && sc->data[SC_LONGING].timer == -1) ||
+ sc->data[SC_DANCING].val1 == CG_HERMODE //cannot move while Hermod is active.
+ )) ||
+ (sc->data[SC_GOSPEL].timer !=-1 && sc->data[SC_GOSPEL].val4 == BCT_SELF) || // cannot move while gospel is in effect
+ sc->data[SC_STOP].timer != -1 ||
+ sc->data[SC_CLOSECONFINE].timer != -1 ||
+ sc->data[SC_CLOSECONFINE2].timer != -1
+ ))
+ return 0;
+ }
+ return 1;
+}
+
+
+/*==========================================
+ * Applies walk delay to character, considering that
+ * if type is 0, this is a damage induced delay: if previous delay is active, do not change it.
+ * if type is 1, this is a skill induced delay: walk-delay may only be increased, not decreased.
+ *------------------------------------------
+ */
+int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int type)
+{
+ struct unit_data *ud = unit_bl2ud(bl);
+ if (delay <= 0 || !ud) return 0;
+
+ if (type) {
+ if (DIFF_TICK(ud->canmove_tick, tick+delay) > 0)
+ return 0;
+ } else {
+ if (DIFF_TICK(ud->canmove_tick, tick) > 0)
+ return 0;
+ }
+ ud->canmove_tick = tick + delay;
+ return 1;
+}
+
+static int unit_walkdelay_sub(int tid, unsigned int tick, int id, int data)
+{
+ struct block_list *bl = map_id2bl(id);
+ if (!bl || status_isdead(bl))
+ return 0;
+
+ if (unit_set_walkdelay(bl, tick, data, 0))
+ unit_stop_walking(bl,3);
+ return 0;
+}
+
+/*==========================================
+ * Applies walk delay based on attack type. [Skotlex]
+ *------------------------------------------
+ */
+int unit_walkdelay(struct block_list *bl, unsigned int tick, int adelay, int delay, int div_) {
+
+ if (status_isdead(bl))
+ return 0;
+
+ if (bl->type == BL_PC) {
+ if (battle_config.pc_walk_delay_rate != 100)
+ delay = delay*battle_config.pc_walk_delay_rate/100;
+ } else
+ if (battle_config.walk_delay_rate != 100)
+ delay = delay*battle_config.walk_delay_rate/100;
+
+ if (div_ > 1) //Multi-hit skills mean higher delays.
+ delay += battle_config.multihit_delay*(div_-1);
+
+ if (delay <= 0)
+ return 0;
+
+ if (adelay > 0)
+ add_timer(tick+adelay, unit_walkdelay_sub, bl->id, delay);
+ else
+ unit_set_walkdelay(bl, tick, delay, 0);
+ return 1;
+}
+
+
+int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int skill_lv, int casttime, int castcancel) {
+ struct unit_data *ud;
+ struct status_change *sc;
+ struct map_session_data *sd = NULL;
+ struct block_list * target = NULL;
+ unsigned int tick = gettick();
+ int temp;
+
+ nullpo_retr(0, src);
+ if(status_isdead(src))
+ return 0; // Ž€‚ñ‚Å‚¢‚È‚¢‚©
+
+ if( BL_CAST( BL_PC, src, sd ) ) {
+ ud = &sd->ud;
+ } else
+ ud = unit_bl2ud(src);
+
+ if(ud == NULL) return 0;
+ sc = status_get_sc(src);
+ if (sc && !sc->count)
+ sc = NULL; //Unneeded
+ //temp: used to signal combo-skills right now.
+ temp = (target_id == src->id
+ && skill_get_inf(skill_num)&INF_SELF_SKILL
+ && skill_get_inf2(skill_num)&INF2_NO_TARGET_SELF);
+ if (temp)
+ target_id = ud->attacktarget; //Auto-select skills. [Skotlex]
+
+ if (sd) {
+ //Target_id checking.
+ if(skillnotok(skill_num, sd)) // [MouseJstr]
+ return 0;
+ switch(skill_num)
+ { //Check for skills that auto-select target
+ case MO_CHAINCOMBO:
+ if (sc && sc->data[SC_BLADESTOP].timer != -1){
+ if ((target=(struct block_list *)sc->data[SC_BLADESTOP].val4) == NULL)
+ return 0;
+ target_id = target->id;
+ }
+ break;
+ case TK_JUMPKICK:
+ case TK_COUNTER:
+ case HT_POWER:
+ if (sc && sc->data[SC_COMBO].timer != -1 && sc->data[SC_COMBO].val1 == skill_num)
+ target_id = sc->data[SC_COMBO].val2;
+ break;
+ case WE_MALE:
+ case WE_FEMALE:
+ if (!sd->status.partner_id)
+ return 0;
+ target = (struct block_list*)map_charid2sd(sd->status.partner_id);
+ if (!target)
+ {
+ clif_skill_fail(sd,skill_num,0,0);
+ return 0;
+ }
+ break;
+ }
+ }
+ if(!target && (target=map_id2bl(target_id)) == NULL )
+ return 0;
+ if(src->m != target->m)
+ return 0; // “¯‚¶ƒ}ƒbƒv‚©‚Ç‚¤‚©
+ if(!src->prev || !target->prev)
+ return 0; // map ã‚É‘¶Ý‚·‚é‚©
+
+ //Normally not needed because clif.c checks for it, but the at/char/script commands don't! [Skotlex]
+ if(ud->skilltimer != -1 && skill_num != SA_CASTCANCEL)
+ return 0;
+
+ if(skill_get_inf2(skill_num)&INF2_NO_TARGET_SELF && src->id == target_id)
+ return 0;
+
+ if(!status_check_skilluse(src, target, skill_num, 0))
+ return 0;
+
+ //’¼‘O‚̃XƒLƒ‹ó‹µ‚Ì‹L˜^
+ if(sd) {
+ switch(skill_num){
+ case SA_CASTCANCEL:
+ if(ud->skillid != skill_num){ //ƒLƒƒƒXƒgƒLƒƒƒ“ƒZƒ‹Ž©‘Ì‚ÍŠo‚¦‚È‚¢
+ sd->skillid_old = ud->skillid;
+ sd->skilllv_old = ud->skilllv;
+ break;
+ }
+ case BD_ENCORE: /* ƒAƒ“ƒR[ƒ‹ */
+ //Prevent using the dance skill if you no longer have the skill in your tree.
+ if(!sd->skillid_dance || pc_checkskill(sd,sd->skillid_dance)<=0){
+ clif_skill_fail(sd,skill_num,0,0);
+ return 0;
+ }
+ sd->skillid_old = skill_num;
+ break;
+ case BD_LULLABY: /* ŽqŽç‰Ì */
+ case BD_RICHMANKIM: /* ƒjƒˆƒ‹ƒh‚̉ƒ */
+ case BD_ETERNALCHAOS: /* ‰i‰“‚Ì?¬“× */
+ case BD_DRUMBATTLEFIELD: /* ?‘¾ŒÛ‚Ì‹¿‚« */
+ case BD_RINGNIBELUNGEN: /* ƒj?ƒxƒ‹ƒ“ƒO‚ÌŽw—Ö */
+ case BD_ROKISWEIL: /* ƒ?ƒL‚Ì‹©‚Ñ */
+ case BD_INTOABYSS: /* ?[•£‚Ì’†‚É */
+ case BD_SIEGFRIED: /* •sŽ€?g‚̃W?ƒNƒtƒŠ?ƒh */
+ case CG_MOONLIT: /* ŒŽ–¾‚è‚Ì?ò‚É—Ž‚¿‚é‰Ô‚Ñ‚ç */
+ if (battle_config.player_skill_partner_check &&
+ (!battle_config.gm_skilluncond || pc_isGM(sd) < battle_config.gm_skilluncond) &&
+ (skill_check_pc_partner(sd, skill_num, &skill_lv, 1, 0) < 1)
+ ) {
+ clif_skill_fail(sd,skill_num,0,0);
+ return 0;
+ }
+ break;
+ }
+ if (!skill_check_condition(sd, skill_num, skill_lv, 0))
+ return 0;
+ }
+
+ if(src->id != target_id &&
+ !battle_check_range(src,target,skill_get_range2(src, skill_num,skill_lv)
+ +(skill_num==RG_CLOSECONFINE?0:1))) //Close confine is exploitable thanks to this extra range "feature" of the client. [Skotlex]
+ return 0;
+
+ if (!temp) //Stop attack on non-combo skills [Skotlex]
+ unit_stop_attack(src);
+ else if(ud->attacktimer != -1) //Elsewise, delay current attack sequence
+ ud->attackabletime = tick + status_get_adelay(src);
+
+ ud->state.skillcastcancel = castcancel;
+
+ //temp: Used to signal force cast now.
+ temp = 0;
+ /* ‰½‚©“ÁŽê‚Ȉ—‚ª•K—v */
+ // Ž¸”s”»’è‚Ískill_check_condition() ‚É‘‚­‚±‚Æ
+ switch(skill_num){
+ case ALL_RESURRECTION: /* ƒŠƒUƒŒƒNƒVƒ‡ƒ“ */
+ if(battle_check_undead(status_get_race(target),status_get_elem_type(target))){ /* “G‚ªƒAƒ“ƒfƒbƒh‚È‚ç */
+ temp=1; /* ƒ^[ƒ“ƒAƒ“ƒfƒbƒg‚Æ“¯‚¶‰r¥ŽžŠÔ */
+ casttime = skill_castfix(src, PR_TURNUNDEAD, skill_lv, skill_get_cast(PR_TURNUNDEAD, skill_lv));
+ }
+ break;
+ case MO_FINGEROFFENSIVE: /* Žw’e */
+ if(sd)
+ casttime += casttime * ((skill_lv > sd->spiritball)? sd->spiritball:skill_lv);
+ break;
+ case MO_EXTREMITYFIST: /*ˆ¢?C—…”e–PŒ?*/
+ if (sc && sc->data[SC_COMBO].timer != -1 &&
+ (sc->data[SC_COMBO].val1 == MO_COMBOFINISH ||
+ sc->data[SC_COMBO].val1 == CH_TIGERFIST ||
+ sc->data[SC_COMBO].val1 == CH_CHAINCRUSH))
+ casttime = 0;
+ temp = 1;
+ break;
+ case SA_MAGICROD:
+ case SA_SPELLBREAKER:
+ temp =1;
+ break;
+ case KN_CHARGEATK: //ƒ`ƒƒ[ƒWƒAƒ^ƒbƒN
+ //Taken from jA: Casttime is increased by dist/3*100%
+ casttime = casttime * ((distance_bl(src,target)-1)/3+1);
+ break;
+ }
+
+ //ƒƒ‚ƒ‰ƒCƒYó‘Ô‚È‚çƒLƒƒƒXƒgƒ^ƒCƒ€‚ª1/2
+ if (sc && sc->data[SC_MEMORIZE].timer != -1 && casttime > 0) {
+ casttime = casttime/2;
+ if ((--sc->data[SC_MEMORIZE].val2) <= 0)
+ status_change_end(src, SC_MEMORIZE, -1);
+ }
+
+ if( casttime>0 || temp){ /* ‰r¥‚ª•K—v */
+ if(sd && sd->disguise) { // [Valaris]
+ clif_skillcasting(src, src->id, target_id, 0,0, skill_num,0);
+ clif_skillcasting(src,-src->id, target_id, 0,0, skill_num,casttime);
+ } else
+ clif_skillcasting(src, src->id, target_id, 0,0, skill_num,casttime);
+
+ /* ‰r¥”½‰žƒ‚ƒ“ƒXƒ^[ */
+ if (sd && target->type == BL_MOB)
+ {
+ TBL_MOB *md = (TBL_MOB*)target;
+ mobskill_event(md, src, tick, -1); //Cast targetted skill event.
+ //temp: used to store mob's mode now.
+ if ((temp=status_get_mode(target))&MD_CASTSENSOR &&
+ battle_check_target(target, src, BCT_ENEMY) > 0)
+ {
+ switch (md->state.skillstate) {
+ case MSS_ANGRY:
+ case MSS_RUSH:
+ case MSS_FOLLOW:
+ if (!(temp&(MD_AGGRESSIVE|MD_ANGRY)))
+ break; //Only Aggressive mobs change target while chasing.
+ case MSS_IDLE:
+ case MSS_WALK:
+ md->target_id = src->id;
+ md->state.aggressive = (temp&MD_ANGRY)?1:0;
+ md->min_chase = md->db->range3;
+ }
+ }
+ }
+ }
+
+ if( casttime<=0 )
+ ud->state.skillcastcancel=0;
+
+ ud->canact_tick = tick + casttime + 100;
+ ud->skilltarget = target_id;
+ ud->skillx = 0;
+ ud->skilly = 0;
+ ud->skillid = skill_num;
+ ud->skilllv = skill_lv;
+
+ if(
+ (sd && !(battle_config.pc_cloak_check_type&2) ) ||
+ (src->type == BL_MOB && !(battle_config.monster_cloak_check_type&2) )
+ ) {
+ if( sc && sc->data[SC_CLOAKING].timer != -1 && skill_num != AS_CLOAKING)
+ status_change_end(src,SC_CLOAKING,-1);
+ }
+
+ if(casttime > 0) {
+ ud->skilltimer = add_timer( tick+casttime, skill_castend_id, src->id, 0 );
+ //temp: used to hold FreeCast's level
+ if(sd && (temp = pc_checkskill(sd,SA_FREECAST)) > 0)
+ status_quick_recalc_speed (sd, SA_FREECAST, temp, 1);
+ else
+ unit_stop_walking(src,1);
+ }
+ else {
+// if(skill_num != SA_CASTCANCEL)
+// ud->skilltimer = -1; //This check is done above...
+ skill_castend_id(ud->skilltimer,tick,src->id,0);
+ }
+ return 1;
+}
+
+int unit_skilluse_pos(struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv) {
+ if(skill_num < 0)
+ return 0;
+ return unit_skilluse_pos2(
+ src, skill_x, skill_y, skill_num, skill_lv,
+ skill_castfix(src, skill_num, skill_lv, skill_get_cast(skill_num, skill_lv)),
+ skill_get_castcancel(skill_num)
+ );
+}
+
+int unit_skilluse_pos2( struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv, int casttime, int castcancel) {
+ struct map_session_data *sd = NULL;
+ struct unit_data *ud = NULL;
+ struct status_change *sc;
+ struct block_list bl;
+ unsigned int tick = gettick();
+
+ nullpo_retr(0, src);
+
+ if(!src->prev) return 0; // map ã‚É‘¶Ý‚·‚é‚©
+ if(status_isdead(src)) return 0;
+
+ if( BL_CAST( BL_PC, src, sd ) ) {
+ ud = &sd->ud;
+ } else
+ ud = unit_bl2ud(src);
+ if(ud == NULL) return 0;
+
+ if(ud->skilltimer != -1) //Normally not needed since clif.c checks for it, but at/char/script commands don't! [Skotlex]
+ return 0;
+
+ sc = status_get_sc(src);
+ if (sc && !sc->count)
+ sc = NULL;
+
+ if(sd) {
+ if (skillnotok(skill_num, sd) ||
+ !skill_check_condition(sd, skill_num, skill_lv,0))
+ return 0;
+ }
+
+ if (!status_check_skilluse(src, NULL, skill_num, 0))
+ return 0;
+
+ if (map_getcell(src->m, skill_x, skill_y, CELL_CHKNOPASS))
+ { //prevent casting ground targeted spells on non-walkable areas. [Skotlex]
+ if (sd) clif_skill_fail(sd,skill_num,0,0);
+ return 0;
+ }
+
+ /* ŽË’ö‚ÆáŠQ•¨ƒ`ƒFƒbƒN */
+ bl.type = BL_NUL;
+ bl.m = src->m;
+ bl.x = skill_x;
+ bl.y = skill_y;
+ if(skill_num != TK_HIGHJUMP &&
+ !battle_check_range(src,&bl,skill_get_range2(&sd->bl, skill_num,skill_lv)+1))
+ return 0;
+
+ unit_stop_attack(src);
+ ud->state.skillcastcancel = castcancel;
+
+ //ƒ?ƒ‚ƒ‰ƒCƒY?‘Ô‚È‚çƒLƒƒƒXƒgƒ^ƒCƒ€‚ª1/3
+ if (sc && sc->data[SC_MEMORIZE].timer != -1 && casttime > 0){
+ casttime = casttime/3;
+ if ((--sc->data[SC_MEMORIZE].val2)<=0)
+ status_change_end(src, SC_MEMORIZE, -1);
+ }
+
+ if( casttime>0 ) {
+ /* ‰r¥‚ª•K—v */
+ unit_stop_walking( src, 1); // •às’âŽ~
+ if(sd && sd->disguise) { // [Valaris]
+ clif_skillcasting(src, src->id, 0, skill_x,skill_y, skill_num,0);
+ clif_skillcasting(src,-src->id, 0, skill_x,skill_y, skill_num,casttime);
+ }
+ else
+ clif_skillcasting(src, src->id, 0, skill_x,skill_y, skill_num,casttime);
+ }
+
+ if( casttime<=0 ) /* ‰r¥‚Ì–³‚¢‚à‚̂̓Lƒƒƒ“ƒZƒ‹‚³‚ê‚È‚¢ */
+ ud->state.skillcastcancel=0;
+
+ ud->canact_tick = tick + casttime + 100;
+ ud->skillid = skill_num;
+ ud->skilllv = skill_lv;
+ ud->skillx = skill_x;
+ ud->skilly = skill_y;
+ ud->skilltarget = 0;
+
+ if((sd && !(battle_config.pc_cloak_check_type&2)) ||
+ (src->type==BL_MOB && !(battle_config.monster_cloak_check_type&2))
+ ) {
+ if (sc && sc->data[SC_CLOAKING].timer != -1)
+ status_change_end(src,SC_CLOAKING,-1);
+ }
+
+ if(casttime > 0) {
+ ud->skilltimer = add_timer( tick+casttime, skill_castend_pos, src->id, 0 );
+ //castcancel recylced to store FREECAST lv.
+ if(sd && (castcancel = pc_checkskill(sd,SA_FREECAST)) > 0)
+ status_quick_recalc_speed (sd, SA_FREECAST, castcancel, 1);
+ else
+ unit_stop_walking(src,1);
+ }
+ else {
+ ud->skilltimer = -1;
+ skill_castend_pos(ud->skilltimer,tick,src->id,0);
+ }
+ return 1;
+}
+
+static int unit_attack_timer(int tid,unsigned int tick,int id,int data);
+
+// UŒ‚’âŽ~
+int unit_stop_attack(struct block_list *bl)
+{
+ struct unit_data *ud = unit_bl2ud(bl);
+ nullpo_retr(0, bl);
+
+ if(!ud || ud->attacktimer == -1)
+ return 0;
+
+ delete_timer( ud->attacktimer, unit_attack_timer );
+ ud->attacktimer = -1;
+ ud->state.attack_continue = 0;
+ return 0;
+}
+
+//Means current target is unattackable. For now only unlocks mobs.
+int unit_unattackable(struct block_list *bl) {
+ struct unit_data *ud = unit_bl2ud(bl);
+ if (ud) ud->attacktarget = 0;
+ if(bl->type == BL_MOB)
+ mob_unlocktarget((struct mob_data*)bl, gettick()) ;
+ else if(bl->type == BL_PET)
+ pet_unlocktarget((struct pet_data*)bl);
+ return 0;
+}
+
+/*==========================================
+ * UŒ‚—v‹
+ * type‚ª1‚È‚çŒp‘±UŒ‚
+ *------------------------------------------
+ */
+
+int unit_attack(struct block_list *src,int target_id,int type)
+{
+ struct block_list *target;
+ struct unit_data *ud;
+
+ nullpo_retr(0, ud = unit_bl2ud(src));
+
+ target=map_id2bl(target_id);
+ if(target==NULL || status_isdead(target)) {
+ unit_unattackable(src);
+ return 1;
+ }
+
+ if(src->type == BL_PC && target->type==BL_NPC) { // monster npcs [Valaris]
+ npc_click((TBL_PC*)src,target_id); // submitted by leinsirk10 [Celest]
+ return 0;
+ }
+
+ if(battle_check_target(src,target,BCT_ENEMY)<=0 ||
+ !status_check_skilluse(src, target, 0, 0)
+ ) {
+ unit_unattackable(src);
+ return 1;
+ }
+
+ ud->attacktarget = target_id;
+ ud->state.attack_continue = type;
+ //Just change target/type. [Skotlex]
+ if(ud->attacktimer != -1)
+ return 0;
+
+ if(DIFF_TICK(ud->attackabletime, gettick()) > 0)
+ //Do attack next time it is possible. [Skotlex]
+ ud->attacktimer=add_timer(ud->attackabletime,unit_attack_timer,src->id,0);
+ else //Attack NOW.
+ unit_attack_timer(-1,gettick(),src->id,0);
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+int unit_can_reach(struct block_list *bl,int x,int y)
+{
+ struct walkpath_data wpd;
+
+ nullpo_retr(0, bl);
+
+ if( bl->x==x && bl->y==y ) // “¯‚¶ƒ}ƒX
+ return 1;
+
+ // áŠQ•¨”»’è
+ wpd.path_len=0;
+ wpd.path_pos=0;
+ wpd.path_half=0;
+ return (path_search_real(&wpd,bl->m,bl->x,bl->y,x,y,0,CELL_CHKNOREACH)!=-1)?1:0;
+}
+
+/*==========================================
+ * PC‚ÌUŒ‚ (timerŠÖ”)
+ *------------------------------------------
+ */
+static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int tick)
+{
+ struct block_list *target;
+ struct unit_data *ud;
+ struct map_session_data *sd = NULL;
+ struct mob_data *md = NULL;
+ int range;
+
+ if((ud=unit_bl2ud(src))==NULL)
+ return 0;
+ if(ud->attacktimer != tid){
+ if(battle_config.error_log)
+ printf("unit_attack_timer %d != %d\n",ud->attacktimer,tid);
+ return 0;
+ }
+ BL_CAST( BL_PC , src, sd);
+ BL_CAST( BL_MOB, src, md);
+ ud->attacktimer=-1;
+ target=map_id2bl(ud->attacktarget);
+
+ if(src->prev == NULL || target==NULL || target->prev == NULL)
+ return 0;
+
+ if(ud->skilltimer != -1 && (!sd || pc_checkskill(sd,SA_FREECAST) <= 0))
+ return 0;
+
+ if(src->m != target->m || status_isdead(src) || status_isdead(target) || !status_check_skilluse(src, target, 0, 0))
+ return 0;
+
+ if(!battle_config.sdelay_attack_enable &&
+ DIFF_TICK(ud->canact_tick,tick) > 0 &&
+ (!sd || pc_checkskill(sd,SA_FREECAST) <= 0)
+ ) {
+ if (tid == -1) { //requested attack.
+ if(sd) clif_skill_fail(sd,1,4,0);
+ return 0;
+ }
+ //Otherwise, we are in a combo-attack, delay this until your canact time is over. [Skotlex]
+ if(ud->state.attack_continue) {
+ if (DIFF_TICK(ud->canact_tick, ud->attackabletime) > 0)
+ ud->attackabletime = ud->canact_tick;
+ ud->attacktimer=add_timer(ud->attackabletime,unit_attack_timer,src->id,0);
+ }
+ return 1;
+ }
+
+ range = status_get_range( src );
+
+ if(ud->walktimer != -1) range++; //Extra range when walking.
+ if(!sd || sd->status.weapon != 11) range++; //Dunno why everyone but bows gets this extra range...
+ if(unit_is_walking(target)) range++; //Extra range when chasing
+
+ if(!check_distance_bl(src,target,range) ) {
+ if(!unit_can_reach(src,target->x,target->y))
+ return 0;
+ if(sd) clif_movetoattack(sd,target);
+ return 1;
+ }
+ if(!battle_check_range(src,target,range)) { //Within range, but no direct line of attack
+ if(unit_can_reach(src,target->x,target->y))
+ unit_walktoxy(src,target->x,target->y, ud->state.walk_easy);
+ if(ud->state.attack_continue)
+ ud->attacktimer = add_timer(tick + status_get_adelay(src),unit_attack_timer,src->id,0);
+ return 1;
+ }
+
+ if(DIFF_TICK(ud->attackabletime,tick) <= 0) {
+ if (battle_config.attack_direction_change &&
+ (src->type&battle_config.attack_direction_change)) {
+ ud->dir = map_calc_dir(src, target->x,target->y );
+ if (sd) sd->head_dir = ud->dir;
+ }
+ if(ud->walktimer != -1)
+ unit_stop_walking(src,1);
+ if(md) {
+ if (mobskill_use(md,tick,-1))
+ return 1;
+ if (status_get_mode(src)&MD_ASSIST && DIFF_TICK(md->last_linktime, tick) < MIN_MOBLINKTIME)
+ { // Link monsters nearby [Skotlex]
+ md->last_linktime = tick;
+ map_foreachinrange(mob_linksearch, src, md->db->range2,
+ BL_MOB, md->class_, target, tick);
+ }
+ }
+ if(src->type == BL_PET && pet_attackskill((TBL_PET*)src, target->id))
+ return 1;
+
+ map_freeblock_lock();
+ ud->attacktarget_lv = battle_weapon_attack(src,target,tick,0);
+ if(
+ (sd && !(battle_config.pc_cloak_check_type&2)) ||
+ (!sd && !(battle_config.monster_cloak_check_type&2))
+ ) {
+ struct status_change *sc = status_get_sc(src);
+ if (sc && sc->count && sc->data[SC_CLOAKING].timer != -1)
+ status_change_end(src,SC_CLOAKING,-1);
+ }
+
+ if(sd && sd->status.pet_id > 0 && sd->pd && sd->petDB && battle_config.pet_attack_support)
+ pet_target_check(sd,target,0);
+ map_freeblock_unlock();
+
+ if(ud->skilltimer != -1 && sd && (range = pc_checkskill(sd,SA_FREECAST)) > 0 ) // ƒtƒŠ[ƒLƒƒƒXƒg
+ ud->attackabletime = tick + (status_get_adelay(src)*(150 - range*5)/100);
+ else
+ ud->attackabletime = tick + status_get_adelay(src);
+
+// You can't move if you can't attack neither.
+// Only for non-players, since it makes it near impossible to run away when you are on auto-attack.
+ if (src->type != BL_PC)
+ unit_set_walkdelay(src, tick, status_get_amotion(src), 1);
+ }
+
+ if(ud->state.attack_continue)
+ ud->attacktimer = add_timer(ud->attackabletime,unit_attack_timer,src->id,0);
+
+ return 1;
+}
+
+static int unit_attack_timer(int tid,unsigned int tick,int id,int data) {
+ struct block_list *bl;
+ bl = map_id2bl(id);
+ if(bl && unit_attack_timer_sub(bl, tid, tick) == 0)
+ unit_unattackable(bl);
+ return 0;
+}
+
+/*==========================================
+ * Cancels an ongoing skill cast.
+ * flag&1: Cast-Cancel invoked.
+ * flag&2: Cancel only if skill is cancellable.
+ *------------------------------------------
+ */
+int unit_skillcastcancel(struct block_list *bl,int type)
+{
+ struct map_session_data *sd = NULL;
+ struct unit_data *ud = unit_bl2ud( bl);
+ unsigned int tick=gettick();
+ int ret=0, skill;
+
+ nullpo_retr(0, bl);
+ if (!ud || ud->skilltimer==-1)
+ return 0; //Nothing to cancel.
+
+ BL_CAST(BL_PC, bl, sd);
+
+ if (type&2) {
+ //See if it can be cancelled.
+ if (!ud->state.skillcastcancel)
+ return 0;
+
+ if (sd && !sd->special_state.no_castcancel2 &&
+ !(sd->special_state.no_castcancel && !map_flag_gvg(bl->m)))
+ return 0;
+ }
+
+ ud->canact_tick=tick;
+ if(sd && (skill = pc_checkskill(sd,SA_FREECAST)) > 0)
+ status_quick_recalc_speed(sd, SA_FREECAST, skill, 0); //Updated to use calc_speed [Skotlex]
+
+ if(type&1 && sd)
+ skill = sd->skillid_old;
+ else
+ skill = ud->skillid;
+
+ if (skill_get_inf(skill) & INF_GROUND_SKILL)
+ ret=delete_timer( ud->skilltimer, skill_castend_pos );
+ else
+ ret=delete_timer( ud->skilltimer, skill_castend_id );
+ if(ret<0)
+ printf("delete timer error : skillid : %d\n",ret);
+
+ if(bl->type==BL_MOB) ((TBL_MOB*)bl)->skillidx = -1;
+
+ ud->skilltimer = -1;
+ clif_skillcastcancel(bl);
+ return 1;
+}
+
+// unit_data ‚̉Šú‰»ˆ—
+void unit_dataset(struct block_list *bl) {
+ struct unit_data *ud;
+ int i;
+ nullpo_retv(ud = unit_bl2ud(bl));
+
+ memset( ud, 0, sizeof( struct unit_data) );
+ ud->bl = bl;
+ ud->walktimer = -1;
+ ud->skilltimer = -1;
+ ud->attacktimer = -1;
+ ud->attackabletime =
+ ud->canact_tick =
+ ud->canmove_tick = gettick();
+ for(i=0;i<MAX_SKILLTIMERSKILL;i++)
+ ud->skilltimerskill[i].timer=-1;
+}
+
+/*==========================================
+ * Ž©•ª‚ðƒƒbƒN‚µ‚Ä‚¢‚郆ƒjƒbƒg‚Ì”‚𔂦‚é(foreachclient)
+ *------------------------------------------
+ */
+static int unit_counttargeted_sub(struct block_list *bl, va_list ap)
+{
+ int id, target_lv;
+ struct unit_data *ud;
+ id = va_arg(ap,int);
+ target_lv = va_arg(ap,int);
+ if(bl->id == id)
+ return 0;
+
+ ud = unit_bl2ud(bl);
+
+ if (ud && ud->attacktarget == id && ud->attacktimer != -1 && ud->attacktarget_lv >= target_lv)
+ return 1;
+
+ return 0;
+}
+
+/*==========================================
+ *
+ *------------------------------------------
+ */
+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)
+{
+
+ nullpo_retr(0, target);
+
+ if(damage+damage2 <= 0)
+ return 0;
+
+ clif_damage(target,target,tick,sdelay,ddelay,damage,div,type,damage2);
+ return battle_damage(src,target,damage+damage2,0);
+}
+/*==========================================
+ * Ž©•ª‚ðƒƒbƒN‚µ‚Ä‚¢‚é‘ÎÛ‚Ì”‚ð•Ô‚·
+ * –ß‚è‚Í®”‚Å0ˆÈã
+ *------------------------------------------
+ */
+int unit_counttargeted(struct block_list *bl,int target_lv)
+{
+ nullpo_retr(0, bl);
+ return (map_foreachinrange(unit_counttargeted_sub, bl, AREA_SIZE, BL_CHAR,
+ bl->id, target_lv));
+}
+
+/*==========================================
+ * id‚ðUŒ‚‚µ‚Ä‚¢‚éPC‚ÌUŒ‚‚ð’âŽ~
+ * clif_foreachclient‚ÌcallbackŠÖ”
+ *------------------------------------------
+ */
+int unit_mobstopattacked(struct map_session_data *sd,va_list ap)
+{
+ int id=va_arg(ap,int);
+ if(sd->ud.attacktarget==id)
+ unit_stop_attack(&sd->bl);
+ return 0;
+}
+/*==========================================
+ * Œ©‚½–ڂ̃TƒCƒY‚ð•ÏX‚·‚é
+ *------------------------------------------
+ */
+int unit_changeviewsize(struct block_list *bl,short size)
+{
+ nullpo_retr(0, bl);
+
+ size=(size<0)?-1:(size>0)?1:0;
+
+ if(bl->type == BL_PC) {
+ ((TBL_PC*)bl)->state.size=size;
+ } else if(bl->type == BL_MOB) {
+ ((TBL_MOB*)bl)->special_state.size=size;
+ } else
+ return 0;
+ if(size!=0)
+ clif_misceffect2(bl,421+size);
+ return 0;
+}
+
+/*==========================================
+ * Removes a bl/ud from the map.
+ * Returns 1 on success. 0 if it couldn't be removed or the bl was free'd
+ * if clrtype is 1 (death), appropiate cleanup is performed.
+ * Otherwise it is assumed bl is being warped.
+ *------------------------------------------
+ */
+int unit_remove_map(struct block_list *bl, int clrtype) {
+ struct unit_data *ud = unit_bl2ud(bl);
+ struct status_change *sc = status_get_sc(bl);
+ nullpo_retr(0, ud);
+
+ if(bl->prev == NULL)
+ return 0; //Already removed?
+
+ map_freeblock_lock();
+
+ unit_stop_walking(bl,1); // •às’†’f
+ unit_stop_attack(bl); // UŒ‚’†’f
+ unit_skillcastcancel(bl,0); // ‰r¥’†’f
+ clif_clearchar_area(bl,clrtype);
+
+ if (clrtype == 1) //Death. Remove all status changes.
+ status_change_clear(bl,0);
+ else if(sc && sc->count ) { //map-change/warp dispells.
+ if(sc->data[SC_BLADESTOP].timer!=-1)
+ status_change_end(bl,SC_BLADESTOP,-1);
+ if(sc->data[SC_BASILICA].timer!=-1)
+ status_change_end(bl,SC_BASILICA,-1);
+ if(sc->data[SC_ANKLE].timer != -1)
+ status_change_end(bl, SC_ANKLE, -1);
+ if (sc->data[SC_TRICKDEAD].timer != -1)
+ status_change_end(bl, SC_TRICKDEAD, -1);
+ if (sc->data[SC_BLADESTOP].timer!=-1)
+ status_change_end(bl,SC_BLADESTOP,-1);
+ if (sc->data[SC_RUN].timer!=-1)
+ status_change_end(bl,SC_RUN,-1);
+ if (sc->data[SC_DANCING].timer!=-1) // clear dance effect when warping [Valaris]
+ skill_stop_dancing(bl);
+ if (sc->data[SC_DEVOTION].timer!=-1)
+ status_change_end(bl,SC_DEVOTION,-1);
+ if (sc->data[SC_CLOSECONFINE].timer!=-1)
+ status_change_end(bl,SC_CLOSECONFINE,-1);
+ if (sc->data[SC_CLOSECONFINE2].timer!=-1)
+ status_change_end(bl,SC_CLOSECONFINE2,-1);
+ if (sc->data[SC_HIDING].timer!=-1)
+ status_change_end(bl, SC_HIDING, -1);
+ if (sc->data[SC_CLOAKING].timer!=-1)
+ status_change_end(bl, SC_CLOAKING, -1);
+ if (sc->data[SC_CHASEWALK].timer!=-1)
+ status_change_end(bl, SC_CHASEWALK, -1);
+ if (sc->data[SC_GOSPEL].timer != -1 && sc->data[SC_GOSPEL].val4 == BCT_SELF)
+ status_change_end(bl, SC_GOSPEL, -1);
+ }
+
+ if (battle_config.clear_unit_ondeath || clrtype != 1) //Clrtype 1 = died.
+ skill_clear_unitgroup(bl); // ƒXƒLƒ‹ƒ†ƒjƒbƒgƒOƒ‹[ƒv‚Ìíœ
+ if (bl->type&BL_CHAR) {
+ skill_unit_move(bl,gettick(),4);
+ skill_cleartimerskill(bl); // ƒ^ƒCƒ}[ƒXƒLƒ‹ƒNƒŠƒA
+ }
+
+ if(bl->type == BL_PC) {
+ struct map_session_data *sd = (struct map_session_data*)bl;
+
+ //Leave/reject all invitations.
+ if(sd->chatID)
+ chat_leavechat(sd);
+ if(sd->trade_partner)
+ trade_tradecancel(sd);
+ if(sd->vender_id)
+ vending_closevending(sd);
+ if(sd->state.storage_flag == 1)
+ storage_storage_quit(sd,0);
+ else if (sd->state.storage_flag == 2)
+ storage_guild_storage_quit(sd,0);
+
+ if(sd->party_invite>0)
+ party_reply_invite(sd,sd->party_invite_account,0);
+ if(sd->guild_invite>0)
+ guild_reply_invite(sd,sd->guild_invite,0);
+ if(sd->guild_alliance>0)
+ guild_reply_reqalliance(sd,sd->guild_alliance_account,0);
+
+ pc_stop_following(sd);
+ pc_delinvincibletimer(sd);
+
+ if(sd->pvp_timer!=-1) {
+ delete_timer(sd->pvp_timer,pc_calc_pvprank_timer);
+ sd->pvp_timer = -1;
+ }
+
+ if(pc_issit(sd)) {
+ pc_setstand(sd);
+ skill_gangsterparadise(sd,0);
+ skill_rest(sd,0);
+ }
+ party_send_dot_remove(sd);//minimap dot fix [Kevin]
+ guild_send_dot_remove(sd);
+ } else if(bl->type == BL_MOB) {
+ struct mob_data *md = (struct mob_data*)bl;
+ md->target_id=0;
+ md->attacked_id=0;
+ md->state.skillstate= clrtype==1?MSS_DEAD:MSS_IDLE;
+ if (md->master_id) md->master_dist = 0;
+ if (clrtype == 1) { //Death.
+ md->last_deadtime=gettick();
+// Isn't this too much? Why not let the attack-timer fail when the mob is dead? [Skotlex]
+// clif_foreachclient(unit_mobstopattacked,md->bl.id);
+ if(md->deletetimer!=-1)
+ delete_timer(md->deletetimer,mob_timer_delete);
+ md->deletetimer=-1;
+ md->hp=0;
+ if(pcdb_checkid(mob_get_viewclass(md->class_))) //Player mobs are not removed automatically by the client.
+ clif_clearchar_delay(gettick()+3000,bl,0);
+ mob_deleteslave(md);
+
+ if(!md->spawn) {
+ map_delblock(bl);
+ unit_free(bl); //Mob does not respawn.
+ map_freeblock_unlock();
+ return 0;
+ }
+ mob_setdelayspawn(md); //Set respawning.
+ }
+ } else if (bl->type == BL_PET) {
+ struct pet_data *pd = (struct pet_data*)bl;
+ struct map_session_data *sd = pd->msd;
+
+ if(!sd) {
+ map_delblock(bl);
+ unit_free(bl);
+ map_freeblock_unlock();
+ return 0;
+ }
+ if (sd->bl.m != bl->m && sd->pet.intimate <= 0)
+ { //Remove pet.
+ intif_delete_petdata(sd->status.pet_id);
+ sd->status.pet_id = 0;
+ sd->pd = NULL;
+ sd->petDB = NULL;
+ pd->msd = NULL;
+ if(battle_config.pet_status_support)
+ status_calc_pc(sd,2);
+ map_delblock(bl);
+ unit_free(bl);
+ map_freeblock_unlock();
+ return 0;
+ }
+ }
+ map_delblock(bl);
+ map_freeblock_unlock();
+ return 1;
+}
+
+/*==========================================
+ * Function to free all related resources to the bl
+ * if unit is on map, it is removed using clrtype 0.
+ *------------------------------------------
+ */
+
+int unit_free(struct block_list *bl) {
+ struct unit_data *ud = unit_bl2ud( bl );
+ nullpo_retr(0, ud);
+
+ map_freeblock_lock();
+ if( bl->prev )
+ unit_remove_map(bl, 0);
+
+ if( bl->type == BL_PC ) {
+ struct map_session_data *sd = (struct map_session_data*)bl;
+
+ if(status_isdead(&sd->bl))
+ pc_setrestartvalue(sd,2);
+
+ //Status that are not saved...
+ if(sd->sc.count) {
+ if(sd->sc.data[SC_SPURT].timer!=-1)
+ status_change_end(&sd->bl,SC_SPURT,-1);
+ if(sd->sc.data[SC_BERSERK].timer!=-1)
+ status_change_end(&sd->bl,SC_BERSERK,-1);
+ if(sd->sc.data[SC_TRICKDEAD].timer!=-1)
+ status_change_end(&sd->bl,SC_TRICKDEAD,-1);
+ if (battle_config.debuff_on_logout) {
+ if(sd->sc.data[SC_STRIPWEAPON].timer!=-1)
+ status_change_end(&sd->bl,SC_STRIPWEAPON,-1);
+ if(sd->sc.data[SC_STRIPARMOR].timer!=-1)
+ status_change_end(&sd->bl,SC_STRIPARMOR,-1);
+ if(sd->sc.data[SC_STRIPSHIELD].timer!=-1)
+ status_change_end(&sd->bl,SC_STRIPSHIELD,-1);
+ if(sd->sc.data[SC_STRIPHELM].timer!=-1)
+ status_change_end(&sd->bl,SC_STRIPHELM,-1);
+ if(sd->sc.data[SC_EXTREMITYFIST].timer!=-1)
+ status_change_end(&sd->bl,SC_EXTREMITYFIST,-1);
+ if(sd->sc.data[SC_EXPLOSIONSPIRITS].timer!=-1)
+ status_change_end(&sd->bl,SC_EXPLOSIONSPIRITS,-1);
+ }
+ }
+
+ // Notify friends that this char logged out. [Skotlex]
+ clif_foreachclient(clif_friendslist_toggle_sub, sd->status.account_id, sd->status.char_id, 0);
+ party_send_logout(sd);
+ guild_send_memberinfoshort(sd,0);
+ pc_cleareventtimer(sd);
+ pc_delspiritball(sd,sd->spiritball,1);
+ chrif_save_scdata(sd); //Save status changes, then clear'em out from memory. [Skotlex]
+ storage_delete(sd->status.account_id);
+ pc_makesavestatus(sd);
+ sd->state.waitingdisconnect = 1;
+ } else if( bl->type == BL_PET ) {
+ struct pet_data *pd = (struct pet_data*)bl;
+ struct map_session_data *sd = pd->msd;
+ if(sd && sd->pet_hungry_timer != -1)
+ pet_hungry_timer_delete(sd);
+ if (pd->a_skill)
+ {
+ aFree(pd->a_skill);
+ pd->a_skill = NULL;
+ }
+ if (pd->s_skill)
+ {
+ if (pd->s_skill->timer != -1) {
+ if (pd->s_skill->id)
+ delete_timer(pd->s_skill->timer, pet_skill_support_timer);
+ else
+ delete_timer(pd->s_skill->timer, pet_heal_timer);
+ }
+ aFree(pd->s_skill);
+ pd->s_skill = NULL;
+ }
+ if(pd->recovery)
+ {
+ if(pd->recovery->timer != -1)
+ delete_timer(pd->recovery->timer, pet_recovery_timer);
+ aFree(pd->recovery);
+ pd->recovery = NULL;
+ }
+ if(pd->bonus)
+ {
+ if (pd->bonus->timer != -1)
+ delete_timer(pd->bonus->timer, pet_skill_bonus_timer);
+ aFree(pd->bonus);
+ pd->bonus = NULL;
+ }
+ if (pd->loot)
+ {
+ if (pd->loot->item)
+ aFree(pd->loot->item);
+ aFree (pd->loot);
+ pd->loot = NULL;
+ }
+ if (pd->status)
+ {
+ aFree(pd->status);
+ pd->status = NULL;
+ }
+ map_deliddb(&pd->bl);
+ map_freeblock(&pd->bl);
+ if (sd) sd->pd = NULL;
+ } else if(bl->type == BL_MOB) {
+ struct mob_data *md = (struct mob_data*)bl;
+ if(md->deletetimer!=-1)
+ delete_timer(md->deletetimer,mob_timer_delete);
+ md->deletetimer=-1;
+ map_deliddb(&md->bl);
+ if(md->lootitem) {
+ aFree(md->lootitem);
+ md->lootitem=NULL;
+ }
+ if (md->guardian_data)
+ {
+ if (md->guardian_data->number < MAX_GUARDIANS)
+ md->guardian_data->castle->guardian[md->guardian_data->number].id = 0;
+ aFree(md->guardian_data);
+ md->guardian_data = NULL;
+ }
+ if (md->spawn && md->spawn_n < 0 && --(md->spawn->num) == 0)
+ { //Spawning data is not attached to the map, so free it
+ //if this is the last mob who is pointing at it.
+ aFree(md->spawn);
+ md->spawn = NULL;
+ }
+ if(mob_is_clone(md->class_))
+ mob_clone_delete(md->class_);
+ map_freeblock(bl);
+ }
+ status_change_clear(bl,1);
+ map_freeblock_unlock();
+ return 0;
+}
+
+int do_init_unit(void) {
+ add_timer_func_list(unit_attack_timer, "unit_attack_timer");
+ add_timer_func_list(unit_walktoxy_timer,"unit_walktoxy_timer");
+ add_timer_func_list(unit_walkdelay_sub, "unit_walkdelay_sub");
+ return 0;
+}
+
+int do_final_unit(void) {
+ // nothing to do
+ return 0;
+}
+
diff --git a/src/map/unit.h b/src/map/unit.h
new file mode 100644
index 000000000..d711f19c8
--- /dev/null
+++ b/src/map/unit.h
@@ -0,0 +1,69 @@
+// Copyright (c) jAthena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+// Merged originally from jA by Skotlex
+#ifndef _UNIT_H_
+#define _UNIT_H_
+
+#include "map.h"
+
+// PC, MOB, PET ‚É‹¤’Ê‚·‚鈗‚ð‚P‚‚ɂ܂Ƃ߂éŒv‰æ
+
+// •àsŠJŽn
+// –ß‚è’l‚ÍA0 ( ¬Œ÷ ), 1 ( Ž¸”s )
+int unit_walktoxy( struct block_list *bl, int x, int y, int easy);
+
+// •às’âŽ~
+// type‚͈ȉº‚Ì‘g‚݇‚킹 :
+// 1: ˆÊ’uî•ñ‚Ì‘—M( ‚±‚ÌŠÖ”‚ÌŒã‚Ɉʒuî•ñ‚ð‘—M‚·‚éꇂ͕s—v )
+// 2: ƒ_ƒ[ƒWƒfƒBƒŒƒC—L‚è
+// 4: •s–¾(MOB‚Ì‚ÝH)
+int unit_stop_walking(struct block_list *bl,int type);
+int unit_can_move(struct block_list *bl);
+int unit_is_walking(struct block_list *bl);
+int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int type);
+int unit_walkdelay(struct block_list *bl, unsigned int tick, int adelay, int delay, int div_);
+
+
+// ˆÊ’u‚Ì‹­§ˆÚ“®(‚«”ò‚΂µ‚È‚Ç)
+int unit_movepos(struct block_list *bl,int dst_x,int dst_y, int easy, int checkpath);
+int unit_warp(struct block_list *bl, int map, int x, int y, int type);
+int unit_setdir(struct block_list *bl,unsigned short dir);
+int unit_getdir(struct block_list *bl);
+
+// ‚»‚±‚Ü‚Å•às‚Å‚½‚Ç‚è’…‚¯‚é‚©‚Ì”»’è
+int unit_can_reach(struct block_list *bl,int x,int y);
+
+// UŒ‚ŠÖ˜A
+int unit_stop_attack(struct block_list *bl);
+int unit_attack(struct block_list *src,int target_id,int type);
+
+// int unit_setpos( struct block_list *bl, const char* map, int x, int y);
+
+// ƒXƒLƒ‹Žg—p
+int unit_skilluse_id(struct block_list *src, int target_id, int skill_num, int skill_lv);
+int unit_skilluse_pos(struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv);
+
+// ƒXƒLƒ‹Žg—p( •â³Ï‚݃LƒƒƒXƒgŽžŠÔAƒLƒƒƒ“ƒZƒ‹•s‰ÂÝ’è•t‚« )
+int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int skill_lv, int casttime, int castcancel);
+int unit_skilluse_pos2( struct block_list *src, int skill_x, int skill_y, int skill_num, int skill_lv, int casttime, int castcancel);
+
+// ‰r¥ƒLƒƒƒ“ƒZƒ‹
+int unit_skillcastcancel(struct block_list *bl,int type);
+
+int unit_counttargeted(struct block_list *bl,int target_lv);
+
+// unit_data ‚̉Šú‰»ˆ—
+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);
+int unit_remove_map(struct block_list *bl, int clrtype);
+int unit_free(struct block_list *bl);
+int unit_changeviewsize(struct block_list *bl,short size);
+
+// ‰Šú‰»ƒ‹[ƒ`ƒ“
+int do_init_unit(void);
+int do_final_unit(void);
+
+#endif /* _UNIT_H_ */