Просмотр исходного кода

Monster behavior when hiding (#8778)

- Monsters will now cast skills in berserk state when they are hiding and a target is in attack range
- Monsters will now switch to berserk state (losing angry mode) when they search for a target and find a new one that is already in attack range
- Fixes #8774
Playtester 6 месяцев назад
Родитель
Сommit
c21aec4492
1 измененных файлов с 37 добавлено и 15 удалено
  1. 37 15
      src/map/mob.cpp

+ 37 - 15
src/map/mob.cpp

@@ -1858,7 +1858,14 @@ static bool mob_ai_sub_hard(struct mob_data *md, t_tick tick)
 
 	if ((mode&MD_AGGRESSIVE && (!tbl || slave_lost_target)) || md->state.skillstate == MSS_FOLLOW)
 	{
+		int32 prev_id = md->target_id;
 		map_foreachinallrange (mob_ai_sub_hard_activesearch, &md->bl, view_range, DEFAULT_ENEMY_TYPE(md), md, &tbl, mode);
+		// If a monster finds a target through search that is already in attack range it immediately switches to berserk mode
+		// This behavior overrides even angry mode and other mode-specific behavior
+		if (tbl != nullptr && prev_id != md->target_id && battle_check_range(&md->bl, tbl, md->status.rhw.range)) {
+			md->state.aggressive = 0;
+			md->state.skillstate = MSS_BERSERK;
+		}
 	}
 	else
 	if (mode&MD_CHANGECHASE && (md->state.skillstate == MSS_RUSH || md->state.skillstate == MSS_FOLLOW))
@@ -1961,24 +1968,39 @@ static bool mob_ai_sub_hard(struct mob_data *md, t_tick tick)
 	}
 
 	// Normal attack / berserk skill is only used when target is in range
-	if (battle_check_range(&md->bl, tbl, md->status.rhw.range) && !(md->sc.option&OPTION_HIDE))
-	{	//Target within range and able to use normal attack, engage
-		if (md->ud.target != tbl->id || md->ud.attacktimer == INVALID_TIMER) 
-		{ //Only attack if no more attack delay left
-			if(tbl->type == BL_PC)
-				mob_log_damage(md, tbl, 0); //Log interaction (counts as 'attacker' for the exp bonus)
-
-			if( !(mode&MD_RANDOMTARGET) )
-				unit_attack(&md->bl,tbl->id,1);
-			else { // Attack once and find a new random target
-				int search_size = (view_range < md->status.rhw.range) ? view_range : md->status.rhw.range;
-				unit_attack(&md->bl, tbl->id, 0);
-				if ((tbl = battle_getenemy(&md->bl, DEFAULT_ENEMY_TYPE(md), search_size))) {
-					md->target_id = tbl->id;
-					md->min_chase = md->db->range3;
+	if (battle_check_range(&md->bl, tbl, md->status.rhw.range))
+	{
+		// Hiding is a special case because it prevents normal attacks but allows skill usage
+		// TODO: Some other states also have this behavior and should be investigated (e.g. NPC_SR_CURSEDCIRCLE)
+		if (!(md->sc.option&OPTION_HIDE)) {
+			// Target within range and potentially able to use normal attack, engage
+			if (md->ud.target != tbl->id || md->ud.attacktimer == INVALID_TIMER)
+			{ //Only attack if no more attack delay left
+				if (tbl->type == BL_PC)
+					mob_log_damage(md, tbl, 0); //Log interaction (counts as 'attacker' for the exp bonus)
+
+				if (!(mode&MD_RANDOMTARGET))
+					unit_attack(&md->bl,tbl->id,1);
+				else { // Attack once and find a new random target
+					int search_size = (view_range < md->status.rhw.range) ? view_range : md->status.rhw.range;
+					unit_attack(&md->bl, tbl->id, 0);
+					tbl = battle_getenemy(&md->bl, DEFAULT_ENEMY_TYPE(md), search_size);
+					if (tbl != nullptr) {
+						md->target_id = tbl->id;
+						md->min_chase = md->db->range3;
+					}
 				}
 			}
 		}
+		else if (md->state.skillstate == MSS_BERSERK && DIFF_TICK(md->ud.attackabletime, tick) <= 0) {
+			// Target within range and no attack delay, but unable to use normal attack, check for skill
+			// On official servers this check happens every 20ms
+			// If you want fully official behavior you will need to set MIN_MOBTHINKTIME to 20
+			if (mobskill_use(md, tick, -1)) {
+				// When a skill was used, the attack delay is applied
+				md->ud.attackabletime = tick + md->status.adelay;
+			}
+		}
 		return true;
 	}