1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include "QuitBox.h"
4
5 #include "MouseHandler.h"
6 #include "Game/GameSetup.h"
7 #include "Game/GlobalUnsynced.h"
8 #include "Game/Players/Player.h"
9 #include "Game/Players/PlayerHandler.h"
10 #include "Rendering/Fonts/glFont.h"
11 #include "Rendering/GL/myGL.h"
12 #include "Sim/Misc/GlobalSynced.h"
13 #include "Sim/Misc/ModInfo.h"
14 #include "Sim/Misc/TeamHandler.h"
15 #include "System/Log/ILog.h"
16 #include "Net/Protocol/NetProtocol.h"
17 #include "System/TimeUtil.h"
18 #include "System/FileSystem/FileSystem.h"
19 #include "System/LoadSave/LoadSaveHandler.h"
20 #include "System/MsgStrings.h"
21
22 #include <SDL_keycode.h>
23
24
25 #define MAX_QUIT_TEAMS (teamHandler->ActiveTeams() - 1)
26
27 #undef CreateDirectory
28
CQuitBox()29 CQuitBox::CQuitBox()
30 {
31 box.x1 = 0.34f;
32 box.y1 = 0.18f;
33 box.x2 = 0.66f;
34 box.y2 = 0.78f;
35
36 resignBox.x1=0.02f;
37 resignBox.y1=0.53f;
38 resignBox.x2=0.30f;
39 resignBox.y2=0.57f;
40
41 saveBox.x1=0.02f;
42 saveBox.y1=0.49f;
43 saveBox.x2=0.30f;
44 saveBox.y2=0.53f;
45
46 giveAwayBox.x1=0.02f;
47 giveAwayBox.y1=0.44f;
48 giveAwayBox.x2=0.30f;
49 giveAwayBox.y2=0.48f;
50
51 teamBox.x1=0.02f;
52 teamBox.y1=0.11f;
53 teamBox.x2=0.30f;
54 teamBox.y2=0.43f;
55
56 scrollbarBox.x1 = 0.28f;
57 scrollbarBox.y1 = 0.11f;
58 scrollbarBox.x2 = 0.30f;
59 scrollbarBox.y2 = 0.43f;
60
61 scrollBox.x1 = 0.28f;
62 scrollBox.y1 = 0.40f;
63 scrollBox.x2 = 0.30f;
64 scrollBox.y2 = 0.43f;
65
66 quitBox.x1=0.02f;
67 quitBox.y1=0.06f;
68 quitBox.x2=0.30f;
69 quitBox.y2=0.10f;
70
71 cancelBox.x1=0.02f;
72 cancelBox.y1=0.02f;
73 cancelBox.x2=0.30f;
74 cancelBox.y2=0.06f;
75
76 startTeam = 0;
77 numTeamsDisp = (int)((teamBox.y2 - teamBox.y1) / 0.025f);
78 scrolling = false;
79 scrollGrab = 0.0f;
80 hasScroll = MAX_QUIT_TEAMS > numTeamsDisp;
81
82 moveBox=false;
83 noAlliesLeft=true;
84 shareTeam=0;
85 // if we have alive allies left, set the shareteam to an undead ally.
86 for(int team=0;team<teamHandler->ActiveTeams();++team){
87 if (teamHandler->Team(team)->gaia) continue;
88 if(team!=gu->myTeam && !teamHandler->Team(team)->isDead)
89 {
90 if(shareTeam==gu->myTeam || teamHandler->Team(shareTeam)->isDead)
91 shareTeam=team;
92 if(teamHandler->Ally(gu->myAllyTeam, teamHandler->AllyTeam(team))){
93 noAlliesLeft=false;
94 shareTeam=team;
95 break;
96 }
97 }
98 }
99 }
100
~CQuitBox()101 CQuitBox::~CQuitBox()
102 {
103 }
104
Draw()105 void CQuitBox::Draw()
106 {
107 float mx=MouseX(mouse->lastx);
108 float my=MouseY(mouse->lasty);
109
110 glDisable(GL_TEXTURE_2D);
111 glEnable(GL_BLEND);
112 glDisable(GL_ALPHA_TEST);
113
114 // Large Box
115 glColor4f(0.2f,0.2f,0.2f,guiAlpha);
116 DrawBox(box);
117
118 // resign Box on mouse over
119 if(InBox(mx,my,box+resignBox)){
120 glColor4f(0.7f,0.2f,0.2f,guiAlpha);
121 DrawBox(box+resignBox);
122 }
123 // save Box on mouse over
124 if(InBox(mx,my,box+saveBox)){
125 glColor4f(0.7f,0.2f,0.2f,guiAlpha);
126 DrawBox(box+saveBox);
127 }
128 // give away Box on mouse over
129 if(InBox(mx,my,box+giveAwayBox)){
130 glColor4f(0.7f,0.2f,0.2f,guiAlpha);
131 DrawBox(box+giveAwayBox);
132 }
133 // cancel Box on mouse over
134 if(InBox(mx,my,box+cancelBox)){
135 glColor4f(0.7f,0.2f,0.2f,guiAlpha);
136 DrawBox(box+cancelBox);
137 }
138 // quit Box on mouse over
139 if(InBox(mx,my,box+quitBox)){
140 glColor4f(0.7f,0.2f,0.2f,guiAlpha);
141 DrawBox(box+quitBox);
142 }
143
144
145 glColor4f(0.2f,0.2f,0.2f,guiAlpha);
146 DrawBox(box+teamBox);
147
148 if (hasScroll) {
149 glColor4f(0.1f, 0.1f, 0.1f, guiAlpha);
150 DrawBox(box + scrollbarBox);
151
152 float sz = scrollbarBox.y2 - scrollbarBox.y1;
153 float tsz = sz / (float)(MAX_QUIT_TEAMS);
154 float psz = tsz * (float)numTeamsDisp;
155
156 scrollBox.y2 = scrollbarBox.y2 - startTeam * tsz;
157 scrollBox.y1 = scrollBox.y2 - psz;
158
159 glColor4f(0.8f, 0.8f, 0.8f, guiAlpha);
160 DrawBox(box + scrollBox);
161 }
162
163 glEnable(GL_TEXTURE_2D);
164 glColor4f(1,1,0.4f,0.8f);
165 font->glPrint(box.x1+0.045f,box.y1+0.58f,0.7f, FONT_VCENTER | FONT_SCALE | FONT_NORM,"Do you want to ...");
166 glColor4f(1,1,1,0.8f);
167 font->glPrint(box.x1 + resignBox.x1 + 0.025f,
168 box.y1 + (resignBox.y1 + resignBox.y2)/2, 1, FONT_VCENTER | FONT_SCALE | FONT_NORM, "Resign");
169 font->glPrint(box.x1 + saveBox.x1 + 0.025f,
170 box.y1 + (saveBox.y1 + saveBox.y2)/2, 1, FONT_VCENTER | FONT_SCALE | FONT_NORM, "Save");
171 font->glPrint(box.x1 + giveAwayBox.x1 + 0.025f,
172 box.y1 + (giveAwayBox.y1 + giveAwayBox.y2)/2, 1, FONT_VCENTER | FONT_SCALE | FONT_NORM, "Give everything to ...");
173 font->glPrint(box.x1 + cancelBox.x1 + 0.025f,
174 box.y1 + (cancelBox.y1 + cancelBox.y2)/2, 1, FONT_VCENTER | FONT_SCALE | FONT_NORM, "Cancel");
175 font->glPrint(box.x1 + quitBox.x1 + 0.025f,
176 box.y1 + (quitBox.y1 + quitBox.y2)/2, 1, FONT_VCENTER | FONT_SCALE | FONT_NORM, "Quit");
177
178 int teamPos = 0;
179 for(int team = startTeam; team < MAX_QUIT_TEAMS && teamPos < numTeamsDisp; ++team, ++teamPos) {
180 int actualTeam=team;
181 if (team >= gu->myTeam) {
182 actualTeam++;
183 }
184 if (teamHandler->Team(actualTeam)->gaia) continue;
185
186 if (shareTeam == actualTeam) {
187 glColor4f(1,1,1,0.8f);
188 } else {
189 glColor4f(1,1,1,0.4f);
190 }
191
192 std::string teamName = teamHandler->Team(actualTeam)->GetControllerName();
193 std::string ally, dead;
194
195 if (teamHandler->Ally(gu->myAllyTeam, teamHandler->AllyTeam(actualTeam))) {
196 ally = " <Ally>)";
197 } else {
198 ally = " <Enemy>";
199 }
200 if (teamHandler->Team(actualTeam)->isDead) {
201 dead = " <Dead>";
202 }
203 if (actualTeam == teamHandler->GaiaTeamID()) {
204 teamName = "Gaia";
205 ally = " <Gaia>";
206 }
207 font->glFormat(box.x1 + teamBox.x1 + 0.002f,
208 box.y1 + teamBox.y2 - 0.025f - teamPos * 0.025f, 0.7f, FONT_SCALE | FONT_NORM,
209 "Team%i (%s)%s%s", actualTeam,
210 teamName.c_str(), ally.c_str(), dead.c_str());
211 }
212 }
213
IsAbove(int x,int y)214 bool CQuitBox::IsAbove(int x, int y)
215 {
216 float mx=MouseX(x);
217 float my=MouseY(y);
218 if(InBox(mx,my,box))
219 return true;
220 return false;
221 }
222
GetTooltip(int x,int y)223 std::string CQuitBox::GetTooltip(int x, int y)
224 {
225 float mx=MouseX(x);
226 float my=MouseY(y);
227
228 if(InBox(mx,my,box+resignBox))
229 return "Resign the match, remain in the game";
230 if(InBox(mx,my,box+saveBox))
231 return "Save the current game state to a file \nfor later reload";
232 if(InBox(mx,my,box+giveAwayBox))
233 return "Give away all units and resources \nto the team specified below";
234 if (hasScroll && InBox(mx, my, box + scrollBox))
235 return "Scroll the team list here";
236 if (hasScroll && InBox(mx, my, box + scrollbarBox))
237 return "Scroll the team list here";
238 if(InBox(mx,my,box+teamBox))
239 return "Select which team recieves everything";
240 if(InBox(mx,my,box+cancelBox))
241 return "Return to the game";
242 if(InBox(mx,my,box+quitBox))
243 return "Forget about the other players and quit";
244 if(InBox(mx,my,box))
245 return " ";
246 return "";
247 }
248
MousePress(int x,int y,int button)249 bool CQuitBox::MousePress(int x, int y, int button)
250 {
251 float mx=MouseX(x);
252 float my=MouseY(y);
253 if(InBox(mx,my,box)){
254 moveBox=true;
255 if(InBox(mx,my,box+resignBox) || InBox(mx,my,box+saveBox) || InBox(mx,my,box+giveAwayBox) || InBox(mx,my,box+teamBox) || InBox(mx,my,box+cancelBox) || InBox(mx,my,box+quitBox) ||
256 InBox(mx, my, box + scrollbarBox) || InBox(mx, my, box + scrollBox))
257 moveBox=false;
258 if (hasScroll && InBox(mx, my, box + scrollBox)) {
259 scrolling = true;
260 scrollGrab = (box + scrollBox).y2 - my;
261 }
262 else if (hasScroll && InBox(mx, my, box + scrollbarBox)) {
263 if(my < (box + scrollBox).y1)
264 *(volatile int *)&startTeam = startTeam + std::min(MAX_QUIT_TEAMS - numTeamsDisp - startTeam, numTeamsDisp);
265 if(my > (box + scrollBox).y2)
266 *(volatile int *)&startTeam = startTeam - std::min(startTeam, numTeamsDisp);
267 }
268 else if(InBox(mx,my,box+teamBox)){
269 int team = startTeam + (int)((box.y1 + teamBox.y2 - my) / 0.025f);
270 if(team>=gu->myTeam)
271 team++;
272 if(teamHandler->IsValidTeam(team) && !teamHandler->Team(team)->isDead){
273 // we don't want to give everything to the enemy if there are allies left
274 if(noAlliesLeft || (!noAlliesLeft && teamHandler->Ally(gu->myAllyTeam, teamHandler->AllyTeam(team)))){
275 shareTeam=team;
276 }
277 }
278 }
279 return true;
280 }
281 return false;
282 }
283
MouseRelease(int x,int y,int button)284 void CQuitBox::MouseRelease(int x,int y,int button)
285 {
286 float mx=MouseX(x);
287 float my=MouseY(y);
288
289 scrolling = false;
290 scrollGrab = 0.0f;
291
292 if(InBox(mx,my,box+resignBox)
293 || (InBox(mx,my,box+saveBox) && !teamHandler->Team(gu->myTeam)->isDead)
294 || (InBox(mx,my,box+giveAwayBox) && !teamHandler->Team(shareTeam)->isDead && !teamHandler->Team(gu->myTeam)->isDead)) {
295 // give away all units (and resources)
296 if(InBox(mx,my,box+giveAwayBox) && !playerHandler->Player(gu->myPlayerNum)->spectator) {
297 net->Send(CBaseNetProtocol::Get().SendGiveAwayEverything(gu->myPlayerNum, shareTeam, playerHandler->Player(gu->myPlayerNum)->team));
298 }
299 // resign, so self-d all units
300 if (InBox(mx,my,box+resignBox) && !playerHandler->Player(gu->myPlayerNum)->spectator) {
301 net->Send(CBaseNetProtocol::Get().SendResign(gu->myPlayerNum));
302 }
303 // save current game state
304 if (InBox(mx,my,box+saveBox)) {
305 if (FileSystem::CreateDirectory("Saves")) {
306 std::string timeStr = CTimeUtil::GetCurrentTimeStr();
307 std::string saveFileName(timeStr + "_" + modInfo.filename + "_" + gameSetup->mapName);
308 saveFileName = "Saves/" + saveFileName + ".ssf";
309 if (!FileSystem::FileExists(saveFileName)) {
310 LOG("Saving game to %s", saveFileName.c_str());
311 ILoadSaveHandler* ls = ILoadSaveHandler::Create();
312 ls->mapName = gameSetup->mapName;
313 ls->modName = modInfo.filename;
314 ls->SaveGame(saveFileName);
315 delete ls;
316 } else {
317 LOG_L(L_ERROR, "File %s already exists, game NOT saved!",
318 saveFileName.c_str());
319 }
320 }
321 }
322 }
323 else if (InBox(mx, my, box + quitBox)) {
324 LOG("User exited");
325 gu->globalQuit = true;
326 }
327 // if we're still in the game, remove the resign box
328 if(InBox(mx,my,box+resignBox) || InBox(mx,my,box+saveBox) || InBox(mx,my,box+giveAwayBox) || InBox(mx,my,box+cancelBox) || InBox(mx,my,box+quitBox)){
329 delete this;
330 return;
331 }
332 moveBox=false;
333 }
334
MouseMove(int x,int y,int dx,int dy,int button)335 void CQuitBox::MouseMove(int x, int y, int dx,int dy, int button)
336 {
337 float mx=MouseX(x);
338 float my=MouseY(y);
339
340 if(scrolling) {
341 float scr = (box+scrollbarBox).y2 - (my + scrollGrab);
342 float sz = scrollbarBox.y2 - scrollbarBox.y1;
343 float tsz = sz / (float)MAX_QUIT_TEAMS;
344
345 *(volatile int *)&startTeam = std::max(0, std::min((int)(scr / tsz + 0.5), MAX_QUIT_TEAMS - numTeamsDisp));
346 return;
347 }
348 if(moveBox){
349 box.x1+=MouseMoveX(dx);
350 box.x2+=MouseMoveX(dx);
351 box.y1+=MouseMoveY(dy);
352 box.y2+=MouseMoveY(dy);
353 }
354 if(!(hasScroll && (InBox(mx, my, box + scrollBox) || InBox(mx, my, box + scrollbarBox))) && InBox(mx,my,box+teamBox)){
355 int team = startTeam + (int)((box.y1 + teamBox.y2 - my) / 0.025f);
356 if(team>=gu->myTeam)
357 team++;
358 if(teamHandler->IsValidTeam(team) && !teamHandler->Team(team)->isDead){
359 // we don't want to give everything to the enemy if there are allies left
360 if(noAlliesLeft || (!noAlliesLeft && teamHandler->Ally(gu->myAllyTeam, teamHandler->AllyTeam(team)))){
361 shareTeam=team;
362 }
363 }
364 }
365 }
366
367
KeyPressed(int key,bool isRepeat)368 bool CQuitBox::KeyPressed(int key, bool isRepeat)
369 {
370 if (key == SDLK_ESCAPE) {
371 delete this;
372 return true;
373 }
374 return false;
375 }
376