ソースを参照

Random walking, monster target dropping
- Implemented official behavior for random walking of monsters (bugreport:9340)
* Updated the interval between walks from 3-6 seconds to 4-5 seconds
* Added a define MIN_RANDOMWALKTIME that is now used anywhere the interval is applied so it's easier to change
* Monsters will no longer attempt to walk to the cell they are currently standing on (note: still requires a proper "no cell stacking" implementation)
* Monsters will only target a cell within a 15x15 area around them
- Moved the "mob_ai" 0x008 configuration setting to mob_unlocktarget, so it applies to all cases of monsters unlocking targets
- Cleaned up the unit_stop_attack and unit_stop_stepaction functions
* unit_stop_attack now makes sure that the target is always set to 0, even if no attack timer currently exists
* replaced several calls of unit_set_target that set target to 0 with unit_stop_attack, this is important because the attack timer should always be deleted at the same time the target is set to 0
* this also fixes the problem that caused monsters to sometimes drop their target after an attack

Playtester 10 年 前
コミット
b1330a4c63
5 ファイル変更42 行追加47 行削除
  1. 11 7
      src/map/mob.c
  2. 2 0
      src/map/mob.h
  3. 1 1
      src/map/pet.c
  4. 26 37
      src/map/unit.c
  5. 2 2
      src/map/unit.h

+ 11 - 7
src/map/mob.c

@@ -960,7 +960,7 @@ int mob_spawn (struct mob_data *md)
 
 	md->state.aggressive = md->status.mode&MD_ANGRY?1:0;
 	md->state.skillstate = MSS_IDLE;
-	md->next_walktime = tick+rnd()%5000+1000;
+	md->next_walktime = tick+rnd()%1000+MIN_RANDOMWALKTIME;
 	md->last_linktime = tick;
 	md->dmgtick = tick - 5000;
 	md->last_pcneartime = 0;
@@ -1312,13 +1312,16 @@ int mob_unlocktarget(struct mob_data *md, unsigned int tick)
 			DIFF_TICK(md->next_walktime, tick) <= 0 &&
 			!mob_randomwalk(md,tick))
 			//Delay next random walk when this one failed.
-			md->next_walktime=tick+rnd()%3000;
+			md->next_walktime = tick+rnd()%1000;
 		break;
 	default:
 		mob_stop_attack(md);
 		mob_stop_walking(md,1); //Stop chasing.
 		md->state.skillstate = MSS_IDLE;
-		md->next_walktime=tick+rnd()%3000+3000;
+		if(battle_config.mob_ai&0x8) //Walk instantly after dropping target
+			md->next_walktime = tick+rnd()%1000;
+		else
+			md->next_walktime = tick+rnd()%1000+MIN_RANDOMWALKTIME;
 		break;
 	}
 	if (md->target_id) {
@@ -1346,6 +1349,7 @@ int mob_randomwalk(struct mob_data *md,unsigned int tick)
 
 	d =12-md->move_fail_count;
 	if(d<5) d=5;
+	if(d>7) d=7;
 	for(i=0;i<retrycount;i++){	// Search of a movable place
 		int r=rnd();
 		int x=r%(d*2+1)-d;
@@ -1353,7 +1357,7 @@ int mob_randomwalk(struct mob_data *md,unsigned int tick)
 		x+=md->bl.x;
 		y+=md->bl.y;
 
-		if((map_getcell(md->bl.m,x,y,CELL_CHKPASS)) && unit_walktoxy(&md->bl,x,y,1)){
+		if(((x != md->bl.x) || (y != md->bl.y)) && map_getcell(md->bl.m,x,y,CELL_CHKPASS) && unit_walktoxy(&md->bl,x,y,1)){
 			break;
 		}
 	}
@@ -1375,7 +1379,7 @@ int mob_randomwalk(struct mob_data *md,unsigned int tick)
 	}
 	md->state.skillstate=MSS_WALK;
 	md->move_fail_count=0;
-	md->next_walktime = tick+rnd()%3000+3000+c;
+	md->next_walktime = tick+rnd()%1000+MIN_RANDOMWALKTIME+c;
 	return 1;
 }
 
