]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/menu/xonotic/util.qc
Merge branch 'master' into samual/balancesamual
[xonotic/xonotic-data.pk3dir.git] / qcsrc / menu / xonotic / util.qc
1 float GL_CheckExtension(string ext)
2 {
3         return (strstrofs(strcat(" ", cvar_string("gl_info_extensions"), " "), strcat(" ", ext, " "), 0) >= 0);
4 }
5
6 float GL_Have_TextureCompression()
7 {
8         return (GL_CheckExtension("GL_EXT_texture_compression_s3tc") && GL_CheckExtension("GL_ARB_texture_compression"));
9 }
10
11 float tooltipdb;
12 void loadTooltips()
13 {
14         tooltipdb = db_load("tooltips.db");
15 }
16 void unloadTooltips()
17 {
18         db_close(tooltipdb);
19         tooltipdb = -1;
20 }
21 string getZonedTooltipForIdentifier(string s)
22 {
23         string t;
24         if(s == "")
25                 return string_null;
26         t = db_get(tooltipdb, s);
27         if(t == "-")
28                 return string_null;
29         if(t != "")
30                 return strzone(t);
31         t = cvar_description(s);
32         if(t != "" && t != "custom cvar")
33                 return strzone(t);
34         dprint("WARNING: no tooltip set for ", s, "\n");
35         return string_null;
36 }
37
38 void forAllDescendants(entity root, void(entity, entity) funcPre, void(entity, entity) funcPost, entity pass)
39 {
40         depthfirst(root, parent, firstChild, nextSibling, funcPre, funcPost, pass);
41 }
42
43 .string cvarName;
44 void SUB_Null_ee(entity e1, entity e2)
45 {
46 }
47 void saveCvarsOf(entity ignore, entity e)
48 {
49         if(e.saveCvars)
50                 e.saveCvars(e);
51 }
52 void loadCvarsOf(entity ignore, entity e)
53 {
54         if(e.loadCvars)
55                 e.loadCvars(e);
56 }
57 void saveAllCvars(entity root)
58 {
59         forAllDescendants(root, saveCvarsOf, SUB_Null_ee, NULL);
60 }
61 void loadAllCvars(entity root)
62 {
63         forAllDescendants(root, loadCvarsOf, SUB_Null_ee, NULL);
64 }
65
66 .string cvarNames_Multi;
67 .void(entity me) saveCvars_Multi;
68 void saveCvarsMulti(entity me)
69 {
70         float n, i;
71         string s;
72
73         me.saveCvars_Multi(me);
74         s = cvar_string(me.cvarName);
75
76         n = tokenize_console(me.cvarNames_Multi);
77         for(i = 0; i < n; ++i)
78                 cvar_set(argv(i), s);
79 }
80 void makeMulti(entity e, string otherCvars)
81 {
82         e.cvarNames_Multi = otherCvars;
83         e.saveCvars_Multi = e.saveCvars;
84         e.saveCvars = saveCvarsMulti;
85 }
86
87 .void(entity me) saveCvars_Callback;
88 .entity saveCvars_Callback_ent;
89 .void(entity me, entity cb) saveCvars_Callback_func;
90 void saveCvarsCallback(entity me)
91 {
92         me.saveCvars_Callback(me);
93         me.saveCvars_Callback_func(me.saveCvars_Callback_ent, me);
94 }
95 void makeCallback(entity e, entity cbent, void(entity, entity) cbfunc)
96 {
97         e.saveCvars_Callback = e.saveCvars;
98         e.saveCvars = saveCvarsCallback;
99         e.saveCvars_Callback_ent = cbent;
100         e.saveCvars_Callback_func = cbfunc;
101 }
102
103 .void(entity) draw_setDependent;
104 .string cvar_setDependent;
105 .float cvarMin_setDependent;
106 .float cvarMax_setDependent;
107 .string cvar2_setDependent;
108 .float cvar2Min_setDependent;
109 .float cvar2Max_setDependent;
110 .string cvar3_setDependent;
111 .float cvar3Min_setDependent;
112 .float cvar3Max_setDependent;
113 .float op_setDependent;
114 .string cvarString_setDependent;
115 .string cvarValue_setDependent;
116 .float(entity) func_setDependent;
117 void setDependent_Check(entity e)
118 {
119         float f;
120         string s;
121         if(e.func_setDependent)
122         {
123                 e.disabled = !(e.func_setDependent(e));
124         }
125         else if(e.cvarString_setDependent)
126         {
127                 s = cvar_string(e.cvarString_setDependent);
128                 e.disabled = (cvar_string(e.cvarString_setDependent) == e.cvarValue_setDependent);
129         }
130         else
131         {
132                 if(e.cvar_setDependent)
133                 {
134                         f = cvar(e.cvar_setDependent);
135                         if(e.cvarMin_setDependent <= e.cvarMax_setDependent)
136                                 e.disabled = ((f < e.cvarMin_setDependent) || (f > e.cvarMax_setDependent));
137                         else
138                                 e.disabled = ((f >= e.cvarMax_setDependent) && (f <= e.cvarMin_setDependent));
139                 }
140                 if(e.cvar2_setDependent)
141                 {
142                         f = cvar(e.cvar2_setDependent);
143                         if(e.cvar2Min_setDependent <= e.cvar2Max_setDependent)
144                                 e.disabled = (e.disabled + ((f < e.cvar2Min_setDependent) || (f > e.cvar2Max_setDependent)) > e.op_setDependent);
145                         else
146                                 e.disabled = (e.disabled + ((f >= e.cvar2Max_setDependent) && (f <= e.cvar2Min_setDependent)) > e.op_setDependent);
147                 }
148                 if(e.cvar3_setDependent)
149                 {
150                         f = cvar(e.cvar3_setDependent);
151                         if(e.cvar3Min_setDependent <= e.cvar3Max_setDependent)
152                                 e.disabled = (e.disabled + ((f < e.cvar3Min_setDependent) || (f > e.cvar3Max_setDependent)) > e.op_setDependent);
153                         else
154                                 e.disabled = (e.disabled + ((f >= e.cvar3Max_setDependent) && (f <= e.cvar3Min_setDependent)) > e.op_setDependent);
155                 }
156         }
157 }
158 void setDependent_Draw(entity e)
159 {
160         setDependent_Check(e);
161         e.draw_setDependent(e);
162 }
163 void setDependent(entity e, string theCvarName, float theCvarMin, float theCvarMax)
164 {
165         e.draw_setDependent = e.draw;
166         e.cvar_setDependent = theCvarName;
167         e.cvarMin_setDependent = theCvarMin;
168         e.cvarMax_setDependent = theCvarMax;
169         e.cvar2_setDependent = string_null;
170         e.cvar3_setDependent = string_null;
171         e.func_setDependent = func_null;
172         e.draw = setDependent_Draw;
173         setDependent_Check(e);
174 }
175 void setDependentStringNotEqual(entity e, string theCvarName, string theCvarValue)
176 {
177         e.draw_setDependent = e.draw;
178         e.cvarString_setDependent = theCvarName;
179         e.cvarValue_setDependent = theCvarValue;
180         e.cvar_setDependent = string_null;
181         e.cvar2_setDependent = string_null;
182         e.cvar3_setDependent = string_null;
183         e.func_setDependent = func_null;
184         e.draw = setDependent_Draw;
185         setDependent_Check(e);
186 }
187 void setDependentAND(entity e, string theCvarName, float theCvarMin, float theCvarMax, string theCvar2Name, float theCvar2Min, float theCvar2Max)
188 {
189         e.draw_setDependent = e.draw;
190         e.cvar_setDependent = theCvarName;
191         e.cvarMin_setDependent = theCvarMin;
192         e.cvarMax_setDependent = theCvarMax;
193         e.cvar2_setDependent = theCvar2Name;
194         e.cvar2Min_setDependent = theCvar2Min;
195         e.cvar2Max_setDependent = theCvar2Max;
196         e.cvar3_setDependent = string_null;
197         e.op_setDependent = 0;
198         e.func_setDependent = func_null;
199         e.draw = setDependent_Draw;
200         setDependent_Check(e);
201 }
202 void setDependentOR(entity e, string theCvarName, float theCvarMin, float theCvarMax, string theCvar2Name, float theCvar2Min, float theCvar2Max)
203 {
204         e.draw_setDependent = e.draw;
205         e.cvar_setDependent = theCvarName;
206         e.cvarMin_setDependent = theCvarMin;
207         e.cvarMax_setDependent = theCvarMax;
208         e.cvar2_setDependent = theCvar2Name;
209         e.cvar2Min_setDependent = theCvar2Min;
210         e.cvar2Max_setDependent = theCvar2Max;
211         e.cvar3_setDependent = string_null;
212         e.op_setDependent = 1;
213         e.func_setDependent = func_null;
214         e.draw = setDependent_Draw;
215         setDependent_Check(e);
216 }
217 void setDependentAND3(entity e, string theCvarName, float theCvarMin, float theCvarMax, string theCvar2Name, float theCvar2Min, float theCvar2Max, string theCvar3Name, float theCvar3Min, float theCvar3Max)
218 {
219         e.draw_setDependent = e.draw;
220         e.cvar_setDependent = theCvarName;
221         e.cvarMin_setDependent = theCvarMin;
222         e.cvarMax_setDependent = theCvarMax;
223         e.cvar2_setDependent = theCvar2Name;
224         e.cvar2Min_setDependent = theCvar2Min;
225         e.cvar2Max_setDependent = theCvar2Max;
226         e.cvar3_setDependent = theCvar3Name;
227         e.cvar3Min_setDependent = theCvar3Min;
228         e.cvar3Max_setDependent = theCvar3Max;
229         e.op_setDependent = 0;
230         e.func_setDependent = func_null;
231         e.draw = setDependent_Draw;
232         setDependent_Check(e);
233 }
234 void setDependentWeird(entity e, float(entity) func)
235 {
236         e.draw_setDependent = e.draw;
237         e.func_setDependent = func;
238         e.draw = setDependent_Draw;
239         setDependent_Check(e);
240 }
241
242 // URI SYSTEM ////////////////////////////////////////////////////////
243
244 float _Nex_ExtResponseSystem_Queried;
245 string _Nex_ExtResponseSystem_UpdateTo;
246
247 void URI_Get_Callback(float id, float status, string data)
248 {
249         if (id == URI_GET_DISCARD)
250         {
251                 // discard
252         }
253         else if(id == URI_GET_UPDATENOTIFICATION)
254         {
255                 UpdateNotification_URI_Get_Callback(id, status, data);
256         }
257         else if(id >= URI_GET_CURL && id <= URI_GET_CURL_END)
258         {
259                 Curl_URI_Get_Callback(id, status, data);
260         }
261         else
262         {
263                 print("Received HTTP request data for an invalid id ", ftos(id), ".\n");
264         }
265 }
266
267 void UpdateNotification_URI_Get_Callback(float id, float status, string data)
268 {
269         float n;
270
271         if(_Nex_ExtResponseSystem_UpdateTo)
272         {
273                 print("error: UpdateNotification_URI_Get_Callback has been called before\n");
274                 return;
275         }
276         if(status != 0)
277         {
278                 print(sprintf("error receiving update notification: status is %d\n", status));
279                 return;
280         }
281         if(substring(data, 0, 1) == "<")
282         {
283                 print("error: received HTML instead of an update notification\n");
284                 return;
285         }
286         if(strstrofs(data, "\r", 0) != -1)
287         {
288                 print("error: received carriage returns from update notification server\n");
289                 return;
290         }
291
292         if(data == "")
293                 n = 0;
294         else
295                 n = tokenizebyseparator(data, "\n");
296         
297         if(n >= 1)
298         {
299                 _Nex_ExtResponseSystem_UpdateTo = argv(0);
300
301                 if(vercmp(cvar_string("g_xonoticversion"), _Nex_ExtResponseSystem_UpdateTo) >= 0)
302                 {
303                         _Nex_ExtResponseSystem_UpdateTo = ""; // no update needed
304                 }
305                 else
306                 {
307                         // update needed
308                         if(n >= 2)
309                                 print(sprintf("Update can be downloaded at:\n%s\n", argv(1)));
310                 }
311
312                 _Nex_ExtResponseSystem_UpdateTo = strzone(_Nex_ExtResponseSystem_UpdateTo);
313         }
314 }
315
316 // END OF URI SYSTEM ////////////////////////////////////////////////////////
317
318 float preMenuInit()
319 {
320         vector sz;
321         vector boxA, boxB;
322
323         MapInfo_Cache_Create();
324         MapInfo_Enumerate();
325         if(!MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, 0, 0, 1))
326         {
327                 draw_reset_cropped();
328
329                 sz = eX * 0.025 + eY * 0.025 * (draw_scale_x / draw_scale_y);
330                 draw_CenterText('0.5 0.5 0' - 1.25 * sz_y * eY, "Autogenerating mapinfo for newly added maps...", sz, '1 1 1', 1, 0);
331
332                 boxA = '0.05 0.5 0' + 0.25 * sz_y * eY;
333                 boxB = '0.95 0.5 0' + 1.25 * sz_y * eY;
334                 draw_Fill(boxA, boxB - boxA, '1 1 1', 1);
335                 
336                 boxA += sz * 0.1;
337                 boxB -= sz * 0.1;
338                 draw_Fill(boxA, boxB - boxA, '0.1 0.1 0.1', 1);
339
340                 boxB_x = boxA_x * (1 - MapInfo_progress) + boxB_x * MapInfo_progress;
341                 draw_Fill(boxA, boxB - boxA, '0 0 1', 1);
342
343                 return FALSE;
344         }
345         return TRUE;
346 }
347
348 string campaign_name_previous;
349 float campaign_won_previous;
350 #ifdef WATERMARK
351 var string autocvar_menu_watermark = WATERMARK();
352 #else
353 var string autocvar_menu_watermark = "";
354 #endif
355 void postMenuDraw()
356 {
357         if(autocvar_menu_watermark != "")
358         {
359                 vector fs = '48 48 0';
360                 draw_CenterText('0.5 0.1 0', autocvar_menu_watermark, globalToBoxSize('32 32 0', draw_scale), '1 1 1', 0.05, 1);
361         }
362 }
363 void preMenuDraw()
364 {
365         vector fs, sz, line, mid;
366
367         if(cvar("menu_updatecheck"))
368         {
369                 if(!_Nex_ExtResponseSystem_Queried)
370                 {
371                         _Nex_ExtResponseSystem_Queried = 1;
372                         float startcnt;
373                         string uri;
374
375                         cvar_set("cl_startcount", ftos(startcnt = cvar("cl_startcount") + 1));
376
377                         // for privacy, munge the start count a little
378                         startcnt = floor((floor(startcnt / 10) + random()) * 10);
379                         uri = sprintf("http://www.xonotic.org/dl/checkupdate.txt?version=%s&cnt=%d", uri_escape(cvar_string("g_xonoticversion")), startcnt);
380
381 #ifdef CVAR_POPCON
382                         float cvar_handle, popcon_handle;
383                         float n, i, j;
384                         string k, s;
385                         cvar_handle = buf_create();
386                         buf_cvarlist(cvar_handle, "", "");
387                         n = buf_getsize(cvar_handle);
388                         popcon_handle = buf_create();
389                         for(i= 0, j = 0; i < n; ++i)
390                         {
391                                 k = bufstr_get(cvar_handle, i);
392                                 if(!(cvar_type(k) & CVAR_TYPEFLAG_SAVED))
393                                         continue;
394                                 s = sprintf("%s=%d", uri_escape(k), cvar_string(k) != cvar_defstring(k));
395                                 bufstr_set(popcon_handle, j, s);
396                                 ++j;
397                         }
398                         buf_del(cvar_handle);
399                         uri_postbuf(
400                                 uri, URI_GET_UPDATENOTIFICATION,
401                                 "application/x-www-form-urlencoded",
402                                 "&",
403                                 popcon_handle
404                         );
405                         buf_del(popcon_handle);
406 #else
407                         uri_get(uri, URI_GET_UPDATENOTIFICATION);
408 #endif
409                 }
410         }
411
412         if(_Nex_ExtResponseSystem_UpdateTo != "")
413         {
414                 // TODO rather turn this into a dialog
415                 fs = ((1/draw_scale_x) * eX + (1/draw_scale_y) * eY) * 12;
416                 line = eY * fs_y;
417                 sz_x = draw_TextWidth("  http://www.xonotic.com/  ", 0, fs);
418                 sz_y = 3 * fs_y;
419
420                 draw_alpha = sin(time * 0.112 - 0.3) * 10;
421                 mid = eX * (0.5 + 0.5 * (1 - sz_x) * cos(time * 0.071))
422                     + eY * (0.5 + 0.5 * (1 - sz_y) * sin(time * 0.071));
423
424                 draw_Fill(mid - 0.5 * sz, sz, '1 1 0', 1);
425                 draw_CenterText(mid - 1 * line, strcat("Update to ", _Nex_ExtResponseSystem_UpdateTo, " now!"), fs, '1 0 0', 1, 0);
426                 draw_CenterText(mid - 0 * line, "http://www.xonotic.org/", fs, '0 0 1', 1, 0);
427         }
428         if not(campaign_name_previous)
429                 campaign_name_previous = strzone(strcat(campaign_name, "x")); // force unequal
430         if(campaign_name == campaign_name_previous)
431         {
432                 if(cvar(strcat("g_campaign", campaign_name, "_won")))
433                 {
434                         if(!campaign_won_previous)
435                         {
436                                 m_display();
437                                 DialogOpenButton_Click_withCoords(NULL, main.winnerDialog, '0 0 0', eX * conwidth + eY * conheight);
438                         }
439                         campaign_won_previous = 1;
440                 }
441                 else
442                         campaign_won_previous = 0;
443         }
444         else
445         {
446                 strunzone(campaign_name_previous);
447                 campaign_name_previous = strzone(campaign_name);
448                 campaign_won_previous = cvar(strcat("g_campaign", campaign_name, "_won"));
449         }
450 }
451
452 string resolvemod(string m)
453 {
454         if(m == "=")
455                 return getcurrentmod();
456         else
457                 return m;
458 }
459
460 string HUD_Panel_GetSettingName(float theSetting)
461 {
462         switch(theSetting) {
463                 case HUD_MENU_ENABLE: return ""; break;
464                 default: return "";
465         }
466 }
467
468 float updateCompression()
469 {
470         float fh;
471         float have_dds, have_jpg, have_tga;
472         float can_dds;
473         if((have_dds = ((fh = fopen("dds/particles/particlefont.dds", FILE_READ)) >= 0)))
474                 fclose(fh);
475         if((have_jpg = ((fh = fopen("particles/particlefont.jpg", FILE_READ)) >= 0)))
476                 fclose(fh);
477         if((have_tga = ((fh = fopen("particles/particlefont.tga", FILE_READ)) >= 0)))
478                 fclose(fh);
479         can_dds = GL_Have_TextureCompression();
480         if(have_dds && (have_jpg || have_tga))
481         {
482                 // both? Let's only use good quality precompressed files
483                 // but ONLY if we actually support it!
484                 if(can_dds)
485                 {
486                         cvar_set("gl_texturecompression", "0");
487                         return 1;
488                 }
489                 else
490                 {
491                         cvar_set("gl_texturecompression", "0");
492                         cvar_set("r_texture_dds_load", "0");
493                         return 0;
494                 }
495         }
496         else if(have_dds)
497         {
498                 // DDS only? We probably always want texture compression
499                 cvar_set("gl_texturecompression", "1");
500                 cvar_set("r_texture_dds_load", "1");
501                 if(!can_dds)
502                         print("^1ERROR: Texture compression is required but not supported.\n^1Expect visual problems.\n");
503                 return 0;
504         }
505         else
506         {
507                 // TGA only? Allow runtime compression
508                 if(can_dds)
509                 {
510                         cvar_set("gl_texturecompression", cvar_string("r_texture_dds_load"));
511                         return 2;
512                 }
513                 else
514                 {
515                         cvar_set("gl_texturecompression", "0");
516                         cvar_set("r_texture_dds_load", "0");
517                         return 0;
518                 }
519         }
520 }
521
522 // note: include only those that should be in the menu!
523 #define GAMETYPES \
524         GAMETYPE(MAPINFO_TYPE_ARENA, "Arena") \
525         GAMETYPE(MAPINFO_TYPE_ASSAULT, "Assault") \
526         GAMETYPE(MAPINFO_TYPE_CTF, "Capture The Flag") \
527         GAMETYPE(MAPINFO_TYPE_CA, "Clan Arena") \
528         GAMETYPE(MAPINFO_TYPE_DEATHMATCH, "Deathmatch") \
529         GAMETYPE(MAPINFO_TYPE_DOMINATION, "Domination") \
530         GAMETYPE(MAPINFO_TYPE_FREEZETAG, "Freeze Tag") \
531         GAMETYPE(MAPINFO_TYPE_KEEPAWAY, "Keepaway") \
532         GAMETYPE(MAPINFO_TYPE_KEYHUNT, "Key Hunt") \
533         GAMETYPE(MAPINFO_TYPE_LMS, "Last Man Standing") \
534         GAMETYPE(MAPINFO_TYPE_NEXBALL, "Nexball") \
535         GAMETYPE(MAPINFO_TYPE_ONSLAUGHT, "Onslaught") \
536         GAMETYPE(MAPINFO_TYPE_RACE, "Race") \
537         GAMETYPE(MAPINFO_TYPE_CTS, "Race CTS") \
538         GAMETYPE(MAPINFO_TYPE_RUNEMATCH, "Runematch") \
539         GAMETYPE(MAPINFO_TYPE_TEAM_DEATHMATCH, "Team Deathmatch") \
540         /* nothing */
541
542 float GameType_GetID(float cnt)
543 {
544         float i;
545         i = 0;
546 #define GAMETYPE(id,name) if(i++ == cnt) return id;
547         GAMETYPES
548 #undef GAMETYPE
549         return 0;
550 }
551 string GameType_GetName(float cnt)
552 {
553         float i;
554         i = 0;
555 #define GAMETYPE(id,name) if(i++ == cnt) return name;
556         GAMETYPES
557 #undef GAMETYPE
558         return "@!#%'n Tuba Throwing";
559 }
560 float GameType_GetCount()
561 {
562         float i;
563         i = 0;
564 #define GAMETYPE(id,name) ++i;
565         GAMETYPES
566 #undef GAMETYPE
567         return i;
568 }
569