From 021b26b8409a84b4c83eb0cc1eedbd65eedfd4e0 Mon Sep 17 00:00:00 2001 From: skotlex Date: Wed, 22 Mar 2006 23:58:16 +0000 Subject: - 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 --- src/common/mapindex.c | 1 + src/map/Makefile | 6 +- src/map/atcommand.c | 15 +- src/map/battle.c | 419 +++-------- src/map/battle.h | 25 +- src/map/clif.c | 182 +++-- src/map/log.c | 2 +- src/map/map.c | 312 +++------ src/map/map.h | 261 ++++--- src/map/mob.c | 1844 +++++++++++-------------------------------------- src/map/mob.h | 24 +- src/map/npc.c | 372 ++-------- src/map/npc.h | 4 +- src/map/pc.c | 740 ++------------------ src/map/pc.h | 15 +- src/map/pet.c | 1057 +++++++--------------------- src/map/pet.h | 12 +- src/map/script.c | 173 +++-- src/map/skill.c | 1616 +++++++++++++------------------------------ src/map/skill.h | 11 +- src/map/status.c | 141 ++-- src/map/status.h | 1 - src/map/unit.c | 1680 ++++++++++++++++++++++++++++++++++++++++++++ src/map/unit.h | 69 ++ 24 files changed, 3575 insertions(+), 5407 deletions(-) create mode 100644 src/map/unit.c create mode 100644 src/map/unit.h (limited to 'src') 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] @@ -450,81 +325,6 @@ int battle_attr_fix(struct block_list *src, struct block_list *target, int damag return damage*ratio/100; } -/*========================================== - * 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 { // }; // ŽÀÛ‚É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; - md->n = 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); + + 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=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;countbl.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;countmax_hp += 2000 * gc->defense; md->guardian_data = aCalloc(1, sizeof(struct guardian_data)); @@ -494,125 +507,6 @@ int mob_spawn_guardian(struct map_session_data *sd,char *mapname, return (amount>0)?md->bl.id:0; } -/*========================================== - * 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: @@ -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; @@ -711,275 +603,15 @@ static int mob_linksearch(struct block_list *bl,va_list ap) return 0; } -/*========================================== - * 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; @@ -1196,63 +783,17 @@ int mob_spawn (int id) return 0; } -/*========================================== - * 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_distdb->range3 && (md->master_dist>MOB_SLAVEDISTANCE || md->master_dist == 0) && - mob_can_move(md) && md->state.state == MS_IDLE) + if(md->master_distdb->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;itarget_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;iwalkpath.path_len;i++){ // The next walk start time is calculated. - if(md->walkpath.path[i]&1) + for(i=c=0;iud.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_rangedb->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)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()%1000x0<=0 && md->master_id!=0 && - !(mode&MD_BOSS)) - mob_spawn(md->bl.id); else if(rand()%1000spawn && !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()%1000x0<=0 && md->master_id!=0 && - !(mode&MD_BOSS)) - mob_warp(md,-1,-1,-1,-1); + if( rand()%1000spawn && !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;iskilldelay[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; } @@ -3095,96 +2501,6 @@ int mob_warpslave(struct block_list *bl, int range) return map_foreachinmap(mob_warpslave_sub, bl->m, BL_MOB, bl, 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(;kmode&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;iskillunit[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_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 #include -#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" @@ -349,46 +349,6 @@ int pc_setrestartvalue(struct map_session_data *sd,int type) { return 0; } -/*========================================== - * 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) @@ -402,12 +362,6 @@ int pc_can_give_items(int level) { && level <= battle_config.gm_cant_drop_max_lv); } -/*========================================== - * ƒ?ƒ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;ibl.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;iskilltimerskill[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;iwalkpath.path_len;i++){ - if(pd->walkpath.path[i]&1) + for(i=c=0;iud.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;iloot->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;iloot->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) 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;iskilltimerskill[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 0;i++) { - if(sts[i].timer != -1) { - delete_timer(sts[i].timer, skill_timerskill); - sts[i].timer = -1; - (*count)--; - } - } - } else { - for(i=0;iskilltimerskill[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;iskillunit[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;iskillunit[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;iskillunit[i].alive_count > 0 && sd->skillunit[i].skill_id == skill_num) - c++; + for(i=0;iud.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;iskillunit[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;iskillunit[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;iskillunit[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;iskillunit[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;iskillunit[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;iskillunit){ + for(i=0;iskillunit[i].group_id==0){ + group=&ud->skillunit[i]; break; } if(group==NULL){ /* ‹ó‚¢‚Ä‚È‚¢‚̂Ō¢‚à‚Ì??õ */ int j=0; unsigned maxdiff=0,x,tick=gettick(); - for(i=0;imaxdiff){ + for(i=0;iskillunit[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;i0 && group[i].src_id == src->id) - skill_delunitgroup(&group[i]); - } - return 0; + if(!ud) return 0; + + for(i=0;iskillunit[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; } @@ -2353,22 +2360,6 @@ int status_get_class(struct block_list *bl) return ((struct pet_data *)bl)->class_; 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 +#include +#include + +#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;iskilltimerskill[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_ */ -- cgit v1.2.3-70-g09d2