Merge pull request #8338 from ChillerDragon/pr_goto_tele_refactor

Fix `goto_tele` not finding all teleporters
This commit is contained in:
Robert Müller 2024-06-02 08:47:30 +00:00 committed by GitHub
commit 6cfe54b9c5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 115 additions and 36 deletions

View file

@ -3,7 +3,9 @@
#include <engine/shared/config.h>
#include <base/log.h>
#include <base/math.h>
#include <base/vmath.h>
#include <game/client/gameclient.h>
#include <game/collision.h>
#include <game/mapitems.h>
@ -319,54 +321,56 @@ 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;
vec2 Tele = Collision()->TeleAllGet(Number, Offset);
MatchPos = ivec2(Tele.x / 32, Tele.y / 32);
m_GotoTeleOffset = Offset;
}
else
{
bool FullRound = false;
do
{
for(int y = 0; y < Collision()->GetHeight(); y++)
vec2 Tele = Collision()->TeleAllGet(Number, m_GotoTeleOffset);
MatchPos = ivec2(Tele.x / 32, Tele.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)

View file

@ -74,6 +74,7 @@ private:
int m_GotoTeleOffset;
ivec2 m_GotoSwitchLastPos;
ivec2 m_GotoTeleLastPos;
int m_GotoTeleLastNumber = -1;
};
#endif

View file

@ -139,6 +139,10 @@ void CCollision::Init(class CLayers *pLayers)
{
m_TeleCheckOuts[Number - 1].emplace_back(i % m_Width * 32.0f + 16.0f, i / m_Width * 32.0f + 16.0f);
}
else if(Type)
{
m_TeleOthers[Number - 1].emplace_back(i % m_Width * 32.0f + 16.0f, i / m_Width * 32.0f + 16.0f);
}
}
}
}
@ -156,6 +160,7 @@ void CCollision::Unload()
m_TeleIns.clear();
m_TeleOuts.clear();
m_TeleCheckOuts.clear();
m_TeleOthers.clear();
m_pTele = nullptr;
m_pSpeedup = nullptr;
@ -1260,3 +1265,48 @@ int CCollision::IsFTimeCheckpoint(int Index) const
return z - TILE_TIME_CHECKPOINT_FIRST;
return -1;
}
vec2 CCollision::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();
}
if(m_TeleOthers.count(Number) > 0)
{
if(m_TeleOthers[Number].size() > Offset)
return m_TeleOthers[Number][Offset];
}
return vec2(-1, -1);
}
size_t CCollision::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();
if(m_TeleOthers.count(Number) > 0)
Total += m_TeleOthers[Number].size();
return Total;
}

View file

@ -113,9 +113,28 @@ 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);
/**
* @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);
const std::vector<vec2> &TeleIns(int Number) { return m_TeleIns[Number]; }
const std::vector<vec2> &TeleOuts(int Number) { return m_TeleOuts[Number]; }
const std::vector<vec2> &TeleCheckOuts(int Number) { return m_TeleCheckOuts[Number]; }
const std::vector<vec2> &TeleOthers(int Number) { return m_TeleOthers[Number]; }
private:
class CTile *m_pTiles;
@ -123,9 +142,14 @@ private:
int m_Height;
class CLayers *m_pLayers;
// TILE_TELEIN
std::map<int, std::vector<vec2>> m_TeleIns;
// TILE_TELEOUT
std::map<int, std::vector<vec2>> m_TeleOuts;
// TILE_TELECHECKOUT
std::map<int, std::vector<vec2>> m_TeleCheckOuts;
// TILE_TELEINEVIL, TILE_TELECHECK, TILE_TELECHECKIN, TILE_TELECHECKINEVIL
std::map<int, std::vector<vec2>> m_TeleOthers;
class CTeleTile *m_pTele;
class CSpeedupTile *m_pSpeedup;