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 return TimeFromSecondsStr(pStr);
78}
79
80int CRaceHelper::TimeFromFinishMessage(const char *pStr, char *pNameBuf, int NameBufSize)
81{
82 static const char *const s_pFinishedStr = " finished in: ";
83 const char *pFinished = str_find(haystack: pStr, needle: s_pFinishedStr);
84 if(!pFinished)
85 return -1;
86
87 int FinishedPos = pFinished - pStr;
88 if(FinishedPos == 0 || FinishedPos >= NameBufSize)
89 return -1;
90
91 str_copy(dst: pNameBuf, src: pStr, dst_size: FinishedPos + 1);
92
93 return TimeFromStr(pStr: pFinished + str_length(str: s_pFinishedStr));
94}
95
96bool CRaceHelper::IsStart(vec2 Prev, vec2 Pos) const
97{
98 if(m_pGameClient->m_GameInfo.m_FlagStartsRace)
99 {
100 int EnemyTeam = m_pGameClient->m_aClients[m_pGameClient->m_Snap.m_LocalClientId].m_Team ^ 1;
101 return m_aFlagIndex[EnemyTeam] != -1 && distance(a: Pos, b: m_pGameClient->Collision()->GetPos(Index: m_aFlagIndex[EnemyTeam])) < 32;
102 }
103 else
104 {
105 std::vector<int> vIndices = m_pGameClient->Collision()->GetMapIndices(PrevPos: Prev, Pos);
106 if(!vIndices.empty())
107 {
108 for(const int Index : vIndices)
109 {
110 if(m_pGameClient->Collision()->GetTileIndex(Index) == TILE_START)
111 return true;
112 if(m_pGameClient->Collision()->GetFrontTileIndex(Index) == TILE_START)
113 return true;
114 }
115 }
116 else
117 {
118 const int Index = m_pGameClient->Collision()->GetPureMapIndex(Pos);
119 if(m_pGameClient->Collision()->GetTileIndex(Index) == TILE_START)
120 return true;
121 if(m_pGameClient->Collision()->GetFrontTileIndex(Index) == TILE_START)
122 return true;
123 }
124 }
125 return false;
126}
127