소스 검색

- 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://svn.code.sf.net/p/rathena/svn/trunk@5707 54d463be-8e91-2dee-dedb-b68131a5f0ec

skotlex 19 년 전
부모
커밋
7a8371273a
31개의 변경된 파일3233개의 추가작업 그리고 3826개의 파일을 삭제
  1. 23 0
      Changelog-Trunk.txt
  2. 4 5
      conf-tmpl/battle/battle.conf
  3. 4 5
      conf-tmpl/battle/misc.conf
  4. 1 1
      conf-tmpl/battle/monster.conf
  5. 18 33
      conf-tmpl/battle/skill.conf
  6. 2 0
      db/skill_cast_db.txt
  7. 1 1
      db/skill_db.txt
  8. 1 0
      src/common/mapindex.c
  9. 4 2
      src/map/Makefile
  10. 8 7
      src/map/atcommand.c
  11. 96 323
      src/map/battle.c
  12. 6 19
      src/map/battle.h
  13. 88 94
      src/map/clif.c
  14. 1 1
      src/map/log.c
  15. 92 220
      src/map/map.c
  16. 121 140
      src/map/map.h
  17. 179 592
      src/map/mob.c
  18. 13 11
      src/map/mob.h
  19. 57 315
      src/map/npc.c
  20. 1 3
      src/map/npc.h
  21. 52 688
      src/map/pc.c
  22. 6 9
      src/map/pc.h
  23. 189 706
      src/map/pet.c
  24. 5 7
      src/map/pet.h
  25. 81 92
      src/map/script.c
  26. 367 463
      src/map/skill.c
  27. 5 6
      src/map/skill.h
  28. 59 82
      src/map/status.c
  29. 0 1
      src/map/status.h
  30. 1680 0
      src/map/unit.c
  31. 69 0
      src/map/unit.h

+ 23 - 0
Changelog-Trunk.txt

@@ -5,6 +5,29 @@ IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.  EV
 GOES INTO TRUNK AND WILL BE MERGED INTO STABLE BY VALARIS AND WIZPUTER. -- VALARIS
 
 2006/03/22
+	* Merged the unit_data structure from jA for handling unit-related data
+	  (attack times, walking, auto-attack timers, skill related data). This is a
+	  huge change that affects walking, attacking, auto-attacking, skill usage
+	  and character clean up from maps. I spent the last two days clearing out
+	  bugs, and even though I couldn't find any more, I wouldn't be surprised for
+	  a corner-case or two I missed. [Skotlex]
+	* Modified unit_skillcastcancel to receive flag&2, which stands for "cancel
+	  casting only if current skill is cancellable" [Skotlex]
+	* 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. See (Note 4) in the relevant battle config files.
+	  [Skotlex]
+	* Clif.c will disconnect sessions that send an unknown command packet above
+	  0x30000 instead of just ignoring it. [Skotlex]
+	* Cleaned up error reporting during mob-skill loading to be less spamy with
+	  non-loaded mobs. [Skotlex]
+	* Corrected water_height reading. It works now, with the exception that
+	  cloned maps don't get their water-level read because they don't have a rsw
+	  file. The solution is to add all cloned maps to water_level.txt (ie:
+	  "new_1-1.gat new_zone01.rsw" makes the new_zone01.rsw stored water-level be
+	  applied to map new_1-1.gat).
+	  Anyone can help collect all the clone maps to fill up water_height?
 	* status_check_skilluse won't block skill-specific checks (silence,
 	  berserk, steel-body, etc) when the skill in use is an item-invoked skill.
 	  [Skotlex]

+ 4 - 5
conf-tmpl/battle/battle.conf

@@ -19,6 +19,8 @@
 //Note 2: All rates are in percents, 100 would mean 100%, 200
 //   would mean 200%, etc
 //Note 3: Value is not limited to 60K (see below)
+//Note 4: Use bitmask values to specify who is affected 
+//        (1: Pc, 2: Mob, 4: Pet, 8: Homonculus)
 // Other Information:
 // All options are limited to a max of 60K (aprox) which is 600%
 // or 60secs as appropiate.
@@ -108,11 +110,8 @@ agi_penalty_count_lv: 2
 // Four or more: Except all.
 vit_penalty_count_lv: 3
 
-// Player's Direction Changed When Attacking? (Note 1)
-player_attack_direction_change: yes
-
-// Monsters's Direction Changed When Attacking? (Note 1)
-monster_attack_direction_change: yes
+// Change attacker's direction to face opponent on every attack? (Note 4)
+attack_direction_change: 15
 
 // Is a usual attack of a pet delivered withOUT an attribute? (Note 1)
 pet_attack_attr_none: no

+ 4 - 5
conf-tmpl/battle/misc.conf

@@ -19,6 +19,8 @@
 //Note 2: All rates are in percents, 100 would mean 100%, 200
 //   would mean 200%, etc
 //Note 3: Value is not limited to 60K (see below)
+//Note 4: Use bitmask values to specify who is affected 
+//        (1: Pc, 2: Mob, 4: Pet, 8: Homonculus)
 // Other Information:
 // All options are limited to a max of 60K (aprox) which is 600%
 // or 60secs as appropiate.
