Tweak the system sound to use 0.5 as the default volume, instead of 1.0. This allows...
[voretournament/voretournament.git] / data / qcsrc / menu / menu.qc
1 ///////////////////////////////////////////////\r
2 // Menu Source File\r
3 ///////////////////////\r
4 // This file belongs to dpmod/darkplaces\r
5 // AK contains all menu functions (especially the required ones)\r
6 ///////////////////////////////////////////////\r
7 \r
8 float mouseButtonsPressed;\r
9 vector menuMousePos;\r
10 float menuShiftState;\r
11 float menuPrevTime;\r
12 float menuAlpha;\r
13 float menuLogoAlpha;\r
14 float prevMenuAlpha;\r
15 float menuInitialized;\r
16 float menuNotTheFirstFrame;\r
17 float menuMouseMode;\r
18 \r
19 void SUB_Null() { };\r
20 \r
21 void() m_init =\r
22 {\r
23         cvar_set("_menu_alpha", "0");\r
24 \r
25         check_unacceptable_compiler_bugs();\r
26 \r
27         // list all game dirs (TEST)\r
28         if(cvar("developer"))\r
29         {\r
30                 float i;\r
31                 string s;\r
32                 for(i = 0; ; ++i)\r
33                 {\r
34                         s = getgamedirinfo(i, GETGAMEDIRINFO_NAME);\r
35                         if not(s)\r
36                                 break;\r
37                         print(s, ": ", getgamedirinfo(i, GETGAMEDIRINFO_DESCRIPTION));\r
38                 }\r
39         }\r
40 }\r
41 \r
42 float MENU_ASPECT = 1.25; // 1280x1024\r
43 float MENU_MINHEIGHT = 600;\r
44 float conwidth_s, conheight_s, realconwidth, realconheight, screenconwidth, screenconheight;\r
45 void draw_reset_cropped()\r
46 {\r
47         draw_reset(screenconwidth, screenconheight, 0.5 * (realconwidth - screenconwidth), 0.5 * (realconheight - screenconheight));\r
48 }\r
49 void draw_reset_full()\r
50 {\r
51         draw_reset(realconwidth, realconheight, 0, 0);\r
52 }\r
53 void UpdateConWidthHeight()\r
54 {\r
55         conwidth_s = conwidth;\r
56         conheight_s = conheight;\r
57         realconwidth = cvar("vid_conwidth");\r
58         realconheight = cvar("vid_conheight");\r
59         if(realconwidth / realconheight > MENU_ASPECT)\r
60         {\r
61                 // widescreen\r
62                 conwidth = realconheight * MENU_ASPECT;\r
63                 conheight = realconheight;\r
64         }\r
65         else\r
66         {\r
67                 // squarescreen\r
68                 conwidth = realconwidth;\r
69                 conheight = realconwidth / MENU_ASPECT;\r
70         }\r
71         screenconwidth = conwidth;\r
72         screenconheight = conheight;\r
73         if(conwidth < MENU_MINHEIGHT * MENU_ASPECT)\r
74         {\r
75                 conheight *= MENU_MINHEIGHT * MENU_ASPECT / conwidth;\r
76                 conwidth = MENU_MINHEIGHT * MENU_ASPECT;\r
77         }\r
78         if(conheight < MENU_MINHEIGHT)\r
79         {\r
80                 conwidth *= MENU_MINHEIGHT / conheight;\r
81                 conheight = MENU_MINHEIGHT;\r
82         }\r
83         if(main)\r
84         {\r
85                 if(conwidth_s != conwidth || conheight_s != conheight)\r
86                 {\r
87                         draw_reset_cropped();\r
88                         main.resizeNotify(main, '0 0 0', eX * conwidth + eY * conheight, '0 0 0', eX * conwidth + eY * conheight);\r
89                 }\r
90         }\r
91 }\r
92 \r
93 void() m_init_delayed =\r
94 {\r
95         float fh, glob, n, i;\r
96         string s;\r
97 \r
98         conwidth = conheight = -1;\r
99         UpdateConWidthHeight();\r
100         draw_reset_cropped();\r
101 \r
102         menuInitialized = 0;\r
103         if(!preMenuInit())\r
104                 return;\r
105         menuInitialized = 1;\r
106         GameCommand_Init();\r
107 \r
108         RegisterWeapons();\r
109 \r
110         fh = -1;\r
111         if(cvar_string("menu_skin") != "")\r
112         {\r
113                 draw_currentSkin = strcat("gfx/menu/", cvar_string("menu_skin"));\r
114                 fh = fopen(strcat(draw_currentSkin, "/skinvalues.txt"), FILE_READ);\r
115         }\r
116         if(fh < 0)\r
117         if(cvar_defstring("menu_skin") != "")\r
118         {\r
119                 draw_currentSkin = strcat("gfx/menu/", cvar_defstring("menu_skin"));\r
120                 fh = fopen(strcat(draw_currentSkin, "/skinvalues.txt"), FILE_READ);\r
121         }\r
122         if(fh < 0)\r
123         {\r
124                 draw_currentSkin = "gfx/menu/default";\r
125                 fh = fopen(strcat(draw_currentSkin, "/skinvalues.txt"), FILE_READ);\r
126         }\r
127         draw_currentSkin = strzone(draw_currentSkin);\r
128         while((s = fgets(fh)))\r
129         {\r
130                 // these two are handled by skinlist.qc\r
131                 if(substring(s, 0, 6) == "title ")\r
132                         continue;\r
133                 if(substring(s, 0, 7) == "author ")\r
134                         continue;\r
135                 n = tokenize_console(s);\r
136                 if(n >= 2)\r
137                         Skin_ApplySetting(argv(0), substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)));\r
138         }\r
139         fclose(fh);\r
140 \r
141         glob = search_begin(strcat(draw_currentSkin, "/*.tga"), TRUE, TRUE);\r
142         if(glob >= 0)\r
143         {\r
144                 n = search_getsize(glob);\r
145                 for(i = 0; i < n; ++i)\r
146                         precache_pic(search_getfilename(glob, i));\r
147                 search_end(glob);\r
148         }\r
149 \r
150         draw_setMousePointer(SKINGFX_CURSOR, SKINSIZE_CURSOR, SKINOFFSET_CURSOR);\r
151 \r
152         loadTooltips();\r
153         main = spawnMainWindow(); main.configureMainWindow(main);\r
154         unloadTooltips();\r
155 \r
156         main.resizeNotify(main, '0 0 0', eX * conwidth + eY * conheight, '0 0 0', eX * conwidth + eY * conheight);\r
157         main.focused = 1;\r
158         menuShiftState = 0;\r
159         menuMousePos = '0.5 0.5 0';\r
160 \r
161         if(Menu_Active)\r
162                 m_display(); // delayed menu display\r
163 };\r
164 \r
165 void(float key, float ascii) m_keyup =\r
166 {\r
167         if(!menuInitialized)\r
168                 return;\r
169         if(!Menu_Active)\r
170                 return;\r
171         draw_reset_cropped();\r
172         main.keyUp(main, key, ascii, menuShiftState);\r
173         if(key >= K_MOUSE1 && key <= K_MOUSE3)\r
174         {\r
175                 --mouseButtonsPressed;\r
176                 if(!mouseButtonsPressed)\r
177                         main.mouseRelease(main, menuMousePos);\r
178                 if(mouseButtonsPressed < 0)\r
179                 {\r
180                         mouseButtonsPressed = 0;\r
181                         print("Warning: released an already released button\n");\r
182                 }\r
183         }\r
184         if(key == K_ALT) menuShiftState -= (menuShiftState & S_ALT);\r
185         if(key == K_CTRL) menuShiftState -= (menuShiftState & S_CTRL);\r
186         if(key == K_SHIFT) menuShiftState -= (menuShiftState & S_SHIFT);\r
187 };\r
188 \r
189 void(float key, float ascii) m_keydown =\r
190 {\r
191         if(!menuInitialized)\r
192                 return;\r
193         if(!Menu_Active)\r
194                 return;\r
195         if(keyGrabber)\r
196         {\r
197                 entity e;\r
198                 e = keyGrabber;\r
199                 keyGrabber = NULL;\r
200                 e.keyGrabbed(e, key, ascii);\r
201         }\r
202         else\r
203         {\r
204                 draw_reset_cropped();\r
205                 if(key >= K_MOUSE1 && key <= K_MOUSE3)\r
206                         if(!mouseButtonsPressed)\r
207                                 main.mousePress(main, menuMousePos);\r
208                 if(!main.keyDown(main, key, ascii, menuShiftState))\r
209                         if(key == K_ESCAPE)\r
210                                 if(gamestatus & (GAME_ISSERVER | GAME_CONNECTED)) // don't back out to console only\r
211                                         m_hide(); // disable menu on unhandled ESC\r
212         }\r
213         if(key >= K_MOUSE1 && key <= K_MOUSE3)\r
214         {\r
215                 ++mouseButtonsPressed;\r
216                 if(mouseButtonsPressed > 10)\r
217                 {\r
218                         mouseButtonsPressed = 10;\r
219                         print("Warning: pressed an already pressed button\n");\r
220                 }\r
221         }\r
222         if(key == K_ALT) menuShiftState |= S_ALT;\r
223         if(key == K_CTRL) menuShiftState |= S_CTRL;\r
224         if(key == K_SHIFT) menuShiftState |= S_SHIFT;\r
225 };\r
226 \r
227 float SCALEMODE_CROP = 0;\r
228 float SCALEMODE_LETTERBOX = 1;\r
229 float SCALEMODE_WIDTH = 2;\r
230 float SCALEMODE_HEIGHT = 3;\r
231 float SCALEMODE_STRETCH = 4;\r
232 void draw_Picture_Aligned(vector algn, float scalemode, string img, float a)\r
233 {\r
234         vector sz, org, isz, isz_w, isz_h;\r
235         float width_is_larger;\r
236 \r
237         sz = draw_PictureSize(img);\r
238         width_is_larger = (sz_x * draw_scale_y >= sz_y * draw_scale_x);\r
239         isz_w = '1 0 0' + '0 1 0' * ((sz_y / sz_x) * (draw_scale_x / draw_scale_y)); \r
240         isz_h = '0 1 0' + '1 0 0' * ((sz_x / sz_y) * (draw_scale_y / draw_scale_x)); \r
241 \r
242         switch(scalemode)\r
243         {\r
244                 default:\r
245                 case SCALEMODE_CROP:\r
246                         isz = (width_is_larger ? isz_h : isz_w);\r
247                         break;\r
248                 case SCALEMODE_LETTERBOX:\r
249                         isz = (width_is_larger ? isz_w : isz_h);\r
250                         break;\r
251                 case SCALEMODE_WIDTH:\r
252                         isz = isz_w;\r
253                         break;\r
254                 case SCALEMODE_HEIGHT:\r
255                         isz = isz_h;\r
256                         break;\r
257                 case SCALEMODE_STRETCH:\r
258                         isz = '1 1 0';\r
259                         break;\r
260         }\r
261 \r
262         org = eX * (algn_x * (1 - isz_x)) + eY * (algn_y * (1 - isz_y));\r
263         draw_Picture(org, img, isz, '1 1 1', a);\r
264 }\r
265 \r
266 void(string img, float a, string algn, float force1) drawBackground =\r
267 {\r
268         vector v;\r
269         float i, l;\r
270         string c;\r
271         float scalemode;\r
272 \r
273         v_z = 0;\r
274 \r
275         scalemode = SCALEMODE_CROP;\r
276 \r
277         for(i = 0; i < strlen(algn); ++i)\r
278         {\r
279                 c = substring(algn, i, 1);\r
280                 switch(c)\r
281                 {\r
282                         case "c": scalemode = SCALEMODE_CROP; goto nopic;\r
283                         case "l": scalemode = SCALEMODE_LETTERBOX; goto nopic;\r
284                         case "h": scalemode = SCALEMODE_HEIGHT; goto nopic;\r
285                         case "w": scalemode = SCALEMODE_WIDTH; goto nopic;\r
286                         case "s": scalemode = SCALEMODE_STRETCH; goto nopic;\r
287                         case "1": case "4": case "7": v_x = 0.0; break;\r
288                         case "2": case "5": case "8": v_x = 0.5; break;\r
289                         case "3": case "6": case "9": v_x = 1.0; break;\r
290                         default: v_x = random(); break;\r
291                 }\r
292                 switch(c)\r
293                 {\r
294                         case "7": case "8": case "9": v_y = 0.0; break;\r
295                         case "4": case "5": case "6": v_y = 0.5; break;\r
296                         case "1": case "2": case "3": v_y = 1.0; break;\r
297                         default: v_y = random(); break;\r
298                 }\r
299                 if(l == 0)\r
300                         draw_Picture_Aligned(v, scalemode, img, a);\r
301                 else if(force1)\r
302                         // force all secondary layers to use alpha 1. Prevents ugly issues\r
303                         // with overlap. It's a flag because it cannot be used for the\r
304                         // ingame background\r
305                         draw_Picture_Aligned(v, scalemode, strcat(img, "_l", ftos(l+1)), 1);\r
306                 else\r
307                         draw_Picture_Aligned(v, scalemode, strcat(img, "_l", ftos(l+1)), a);\r
308                 ++l;\r
309 :nopic\r
310         }\r
311 }\r
312 \r
313 vector menuTooltipAveragedMousePos;\r
314 entity menuTooltipItem;\r
315 vector menuTooltipOrigin;\r
316 vector menuTooltipSize;\r
317 float menuTooltipAlpha;\r
318 float menuTooltipState; // 0: no tooltip, 1: fading in, 2: displaying, 3: fading out\r
319 float m_testmousetooltipbox(vector pos)\r
320 {\r
321         if(pos_x >= menuTooltipOrigin_x && pos_x < menuTooltipOrigin_x + menuTooltipSize_x)\r
322         if(pos_y >= menuTooltipOrigin_y && pos_y < menuTooltipOrigin_y + menuTooltipSize_y)\r
323                 return FALSE;\r
324         return TRUE;\r
325 }\r
326 float m_testtooltipbox(vector tooltippos)\r
327 {\r
328         if(tooltippos_x < 0)\r
329                 return FALSE;\r
330         if(tooltippos_y < 0)\r
331                 return FALSE;\r
332         if(tooltippos_x + menuTooltipSize_x > 1)\r
333                 return FALSE;\r
334         if(tooltippos_y + menuTooltipSize_y > 1)\r
335                 return FALSE;\r
336         /*\r
337         menuTooltipOrigin_x = rint(tooltippos_x * cvar("vid_width")) / cvar("vid_width");\r
338         menuTooltipOrigin_y = rint(tooltippos_y * cvar("vid_height")) / cvar("vid_height");\r
339         menuTooltipOrigin_z = 0;\r
340         */\r
341         menuTooltipOrigin = tooltippos;\r
342         return TRUE;\r
343 }\r
344 float m_allocatetooltipbox(vector pos)\r
345 {\r
346         vector avoidplus, avoidminus;\r
347         vector v;\r
348 \r
349         avoidplus_x = (SKINAVOID_TOOLTIP_x + SKINSIZE_CURSOR_x - SKINOFFSET_CURSOR_x) / conwidth;\r
350         avoidplus_y = (SKINAVOID_TOOLTIP_y + SKINSIZE_CURSOR_y - SKINOFFSET_CURSOR_y) / conheight;\r
351         avoidplus_z = 0;\r
352 \r
353         avoidminus_x = (SKINAVOID_TOOLTIP_x + SKINOFFSET_CURSOR_x) / conwidth + menuTooltipSize_x;\r
354         avoidminus_y = (SKINAVOID_TOOLTIP_y + SKINOFFSET_CURSOR_y) / conheight + menuTooltipSize_y;\r
355         avoidminus_z = 0;\r
356 \r
357         // bottom right\r
358         v = pos + avoidplus;\r
359         if(m_testtooltipbox(v))\r
360                 return TRUE;\r
361         \r
362         // bottom center\r
363         v_x = pos_x - menuTooltipSize_x * 0.5;\r
364         if(m_testtooltipbox(v))\r
365                 return TRUE;\r
366 \r
367         // bottom left\r
368         v_x = pos_x - avoidminus_x;\r
369         if(m_testtooltipbox(v))\r
370                 return TRUE;\r
371 \r
372         // top left\r
373         v_y = pos_y - avoidminus_y;\r
374         if(m_testtooltipbox(v))\r
375                 return TRUE;\r
376 \r
377         // top center\r
378         v_x = pos_x - menuTooltipSize_x * 0.5;\r
379         if(m_testtooltipbox(v))\r
380                 return TRUE;\r
381         \r
382         // top right\r
383         v_x = pos_x + avoidplus_x;\r
384         if(m_testtooltipbox(v))\r
385                 return TRUE;\r
386         \r
387         return FALSE;\r
388 }\r
389 entity m_findtooltipitem(entity root, vector pos)\r
390 {\r
391         entity it;\r
392         entity best;\r
393 \r
394         best = world;\r
395         it = root;\r
396 \r
397         while(it.instanceOfContainer)\r
398         {\r
399                 while(it.instanceOfNexposee && it.focusedChild)\r
400                 {\r
401                         it = it.focusedChild;\r
402                         pos = globalToBox(pos, it.Container_origin, it.Container_size);\r
403                 }\r
404                 if(it.instanceOfNexposee)\r
405                 {\r
406                         it = it.itemFromPoint(it, pos);\r
407                         if(it.tooltip)\r
408                                 best = it;\r
409                         it = world;\r
410                 }\r
411                 else if(it.instanceOfModalController)\r
412                         it = it.focusedChild;\r
413                 else\r
414                         it = it.itemFromPoint(it, pos);\r
415                 if(!it)\r
416                         break;\r
417                 if(it.tooltip)\r
418                         best = it;\r
419                 pos = globalToBox(pos, it.Container_origin, it.Container_size);\r
420         }\r
421 \r
422         return best;\r
423 }\r
424 void m_tooltip(vector pos)\r
425 {\r
426         float f, i, w;\r
427         entity it;\r
428         vector fontsize, p;\r
429         string s;\r
430 \r
431         fontsize = '1 0 0' * (SKINFONTSIZE_TOOLTIP / conwidth) + '0 1 0' * (SKINFONTSIZE_TOOLTIP / conheight);\r
432 \r
433         f = bound(0, frametime * 2, 1);\r
434         menuTooltipAveragedMousePos = menuTooltipAveragedMousePos * (1 - f) + pos * f;\r
435         f = vlen(pos - menuTooltipAveragedMousePos);\r
436 \r
437         if(f < 0.01)\r
438                 it = m_findtooltipitem(main, pos);\r
439         else    \r
440                 it = world;\r
441 \r
442         // float menuTooltipState; // 0: static, 1: fading in, 2: fading out\r
443         if(it != menuTooltipItem)\r
444         {\r
445                 switch(menuTooltipState)\r
446                 {\r
447                         case 0:\r
448                                 if(menuTooltipItem)\r
449                                 {\r
450                                         // another item: fade out first\r
451                                         menuTooltipState = 2;\r
452                                 }\r
453                                 else\r
454                                 {\r
455                                         // new item: fade in\r
456                                         menuTooltipState = 1;\r
457                                         menuTooltipItem = it;\r
458 \r
459                                         menuTooltipOrigin_x = -1; // unallocated\r
460                                         i = 0;\r
461                                         w =  0;\r
462                                         getWrappedLine_remaining = it.tooltip;\r
463                                         while(getWrappedLine_remaining)\r
464                                         {\r
465                                                 s = getWrappedLine(SKINWIDTH_TOOLTIP, fontsize, draw_TextWidth_WithoutColors);\r
466                                                 ++i;\r
467                                                 f = draw_TextWidth(s, FALSE, fontsize);\r
468                                                 if(f > w)\r
469                                                         w = f;\r
470                                         }\r
471                                         menuTooltipSize_x = w + 2 * (SKINMARGIN_TOOLTIP_x / conwidth);\r
472                                         menuTooltipSize_y = i * fontsize_y + 2 * (SKINMARGIN_TOOLTIP_y / conheight);\r
473                                         menuTooltipSize_z = 0;\r
474                                 }\r
475                                 break;\r
476                         case 1:\r
477                                 // changing item while fading in: fade out first\r
478                                 menuTooltipState = 2;\r
479                                 break;\r
480                         case 2:\r
481                                 // changing item while fading out: can't\r
482                                 break;\r
483                 }\r
484         }\r
485         else if(menuTooltipState == 2) // re-fade in?\r
486                 menuTooltipState = 1;\r
487 \r
488         if(menuTooltipItem)\r
489                 if(!m_testmousetooltipbox(pos))\r
490                         menuTooltipState = 2; // fade out if mouse touches it\r
491 \r
492         switch(menuTooltipState)\r
493         {\r
494                 case 1:\r
495                         menuTooltipAlpha = bound(0, menuTooltipAlpha + 5 * frametime, 1);\r
496                         if(menuTooltipAlpha == 1)\r
497                                 menuTooltipState = 0;\r
498                         break;\r
499                 case 2:\r
500                         menuTooltipAlpha = bound(0, menuTooltipAlpha - 2 * frametime, 1);\r
501                         if(menuTooltipAlpha == 0)\r
502                         {\r
503                                 menuTooltipState = 0;\r
504                                 menuTooltipItem = world;\r
505                         }\r
506                         break;\r
507         }\r
508 \r
509         if(menuTooltipItem)\r
510         {\r
511                 if(menuTooltipOrigin_x < 0) // unallocated?\r
512                         m_allocatetooltipbox(pos);\r
513 \r
514                 if(menuTooltipOrigin_x >= 0)\r
515                 {\r
516                         // draw the tooltip!\r
517                         p = SKINBORDER_TOOLTIP;\r
518                         p_x *= 1 / conwidth;\r
519                         p_y *= 1 / conheight;\r
520                         draw_BorderPicture(menuTooltipOrigin, SKINGFX_TOOLTIP, menuTooltipSize, '1 1 1', menuTooltipAlpha, p);\r
521                         p = menuTooltipOrigin;\r
522                         p_x += SKINMARGIN_TOOLTIP_x / conwidth;\r
523                         p_y += SKINMARGIN_TOOLTIP_y / conheight;\r
524                         getWrappedLine_remaining = menuTooltipItem.tooltip;\r
525                         while(getWrappedLine_remaining)\r
526                         {\r
527                                 s = getWrappedLine(SKINWIDTH_TOOLTIP, fontsize, draw_TextWidth_WithoutColors);\r
528                                 draw_Text(p, s, fontsize, '1 1 1', SKINALPHA_TOOLTIP * menuTooltipAlpha, FALSE);\r
529                                 p_y += fontsize_y;\r
530                         }\r
531                 }\r
532         }\r
533 }\r
534 \r
535 void() m_draw =\r
536 {\r
537         float t;\r
538         float realFrametime;\r
539 \r
540         menuMouseMode = cvar("menu_mouse_absolute");\r
541 \r
542         if(main)\r
543                 UpdateConWidthHeight();\r
544 \r
545         if(!menuInitialized)\r
546         {\r
547                 // TODO draw an info image about this situation\r
548                 m_init_delayed();\r
549                 return;\r
550         }\r
551         if(!menuNotTheFirstFrame)\r
552         {\r
553                 menuNotTheFirstFrame = 1;\r
554                 if(Menu_Active)\r
555                 if(!cvar("menu_video_played"))\r
556                 {\r
557                         localcmd("set menu_video_played 1; cd loop $menu_cdtrack; play sound/announcer/default/welcome.ogg\n");\r
558                         menuLogoAlpha = -0.8; // no idea why, but when I start this at zero, it jumps instead of fading\r
559                 }\r
560         }\r
561 \r
562         t = gettime();\r
563         realFrametime = frametime = min(0.2, t - menuPrevTime);\r
564         menuPrevTime = t;\r
565         time += frametime;\r
566 \r
567         t = cvar("menu_slowmo");\r
568         if(t)\r
569         {\r
570                 frametime *= t;\r
571                 realFrametime *= t;\r
572         }\r
573         else\r
574                 t = 1;\r
575 \r
576         if(Menu_Active)\r
577         {\r
578                 if(getmousetarget() == (menuMouseMode ? MT_CLIENT : MT_MENU) && (getkeydest() == KEY_MENU || getkeydest() == KEY_MENU_GRABBED))\r
579                         setkeydest(keyGrabber ? KEY_MENU_GRABBED : KEY_MENU);\r
580                 else\r
581                         m_hide();\r
582         }\r
583 \r
584         if(cvar("cl_capturevideo"))\r
585                 frametime = t / cvar("cl_capturevideo_fps"); // make capturevideo work smoothly\r
586 \r
587         gamestatus = 0;\r
588         if(isserver())\r
589                 gamestatus = gamestatus | GAME_ISSERVER;\r
590         if(clientstate() == CS_CONNECTED)\r
591                 gamestatus = gamestatus | GAME_CONNECTED;\r
592         if(cvar("developer"))\r
593                 gamestatus = gamestatus | GAME_DEVELOPER;\r
594 \r
595         prevMenuAlpha = menuAlpha;\r
596         if(Menu_Active)\r
597         {\r
598                 if(menuAlpha == 0 && menuLogoAlpha < 2)\r
599                 {\r
600                         menuLogoAlpha = menuLogoAlpha + frametime * 2;\r
601                 }\r
602                 else\r
603                 {\r
604                         menuAlpha = min(1, menuAlpha + frametime * 5);\r
605                         menuLogoAlpha = 2;\r
606                 }\r
607         }\r
608         else\r
609         {\r
610                 menuAlpha = max(0, menuAlpha - frametime * 5);\r
611                 menuLogoAlpha = 2;\r
612         }\r
613 \r
614         draw_reset_cropped();\r
615 \r
616         if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER)))\r
617         {\r
618                 if(menuLogoAlpha > 0)\r
619                 {\r
620                         draw_reset_full();\r
621                         draw_Fill('0 0 0', '1 1 0', SKINCOLOR_BACKGROUND, 1);\r
622                         drawBackground(SKINGFX_BACKGROUND, bound(0, menuLogoAlpha, 1), SKINALIGN_BACKGROUND, TRUE);\r
623                         draw_reset_cropped();\r
624                         if(menuAlpha <= 0 && SKINALPHA_CURSOR_INTRO > 0)\r
625                         {\r
626                                 draw_alpha = SKINALPHA_CURSOR_INTRO * bound(0, menuLogoAlpha, 1);\r
627                                 draw_drawMousePointer(menuMousePos);\r
628                                 draw_alpha = 1;\r
629                         }\r
630                 }\r
631         }\r
632         else if(SKINALPHA_BACKGROUND_INGAME)\r
633         {\r
634                 if(menuAlpha > 0)\r
635                 {\r
636                         draw_reset_full();\r
637                         drawBackground(SKINGFX_BACKGROUND_INGAME, menuAlpha * SKINALPHA_BACKGROUND_INGAME, SKINALIGN_BACKGROUND_INGAME, FALSE);\r
638                         draw_reset_cropped();\r
639                 }\r
640         }\r
641 \r
642         if(menuAlpha != prevMenuAlpha)\r
643                 cvar_set("_menu_alpha", ftos(menuAlpha));\r
644 \r
645         draw_reset_cropped();\r
646         preMenuDraw();\r
647         draw_reset_cropped();\r
648 \r
649         if(menuAlpha <= 0)\r
650         {\r
651                 if(prevMenuAlpha > 0)\r
652                         main.initializeDialog(main, main.firstChild);\r
653                 draw_reset_cropped();\r
654                 postMenuDraw();\r
655                 return;\r
656         }\r
657 \r
658         draw_alpha *= menuAlpha;\r
659 \r
660         if(menuMouseMode)\r
661         {\r
662                 vector newMouse;\r
663                 newMouse = globalToBox(getmousepos(), draw_shift, draw_scale);\r
664                 if(newMouse != '0 0 0')\r
665                         if(newMouse != menuMousePos)\r
666                         {\r
667                                 menuMousePos = newMouse;\r
668                                 if(mouseButtonsPressed)\r
669                                         main.mouseDrag(main, menuMousePos);\r
670                                 else\r
671                                         main.mouseMove(main, menuMousePos);\r
672                         }\r
673         }\r
674         else\r
675         {\r
676                 if(frametime > 0)\r
677                 {\r
678                         vector dMouse, minpos, maxpos;\r
679                         dMouse = getmousepos() * (frametime / realFrametime); // for capturevideo\r
680                         if(dMouse != '0 0 0')\r
681                         {\r
682                                 minpos = globalToBox('0 0 0', draw_shift, draw_scale);\r
683                                 maxpos = globalToBox(eX * (realconwidth - 1) + eY * (realconheight - 1), draw_shift, draw_scale);\r
684                                 dMouse = globalToBoxSize(dMouse, draw_scale);\r
685                                 menuMousePos += dMouse * cvar("menu_mouse_speed");\r
686                                 menuMousePos_x = bound(minpos_x, menuMousePos_x, maxpos_x);\r
687                                 menuMousePos_y = bound(minpos_y, menuMousePos_y, maxpos_y);\r
688                                 if(mouseButtonsPressed)\r
689                                         main.mouseDrag(main, menuMousePos);\r
690                                 else\r
691                                         main.mouseMove(main, menuMousePos);\r
692                         }\r
693                 }\r
694         }\r
695         main.draw(main);\r
696 \r
697         m_tooltip(menuMousePos);\r
698 \r
699         draw_alpha = max(draw_alpha, SKINALPHA_CURSOR_INTRO * bound(0, menuLogoAlpha, 1));\r
700 \r
701         draw_drawMousePointer(menuMousePos);\r
702 \r
703         draw_reset_cropped();\r
704         postMenuDraw();\r
705 \r
706         frametime = 0;\r
707 };\r
708 \r
709 void() m_display =\r
710 {\r
711         Menu_Active = true;\r
712         setkeydest(KEY_MENU);\r
713         setmousetarget((menuMouseMode ? MT_CLIENT : MT_MENU));\r
714 \r
715         if(!menuInitialized)\r
716                 return;\r
717 \r
718         if(mouseButtonsPressed)\r
719                 main.mouseRelease(main, menuMousePos);\r
720         mouseButtonsPressed = 0;\r
721 \r
722         main.focusEnter(main);\r
723         main.showNotify(main);\r
724 };\r
725 \r
726 void() m_hide =\r
727 {\r
728         Menu_Active = false;\r
729         setkeydest(KEY_GAME);\r
730         setmousetarget(MT_CLIENT);\r
731 \r
732         if(!menuInitialized)\r
733                 return;\r
734 \r
735         main.focusLeave(main);\r
736         main.hideNotify(main);\r
737 };\r
738 \r
739 void() m_toggle =\r
740 {\r
741         if(Menu_Active)\r
742                 m_hide();\r
743         else\r
744                 m_display();\r
745 };\r
746 \r
747 void() m_shutdown =\r
748 {\r
749         entity e;\r
750 \r
751         m_hide();\r
752         for(e = NULL; (e = nextent(e)) != NULL; )\r
753         {\r
754                 if(e.destroy)\r
755                         e.destroy(e);\r
756         }\r
757 };\r
758 \r
759 void m_focus_item_chain(entity outermost, entity innermost)\r
760 {\r
761         if(innermost.parent != outermost)\r
762                 m_focus_item_chain(outermost, innermost.parent);\r
763         innermost.parent.setFocus(innermost.parent, innermost);\r
764 }\r
765 \r
766 void m_activate_window(entity wnd)\r
767 {\r
768         entity par;\r
769         par = wnd.parent;\r
770         if(par)\r
771                 m_activate_window(par);\r
772 \r
773         if(par.instanceOfModalController)\r
774         {\r
775                 if(wnd.tabSelectingButton)\r
776                         // tabs\r
777                         TabButton_Click(wnd.tabSelectingButton, wnd);\r
778                 else\r
779                         // root\r
780                         par.initializeDialog(par, wnd);\r
781         }\r
782         else if(par.instanceOfNexposee)\r
783         {\r
784                 // nexposee (sorry for violating abstraction here)\r
785                 par.selectedChild = wnd;\r
786                 par.animationState = 1;\r
787                 setFocusContainer(par, NULL);\r
788         }\r
789         else if(par.instanceOfContainer)\r
790         {\r
791                 // other containers\r
792                 if(par.focused)\r
793                         par.setFocus(par, wnd);\r
794         }\r
795 }\r
796 \r
797 void m_setpointerfocus(entity wnd)\r
798 {\r
799         if(wnd.instanceOfContainer)\r
800         {\r
801                 entity focus = wnd.preferredFocusedGrandChild(wnd);\r
802                 if(focus)\r
803                 {\r
804                         menuMousePos = focus.origin + 0.5 * focus.size;\r
805                         menuMousePos_x *= 1 / conwidth;\r
806                         menuMousePos_y *= 1 / conheight;\r
807                         if(wnd.focused) // why does this never happen?\r
808                                 m_focus_item_chain(wnd, focus);\r
809                 }\r
810         }\r
811 }\r
812 \r
813 void(string itemname) m_goto =\r
814 {\r
815         entity e;\r
816         if(!menuInitialized)\r
817                 return;\r
818         if(itemname == "") // this can be called by GameCommand\r
819         {\r
820                 if(gamestatus & (GAME_ISSERVER | GAME_CONNECTED))\r
821                         m_hide();\r
822                 else\r
823                 {\r
824                         m_activate_window(main.mainNexposee);\r
825                         m_display();\r
826                 }\r
827         }\r
828         else\r
829         {\r
830                 e = findstring(NULL, name, itemname);\r
831                 if(e)\r
832                 {\r
833                         m_hide();\r
834                         m_activate_window(e);\r
835                         m_setpointerfocus(e);\r
836                         m_display();\r
837                 }\r
838         }\r
839 }\r
840 \r
841 void() m_goto_skin_selector =\r
842 {\r
843         if(!menuInitialized)\r
844                 return;\r
845         // TODO add code to switch back to the skin selector (no idea how to do it now)\r
846         m_goto("skinselector");\r
847 }\r
848 \r
849 void() m_goto_video_settings =\r
850 {\r
851         if(!menuInitialized)\r
852                 return;\r
853         // TODO add code to switch back to the skin selector (no idea how to do it now)\r
854         m_goto("videosettings");\r
855 }\r