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