1#include "proof_mode.h"
2
3#include "editor.h"
4
5#include <game/client/components/menu_background.h>
6
7void CProofMode::OnInit(CEditor *pEditor)
8{
9 CEditorComponent::OnInit(pEditor);
10 InitMenuBackgroundPositionNames();
11 OnReset();
12 OnMapLoad();
13}
14
15void CProofMode::OnReset()
16{
17 m_ProofBorders = EProofBorder::OFF;
18 m_CurrentMenuProofIndex = 0;
19}
20
21void CProofMode::OnMapLoad()
22{
23 InitMenuBackgroundPositions();
24}
25
26void CProofMode::InitMenuBackgroundPositionNames()
27{
28 m_vpMenuBackgroundPositionNames.resize(new_size: CMenuBackground::NUM_POS);
29 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_START] = "start";
30 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_BROWSER_INTERNET] = "browser(internet)";
31 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_BROWSER_LAN] = "browser(lan)";
32 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_DEMOS] = "demos";
33 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_NEWS] = "news";
34 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_BROWSER_FAVORITES] = "favorites";
35 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_LANGUAGE] = "settings(language)";
36 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_GENERAL] = "settings(general)";
37 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_PLAYER] = "settings(player)";
38 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_TEE] = "settings(tee)";
39 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_APPEARANCE] = "settings(appearance)";
40 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_CONTROLS] = "settings(controls)";
41 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_GRAPHICS] = "settings(graphics)";
42 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_SOUND] = "settings(sound)";
43 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_DDNET] = "settings(ddnet)";
44 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_ASSETS] = "settings(assets)";
45 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_BROWSER_CUSTOM0] = "custom(1)";
46 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_BROWSER_CUSTOM1] = "custom(2)";
47 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_BROWSER_CUSTOM2] = "custom(3)";
48 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_BROWSER_CUSTOM3] = "custom(4)";
49 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_BROWSER_CUSTOM4] = "custom(5)";
50 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_RESERVED0] = "reserved settings(1)";
51 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_RESERVED1] = "reserved settings(2)";
52 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_RESERVED0] = "reserved(1)";
53 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_RESERVED1] = "reserved(2)";
54 m_vpMenuBackgroundPositionNames[CMenuBackground::POS_RESERVED2] = "reserved(3)";
55}
56
57void CProofMode::InitMenuBackgroundPositions()
58{
59 std::array<vec2, CMenuBackground::NUM_POS> aBackgroundPositions = GenerateMenuBackgroundPositions();
60 m_vMenuBackgroundPositions.assign(first: aBackgroundPositions.begin(), last: aBackgroundPositions.end());
61
62 if(Map()->m_pGameLayer)
63 {
64 for(int y = 0; y < Map()->m_pGameLayer->m_Height; ++y)
65 {
66 for(int x = 0; x < Map()->m_pGameLayer->m_Width; ++x)
67 {
68 CTile Tile = Map()->m_pGameLayer->GetTile(x, y);
69 if(Tile.m_Index >= TILE_TIME_CHECKPOINT_FIRST && Tile.m_Index <= TILE_TIME_CHECKPOINT_LAST)
70 {
71 int ArrayIndex = std::clamp<int>(val: (Tile.m_Index - TILE_TIME_CHECKPOINT_FIRST), lo: 0, hi: CMenuBackground::NUM_POS);
72 m_vMenuBackgroundPositions[ArrayIndex] = vec2(x * 32.0f + 16.0f, y * 32.0f + 16.0f);
73 }
74
75 x += Tile.m_Skip;
76 }
77 }
78 }
79
80 m_vvMenuBackgroundCollisions.clear();
81 m_vvMenuBackgroundCollisions.resize(new_size: m_vMenuBackgroundPositions.size());
82 for(size_t i = 0; i < m_vMenuBackgroundPositions.size(); i++)
83 {
84 for(size_t j = i + 1; j < m_vMenuBackgroundPositions.size(); j++)
85 {
86 if(i != j && distance(a: m_vMenuBackgroundPositions[i], b: m_vMenuBackgroundPositions[j]) < 0.001f)
87 m_vvMenuBackgroundCollisions.at(n: i).push_back(x: j);
88 }
89 }
90}
91
92void CProofMode::RenderScreenSizes()
93{
94 const vec2 WorldOffset = Editor()->MapView()->GetWorldOffset();
95
96 // render screen sizes
97 if(IsEnabled())
98 {
99 std::shared_ptr<CLayerGroup> pGameGroup = Map()->m_pGameGroup;
100 pGameGroup->MapScreen();
101
102 Graphics()->TextureClear();
103 Graphics()->LinesBegin();
104
105 // possible screen sizes (white border)
106 float aLastPoints[4];
107 float Start = 1.0f; // 9.0f/16.0f;
108 float End = 16.0f / 9.0f;
109 const int NumSteps = 20;
110 for(int i = 0; i <= NumSteps; i++)
111 {
112 float aPoints[4];
113 float Aspect = Start + (End - Start) * (i / (float)NumSteps);
114
115 float Zoom = IsModeMenu() ? 0.7f : 1.0f;
116 Graphics()->MapScreenToWorld(
117 CenterX: WorldOffset.x, CenterY: WorldOffset.y,
118 ParallaxX: 100.0f, ParallaxY: 100.0f, ParallaxZoom: 100.0f, OffsetX: 0.0f, OffsetY: 0.0f, Aspect, Zoom, pPoints: aPoints);
119
120 if(i == 0)
121 {
122 IGraphics::CLineItem aArray[] = {
123 IGraphics::CLineItem(aPoints[0], aPoints[1], aPoints[2], aPoints[1]),
124 IGraphics::CLineItem(aPoints[0], aPoints[3], aPoints[2], aPoints[3])};
125 Graphics()->LinesDraw(pArray: aArray, Num: std::size(aArray));
126 }
127
128 if(i != 0)
129 {
130 IGraphics::CLineItem aArray[] = {
131 IGraphics::CLineItem(aPoints[0], aPoints[1], aLastPoints[0], aLastPoints[1]),
132 IGraphics::CLineItem(aPoints[2], aPoints[1], aLastPoints[2], aLastPoints[1]),
133 IGraphics::CLineItem(aPoints[0], aPoints[3], aLastPoints[0], aLastPoints[3]),
134 IGraphics::CLineItem(aPoints[2], aPoints[3], aLastPoints[2], aLastPoints[3])};
135 Graphics()->LinesDraw(pArray: aArray, Num: std::size(aArray));
136 }
137
138 if(i == NumSteps)
139 {
140 IGraphics::CLineItem aArray[] = {
141 IGraphics::CLineItem(aPoints[0], aPoints[1], aPoints[0], aPoints[3]),
142 IGraphics::CLineItem(aPoints[2], aPoints[1], aPoints[2], aPoints[3])};
143 Graphics()->LinesDraw(pArray: aArray, Num: std::size(aArray));
144 }
145
146 mem_copy(dest: aLastPoints, source: aPoints, size: sizeof(aPoints));
147 }
148 Graphics()->LinesEnd();
149
150 // two screen sizes (green and red border)
151 {
152 Graphics()->SetColor(r: 1, g: 0, b: 0, a: 1);
153 for(int Pass = 0; Pass < 2; Pass++)
154 {
155 float aPoints[4];
156 const float aAspects[] = {4.0f / 3.0f, 16.0f / 10.0f, 5.0f / 4.0f, 16.0f / 9.0f};
157 const ColorRGBA aColors[] = {ColorRGBA(1.0f, 0.0f, 0.0f, 1.0f), ColorRGBA(0.0f, 1.0f, 0.0f, 1.0f)};
158 float Zoom = IsModeMenu() ? 0.7f : 1.0f;
159 Graphics()->MapScreenToWorld(
160 CenterX: WorldOffset.x, CenterY: WorldOffset.y,
161 ParallaxX: 100.0f, ParallaxY: 100.0f, ParallaxZoom: 100.0f, OffsetX: 0.0f, OffsetY: 0.0f, Aspect: aAspects[Pass], Zoom, pPoints: aPoints);
162
163 CUIRect Rect;
164 Rect.x = aPoints[0];
165 Rect.y = aPoints[1];
166 Rect.w = aPoints[2] - aPoints[0];
167 Rect.h = aPoints[3] - aPoints[1];
168 Rect.DrawOutline(Color: aColors[Pass]);
169 }
170 }
171
172 // tee position (blue circle) and other screen positions
173 {
174 Graphics()->TextureClear();
175 Graphics()->QuadsBegin();
176 Graphics()->SetColor(r: 0, g: 0, b: 1, a: 0.3f);
177 Graphics()->DrawCircle(CenterX: WorldOffset.x, CenterY: WorldOffset.y - 3.0f, Radius: 20.0f, Segments: 32);
178
179 if(IsModeMenu())
180 {
181 Graphics()->SetColor(r: 0, g: 1, b: 0, a: 0.3f);
182
183 const std::vector<vec2> &Positions = MenuBackgroundPositions();
184 std::set<int> Indices;
185 for(int i = 0; i < (int)Positions.size(); i++)
186 Indices.insert(x: i);
187
188 while(!Indices.empty())
189 {
190 int i = *Indices.begin();
191 Indices.erase(x: i);
192 for(int k : MenuBackgroundCollisions(MenuProofIndex: i))
193 Indices.erase(x: k);
194
195 vec2 Pos = Positions[i];
196 Pos += WorldOffset - Positions[CurrentMenuProofIndex()];
197
198 if(Pos == WorldOffset)
199 continue;
200
201 Graphics()->DrawCircle(CenterX: Pos.x, CenterY: Pos.y - 3.0f, Radius: 20.0f, Segments: 32);
202 }
203 }
204
205 Graphics()->QuadsEnd();
206 }
207 }
208}
209
210bool CProofMode::IsEnabled() const
211{
212 return m_ProofBorders != EProofBorder::OFF;
213}
214
215bool CProofMode::IsModeMenu() const
216{
217 return m_ProofBorders == EProofBorder::MENU;
218}
219
220bool CProofMode::IsModeIngame() const
221{
222 return m_ProofBorders == EProofBorder::INGAME;
223}
224
225void CProofMode::Toggle()
226{
227 m_ProofBorders = m_ProofBorders == EProofBorder::OFF ? EProofBorder::INGAME : EProofBorder::OFF;
228}
229
230void CProofMode::SetModeIngame()
231{
232 m_ProofBorders = EProofBorder::INGAME;
233}
234
235void CProofMode::SetModeMenu()
236{
237 m_ProofBorders = EProofBorder::MENU;
238}
239
240int CProofMode::CurrentMenuProofIndex() const
241{
242 return m_CurrentMenuProofIndex;
243}
244
245void CProofMode::SetCurrentMenuProofIndex(int MenuProofIndex)
246{
247 m_CurrentMenuProofIndex = MenuProofIndex;
248}
249
250const std::vector<vec2> &CProofMode::MenuBackgroundPositions() const
251{
252 return m_vMenuBackgroundPositions;
253}
254
255vec2 CProofMode::CurrentMenuBackgroundPosition() const
256{
257 return m_vMenuBackgroundPositions[CurrentMenuProofIndex()];
258}
259
260const char *CProofMode::MenuBackgroundPositionName(int MenuProofIndex) const
261{
262 return m_vpMenuBackgroundPositionNames[MenuProofIndex];
263}
264
265const std::vector<int> &CProofMode::MenuBackgroundCollisions(int MenuProofIndex) const
266{
267 return m_vvMenuBackgroundCollisions[MenuProofIndex];
268}
269