@@ -46,11 +48,8 @@ pk_level_range: 0
 // Allow muting of players?
 muting_players: yes
 
-// Display player skill errors in console? (for debug only) (default: off) (Note 1)
-player_skill_log: off
-
-// Display monster skill errors in console? (for debug only) (default: off) (Note 1)
-monster_skill_log: off
+// Display skill usage/errors in console? (for debug only) (default: off) (Note 4)
+skill_log: 0
 
 // Display battle log? (for debug only) (default: off) (Note 1)
 battle_log: off

+ 1 - 1
conf-tmpl/battle/monster.conf

@@ -55,7 +55,7 @@ monster_max_aspd: 199
 //    can't attack back regardless of how they were attacked (eg: GrimTooth), otherwise, their 
 //    rude attack" is only activated if they can't melee reach the target (eg: sniping)
 // 4: If not set, mobs that can change target only do so when melee attacked (distance player/mob < 3),
-//    otherwise mobs may change target and chase ranged attackers.
+//    otherwise mobs may change target and chase ranged attackers. This flag also overrides the 'provoke' target.
 // 8: If set, when a mob loses track of their target, they stop walking inmediately. Otherwise, they continue
 //    to their last target tile. When set mobs also scatter as soon as they lose their target. Use this mode to 
 //    make it much harder to mob-train by hiding and collecting them on a single spot (ie: GrimTooth training)

+ 18 - 33
conf-tmpl/battle/skill.conf

@@ -19,6 +19,8 @@
 //Note 2: All rates are in percents, 100 would mean 100%, 200
 //   would mean 200%, etc
 //Note 3: Value is not limited to 60K (see below)
+//Note 4: Use bitmask values to specify who is affected 
+//        (1: Pc, 2: Mob, 4: Pet, 8: Homonculus)
 // Other Information:
 // All options are limited to a max of 60K (aprox) which is 600%
 // or 60secs as appropiate.
@@ -47,24 +49,16 @@ castrate_dex_scale: 150
 // Will normal attacks be able to ignore the delay after skills? (Note 1)
 skill_delay_attack_enable: yes
 
-// Range added to player skills after their cast time finishes.
+// Range added to skills after their cast time finishes.
 // Decides how far away the target can walk away after the skill began casting before the skill fails.
-player_skill_add_range: 15
+skill_add_range: 15
 
 // If the target moves out of range while casting, do we take the items and SP for the skill anyway? (Note 1)
 skill_out_range_consume: no
 
-// Range added to mob skills after their cast time finishes.
-// Decides how far away the target can walk away after the skill began casting before the skill fails.
-monster_skill_add_range: 15
-
-// Does the distance between caster and target define if the skill is a ranged skill?
+// Does the distance between caster and target define if the skill is a ranged skill? (Note 4)
 // If set, when the distance between caster and target is greater than 3 the skill is considered long-range, otherwise it's a melee range.
 // If not set, then the range is determined by the skill (eg: Double Strafe is always long-ranged). 
-// Mask values (add as necessary):
-// 1: Players
-// 2: Mobs
-// 4: Pets
 // Default 6 (mobs + pets)
 skillrange_by_distance: 6
 
@@ -101,31 +95,22 @@ skill_min_damage: 6
 // The delay rate of monk's combo (Note 2)
 combo_delay_rate: 100
 
-// Counter Attack Skill Type
-// 0 = 100% critical
-// 1 = disregard DEF and HIT+20, CRI*2
-// Players
-player_auto_counter_type: 0
-// Monsters
-monster_auto_counter_type: 0
-
-// Whether or not, ground skills of the players' will stack. (Note 1)
-player_skill_reiteration: no
-
-//Whether or not, ground skills of the monsters' will pile up. (Note 1)
-monster_skill_reiteration: no
+// Use alternate auto Counter Attack Skill Type? (Note 4)
+// For those characters on which it is set, 100% Critical,
+// Otherwise it disregard DEF and HIT+20, CRI*2
+auto_counter_type: 0
 
-// Whether players are not allowed to cast ground based skills of a certain type such
-// as traps straight onto or nearby other players/monsters. (Note 1)
-player_skill_nofootset: yes
+// Can ground skills be placed on top of each other? (Note 4)
+// If set, only skills with UF_NOREITERATION set will be affected (skill_unit_db)
+skill_reiteration: 0
 
-// Whether monsters are not allowed to cast ground based skills of a certain type such
-// as traps straight onto or nearby other players. (Note 1)
-monster_skill_nofootset: no
+// Can ground skills NOT be placed underneath/near players/monsters? (Note 4)
+// If set, only skills with UF_NOFOOTSET set will be affected (skill_unit_db)
+skill_nofootset: 1
 
-// Should traps (hunter traps + quagmire) change their target to "all" inside gvg/pvp grounds? (Note 1)
-// Default on official servers: yes
-gvg_traps_target_all: yes
+// Should traps (hunter traps + quagmire) change their target to "all" inside gvg/pvp grounds? (Note 4)
+// Default on official servers: yes for player-traps
+gvg_traps_target_all: 1
 
 // Whether placed down skills will check walls (Note 1)
 // (Makes it so that Storm Gust/Lord of Vermillion/etc when casted next to a wall, won't hit on the other side) 

