1#include "race.h"
2
3#include <game/client/gameclient.h>
4#include <game/collision.h>
5#include <game/mapitems.h>
6
7#include <cctype>
8#include <vector>
9
10void CRaceHelper::Init(const CGameClient *pGameClient)
11{
12 m_pGameClient = pGameClient;
13
14 m_aFlagIndex[TEAM_RED] = -1;
15 m_aFlagIndex[TEAM_BLUE] = -1;
16
17 const CTile *pGameTiles = m_pGameClient->Collision()->GameLayer();
18 const int MapSize = m_pGameClient->Collision()->GetWidth() * m_pGameClient->Collision()->GetHeight();
19 for(int Index = 0; Index < MapSize; Index++)
20 {
21 const int EntityIndex = pGameTiles[Index].m_Index - ENTITY_OFFSET;
22 if(EntityIndex == ENTITY_FLAGSTAND_RED)
23 {
24 m_aFlagIndex[TEAM_RED] = Index;
25 if(m_aFlagIndex[TEAM_BLUE] != -1)
26 break; // Found both flags
27 }
28 else if(EntityIndex == ENTITY_FLAGSTAND_BLUE)
29 {
30 m_aFlagIndex[TEAM_BLUE] = Index;
31 if(m_aFlagIndex[TEAM_RED] != -1)
32 break; // Found both flags
33 }
34 Index += pGameTiles[Index].m_Skip;
35 }
36}
37
38int CRaceHelper::TimeFromSecondsStr(const char *pStr)
39{
40 while(*pStr == ' ') // skip leading spaces
41 pStr++;
42 if(!isdigit(*pStr))
43 return -1;
44 int Time = str_toint(str: pStr) * 1000;
45 while(isdigit(*pStr))
46 pStr++;
47 if(*pStr == '.' || *pStr == ',')
48 {
49 pStr++;
50 static const int s_aMult[3] = {100, 10, 1};
51 for(size_t i = 0; i < std::size(s_aMult) && isdigit(pStr[i]); i++)
52 Time += (pStr[i] - '0') * s_aMult[i];
53 }
54 return Time;
55}
56
57int CRaceHelper::TimeFromStr(const char *pStr)
58{
59 static constexpr const char *MINUTES_STR = " minute(s) ";
60 static constexpr const char *SECONDS_STR = " second(s)";
61
62 const char *pSeconds = str_find(haystack: pStr, needle: SECONDS_STR);
63 if(!pSeconds)
64 return -1;
65
66 const char *pMinutes = str_find(haystack: pStr, needle: MINUTES_STR);
67 if(pMinutes)
68 {
69 while(*pStr == ' ') // skip leading spaces
70 pStr++;
71 int SecondsTime = TimeFromSecondsStr(pStr: pMinutes + str_length(str: MINUTES_STR));
72 if(SecondsTime == -1 || !isdigit(*pStr))
73 return -1;
74 return str_toint(str: pStr) * 60 * 1000 + SecondsTime;
75 }
76 else
77 {
78 return TimeFromSecondsStr(pStr);
79 }
80}
81
82int CRaceHelper::TimeFromFinishMessage(const char *pStr, char *pNameBuf, int NameBufSize)
83{
84 static const char *const s_pFinishedStr = " finished in: ";
85 const char *pFinished = str_find(haystack: pStr, needle: s_pFinishedStr);
86 if(!pFinished)
87 return -1;
88
89 int FinishedPos = pFinished - pStr;
90 if(FinishedPos == 0 || FinishedPos >= NameBufSize)
91 return -1;
92
93 str_copy(dst: pNameBuf, src: pStr, dst_size: FinishedPos + 1);
94
95 return TimeFromStr(pStr: pFinished + str_length(str: s_pFinishedStr));
96}
97
98bool CRaceHelper::IsStart(vec2 Prev, vec2 Pos) const
99{
100 if(m_pGameClient->m_GameInfo.m_FlagStartsRace)
101 {
102 int EnemyTeam = m_pGameClient->m_aClients[m_pGameClient->m_Snap.m_LocalClientId].m_Team ^ 1;
103 return m_aFlagIndex[EnemyTeam] != -1 && distance(a: Pos, b: m_pGameClient->Collision()->GetPos(Index: m_aFlagIndex[EnemyTeam])) < 32;
104 }
105 else
106 {
107 std::vector<int> vIndices = m_pGameClient->Collision()->GetMapIndices(PrevPos: Prev, Pos);
108 if(!vIndices.empty())
109 {
110 for(const int Index : vIndices)
111 {
112 if(m_pGameClient->Collision()->GetTileIndex(Index) == TILE_START)
113 return true;
114 if(m_pGameClient->Collision()->GetFrontTileIndex(Index) == TILE_START)
115 return true;
116 }
117 }
118 else
119 {
120 const int Index = m_pGameClient->Collision()->GetPureMapIndex(Pos);
121 if(m_pGameClient->Collision()->GetTileIndex(Index) == TILE_START)
122 return true;
123 if(m_pGameClient->Collision()->GetFrontTileIndex(Index) == TILE_START)
124 return true;
125 }
126 }
127 return false;
128}
129