diff --git a/src/game/client/components/camera.cpp b/src/game/client/components/camera.cpp index 4837be0ba..69dba64ed 100644 --- a/src/game/client/components/camera.cpp +++ b/src/game/client/components/camera.cpp @@ -3,7 +3,9 @@ #include +#include #include +#include #include #include #include @@ -304,54 +306,54 @@ void CCamera::GotoTele(int Number, int Offset) { if(Collision()->TeleLayer() == nullptr) return; + Number--; + + if(m_GotoTeleLastNumber != Number) + m_GotoTeleLastPos = ivec2(-1, -1); - int Match = -1; ivec2 MatchPos = ivec2(-1, -1); + const size_t NumTeles = Collision()->TeleAllSize(Number); + if(!NumTeles) + { + log_error("camera", "No teleporter with number %d found.", Number + 1); + return; + } - auto FindTile = [this, &Match, &MatchPos, &Number, &Offset]() { - for(int x = 0; x < Collision()->GetWidth(); x++) + if(Offset != -1 || m_GotoTeleLastPos == ivec2(-1, -1)) + { + if((size_t)Offset >= NumTeles || Offset < 0) + Offset = 0; + MatchPos = ivec2(Collision()->TeleAllGet(Number, Offset).x / 32, Collision()->TeleAllGet(Number, Offset).y / 32); + m_GotoTeleOffset = Offset; + } + else + { + bool FullRound = false; + do { - for(int y = 0; y < Collision()->GetHeight(); y++) + MatchPos = ivec2(Collision()->TeleAllGet(Number, m_GotoTeleOffset).x / 32, Collision()->TeleAllGet(Number, m_GotoTeleOffset).y / 32); + m_GotoTeleOffset++; + if((size_t)m_GotoTeleOffset >= NumTeles) { - int i = y * Collision()->GetWidth() + x; - int Tele = Collision()->TeleLayer()[i].m_Number; - if(Number == Tele) + m_GotoTeleOffset = 0; + if(FullRound) { - Match++; - if(Offset != -1) - { - if(Match == Offset) - { - MatchPos = ivec2(x, y); - m_GotoTeleOffset = Match; - return; - } - continue; - } - MatchPos = ivec2(x, y); - if(m_GotoTeleLastPos != ivec2(-1, -1)) - { - if(distance(m_GotoTeleLastPos, MatchPos) < 10.0f) - { - m_GotoTeleOffset++; - continue; - } - } - m_GotoTeleLastPos = MatchPos; - if(Match == m_GotoTeleOffset) - return; + MatchPos = m_GotoTeleLastPos; + break; + } + else + { + FullRound = true; } } - } - }; - FindTile(); + } while(distance(m_GotoTeleLastPos, MatchPos) < 10.0f); + } if(MatchPos == ivec2(-1, -1)) return; - if(Match < m_GotoTeleOffset) - m_GotoTeleOffset = -1; + m_GotoTeleLastPos = MatchPos; + m_GotoTeleLastNumber = Number; SetView(MatchPos); - m_GotoTeleOffset++; } void CCamera::SetZoom(float Target, int Smoothness) diff --git a/src/game/client/components/camera.h b/src/game/client/components/camera.h index ae8798d86..067e8367f 100644 --- a/src/game/client/components/camera.h +++ b/src/game/client/components/camera.h @@ -72,6 +72,7 @@ private: int m_GotoTeleOffset; ivec2 m_GotoSwitchLastPos; ivec2 m_GotoTeleLastPos; + int m_GotoTeleLastNumber = -1; }; #endif diff --git a/src/game/collision.h b/src/game/collision.h index 0d24ee96b..0bc94b88f 100644 --- a/src/game/collision.h +++ b/src/game/collision.h @@ -113,6 +113,54 @@ public: class CLayers *Layers() { return m_pLayers; } int m_HighestSwitchNumber; + // Index all teleporter types (in, out and checkpoints) + // as one consecutive list + // + // @param Number is the teleporter number (one less than what is shown in game) + // @param Offset picks the n'th occurence of that teleporter in the map + // + // @return The coordinates of the teleporter in the map + // or (-1, -1) if not found + vec2 TeleAllGet(int Number, size_t Offset) + { + if(m_TeleIns.count(Number) > 0) + { + if(m_TeleIns[Number].size() > Offset) + return m_TeleIns[Number][Offset]; + else + Offset -= m_TeleIns[Number].size(); + } + if(m_TeleOuts.count(Number) > 0) + { + if(m_TeleOuts[Number].size() > Offset) + return m_TeleOuts[Number][Offset]; + else + Offset -= m_TeleOuts[Number].size(); + } + if(m_TeleCheckOuts.count(Number) > 0) + { + if(m_TeleCheckOuts[Number].size() > Offset) + return m_TeleCheckOuts[Number][Offset]; + else + Offset -= m_TeleCheckOuts[Number].size(); + } + return vec2(-1, -1); + } + + // @param Number is the teleporter number (one less than what is shown in game) + // @return The amount of occurences of that teleporter across all types (in, out, checkpoint) + size_t TeleAllSize(int Number) + { + size_t Total = 0; + if(m_TeleIns.count(Number) > 0) + Total += m_TeleIns[Number].size(); + if(m_TeleOuts.count(Number) > 0) + Total += m_TeleOuts[Number].size(); + if(m_TeleCheckOuts.count(Number) > 0) + Total += m_TeleCheckOuts[Number].size(); + return Total; + } + const std::vector &TeleIns(int Number) { return m_TeleIns[Number]; } const std::vector &TeleOuts(int Number) { return m_TeleOuts[Number]; } const std::vector &TeleCheckOuts(int Number) { return m_TeleCheckOuts[Number]; }