@@ -1452,7 +1456,7 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick)
 				return true; //Chasing this target.
 			if(md->ud.walktimer != INVALID_TIMER && md->ud.walkpath.path_pos <= battle_config.mob_chase_refresh)
 				return true; //Walk at least "mob_chase_refresh" cells before dropping the target
-			mob_unlocktarget(md, tick-(battle_config.mob_ai&0x8?3000:0)); //Immediately do random walk.
+			mob_unlocktarget(md, tick); //Unlock target
 			tbl = NULL;
 		}
 	}
@@ -2699,7 +2703,7 @@ void mob_revive(struct mob_data *md, unsigned int hp)
 	unsigned int tick = gettick();
 	md->state.skillstate = MSS_IDLE;
 	md->last_thinktime = tick;
-	md->next_walktime = tick+rnd()%50+5000;
+	md->next_walktime = tick+rnd()%1000+MIN_RANDOMWALKTIME;
 	md->last_linktime = tick;
 	md->last_pcneartime = 0;
 	memset(md->dmglog, 0, sizeof(md->dmglog));	// Reset the damage done on the rebirthed monster, otherwise will grant full exp + damage done. [Valaris]

+ 2 - 0
src/map/mob.h

@@ -27,6 +27,8 @@
 #define MIN_MOBTHINKTIME 100
 //Min time before mobs do a check to call nearby friends for help (or for slaves to support their master)
 #define MIN_MOBLINKTIME 1000
+//Min time between random walks
+#define MIN_RANDOMWALKTIME 4000
 
 //Distance that slaves should keep from their master.
 #define MOB_SLAVEDISTANCE 2

+ 1 - 1
src/map/pet.c

@@ -1067,7 +1067,7 @@ static int pet_randomwalk(struct pet_data *pd,unsigned int tick)
 				c += pd->status.speed;
 		}
 
-		pd->next_walktime = tick+rnd()%3000+3000+c;
+		pd->next_walktime = tick+rnd()%1000+MIN_RANDOMWALKTIME+c;
 
 		return 1;
 	}

+ 26 - 37
src/map/unit.c

@@ -101,7 +101,7 @@ int unit_walktoxy_sub(struct block_list *bl)
 		// Trim the last part of the path to account for range,
 		// but always move at least one cell when requested to move.
 		for (i = ud->chaserange*10; i > 0 && ud->walkpath.path_len>1;) {
-		   ud->walkpath.path_len--;
+			ud->walkpath.path_len--;
 			dir = ud->walkpath.path[ud->walkpath.path_len];
 			if(dir&1)
 				i -= MOVE_DIAGONAL_COST;
@@ -594,7 +594,7 @@ int unit_walktoxy( struct block_list *bl, short x, short y, unsigned char flag)
 	ud->state.walk_easy = flag&1;
 	ud->to_x = x;
 	ud->to_y = y;
-	unit_set_target(ud, 0);
+	unit_stop_attack(bl); //Sets target to 0
 
 	sc = status_get_sc(bl);
 	if (sc && sc->data[SC_CONFUSION]) // Randomize the target position
@@ -607,11 +607,6 @@ int unit_walktoxy( struct block_list *bl, short x, short y, unsigned char flag)
 		return 1;
 	}
 
-	if(ud->attacktimer != INVALID_TIMER) {
-		delete_timer( ud->attacktimer, unit_attack_timer );
-		ud->attacktimer = INVALID_TIMER;
-	}
-
 	// Start timer to recall summon
 	if (sd && sd->md)
 		unit_check_start_teleport_timer(&sd->md->bl);
@@ -702,7 +697,7 @@ int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, unsi
 	ud->target_to = tbl->id;
 	ud->chaserange = range; // Note that if flag&2, this SHOULD be attack-range
 	ud->state.attack_continue = flag&2?1:0; // Chase to attack.
-	unit_set_target(ud, 0);
+	unit_stop_attack(bl); //Sets target to 0
 
 	sc = status_get_sc(bl);
 	if (sc && sc->data[SC_CONFUSION]) // Randomize the target position
@@ -723,11 +718,6 @@ int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, unsi
 	if(!unit_can_move(bl))
 		return 0;
 
