void cWolf::TickFollowPlayer() { class cCallback : public cPlayerListCallback { virtual bool Item(cPlayer * a_Player) override { OwnerPos = a_Player->GetPosition(); return false; } public: Vector3d OwnerPos; } Callback; if (m_World->DoWithPlayer(m_OwnerName, Callback)) { // The player is present in the world, follow him: double Distance = (Callback.OwnerPos - GetPosition()).Length(); if (Distance > 20) { Callback.OwnerPos.y = FindFirstNonAirBlockPosition(Callback.OwnerPos.x, Callback.OwnerPos.z); TeleportToCoords(m_World, Callback.OwnerPos.x, Callback.OwnerPos.y, Callback.OwnerPos.z); } else { MoveToPosition(Callback.OwnerPos); } } }
void cMonster::InStateIdle(std::chrono::milliseconds a_Dt) { if (m_IsFollowingPath) { return; // Still getting there } m_IdleInterval += a_Dt; if (m_IdleInterval > std::chrono::seconds(1)) { // At this interval the results are predictable int rem = m_World->GetTickRandomNumber(6) + 1; m_IdleInterval -= std::chrono::seconds(1); // So nothing gets dropped when the server hangs for a few seconds Vector3d Dist; Dist.x = (double)m_World->GetTickRandomNumber(10) - 5; Dist.z = (double)m_World->GetTickRandomNumber(10) - 5; if ((Dist.SqrLength() > 2) && (rem >= 3)) { Vector3d Destination(GetPosX() + Dist.x, 0, GetPosZ() + Dist.z); Destination.y = FindFirstNonAirBlockPosition(Destination.x, Destination.z); MoveToPosition(Destination); } } }
void cMonster::InStateIdle(float a_Dt) { if (m_bMovingToDestination) { return; // Still getting there } m_IdleInterval += a_Dt; if (m_IdleInterval > 1) { // At this interval the results are predictable int rem = m_World->GetTickRandomNumber(6) + 1; m_IdleInterval -= 1; // So nothing gets dropped when the server hangs for a few seconds Vector3d Dist; Dist.x = (double)m_World->GetTickRandomNumber(10) - 5; Dist.z = (double)m_World->GetTickRandomNumber(10) - 5; if ((Dist.SqrLength() > 2) && (rem >= 3)) { Vector3d Destination(GetPosX() + Dist.x, 0, GetPosZ() + Dist.z); int NextHeight = FindFirstNonAirBlockPosition(Destination.x, Destination.z); if (IsNextYPosReachable(NextHeight)) { Destination.y = NextHeight; MoveToPosition(Destination); } } } }
void cWolf::TickFollowPlayer() { Vector3d OwnerPos; bool OwnerFlying; auto Callback = [&](cPlayer & a_Player) { OwnerPos = a_Player.GetPosition(); OwnerFlying = a_Player.IsFlying(); return true; }; if (m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback)) { // The player is present in the world, follow him: double Distance = (OwnerPos - GetPosition()).Length(); if (Distance > 20) { if (!OwnerFlying) { OwnerPos.y = FindFirstNonAirBlockPosition(OwnerPos.x, OwnerPos.z); TeleportToCoords(OwnerPos.x, OwnerPos.y, OwnerPos.z); SetTarget(nullptr); } } if (Distance < 2) { if (GetTarget() == nullptr) { StopMovingToPosition(); } } else { if (GetTarget() == nullptr) { if (!OwnerFlying) { MoveToPosition(OwnerPos); } } } } }
void cMonster::Tick(float a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); if (m_Health <= 0) { // The mob is dead, but we're still animating the "puff" they leave when they die m_DestroyTimer += a_Dt / 1000; if (m_DestroyTimer > 1) { Destroy(true); } return; } if ((m_Target != NULL) && m_Target->IsDestroyed()) m_Target = NULL; // Burning in daylight HandleDaylightBurning(a_Chunk); a_Dt /= 1000; if (m_bMovingToDestination) { if (m_bOnGround) { m_Destination.y = FindFirstNonAirBlockPosition(m_Destination.x, m_Destination.z); if (DoesPosYRequireJump((int)floor(m_Destination.y))) { m_bOnGround = false; AddPosY(1.5); // Jump!! } } Vector3f Distance = m_Destination - GetPosition(); if(!ReachedDestination() && !ReachedFinalDestination()) // If we haven't reached any sort of destination, move { Distance.y = 0; Distance.Normalize(); Distance *= 5; SetSpeedX(Distance.x); SetSpeedZ(Distance.z); if (m_EMState == ESCAPING) { //Runs Faster when escaping :D otherwise they just walk away SetSpeedX (GetSpeedX() * 2.f); SetSpeedZ (GetSpeedZ() * 2.f); } } else { if (ReachedFinalDestination()) // If we have reached the ultimate, final destination, stop pathfinding and attack if appropriate { FinishPathFinding(); } else { TickPathFinding(); // We have reached the next point in our path, calculate another point } } } SetPitchAndYawFromDestination(); HandleFalling(); switch (m_EMState) { case IDLE: { // If enemy passive we ignore checks for player visibility InStateIdle(a_Dt); break; } case CHASING: { // If we do not see a player anymore skip chasing action InStateChasing(a_Dt); break; } case ESCAPING: { InStateEscaping(a_Dt); break; } } // switch (m_EMState) BroadcastMovementUpdate(); }
void cMonster::TickPathFinding() { const int PosX = POSX_TOINT; const int PosY = POSY_TOINT; const int PosZ = POSZ_TOINT; m_FinalDestination.y = (double)FindFirstNonAirBlockPosition(m_FinalDestination.x, m_FinalDestination.z); std::vector<Vector3d> m_PotentialCoordinates; m_TraversedCoordinates.push_back(Vector3i(PosX, PosY, PosZ)); static const struct // Define which directions to try to move to { int x, z; } gCrossCoords[] = { { 1, 0}, {-1, 0}, { 0, 1}, { 0,-1}, } ; if ((PosY - 1 < 0) || (PosY + 2 > cChunkDef::Height) /* PosY + 1 will never be true if PosY + 2 is not */) { // Too low/high, can't really do anything FinishPathFinding(); return; } for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) { if (IsCoordinateInTraversedList(Vector3i(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ))) { continue; } BLOCKTYPE BlockAtY = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ); BLOCKTYPE BlockAtYP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 1, gCrossCoords[i].z + PosZ); BLOCKTYPE BlockAtYPP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 2, gCrossCoords[i].z + PosZ); int LowestY = FindFirstNonAirBlockPosition(gCrossCoords[i].x + PosX, gCrossCoords[i].z + PosZ); BLOCKTYPE BlockAtLowestY = m_World->GetBlock(gCrossCoords[i].x + PosX, LowestY, gCrossCoords[i].z + PosZ); if ( (!cBlockInfo::IsSolid(BlockAtY)) && (!cBlockInfo::IsSolid(BlockAtYP)) && (!IsBlockLava(BlockAtLowestY)) && (BlockAtLowestY != E_BLOCK_CACTUS) && (PosY - LowestY < FALL_DAMAGE_HEIGHT) ) { m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY, gCrossCoords[i].z + PosZ)); } else if ( (cBlockInfo::IsSolid(BlockAtY)) && (BlockAtY != E_BLOCK_CACTUS) && (!cBlockInfo::IsSolid(BlockAtYP)) && (!cBlockInfo::IsSolid(BlockAtYPP)) && (BlockAtY != E_BLOCK_FENCE) && (BlockAtY != E_BLOCK_FENCE_GATE) ) { m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY + 1, gCrossCoords[i].z + PosZ)); } } if (!m_PotentialCoordinates.empty()) { Vector3f ShortestCoords = m_PotentialCoordinates.front(); for (std::vector<Vector3d>::const_iterator itr = m_PotentialCoordinates.begin(); itr != m_PotentialCoordinates.end(); ++itr) { Vector3f Distance = m_FinalDestination - ShortestCoords; Vector3f Distance2 = m_FinalDestination - *itr; if (Distance.SqrLength() > Distance2.SqrLength()) { ShortestCoords = *itr; } } m_Destination = ShortestCoords; m_Destination.z += 0.5f; m_Destination.x += 0.5f; } else { FinishPathFinding(); } }
void cMonster::TickPathFinding() { int PosX = (int)floor(GetPosX()); int PosY = (int)floor(GetPosY()); int PosZ = (int)floor(GetPosZ()); m_FinalDestination.y = (double)FindFirstNonAirBlockPosition(m_FinalDestination.x, m_FinalDestination.z); std::vector<Vector3d> m_PotentialCoordinates; m_TraversedCoordinates.push_back(Vector3i(PosX, PosY, PosZ)); static const struct // Define which directions to try to move to { int x, z; } gCrossCoords[] = { { 1, 0}, {-1, 0}, { 0, 1}, { 0,-1}, } ; for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) { if ((gCrossCoords[i].x + PosX == PosX) && (gCrossCoords[i].z + PosZ == PosZ)) { continue; } if (IsCoordinateInTraversedList(Vector3i(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ))) { continue; } BLOCKTYPE BlockAtY = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ); BLOCKTYPE BlockAtYP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 1, gCrossCoords[i].z + PosZ); BLOCKTYPE BlockAtYPP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 2, gCrossCoords[i].z + PosZ); BLOCKTYPE BlockAtYM = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY - 1, gCrossCoords[i].z + PosZ); if ((!g_BlockIsSolid[BlockAtY]) && (!g_BlockIsSolid[BlockAtYP]) && (!IsBlockLava(BlockAtYM)) && (BlockAtY != E_BLOCK_FENCE) && (BlockAtY != E_BLOCK_FENCE_GATE)) { m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY, gCrossCoords[i].z + PosZ)); } else if ((g_BlockIsSolid[BlockAtY]) && (!g_BlockIsSolid[BlockAtYP]) && (!g_BlockIsSolid[BlockAtYPP]) && (!IsBlockLava(BlockAtYM)) && (BlockAtY != E_BLOCK_FENCE) && (BlockAtY != E_BLOCK_FENCE_GATE)) { m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY + 1, gCrossCoords[i].z + PosZ)); } } if (!m_PotentialCoordinates.empty()) { Vector3f ShortestCoords = m_PotentialCoordinates.front(); for (std::vector<Vector3d>::const_iterator itr = m_PotentialCoordinates.begin(); itr != m_PotentialCoordinates.end(); ++itr) { Vector3f Distance = m_FinalDestination - ShortestCoords; Vector3f Distance2 = m_FinalDestination - *itr; if (Distance.SqrLength() > Distance2.SqrLength()) { ShortestCoords = *itr; } } m_Destination = ShortestCoords; m_Destination.z += 0.5f; m_Destination.x += 0.5f; } else { FinishPathFinding(); } }