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