- Rename CD track files to proper names
[divverent/nexuiz.git] / data / qcsrc / menu / menu.qc
1 ///////////////////////////////////////////////
2 // Menu Source File
3 ///////////////////////
4 // This file belongs to dpmod/darkplaces
5 // AK contains all menu functions (especially the required ones)
6 ///////////////////////////////////////////////
7
8 float mouseButtonsPressed;
9 vector menuMousePos;
10 float menuShiftState;
11 float menuPrevTime;
12 float menuAlpha;
13 float menuLogoAlpha;
14 float prevMenuAlpha;
15 float menuInitialized;
16 float menuNotTheFirstFrame;
17 float menuMouseMode;
18
19 void SUB_Null() { };
20
21 void() m_init =
22 {
23         dprint_load();
24 }
25
26 void UpdateConWidthHeight()
27 {
28         float conwidth_s, conheight_s;
29         conwidth_s = conwidth;
30         conheight_s = conheight;
31         conwidth = cvar("vid_conwidth");
32         conheight = cvar("vid_conheight");
33         if(conwidth < 800)
34         {
35                 conheight *= 800 / conwidth;
36                 conwidth = 800;
37         }
38         if(conheight < 600)
39         {
40                 conwidth *= 600 / conheight;
41                 conheight = 600;
42         }
43         if(main)
44         {
45                 if(conwidth_s != conwidth || conheight_s != conheight)
46                 {
47                         draw_reset();
48                         main.resizeNotify(main, '0 0 0', eX * conwidth + eY * conheight, '0 0 0', eX * conwidth + eY * conheight);
49                 }
50         }
51 }
52
53 void() m_init_delayed =
54 {
55         float fh, glob, n, i;
56         string s;
57
58         dprint_load();
59
60         menuInitialized = 0;
61         if(!preMenuInit())
62                 return;
63         menuInitialized = 1;
64         GameCommand_Init();
65
66         fh = -1;
67         if(cvar_string("menu_skin") != "")
68         {
69                 draw_currentSkin = strcat("gfx/menu/", cvar_string("menu_skin"));
70                 fh = fopen(strcat(draw_currentSkin, "/skinvalues.txt"), FILE_READ);
71         }
72         if(fh < 0)
73         {
74                 draw_currentSkin = "gfx/menu/default";
75                 fh = fopen(strcat(draw_currentSkin, "/skinvalues.txt"), FILE_READ);
76         }
77         draw_currentSkin = strzone(draw_currentSkin);
78         while((s = fgets(fh)))
79                 if(tokenize(s) == 2)
80                         Skin_ApplySetting(argv(0), argv(1));
81         fclose(fh);
82
83         glob = search_begin(strcat(draw_currentSkin, "/*.tga"), TRUE, TRUE);
84         if(glob >= 0)
85         {
86                 n = search_getsize(glob);
87                 for(i = 0; i < n; ++i)
88                         precache_pic(search_getfilename(glob, i));
89                 search_end(glob);
90         }
91
92         draw_setMousePointer(SKINGFX_CURSOR, SKINSIZE_CURSOR, SKINOFFSET_CURSOR);
93
94         conwidth = conheight = -1;
95         draw_reset();
96         UpdateConWidthHeight();
97         main = spawnMainWindow(); main.configureMainWindow(main);
98         main.resizeNotify(main, '0 0 0', eX * conwidth + eY * conheight, '0 0 0', eX * conwidth + eY * conheight);
99         main.focused = 1;
100         menuShiftState = 0;
101         menuMousePos = '0.5 0.5 0';
102
103         if(Menu_Active)
104                 m_display(); // delayed menu display
105 };
106
107 void(float key, float ascii) m_keyup =
108 {
109         if(!menuInitialized)
110                 return;
111         if(!Menu_Active)
112                 return;
113         draw_reset();
114         main.keyUp(main, key, ascii, menuShiftState);
115         if(key >= K_MOUSE1 && key <= K_MOUSE3)
116         {
117                 --mouseButtonsPressed;
118                 if(!mouseButtonsPressed)
119                         main.mouseRelease(main, menuMousePos);
120                 if(mouseButtonsPressed < 0)
121                 {
122                         mouseButtonsPressed = 0;
123                         print("Warning: released an already released button\n");
124                 }
125         }
126         if(key == K_ALT) menuShiftState -= (menuShiftState & S_ALT);
127         if(key == K_CTRL) menuShiftState -= (menuShiftState & S_CTRL);
128         if(key == K_SHIFT) menuShiftState -= (menuShiftState & S_SHIFT);
129 };
130
131 void(float key, float ascii) m_keydown =
132 {
133         if(!menuInitialized)
134                 return;
135         if(!Menu_Active)
136                 return;
137         if(keyGrabber)
138         {
139                 entity e;
140                 e = keyGrabber;
141                 keyGrabber = NULL;
142                 e.keyGrabbed(e, key, ascii);
143         }
144         else
145         {
146                 draw_reset();
147                 if(!main.keyDown(main, key, ascii, menuShiftState))
148                         if(key == K_ESCAPE)
149                                 if(gamestatus & (GAME_ISSERVER | GAME_CONNECTED)) // don't back out to console only
150                                         m_hide(); // disable menu on unhandled ESC
151                 if(key >= K_MOUSE1 && key <= K_MOUSE3)
152                         if(!mouseButtonsPressed)
153                                 main.mousePress(main, menuMousePos);
154         }
155         if(key >= K_MOUSE1 && key <= K_MOUSE3)
156         {
157                 ++mouseButtonsPressed;
158                 if(mouseButtonsPressed > 10)
159                 {
160                         mouseButtonsPressed = 10;
161                         print("Warning: pressed an already pressed button\n");
162                 }
163         }
164         if(key == K_ALT) menuShiftState |= S_ALT;
165         if(key == K_CTRL) menuShiftState |= S_CTRL;
166         if(key == K_SHIFT) menuShiftState |= S_SHIFT;
167 };
168
169 void(string img, float a) drawBackground =
170 {
171         vector sz;
172         vector isz;
173         sz = draw_PictureSize(img);
174         // keep aspect of image
175         if(sz_x * draw_scale_y >= sz_y * draw_scale_x)
176         {
177                 // that is, sz_x/sz_y >= draw_scale_x/draw_scale_y
178                 // match up the height
179                 isz_y = 1;
180                 isz_x = isz_y * (sz_x / sz_y) * (draw_scale_y / draw_scale_x);
181         }
182         else
183         {
184                 // that is, sz_x/sz_y <= draw_scale_x/draw_scale_y
185                 // match up the width
186                 isz_x = 1;
187                 isz_y = isz_x * (sz_y / sz_x) * (draw_scale_x / draw_scale_y);
188         }
189         draw_Picture('0.5 0.5 0' - 0.5 * isz, img, isz, '1 1 1', a);
190 }
191
192 void() m_draw =
193 {
194         float t;
195         float realFrametime;
196
197         menuMouseMode = cvar("menu_mouse_absolute");
198
199         if(main)
200                 UpdateConWidthHeight();
201
202         if(!menuInitialized)
203         {
204                 // TODO draw an info image about this situation
205                 m_init_delayed();
206                 return;
207         }
208         if(!menuNotTheFirstFrame)
209         {
210                 menuNotTheFirstFrame = 1;
211                 if(Menu_Active)
212                 if(!cvar("menu_video_played"))
213                 {
214                         localcmd("set menu_video_played 1; cd loop $menu_cdtrack; play sound/announcer/male/welcome.ogg\n");
215                         menuLogoAlpha = -0.8; // no idea why, but when I start this at zero, it jumps instead of fading
216                 }
217         }
218
219         t = gettime();
220         realFrametime = frametime = min(0.2, t - menuPrevTime);
221         menuPrevTime = t;
222         time += frametime;
223
224         t = cvar("menu_slowmo");
225         if(t)
226         {
227                 frametime *= t;
228                 realFrametime *= t;
229         }
230         else
231                 t = 1;
232
233         if(Menu_Active)
234         {
235                 if(getmousetarget() == (menuMouseMode ? MT_CLIENT : MT_MENU) && (getkeydest() == KEY_MENU || getkeydest() == KEY_MENU_GRABBED))
236                         setkeydest(keyGrabber ? KEY_MENU_GRABBED : KEY_MENU);
237                 else
238                         m_hide();
239         }
240
241         if(cvar("cl_capturevideo"))
242                 frametime = t / cvar("cl_capturevideo_fps"); // make capturevideo work smoothly
243
244         dprint_load();
245         gamestatus = 0;
246         if(isserver())
247                 gamestatus = gamestatus | GAME_ISSERVER;
248         if(clientstate() == CS_CONNECTED)
249                 gamestatus = gamestatus | GAME_CONNECTED;
250         if(cvar("developer"))
251                 gamestatus = gamestatus | GAME_DEVELOPER;
252
253         prevMenuAlpha = menuAlpha;
254         if(Menu_Active)
255         {
256                 if(menuAlpha == 0 && menuLogoAlpha < 2)
257                 {
258                         menuLogoAlpha = menuLogoAlpha + frametime * 2;
259                 }
260                 else
261                 {
262                         menuAlpha = min(1, menuAlpha + frametime * 5);
263                         menuLogoAlpha = 2;
264                 }
265         }
266         else
267         {
268                 menuAlpha = max(0, menuAlpha - frametime * 5);
269                 menuLogoAlpha = 2;
270         }
271
272         draw_reset();
273
274         if(!(gamestatus & (GAME_CONNECTED | GAME_ISSERVER)))
275         {
276                 if(menuLogoAlpha > 0)
277                 {
278                         drawBackground(SKINGFX_BACKGROUND, bound(0, menuLogoAlpha, 1));
279                         if(menuAlpha <= 0 && SKINALPHA_CURSOR_INTRO > 0)
280                         {
281                                 draw_alpha = SKINALPHA_CURSOR_INTRO * bound(0, menuLogoAlpha, 1);
282                                 draw_drawMousePointer(menuMousePos);
283                                 draw_alpha = 1;
284                         }
285                 }
286         }
287         else if(SKINALPHA_BACKGROUND_INGAME)
288         {
289                 if(menuAlpha > 0)
290                         drawBackground(SKINGFX_BACKGROUND_INGAME, menuAlpha * SKINALPHA_BACKGROUND_INGAME);
291         }
292
293         draw_reset();
294         preMenuDraw();
295         draw_reset();
296
297         if(menuAlpha <= 0)
298         {
299                 if(prevMenuAlpha > 0)
300                         main.initializeDialog(main, main.firstChild);
301                 draw_reset();
302                 postMenuDraw();
303                 return;
304         }
305
306         draw_alpha *= menuAlpha;
307
308         if(menuMouseMode)
309         {
310                 vector newMouse;
311                 newMouse = globalToBoxSize(getmousepos(), draw_scale);
312                 if(newMouse != '0 0 0')
313                         if(newMouse != menuMousePos)
314                         {
315                                 menuMousePos = newMouse;
316                                 if(mouseButtonsPressed)
317                                         main.mouseDrag(main, menuMousePos);
318                                 else
319                                         main.mouseMove(main, menuMousePos);
320                         }
321         }
322         else
323         {
324                 if(frametime > 0)
325                 {
326                         vector dMouse;
327                         dMouse = getmousepos() * (frametime / realFrametime); // for capturevideo
328                         if(dMouse != '0 0 0')
329                         {
330                                 dMouse = globalToBoxSize(dMouse, draw_scale);
331                                 menuMousePos += dMouse * cvar("menu_mouse_speed");
332                                 menuMousePos_x = bound(0, menuMousePos_x, 1);
333                                 menuMousePos_y = bound(0, menuMousePos_y, 1);
334                                 if(mouseButtonsPressed)
335                                         main.mouseDrag(main, menuMousePos);
336                                 else
337                                         main.mouseMove(main, menuMousePos);
338                         }
339                 }
340         }
341         main.draw(main);
342         draw_alpha = max(draw_alpha, SKINALPHA_CURSOR_INTRO * bound(0, menuLogoAlpha, 1));
343
344         draw_drawMousePointer(menuMousePos);
345
346         draw_reset();
347         postMenuDraw();
348
349         frametime = 0;
350 };
351
352 void() m_display =
353 {
354         Menu_Active = true;
355         setkeydest(KEY_MENU);
356         setmousetarget((menuMouseMode ? MT_CLIENT : MT_MENU));
357
358         if(!menuInitialized)
359                 return;
360
361         if(mouseButtonsPressed)
362                 main.mouseRelease(main, menuMousePos);
363         mouseButtonsPressed = 0;
364
365         main.focusEnter(main);
366         main.showNotify(main);
367 };
368
369 void() m_hide =
370 {
371         Menu_Active = false;
372         setkeydest(KEY_GAME);
373         setmousetarget(MT_CLIENT);
374
375         if(!menuInitialized)
376                 return;
377
378         main.focusLeave(main);
379         main.hideNotify(main);
380 };
381
382 void() m_toggle =
383 {
384         if(Menu_Active)
385                 m_hide();
386         else
387                 m_display();
388 };
389
390 void() m_shutdown =
391 {
392         m_hide();
393 };
394
395 void(string itemname) m_goto =
396 {
397         entity e;
398         if(!menuInitialized)
399                 return;
400         if(itemname == "") // this can be called by GameCommand
401         {
402                 if(gamestatus & (GAME_ISSERVER | GAME_CONNECTED))
403                         m_hide();
404                 else
405                 {
406                         main.initializeDialog(main, main.firstChild);
407                         m_display();
408                 }
409         }
410         else
411         {
412                 e = findstring(NULL, name, itemname);
413                 if(e && e.parent == main)
414                 {
415                         m_hide();
416                         main.initializeDialog(main, e);
417                         m_display();
418                 }
419         }
420 }