Browse Source

Support for flying mobs (InitialState = 49156), runback also supports original gridid for NPC

Fix #78
- Flying mobs only follow pathing when Line of Sight is not established, otherwise they 'free float'
- The runback logic needs to keep the original gridid for NPCs in case they don't properly 'reset'
- In the same respect flying mobs do NOT change their gridid, this causes their return to ghost out of visual sight.  Keeping gridid static keeps NPC visual.
Image 4 years ago
parent
commit
a17c7915ee

+ 15 - 4
EQ2/source/WorldServer/NPC.cpp

@@ -161,12 +161,13 @@ void NPC::SetSpells(vector<Spell*>* in_spells){
 	spells = in_spells;
 }
 
-void NPC::SetRunbackLocation(float x, float y, float z){
+void NPC::SetRunbackLocation(float x, float y, float z, int32 gridid){
 	safe_delete(runback);
 	runback = new MovementLocation;
 	runback->x = x;
 	runback->y = y;
 	runback->z = z;
+	runback->gridid = gridid;
 }
 
 MovementLocation* NPC::GetRunbackLocation(){
@@ -188,9 +189,19 @@ void NPC::Runback(){
 	}
 
 	m_runningBack = true;
-	FaceTarget(runback->x, runback->z);
 	SetSpeed(GetMaxSpeed()*2);
-	GetZone()->movementMgr->NavigateTo((Entity*)this, runback->x, runback->y, runback->z);
+
+	if (GetInitialState() == 49156 && CheckLoS(glm::vec3(runback->x, runback->z, runback->y + 1.0f), glm::vec3(GetX(), GetZ(), GetY() + 1.0f)))
+	{
+		FaceTarget(runback->x, runback->z);
+		ClearRunningLocations();
+		GetZone()->movementMgr->DisruptNavigation((Entity*)this);
+		if (GetRunbackLocation()->gridid > 0)
+			SetLocation(GetRunbackLocation()->gridid);
+		AddRunningLocation(runback->x, runback->y, runback->z, GetSpeed(), 0, true, true, "", true);
+	}
+	else
+		GetZone()->movementMgr->NavigateTo((Entity*)this, runback->x, runback->y, runback->z);
 
 	//AddRunningLocation(runback->x, runback->y, runback->z, GetSpeed(), 0, false);	
 	last_movement_update = Timer::GetCurrentTime2();
@@ -237,7 +248,7 @@ void NPC::InCombat(bool val){
 	if(val){
 		// if not a pet and no current run back location set then set one to the current location
 		if(!IsPet() && !GetRunbackLocation()) {
-			SetRunbackLocation(GetX(), GetY(), GetZ());
+			SetRunbackLocation(GetX(), GetY(), GetZ(), GetLocation());
 			m_runbackHeading = appearance.pos.Dir1;
 		}
 	}

+ 1 - 1
EQ2/source/WorldServer/NPC.h

@@ -110,7 +110,7 @@ public:
 	int8	GetCastPercentage();
 	void	SetSkills(map<string, Skill*>* in_skills);
 	void	SetSpells(vector<Spell*>* in_spells);
-	void	SetRunbackLocation(float x, float y, float z);
+	void	SetRunbackLocation(float x, float y, float z, int32 gridid);
 	MovementLocation* GetRunbackLocation();
 	float	GetRunbackDistance();
 	void	Runback();

+ 2 - 0
EQ2/source/WorldServer/NPC_AI.cpp

@@ -135,6 +135,8 @@ void Brain::Think() {
 				m_body->SetX(m_body->GetRunbackLocation()->x,false);
 				m_body->SetZ(m_body->GetRunbackLocation()->z,false);
 				m_body->SetY(m_body->GetRunbackLocation()->y,true);
+				if (m_body->GetRunbackLocation()->gridid > 0)
+					m_body->SetLocation(m_body->GetRunbackLocation()->gridid);
 				m_body->ClearRunback();
 				m_body->GetZone()->movementMgr->StopNavigation((Entity*)m_body);
 				m_body->ClearRunningLocations();

+ 31 - 6
EQ2/source/WorldServer/Spawn.cpp

@@ -2054,7 +2054,14 @@ void Spawn::MoveToLocation(Spawn* spawn, float distance, bool immediate, bool ma
 
 	if (!IsPlayer() && distance > 0.0f)
 	{
-		if (/*!mapped && */GetZone())
+		if (GetInitialState() == 49156 && CheckLoS(spawn))
+		{
+			if (immediate)
+				ClearRunningLocations();
+
+			AddRunningLocation(spawn->GetX(), spawn->GetY(), spawn->GetZ(), GetSpeed(), distance, true, true, "", true);
+		}
+		else if (/*!mapped && */GetZone())
 		{
 			GetZone()->movementMgr->NavigateTo((Entity*)this, spawn->GetX(), spawn->GetY(), spawn->GetZ());
 			last_grid_update = Timer::GetCurrentTime2();
@@ -2178,6 +2185,17 @@ void Spawn::ProcessMovement(bool isSpawnListLocked){
 				// If this waypoint had a lua function then call it
 				if(data->lua_function.length() > 0)
 					GetZone()->CallSpawnScript(this, SPAWN_SCRIPT_CUSTOM, 0, data->lua_function.c_str());
+
+				int16 nextMove;
+				if ((int16)(movement_index + 1) < movement_loop.size())
+					nextMove = movement_index + 1;
+				else
+					nextMove = 0;
+				// Get the next target location
+				data = movement_loop[nextMove];
+				
+				//Go ahead and face the next location
+				FaceTarget(data->x, data->z);
 			}
 			// If this waypoint has no delay or we have waited the required time (current time >= delay + movement_start_time)
 			else if(data->delay == 0 || (data->delay > 0 && Timer::GetCurrentTime2() >= (data->delay+movement_start_time))) {
@@ -2237,13 +2255,13 @@ void Spawn::ProcessMovement(bool isSpawnListLocked){
 	else if (IsRunning()) {
 		CalculateRunningLocation();
 	}
-	else if (IsNPC() && !IsRunning() && !EngagedInCombat() && ((NPC*)this)->GetRunbackLocation()) {
+	/*else if (IsNPC() && !IsRunning() && !EngagedInCombat() && ((NPC*)this)->GetRunbackLocation()) {
 		// Is an npc that is not moving and not engaged in combat but has a run back location set then clear the runback location
 		LogWrite(NPC_AI__DEBUG, 7, "NPC_AI", "Clear runback location for %s", GetName());
 		((NPC*)this)->ClearRunback();
 		resume_movement = true;
 		NeedsToResumeMovement(false);
-	}
+	}*/
 	MMovementLoop.unlock();
 }
 
@@ -2349,6 +2367,8 @@ void Spawn::AddRunningLocation(float x, float y, float z, float speed, float dis
 	data->speed = speed;
 	data->attackable = attackable;
 	data->lua_function = lua_function;
+	data->gridid = 0; // used for runback defaults
+
 	MMovementLocations->writelock(__FUNCTION__, __LINE__);
 	if(movement_locations->size() > 0)
 		current_location = movement_locations->back();
@@ -2461,7 +2481,7 @@ bool Spawn::CalculateChange(){
 				}
 
 				int32 newGrid = GetZone()->Grid->GetGridID(this);
-				if (newGrid != 0 && newGrid != appearance.pos.grid_id)
+				if (GetInitialState() != 49156 && newGrid != 0 && newGrid != appearance.pos.grid_id)
 					SetPos(&(appearance.pos.grid_id), newGrid);
 			}
 		}
@@ -2499,7 +2519,12 @@ void Spawn::CalculateRunningLocation(bool stop){
 	else if (GetZone() && GetTarget() != NULL && EngagedInCombat())
 	{
 		if (GetDistance(GetTarget()) > rule_manager.GetGlobalRule(R_Combat, MaxCombatRange)->GetFloat())
-			GetZone()->movementMgr->NavigateTo((Entity*)this, GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ());
+		{
+			if (GetInitialState() == 49156 && CheckLoS(GetTarget()))
+				AddRunningLocation(GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ(), GetSpeed(), 0, false);
+			else
+				GetZone()->movementMgr->NavigateTo((Entity*)this, GetTarget()->GetX(), GetTarget()->GetY(), GetTarget()->GetZ());
+		}
 		else
 			GetZone()->movementMgr->StopNavigation((Entity*)this);
 	} 
@@ -2951,7 +2976,7 @@ float Spawn::GetFixedZ(const glm::vec3& destination, int32 z_find_offset) {
 
 
 void Spawn::FixZ(int32 z_find_offset /*= 1*/, bool fix_client_z /*= false*/) {
-	if (IsPlayer() && !fix_client_z) {
+	if (IsPlayer() && !fix_client_z || (this->GetInitialState() == 49156)) {
 		return;
 	}
 	/*

+ 1 - 0
EQ2/source/WorldServer/Spawn.h

@@ -192,6 +192,7 @@ struct MovementLocation{
 	bool	attackable;
 	string	lua_function;
 	bool	mapped;
+	int32	gridid;
 };
 
 struct SpawnUpdate {

+ 20 - 0
EQ2/source/WorldServer/Zone/mob_movement_manager.cpp

@@ -723,6 +723,26 @@ void MobMovementManager::StopNavigation(Entity *who)
 	MobListMutex.releasereadlock();
 }
 
+void MobMovementManager::DisruptNavigation(Entity* who)
+{
+	MobListMutex.readlock();
+	auto iter = _impl->Entries.find(who);
+	auto& ent = (*iter);
+	auto& nav = ent.second.NavTo;
+
+	nav.navigate_to_x = 0.0;
+	nav.navigate_to_y = 0.0;
+	nav.navigate_to_z = 0.0;
+	nav.navigate_to_heading = 0.0;
+	nav.last_set_time = 0.0;
+
+	if (!who->IsRunning()) {
+		ent.second.Commands.clear();
+		MobListMutex.releasereadlock();
+		return;
+	}
+}
+
 /**
  * @param in
  * @return

+ 1 - 0
EQ2/source/WorldServer/Zone/mob_movement_manager.h

@@ -51,6 +51,7 @@ public:
 	void Teleport(Entity *who, float x, float y, float z, float heading);
 	void NavigateTo(Entity *who, float x, float y, float z, MobMovementMode mode = MovementRunning, bool overrideDistance=false);
 	void StopNavigation(Entity *who);
+	void DisruptNavigation(Entity* who);
 	/*
 	void SendCommandToClients(
 		Entity *mob,