Browse Source

Fix runback

Fix #212
Image 3 years ago
parent
commit
6be433e3c2

+ 17 - 11
EQ2/source/WorldServer/NPC.cpp

@@ -136,7 +136,7 @@ void NPC::Initialize(){
 	m_brain = new ::Brain(this);
 	MBrain.SetName("NPC::m_brain");
 	m_runningBack = false;
-	m_runbackHeading = 0;
+	m_runbackHeadingDir1 = m_runbackHeadingDir2 = 0;
 	following = false;
 	SetFollowTarget(0);
 	m_petDismissing = false;
@@ -172,6 +172,7 @@ void NPC::SetRunbackLocation(float x, float y, float z, int32 gridid){
 	runback->y = y;
 	runback->z = z;
 	runback->gridid = gridid;
+	runback->stage = 0;
 }
 
 MovementLocation* NPC::GetRunbackLocation(){
@@ -184,7 +185,10 @@ float NPC::GetRunbackDistance(){
 	return GetDistance(runback->x, runback->y, runback->z);
 }
 
-void NPC::Runback(){
+void NPC::Runback(float distance){
+	if ( distance == 0.0f )
+		distance = GetRunbackDistance(); // gotta make sure its true, lua doesn't send the distance
+	
 	following = false;
 	if (!m_runningBack)
 	{
@@ -195,7 +199,7 @@ void NPC::Runback(){
 	m_runningBack = true;
 	SetSpeed(GetMaxSpeed()*2);
 
-	if ((IsFlyingCreature() || IsWaterCreature()) && CheckLoS(glm::vec3(runback->x, runback->z, runback->y + 1.0f), glm::vec3(GetX(), GetZ(), GetY() + 1.0f)))
+	if (CheckLoS(glm::vec3(runback->x, runback->z, runback->y + 1.0f), glm::vec3(GetX(), GetZ(), GetY() + 1.0f)))
 	{
 		FaceTarget(runback->x, runback->z);
 		ClearRunningLocations();
@@ -214,7 +218,7 @@ void NPC::Runback(){
 void NPC::ClearRunback(){
 	safe_delete(runback);
 	m_runningBack = false;
-	m_runbackHeading = 0;
+	m_runbackHeadingDir1 = m_runbackHeadingDir2 = 0;
 	resume_movement = true;
 	NeedsToResumeMovement(false);
 }
@@ -228,6 +232,15 @@ void NPC::InCombat(bool val){
 		GetZone()->CallSpawnScript(this, SPAWN_SCRIPT_ATTACKED, GetTarget());
 		SetTempActionState(0); // disable action states in combat
 	}
+	if(!in_combat && 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(), GetLocation());
+			m_runbackHeadingDir1 = appearance.pos.Dir1;
+			m_runbackHeadingDir2 = appearance.pos.Dir2;
+		}
+	}
+
 	in_combat = val;
 	if(val){
 		LogWrite(NPC__DEBUG, 3, "NPC", "'%s' engaged in combat with '%s'", this->GetName(), ( GetTarget() ) ? GetTarget()->GetName() : "Unknown" );
@@ -250,13 +263,6 @@ void NPC::InCombat(bool val){
 	if(!MovementInterrupted() && val && GetSpeed() > 0 && movement_loop.size() > 0){
 		CalculateRunningLocation(true);
 	}
-	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(), GetLocation());
-			m_runbackHeading = appearance.pos.Dir1;
-		}
-	}
 	MovementInterrupted(val);
 }
 

+ 3 - 2
EQ2/source/WorldServer/NPC.h

@@ -114,7 +114,7 @@ public:
 	void	SetRunbackLocation(float x, float y, float z, int32 gridid);
 	MovementLocation* GetRunbackLocation();
 	float	GetRunbackDistance();
-	void	Runback();
+	void	Runback(float distance=0.0f);
 	void	ClearRunback();
 	void	AddSkillBonus(int32 spell_id, int32 skill_id, float value);
 	virtual void RemoveSkillBonus(int32 spell_id);
@@ -140,7 +140,8 @@ public:
 	/// <returns>The Brain this NPC uses</returns>
 	::Brain* Brain() { return m_brain; }
 	bool m_runningBack;
-	sint16 m_runbackHeading;
+	sint16 m_runbackHeadingDir1;
+	sint16 m_runbackHeadingDir2;
 
 	bool IsDismissing() { return m_petDismissing; }
 	void SetDismissing(bool val) { m_petDismissing = val; }

+ 33 - 13
EQ2/source/WorldServer/NPC_AI.cpp

@@ -131,19 +131,39 @@ void Brain::Think() {
 			CheckBuffs();
 
 			// If run back distance is greater then 0 then run back
-			if ((wasInCombat || m_body->m_runningBack) && run_back_distance > 1) {
-				m_body->Runback();
-			}
-			else if (m_body->m_runningBack)
+			if(!m_body->EngagedInCombat())
 			{
-				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();
+				if (run_back_distance > 1) {
+					m_body->Runback(run_back_distance);
+				}
+				else if (m_body->GetRunbackLocation())
+				{
+					switch(m_body->GetRunbackLocation()->stage)
+					{
+						case 0:
+							m_body->GetZone()->movementMgr->StopNavigation((Entity*)m_body);
+							m_body->ClearRunningLocations();
+							m_body->SetX(m_body->GetRunbackLocation()->x,false);
+							m_body->SetZ(m_body->GetRunbackLocation()->z,false);
+							m_body->SetY(m_body->GetRunbackLocation()->y,false);
+							m_body->CalculateRunningLocation(true);
+							m_body->GetRunbackLocation()->stage = 1;
+							m_body->GetZone()->AddChangedSpawn(m_body);
+							break;
+						case 6: // artificially 1500ms per 250ms Think() call
+							if (m_body->GetRunbackLocation()->gridid > 0)
+								m_body->SetLocation(m_body->GetRunbackLocation()->gridid);
+							m_body->SetHeading(m_body->m_runbackHeadingDir1,m_body->m_runbackHeadingDir2,false);
+							m_body->ClearRunback();
+							m_body->SetHP(m_body->GetTotalHP());
+							m_body->GetZone()->AddChangedSpawn(m_body);
+						break;
+						default: // captures case 1 up to case 5 to turn around / reset hp
+                                                        m_body->GetRunbackLocation()->stage++; // artificially delay
+							break;
+
+					}
+				}
 			}
 			// If encounter size is greater then 0 then clear it
 			if (GetEncounterSize() > 0)
@@ -658,4 +678,4 @@ void DumbFirePetBrain::Think() {
 			LogWrite(NPC_AI__DEBUG, 7, "NPC AI", "Dumbfire being killed because timer expired.");
 		}
 	 }
-}
+}

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

@@ -214,6 +214,7 @@ struct MovementLocation{
 	string	lua_function;
 	bool	mapped;
 	int32	gridid;
+	int8	stage;
 };
 
 struct SpawnUpdate {
@@ -795,6 +796,7 @@ public:
 		case 241:
 		case 242:
 		case 254:
+		case 10668:
 		case 20828:
 			is_water_creature = true;
 			break;