+ 2 - 0
db/skill_cast_db.txt

@@ -512,6 +512,8 @@
 349,0,0,0,60000:120000:180000:240000:300000,0
 //-- NPC_AGIUP
 350,0,0,0,60000:120000:180000:240000:300000,0
+//-- NPC_RUN
+354,0,0:500:1000:1500:2000:2500,0,0,0
 //==========================================
 
 

+ 1 - 1
db/skill_db.txt

@@ -373,7 +373,7 @@
 351,0,0,0,0,1,0,0,0,no,0,2,0,none,0	//NPC_SIEGEMODE
 352,2,0,4,0,1,0,1,0,no,0,2,0,none,0	//NPC_CALLSLAVE
 353,0,0,0,0,1,0,0,0,no,0,2,0,none,0	//NPC_INVISIBLE
-354,2,6,4,0,1,0,20,0,no,0,2,0,magic,0	//NPC_RUN
+354,2,6,4,0,1,0,20,0,no,0,2,0,misc,0	//NPC_RUN
 355,0,6,4,0,1,0,5,1,no,0,0,0,weapon,0	//LK_AURABLADE#Aura Blade#
 356,0,6,4,0,1,0,10,1,no,0,0,0,weapon,0	//LK_PARRYING#Parrying#
 357,0,6,4,0,1,0,5,1,no,0,0,0,weapon,0	//LK_CONCENTRATION#Concentration#

+ 1 - 0
src/common/mapindex.c

@@ -123,6 +123,7 @@ void mapindex_init(void) {
 		}
 		last_index = index;
 	}
+	fclose(fp);
 }
 
 void mapindex_final(void) {

+ 4 - 2
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)

+ 8 - 7
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;

+ 96 - 323
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;

+ 6 - 19
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);
 
-// 攻撃や移動を止める
-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);
 
 // 通常攻撃処理まとめ
 int battle_weapon_attack( struct block_list *bl,struct block_list *target,
 	 unsigned int tick,int flag);
 
 // 各種パラメータを得る
-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;

+ 88 - 94
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;//矢のアイテム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) // フリーキャスト
-		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); // ギャングスターパラダイス設定 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) {
 	// 管理用パケット処理
 	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: // 接続の切断
 			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--);

+ 1 - 1
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);

+ 92 - 220
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)	// チャットから出る
-			chat_leavechat(sd);
-
-		if(sd->trade_partner)	// 取引を中?する
-			trade_tradecancel(sd);
-
-		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);
-	    
-		// 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);	// パ?ティのログアウトメッセ?ジ送信
-
-		party_send_dot_remove(sd);//minimap dot fix [Kevin]
-
-		guild_send_memberinfoshort(sd,0);	// ギルドのログアウトメッセ?ジ送信
-
-		guild_send_dot_remove(sd);
-		 
-		pc_cleareventtimer(sd);	// イベントタイマを破棄する
-
-		// check if we've been authenticated [celest]
-		if (sd->state.auth)
-			skill_castcancel(&sd->bl,0);	// 詠唱を中?する
-
-		skill_stop_dancing(&sd->bl);// ダンス/演奏中?
-
-		//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);	// スキルユニットグル?プの削除
-
-		// 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を探す。居なければ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鯖終了・理
  *------------------------------------------
@@ -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();
 

+ 121 - 140
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};	// 囲まれペナルティ計算用
 
 // 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]
 

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 179 - 592
src/map/mob.c


+ 13 - 11
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);

+ 57 - 315
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;	// 時計イベント用
 
 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の無効化/有効化
@@ -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));
 
 	// 引数の個数チェック
-	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");

+ 1 - 3
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);

+ 52 - 688
src/map/pc.c

@@ -8,10 +8,13 @@
 #include <time.h>
 #include <limits.h>
 
-#include "socket.h" // [Valaris]
-#include "timer.h"
+#include "../common/socket.h" // [Valaris]
+#include "../common/timer.h"
+#include "../common/nullpo.h"
+#include "../common/showmsg.h"
+#include "../common/malloc.h"
+#include "../common/core.h"
 
-#include "malloc.h"
 #include "map.h"
 #include "chrif.h"
 #include "clif.h"
@@ -31,11 +34,8 @@
 #include "trade.h"
 #include "storage.h"
 #include "vending.h"
-#include "nullpo.h"
 #include "atcommand.h"
 #include "log.h"
-#include "showmsg.h"
-#include "core.h"
 
 #ifndef TXT_ONLY // mail system [Valaris]
 #include "mail.h"
@@ -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);
 }
 