-	if(ud->attacktimer != INVALID_TIMER) {
-		delete_timer( ud->attacktimer, unit_attack_timer );
-		ud->attacktimer = INVALID_TIMER;
-	}
-
 	if (unit_walktoxy_sub(bl)) {
 		set_mobstate(bl, flag&2);
 
@@ -2069,37 +2059,37 @@ int unit_set_target(struct unit_data* ud, int target_id)
 /**
  * Stop a unit's attacks
  * @param bl: Object to stop
- * @return 0
  */
-int unit_stop_attack(struct block_list *bl)
+void unit_stop_attack(struct block_list *bl)
 {
-	struct unit_data *ud = unit_bl2ud(bl);
-
+	struct unit_data *ud;
 	nullpo_ret(bl);
+	ud = unit_bl2ud(bl);
+	nullpo_ret(ud);
 
-	if(!ud || ud->attacktimer == INVALID_TIMER)
-		return 0;
+	//Clear target
+	unit_set_target(ud, 0);
 
-	delete_timer( ud->attacktimer, unit_attack_timer );
+	if(ud->attacktimer == INVALID_TIMER)
+		return;
+
+	//Clear timer
+	delete_timer(ud->attacktimer, unit_attack_timer);
 	ud->attacktimer = INVALID_TIMER;
-	unit_set_target(ud, 0);
 
-	return 0;
+	return;
 }
 
 /**
  * Stop a unit's step action
  * @param bl: Object to stop
- * @return 0
  */
-int unit_stop_stepaction(struct block_list *bl)
+void unit_stop_stepaction(struct block_list *bl)
 {
-	struct unit_data *ud = unit_bl2ud(bl);
-
+	struct unit_data *ud;
 	nullpo_ret(bl);
-
-	if(!ud)
-		return 0;
+	ud = unit_bl2ud(bl);
+	nullpo_ret(ud);
 
 	//Clear remembered step action
 	ud->stepaction = false;
@@ -2108,13 +2098,13 @@ int unit_stop_stepaction(struct block_list *bl)
 	ud->stepskill_lv = 0;
 
 	if(ud->steptimer == INVALID_TIMER)
-		return 0;
+		return;
 
 	//Clear timer
 	delete_timer(ud->steptimer, unit_step_timer);
 	ud->steptimer = INVALID_TIMER;
 	
-	return 0;
+	return;
 }
 
 /**
@@ -2133,7 +2123,7 @@ int unit_unattackable(struct block_list *bl)
 	}
 
 	if(bl->type == BL_MOB)
-		mob_unlocktarget((struct mob_data*)bl, gettick()) ;
+		mob_unlocktarget((struct mob_data*)bl, gettick());
 	else if(bl->type == BL_PET)
 		pet_unlocktarget((struct pet_data*)bl);
 
@@ -2736,17 +2726,16 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file,
 
 	map_freeblock_lock();
 
-	unit_set_target(ud, 0);
-
 	if (ud->walktimer != INVALID_TIMER)
 		unit_stop_walking(bl,0);
 
-	if (ud->attacktimer != INVALID_TIMER)
-		unit_stop_attack(bl);
-
 	if (ud->skilltimer != INVALID_TIMER)
 		unit_skillcastcancel(bl,0);
 
+	//Clear target even if there is no timer
+	if (ud->target || ud->attacktimer != INVALID_TIMER)
+		unit_stop_attack(bl);
+
 	//Clear stepaction even if there is no timer
 	if (ud->stepaction || ud->steptimer != INVALID_TIMER)
 		unit_stop_stepaction(bl);

+ 2 - 2
src/map/unit.h

@@ -107,7 +107,7 @@ bool unit_can_reach_pos(struct block_list *bl,int x,int y,int easy);
 bool unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int easy, short *x, short *y);
 
 // Unit attack functions
-int unit_stop_attack(struct block_list *bl);
+void unit_stop_attack(struct block_list *bl);
 int unit_attack(struct block_list *src,int target_id,int continuous);
 int unit_cancel_combo(struct block_list *bl);
 
@@ -119,7 +119,7 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, ui
 
 // Step timer used for delayed attack and skill use
 int unit_step_timer(int tid, unsigned int tick, int id, intptr_t data);
-int unit_stop_stepaction(struct block_list *bl);
+void unit_stop_stepaction(struct block_list *bl);
 
 // Cancel unit cast
 int unit_skillcastcancel(struct block_list *bl, char type);