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