Преглед на файлове

Fixes monster escape AI issues (#7927)

* Fixes #7904 and fixes #7916.
* Resolves NPC_RUN and NPC_RANDOMMOVE monsters not always reaching their intended escape distance.
* Resolves Marine Sphere calling the run skill too early resulting in the distance escaped not always being the same.
* Resolves Wink of Charm not forcing the target to fail skill use on the caster.
* Renames the monster alchemist state to can_escape to fit multiple uses.
Thanks to @Leemonn and @Lemongrass3110!
Aleos преди 1 година
родител
ревизия
442cf87fcc
променени са 5 файла, в които са добавени 12 реда и са изтрити 6 реда
  1. 2 3
      src/map/mob.cpp
  2. 1 1
      src/map/mob.hpp
  3. 1 0
      src/map/skill.cpp
  4. 2 1
      src/map/status.cpp
  5. 6 1
      src/map/unit.cpp

+ 2 - 3
src/map/mob.cpp

@@ -2417,8 +2417,7 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
 void mob_damage(struct mob_data *md, struct block_list *src, int damage)
 {
 	if( src != nullptr && md->special_state.ai == AI_SPHERE && !md->dmglog[0].id ) {//LOne WOlf explained that ANYONE can trigger the marine countdown skill. [Skotlex]
-		md->state.alchemist = 1;
-		mobskill_use(md, gettick(), MSC_ALCHEMIST);
+		md->state.can_escape = 1;
 	}
 
 	if (src && damage > 0) { //Store total damage...
@@ -3828,7 +3827,7 @@ int mobskill_use(struct mob_data *md, t_tick tick, int event, int64 damage)
 				case MSC_MASTERATTACKED:
 					flag = (md->master_id > 0 && (fbl=map_id2bl(md->master_id)) && unit_counttargeted(fbl) > 0); break;
 				case MSC_ALCHEMIST:
-					flag = (md->state.alchemist); break;
+					flag = (md->state.can_escape); break;
 				case MSC_MOBNEARBYGT:
 					flag = (map_foreachinallrange(mob_count_sub, &md->bl, AREA_SIZE, BL_MOB) > c2 ); break;
 			}

+ 1 - 1
src/map/mob.hpp

@@ -331,7 +331,7 @@ struct mob_data {
 		unsigned int aggressive : 1; //Signals whether the mob AI is in aggressive mode or reactive mode. [Skotlex]
 		unsigned int steal_coin_flag : 1;
 		unsigned int soul_change_flag : 1; // Celest
-		unsigned int alchemist: 1;
+		unsigned int can_escape: 1;
 		unsigned int npc_killmonster: 1; //for new killmonster behavior
 		unsigned int rebirth: 1; // NPC_Rebirth used
 		unsigned int boss : 1;

+ 1 - 0
src/map/skill.cpp

@@ -9792,6 +9792,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui
 			block_list* tbl = map_id2bl(md->target_id);
 
 			if (tbl) {
+				md->state.can_escape = 1;
 				mob_unlocktarget(md, tick);
 				unit_escape(src, tbl, skill_lv > 1 ? skill_lv : AREA_SIZE, 2); // Send distance in skill level > 1
 			}

+ 2 - 1
src/map/status.cpp

@@ -2008,8 +2008,9 @@ bool status_check_skilluse(struct block_list *src, struct block_list *target, ui
 			if (wink_target != nullptr) {
 				unit_data *wink_ud = unit_bl2ud(src);
 				if (wink_ud != nullptr && wink_ud->walktimer == INVALID_TIMER)
-					unit_walktobl(src, wink_target, 3, 1);
+					unit_walktobl(src, map_id2bl(sc->getSCE(SC_WINKCHARM)->val2), 3, 1);
 				clif_emotion(src, ET_THROB);
+				return false;
 			} else
 				status_change_end(src, SC_WINKCHARM);
 		}

+ 6 - 1
src/map/unit.cpp

@@ -481,6 +481,11 @@ static TIMER_FUNC(unit_walktoxy_timer)
 		}
 #endif
 
+		// Remove any possible escape states present for mobs once they stopped moving.
+		if (md != nullptr) {
+			md->state.can_escape = 0;
+		}
+
 		ud->state.force_walk = false;
 
 		if (ud->walk_done_event[0]){
@@ -1560,7 +1565,7 @@ int unit_set_walkdelay(struct block_list *bl, t_tick tick, t_tick delay, int typ
 			if (bl->type == BL_MOB) {
 				mob_data *md = BL_CAST(BL_MOB, bl);
 
-				if (md && md->state.alchemist == 1) // Sphere Mine needs to escape, don't stop it
+				if (md && md->state.can_escape == 1) // Mob needs to escape, don't stop it
 					return 0;
 			}
 			unit_stop_walking(bl,4); //Unit might still be moving even though it can't move