-/*==========================================
- * ロ?カルプロトタイプ宣言 (必要な物のみ)
- *------------------------------------------
- */
-static int pc_walktoxy_sub(struct map_session_data *);
-
 /*==========================================
  * saveに必要なステ?タス修正を行なう
  *------------------------------------------
@@ -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)	// チャットから出る
-		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);
-
-	// 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);	// 詠唱中?
-	pc_stop_walking(sd,0);		// ?行中?
-	pc_stopattack(sd);			// 攻?中?
-
-	if(pc_issit(sd)) {
-		pc_setstand(sd);
-		skill_gangsterparadise(sd,0);
-	}
 
 	m=map_mapindex2mapid(mapindex);
 
-	if (sd->sc.count) {
-		if (sd->sc.data[SC_TRICKDEAD].timer != -1)
-			status_change_end(&sd->bl, SC_TRICKDEAD, -1);
-		if (sd->sc.data[SC_BLADESTOP].timer!=-1)
-			status_change_end(&sd->bl,SC_BLADESTOP,-1);
-		if (sd->sc.data[SC_RUN].timer!=-1)
-			status_change_end(&sd->bl,SC_RUN,-1);
-		if (sd->sc.data[SC_DANCING].timer!=-1) // clear dance effect when warping [Valaris]
-			skill_stop_dancing(&sd->bl);
-		if (sd->sc.data[SC_DEVOTION].timer!=-1)
-			status_change_end(&sd->bl,SC_DEVOTION,-1);
-		if (sd->sc.data[SC_CLOSECONFINE].timer!=-1)
-			status_change_end(&sd->bl,SC_CLOSECONFINE,-1);
-		if (sd->sc.data[SC_CLOSECONFINE2].timer!=-1)
-			status_change_end(&sd->bl,SC_CLOSECONFINE2,-1);
-		if (sd->sc.data[SC_RUN].timer!=-1)
-			status_change_end(&sd->bl,SC_RUN,-1);
-		if (sd->sc.data[SC_HIDING].timer!=-1)
-			status_change_end(&sd->bl, SC_HIDING, -1);
-		if (sd->sc.data[SC_CLOAKING].timer!=-1)
-			status_change_end(&sd->bl, SC_CLOAKING, -1);
-		if (sd->sc.data[SC_CHASEWALK].timer!=-1)
-			status_change_end(&sd->bl, SC_CHASEWALK, -1);
-		if (sd->bl.m != m) { //Cancel some map related stuff.
+	if (sd->mapindex != mapindex)
+	{	//Misc map-changing settings
+		party_send_dot_remove(sd); //minimap dot fix [Kevin]
+		guild_send_dot_remove(sd);
+		skill_clear_element_field(&sd->bl);
+		if (sd->sc.count)
+		{ //Cancel some map related stuff.
 			if (sd->sc.data[SC_WARM].timer != -1)
 				status_change_end(&sd->bl,SC_WARM,-1);
 			if (sd->sc.data[SC_SUN_COMFORT].timer != -1)
@@ -3119,61 +3014,21 @@ int pc_setpos(struct map_session_data *sd,unsigned short mapindex,int x,int y,in
 		}
 	}
 
-	if (sd->mapindex != mapindex)
-	{	//Misc map-changing settings
-		party_send_dot_remove(sd); //minimap dot fix [Kevin]
-		guild_send_dot_remove(sd);
-		skill_clear_element_field(&sd->bl);
-	}
-
-	if(sd->status.pet_id > 0 && sd->pd && sd->pet.intimate > 0) {
-		pet_stopattack(sd->pd);
-		pet_changestate(sd->pd,MS_IDLE,0);
-	}
-
 	if(m<0){
 		if(sd->mapindex){
 			int ip,port;
 			if(map_mapname2ipport(mapindex,&ip,&port)==0){
-
-				skill_stop_dancing(&sd->bl);
-				skill_unit_move(&sd->bl,gettick(),4);
-				clif_clearchar_area(&sd->bl,clrtype&0xffff);
-				skill_gangsterparadise(sd,0);
-				map_delblock(&sd->bl);
-				if(sd->status.pet_id > 0 && sd->pd) {
-					if(sd->pd->bl.m != m && sd->pet.intimate <= 0) {
-						pet_remove_map(sd);
-						intif_delete_petdata(sd->status.pet_id);
-						sd->status.pet_id = 0;
-						sd->pd = NULL;
-						sd->petDB = NULL;
-						if(battle_config.pet_status_support)
-							status_calc_pc(sd,2);
-					}
-					else if(sd->pet.intimate > 0) {
-						pet_stopattack(sd->pd);
-						pet_changestate(sd->pd,MS_IDLE,0);
-						clif_clearchar_area(&sd->pd->bl,clrtype&0xffff);
-						map_delblock(&sd->pd->bl);
-					}
-				}
+				unit_remove_map(&sd->bl,0);
 				sd->mapindex = mapindex;
 				sd->bl.x=x;
 				sd->bl.y=y;
 				sd->state.waitingdisconnect=1;
 				pc_clean_skilltree(sd);
-
-				if(sd->status.pet_id > 0 && sd->pd)
+				if(sd->status.pet_id > 0 && sd->pd) {
+					unit_remove_map(&sd->pd->bl, 0);
 					intif_save_petdata(sd->status.account_id,&sd->pet);
-				//The storage close routines save the char data. [Skotlex]
-				if (!sd->state.storage_flag)
-					chrif_save(sd,1);
-				else if (sd->state.storage_flag == 1) {
-					storage_storage_quit(sd,1);
-				} else if (sd->state.storage_flag == 2)
-					storage_guild_storage_quit(sd,1);
-					
+				}
+				chrif_save(sd,1);
 				chrif_changemapserver(sd, mapindex, x, y, ip, (short)port);
 				return 0;
 			}
@@ -3202,52 +3057,22 @@ int pc_setpos(struct map_session_data *sd,unsigned short mapindex,int x,int y,in
 	}
 
 	if(sd->mapindex && sd->bl.prev != NULL){
-		skill_unit_move(&sd->bl,gettick(),4);
-		clif_clearchar_area(&sd->bl,clrtype&0xffff);
-		skill_gangsterparadise(sd,0);
-		
-		map_delblock(&sd->bl);
-		// pet
-		if(sd->status.pet_id > 0 && sd->pd) {
-			if(sd->pd->bl.m != m && sd->pet.intimate <= 0) {
-				pet_remove_map(sd);
-				intif_delete_petdata(sd->status.pet_id);
-				sd->status.pet_id = 0;
-				sd->pd = NULL;
-				sd->petDB = NULL;
-				if(battle_config.pet_status_support)
-					status_calc_pc(sd,2);
-			}
-			else if(sd->pet.intimate > 0) {
-				pet_stopattack(sd->pd);
-				pet_changestate(sd->pd,MS_IDLE,0);
-				clif_clearchar_area(&sd->pd->bl,clrtype&0xffff);
-				map_delblock(&sd->pd->bl);
-			}
-		}
-		if (sd->state.storage_flag == 1)
-			storage_storageclose(sd);
-		else if (sd->state.storage_flag == 2)
-			storage_guild_storageclose(sd);
-
+		unit_remove_map(&sd->bl, 0);
+		if(sd->status.pet_id > 0 && sd->pd)
+			unit_remove_map(&sd->pd->bl, 0);
 		clif_changemap(sd,map[m].index,x,y); // [MouseJstr]
 	}
 		
 	sd->mapindex =  mapindex;
 	sd->bl.m = m;
-	sd->to_x = x;
-	sd->to_y = y;
-
-	// moved and changed dance effect stopping
-
-	sd->bl.x =  x;
-	sd->bl.y =  y;
+	sd->bl.x = sd->ud.to_x = x;
+	sd->bl.y = sd->ud.to_y = y;
 
 	if(sd->status.pet_id > 0 && sd->pd && sd->pet.intimate > 0) {
 		sd->pd->bl.m = m;
-		sd->pd->bl.x = sd->pd->to_x = x;
-		sd->pd->bl.y = sd->pd->to_y = y;
-		sd->pd->dir = sd->dir;
+		sd->pd->bl.x = sd->pd->ud.to_x = x;
+		sd->pd->bl.y = sd->pd->ud.to_y = y;
+		sd->pd->ud.dir = sd->ud.dir;
 	}
 
 	return 0;
@@ -3274,7 +3099,7 @@ int pc_randomwarp(struct map_session_data *sd, int type) {
 	}while(map_getcell(m,x,y,CELL_CHKNOPASS) && (i++)<1000 );
 
 	if (i < 1000)
-		pc_setpos(sd,map[sd->bl.m].index,x,y,type);
+		return pc_setpos(sd,map[sd->bl.m].index,x,y,type);
 
 	return 0;
 }
@@ -3340,7 +3165,7 @@ int pc_run(struct map_session_data *sd, int skilllv, int dir)
 
 	nullpo_retr(0, sd);
 
-	if (!pc_can_move(sd)) {
+	if (!unit_can_move(&sd->bl)) {
 		if(sd->sc.data[SC_RUN].timer!=-1)
 			status_change_end(&sd->bl,SC_RUN,-1);
 		return 0;
@@ -3366,7 +3191,7 @@ int pc_run(struct map_session_data *sd, int skilllv, int dir)
 			status_change_end(&sd->bl,SC_RUN,-1);
 		return 0;
 	}
-	pc_walktoxy(sd, to_x, to_y);
+	unit_walktoxy(&sd->bl, to_x, to_y, 1);
 	return 1;
 }
 /*==========================================
@@ -3381,321 +3206,22 @@ int pc_walktodir(struct map_session_data *sd,int step)
 
 	to_x = sd->bl.x;
 	to_y = sd->bl.y;
-	dir_x = dirx[(int)sd->dir];
-	dir_y = diry[(int)sd->dir];
+	dir_x = dirx[(int)sd->ud.dir];
+	dir_y = diry[(int)sd->ud.dir];
 
 	for(i=0;i<step;i++)
 	{
 		if(map_getcell(sd->bl.m,to_x+dir_x,to_y+dir_y,CELL_CHKNOPASS))
 			break;
 
-		if(map_getcell(sd->bl.m,to_x+dir_x,to_y+dir_y,CELL_CHKPASS))
-		{
-			to_x += dir_x;
-			to_y += dir_y;
-			continue;
-		}
-		break;
+		to_x += dir_x;
+		to_y += dir_y;
 	}
-	pc_walktoxy(sd, sd->to_x, sd->to_y);
+	unit_walktoxy(&sd->bl, sd->to_x, sd->to_y, 1);
 
 	return 1;
 }
 
-/*==========================================
- *
- *------------------------------------------
- */
-int pc_can_reach(struct map_session_data *sd,int x,int y)
-{
-	struct walkpath_data wpd;
-
-	nullpo_retr(0, sd);
-
-	if( sd->bl.x==x && sd->bl.y==y )	// 同じマス
-		return 1;
-
-	// 障害物判定
-	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;
-}
-
-//
-// ? 行物
-//
-/*==========================================
- * 次の1?にかかる史ヤを計算
- *------------------------------------------
- */
-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;
-}
-
-/*==========================================
- * 半?進む(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;
-
-	//?いたので息吹のタイマ?を初期化
-	sd->inchealspirithptick = 0;
-	sd->inchealspiritsptick = 0;
-
-	sd->walkpath.path_half ^= 1;
-	if (sd->walkpath.path_half == 0) { // マス目中心へ途
-		sd->walkpath.path_pos++;
-		if (sd->state.change_walk_target) {
-			pc_walktoxy_sub(sd);
-			return 0;
-		}
-	} else { // マス目境界へ途
-		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;
-}
-
-/*==========================================
- * 移動可能か確認して、可能なら?行開始
- *------------------------------------------
- */
-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? 行要求
- *------------------------------------------
- */
-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;
-}
-
-/*==========================================
- * ? 行停止
- *------------------------------------------
- */
-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の攻? (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でないなら攻?しない
-	// PCが死んでても攻?しない
-	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 ) // フリ?キャスト
-			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;
-}
-
-/*==========================================
- * 攻?要求
- * typeが1なら??攻?
- *------------------------------------------
- */
-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;
-}
-
-/*==========================================
- * ??攻?停止
- *------------------------------------------
- */
-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);	// 詠唱の中止
+	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 ){	// テンションリラックス
 			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");

+ 6 - 9
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*);
 

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 189 - 706
src/map/pet.c


+ 5 - 7
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);

+ 81 - 92
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]));
 
 	// 詠唱中にスキルアイテムは使用できない
-	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;
 }

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 367 - 463
src/map/skill.c


+ 5 - 6
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)

+ 59 - 82
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;
 }
-/*==========================================
- * 対象の方向を返す(汎用)
- * 戻りは整数で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;
-}
 /*==========================================
  * 対象のレベルを返す(汎用)
  * 戻りは整数で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:	//結婚用(結婚衣裳になって?くのが?いとか)
 		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);	/* 演奏/ダンスの中? */
 			// 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);	/* 攻?停止 */
+			unit_stop_attack(bl);	/* 攻?停止 */
 		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;

+ 0 - 1
src/map/status.h

@@ -442,7 +442,6 @@ enum {
 
 // パラメータ所得系 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);

+ 1680 - 0
src/map/unit.c

@@ -0,0 +1,1680 @@
+// Copyright (c) jAthena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+// Merged originally from jA by Skotlex
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../common/showmsg.h"
+#include "../common/timer.h"
+#include "../common/nullpo.h"
+#include "../common/db.h"
+#include "../common/malloc.h"
+#include "unit.h"
+#include "map.h"
+#include "pc.h"
+#include "mob.h"
+#include "pet.h"
+#include "skill.h"
+#include "clif.h"
+#include "npc.h"
+#include "guild.h"
+#include "status.h"
+#include "battle.h"
+#include "chat.h"
+#include "trade.h"
+#include "vending.h"
+#include "party.h"
+#include "intif.h"
+#include "chrif.h"
+
+static int dirx[8]={0,-1,-1,-1,0,1,1,1};
+static int diry[8]={1,1,0,-1,-1,-1,0,1};
+
+struct unit_data* unit_bl2ud(struct block_list *bl) {
+	if( bl == NULL) return NULL;
+	if( bl->type == BL_PC)  return &((struct map_session_data*)bl)->ud;
+	if( bl->type == BL_MOB) return &((struct mob_data*)bl)->ud;
+	if( bl->type == BL_PET) return &((struct pet_data*)bl)->ud;
+	if( bl->type == BL_NPC) return &((struct npc_data*)bl)->ud;
+	return NULL;
+}
+
+static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data);
+
+int unit_walktoxy_sub(struct block_list *bl)
+{
+	int i;
+	struct walkpath_data wpd;
+	struct unit_data        *ud = NULL;
+
+	nullpo_retr(1, bl);
+	ud = unit_bl2ud(bl);
+	if(ud == NULL) return 0;
+
+	if(path_search(&wpd,bl->m,bl->x,bl->y,ud->to_x,ud->to_y,ud->state.walk_easy))
+		return 0;
+
+	memcpy(&ud->walkpath,&wpd,sizeof(wpd));
+
+	switch (bl->type) {
+	case BL_PC:
+		clif_walkok((TBL_PC*)bl);
+		clif_movechar((TBL_PC*)bl);
+		break;
+	case BL_MOB:
+		clif_movemob((TBL_MOB*)bl);
+		break;
+	case BL_PET:
+		clif_movepet((TBL_PET*)bl);
+		break;
+	case BL_NPC:
+		clif_movenpc((TBL_NPC*)bl);
+		break;
+	}
+
+	ud->state.change_walk_target=0;
+
+	if(ud->walkpath.path_pos>=ud->walkpath.path_len)
+		i = -1;
+	else if(ud->walkpath.path[ud->walkpath.path_pos]&1)
+		i = status_get_speed(bl)*14/10;
+	else
+		i = status_get_speed(bl);
+	if( i  > 0) {
+		i = i>>1;
+		ud->walktimer = add_timer(gettick()+i,unit_walktoxy_timer,bl->id,0);
+	}
+	return 1;
+}
+
+static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data)
+{
+	int i;
+	int x,y,dx,dy,dir;
+	struct block_list       *bl;
+	struct map_session_data *sd = NULL;
+	struct mob_data         *md = NULL;
+	struct unit_data        *ud = NULL;
+
+	bl=map_id2bl(id);
+	if(bl == NULL)
+		return 0;
+	if( BL_CAST( BL_PC,  bl, sd ) ) {
+		ud = &sd->ud;
+	} else if( BL_CAST( BL_MOB, bl, md ) ) {
+		ud = &md->ud;
+	} else
+		ud = unit_bl2ud(bl);
+	
+	if(ud == NULL) return 0;
+
+	if(ud->walktimer != tid){
+		if(battle_config.error_log)
+			ShowError("unit_walk_timer mismatch %d != %d\n",ud->walktimer,tid);
+		return 0;
+	}
+	ud->walktimer=-1;
+	if( bl->prev == NULL ) return 0; // block_list から抜けているので移動停止する
+
+	if(ud->walkpath.path_pos>=ud->walkpath.path_len || ud->walkpath.path_pos!=data)
+		return 0;
+
+	//歩いたので息吹のタイマーを初期化
+	if(sd) {
+		sd->inchealspirithptick = 0;
+		sd->inchealspiritsptick = 0;
+	}
+	ud->walkpath.path_half ^= 1;
+	if(ud->walkpath.path_half==0){ // マス目中心へ到着
+		ud->walkpath.path_pos++;
+		if(ud->state.change_walk_target) {
+			unit_walktoxy_sub(bl);
+			return 0;
+		}
+	} else { // マス目境界へ到着
+		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);
+		
+		// バシリカ判定
+
+		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;
+
+	// 移動出来ないユニットは弾く
+	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) {
+		// 現在歩いている最中の目的地変更なのでマス目の中心に来た時に
+		// 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;
+}
+
+/*==========================================
+ * 歩行停止
+ *------------------------------------------
+ */
+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) // 位置補正送信が必要
+		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; // 同じマップかどうか
+	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;
+
+	//直前のスキル状況の記録
+	if(sd) {
+		switch(skill_num){
+		case SA_CASTCANCEL:
+			if(ud->skillid != skill_num){ //キャストキャンセル自体は覚えない
+				sd->skillid_old = ud->skillid;
+				sd->skilllv_old = ud->skilllv;
+				break;
+			}
+		case BD_ENCORE:					/* アンコール */
+			//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:				/* 子守歌 */
+		case BD_RICHMANKIM:				/* ニヨルドの宴 */
+		case BD_ETERNALCHAOS:			/* 永遠の?ャ沌 */
+		case BD_DRUMBATTLEFIELD:		/* ?太鼓の響き */
+		case BD_RINGNIBELUNGEN:			/* ニ?ベルングの指輪 */
+		case BD_ROKISWEIL:				/* �?キの叫び */
+		case BD_INTOABYSS:				/* ?[淵の中に */
+		case BD_SIEGFRIED:				/* 不死?gのジ?クフリ?ド */
+		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;
+	/* 何か特殊な処理が必要 */
+	// 失敗判定はskill_check_condition() に書くこと
+	switch(skill_num){
+	case ALL_RESURRECTION:	/* リザレクション */
+		if(battle_check_undead(status_get_race(target),status_get_elem_type(target))){	/* 敵がアンデッドなら */
+			temp=1;	/* ターンアンデットと同じ詠唱時間 */
+			casttime = skill_castfix(src, PR_TURNUNDEAD, skill_lv,  skill_get_cast(PR_TURNUNDEAD, skill_lv));
+		}
+		break;
+	case MO_FINGEROFFENSIVE:	/* 指弾 */
+		if(sd)
+			casttime += casttime * ((skill_lv > sd->spiritball)? sd->spiritball:skill_lv);
+		break;
+	case MO_EXTREMITYFIST:	/*阿?C羅覇鳳�?*/
+		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:			//チャージアタック
+		//Taken from jA: Casttime is increased by dist/3*100%
+		casttime = casttime * ((distance_bl(src,target)-1)/3+1);
+		break;
+	}
+
+	//メモライズ状態ならキャストタイムが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){ /* 詠唱が必要 */
+		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);
+
+		/* 詠唱反応モンスター */
+		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;
+	}
+
+	/* 射程と障害物チェック */
+	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;
+
+	//�?モライズ?態ならキャストタイムが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 ) {
+		/* 詠唱が必要 */
+		unit_stop_walking( src, 1);		// 歩行停止
+		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 )	/* 詠唱の無いものはキャンセルされない */
+		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);
+
+// 攻撃停止
+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;
+}
+
+/*==========================================
+ * 攻撃要求
+ * typeが1なら継続攻撃
+ *------------------------------------------
+ */
+
+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 )	// 同じマス
+		return 1;
+
+	// 障害物判定
+	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の攻撃 (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 ) // フリーキャスト
+			ud->attackabletime = tick + (status_get_adelay(src)*(150 - range*5)/100);
+		else
+			ud->attackabletime = tick + status_get_adelay(src);
+
+//		You can't move if you can't attack neither.
+//		Only for non-players, since it makes it near impossible to run away when you are on auto-attack.
+		if (src->type != BL_PC)		
+			unit_set_walkdelay(src, tick, status_get_amotion(src), 1);
+	}
+
+	if(ud->state.attack_continue)
+		ud->attacktimer = add_timer(ud->attackabletime,unit_attack_timer,src->id,0);
+
+	return 1;
+}
+
+static int unit_attack_timer(int tid,unsigned int tick,int id,int data) {
+	struct block_list *bl;
+	bl = map_id2bl(id);
+	if(bl && unit_attack_timer_sub(bl, tid, tick) == 0)
+		unit_unattackable(bl);
+	return 0;
+}
+
+/*==========================================
+ * Cancels an ongoing skill cast.
+ * flag&1: Cast-Cancel invoked.
+ * flag&2: Cancel only if skill is cancellable.
+ *------------------------------------------
+ */
+int unit_skillcastcancel(struct block_list *bl,int type)
+{
+	struct map_session_data *sd = NULL;
+	struct unit_data *ud = unit_bl2ud( bl);
+	unsigned int tick=gettick();
+	int ret=0, skill;
+	
+	nullpo_retr(0, bl);
+	if (!ud || ud->skilltimer==-1)
+		return 0; //Nothing to cancel.
+
+	BL_CAST(BL_PC,  bl, sd);
+
+	if (type&2) {
+		//See if it can be cancelled.
+		if (!ud->state.skillcastcancel)
+			return 0;
+
+		if (sd && !sd->special_state.no_castcancel2 &&
+			!(sd->special_state.no_castcancel && !map_flag_gvg(bl->m)))
+			return 0;
+	}
+	
+	ud->canact_tick=tick;
+	if(sd && (skill = pc_checkskill(sd,SA_FREECAST)) > 0)
+		status_quick_recalc_speed(sd, SA_FREECAST, skill, 0);	//Updated to use calc_speed [Skotlex]
+	
+	if(type&1 && sd)
+		skill = sd->skillid_old;
+	else
+		skill = ud->skillid;
+	
+	if (skill_get_inf(skill) & INF_GROUND_SKILL)
+		ret=delete_timer( ud->skilltimer, skill_castend_pos );
+	else
+		ret=delete_timer( ud->skilltimer, skill_castend_id );
+	if(ret<0)
+		printf("delete timer error : skillid : %d\n",ret);
+	
+	if(bl->type==BL_MOB) ((TBL_MOB*)bl)->skillidx  = -1;
+
+	ud->skilltimer = -1;
+	clif_skillcastcancel(bl);
+	return 1;
+}
+
+// unit_data の初期化処理
+void unit_dataset(struct block_list *bl) {
+	struct unit_data *ud;
+	int i;
+	nullpo_retv(ud = unit_bl2ud(bl));
+
+	memset( ud, 0, sizeof( struct unit_data) );
+	ud->bl             = bl;
+	ud->walktimer      = -1;
+	ud->skilltimer     = -1;
+	ud->attacktimer    = -1;
+	ud->attackabletime = 
+	ud->canact_tick    = 
+	ud->canmove_tick   = gettick();
+	for(i=0;i<MAX_SKILLTIMERSKILL;i++)
+		ud->skilltimerskill[i].timer=-1;
+}
+
+/*==========================================
+ * 自分をロックしているユニットの数を数える(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);
+}
+/*==========================================
+ * 自分をロックしている対象の数を返す
+ * 戻りは整数で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を攻撃しているPCの攻撃を停止
+ * 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;
+}
+/*==========================================
+ * 見た目のサイズを変更する
+ *------------------------------------------
+ */
+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);			// 歩行中断
+	unit_stop_attack(bl);				// 攻撃中断
+	unit_skillcastcancel(bl,0);			// 詠唱中断
+	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);			// スキルユニットグループの削除
+	if (bl->type&BL_CHAR) {
+		skill_unit_move(bl,gettick(),4);
+		skill_cleartimerskill(bl);			// タイマースキルクリア
+	}
+
+	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;
+}
+

+ 69 - 0
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 に共通する処理を1つにまとめる計画
+
+// 歩行開始
+//     戻り値は、0 ( 成功 ), 1 ( 失敗 )
+int unit_walktoxy( struct block_list *bl, int x, int y, int easy);
+
+// 歩行停止
+// typeは以下の組み合わせ : 
+//     1: 位置情報の送信( この関数の後に位置情報を送信する場合は不要 )
+//     2: ダメージディレイ有り
+//     4: 不明(MOBのみ?)
+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_);
+
+
+// 位置の強制移動(吹き飛ばしなど)
+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);
+
+// そこまで歩行でたどり着けるかの判定
+int unit_can_reach(struct block_list *bl,int x,int y);
+
+// 攻撃関連
+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);
+
+// スキル使用
+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);
+
+// スキル使用( 補正済みキャスト時間、キャンセル不可設定付き )
+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);
+
+// 詠唱キャンセル
+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_ */

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.