]> icculus.org git repositories - divverent/nexuiz.git/blob - menu/mcustom.qc
grappling hook
[divverent/nexuiz.git] / menu / mcustom.qc
1 ///////////////////////////////////////////////
2 // Custom Menu Source File
3 ///////////////////////
4 // This file belongs to dpmod/darkplaces
5 // AK contains menu specific stuff that is made especially for dpmod
6 // AK this file is used e.g. for defining some special event functions
7 ////////////////////////////////////////////////
8
9 ////////////////
10 // global stuff
11 ///
12
13 void() nex_setposition =
14 {
15         self.pos_x = 0;
16         self.pos_y = (self.font_size_y + 5) * self.orderpos;
17         self.pos_z = 0;
18
19         self.origin = self.pos;
20 };
21
22 void(entity item) nex_makeonlyvisible =
23 {
24         local entity node;
25
26         if( item.flag & FLAG_HIDDEN )
27                 item.flag = item.flag - FLAG_HIDDEN;
28         for( node = item._next ; node ; node = node._next )
29                 node.flag = item.flag | FLAG_HIDDEN;
30         for( node = item._prev ; node ; node = node._prev )
31                 node.flag = item.flag | FLAG_HIDDEN;
32 };
33
34 void(void) nex_linkrelhack =
35 {
36         self._child._parent = self;
37 };
38
39 void(void) nex_maketextzone =
40 {
41         self.text = strzone(self.text);
42 };
43
44 void(void) nex_slidertext =
45 {
46         entity ent;
47         if(self.link == "")
48         {
49                 print("No link specified\n");
50                 eprint(self);
51                 self.init = null_function;
52                 return;
53         }
54
55         ent = menu_getitem(self.link);
56         if(ent == null_entity)
57         {
58                 objerror("No link found for ", self.link,"\n");
59         }
60
61         self._link = ent;
62
63         self.flag = self.flag | FLAG_DRAWREFRESHONLY;
64
65         self.refresh = _nex_slidertext_refresh;
66 };
67
68 void(void) _nex_slidertext_refresh =
69 {
70         self.text = ftos(self._link.value);
71         if(self.maxlen > 0)
72                 self.text = substring(self.text,0, self.maxlen);
73         // reset the size, so its set
74         self.size = '0 0 0';
75 };
76
77 float(float keynr, float ascii) nex_redirect_key =
78 {
79         if((ascii>=20 && ascii <= 126) || keynr == K_BACKSPACE || keynr == K_ENTER || keynr == K_LEFTARROW || keynr == K_RIGHTARROW || (keynr >= K_MOUSE1 && keynr <= K_MOUSE10))
80         {
81                 raise_key(self._child, keynr, ascii);
82                 return true;
83         }
84         return false;
85 };
86
87 void(void) nex_cvar_slider =
88 {
89         self.value = cvar(self.cvarname);
90         self.slidermove = self.switchchange = _nex_cvar_slider;
91         self.refresh = _nex_cvar_slider_refresh;
92 };
93
94 void(void) _nex_cvar_slider_refresh =
95 {
96         if(self.cvartype == CVAR_INT || self.cvartype == CVAR_FLOAT || self.cvartype == CVAR_STEP)
97                 self.value = cvar(self.cvarname);
98 };
99
100 void(void) _nex_cvar_slider =
101 {
102         if(self.cvarname == "")
103                 return;
104         if(self.cvartype == CVAR_INT) // || self.cvartype == CVAR_STRING)
105                 self.value = rint(self.value);
106         if(self.cvartype == CVAR_STEP)
107                 self.value = rint(self.value / self.step) * self.step;
108         if(self.cvartype == CVAR_INT || self.cvartype == CVAR_FLOAT || self.cvartype == CVAR_STEP)
109                 cvar_set(self.cvarname, ftos(self.value));
110         /*if(cvartype == CVAR_STRING)
111         {
112                 string s;
113                 s = getaltstring(self.value, self.cvarvalues);
114                 cvar_set(self.cvarname, s);
115         }
116         */
117 };
118
119 //////////////
120 // main.menu
121 ///
122
123 void(void) nex_makeselfonlyvisible =
124 {
125         nex_makeonlyvisible( self );
126 };
127
128 // quit menu
129
130 void(void) nex_quit_choose =
131 {
132         entity e;
133         // because of the missing support for real array, we have to do it the stupid way
134         // (we also have to use strzone for the text, cause it the temporary strings wont work
135         // for it)
136         if(nex_quitrequest == 0)
137         {
138                 e = menu_getitem("quit_msg_0");
139                 e.text = getaltstring(0,nex_quitmsg_0);
140         }
141         if(nex_quitrequest == 1)
142         {
143                 e = menu_getitem("quit_msg_0");
144                 e.text = getaltstring(0,nex_quitmsg_1);
145         }
146         if(nex_quitrequest == 2)
147         {
148                 e = menu_getitem("quit_msg_0");
149                 e.text = getaltstring(0,nex_quitmsg_2);
150         }
151         if(nex_quitrequest == 3)
152         {
153                 e = menu_getitem("quit_msg_0");
154                 e.text = getaltstring(0,nex_quitmsg_3);
155         }
156         e.text = strzone(e.text);
157
158         if(nex_quitrequest == 0)
159         {
160                 e = menu_getitem("quit_msg_1");
161                 e.text = getaltstring(1,nex_quitmsg_0);
162         }
163         if(nex_quitrequest == 1)
164         {
165                 e = menu_getitem("quit_msg_1");
166                 e.text = getaltstring(1,nex_quitmsg_1);
167         }
168         if(nex_quitrequest == 2)
169         {
170                 e = menu_getitem("quit_msg_1");
171                 e.text = getaltstring(1,nex_quitmsg_2);
172         }
173         if(nex_quitrequest == 3)
174         {
175                 e = menu_getitem("quit_msg_1");
176                 e.text = getaltstring(1,nex_quitmsg_3);
177         }
178         e.text = strzone(e.text);
179
180         nex_quitrequest = nex_quitrequest + 1;
181         if(nex_quitrequest == DPMOD_QUIT_MSG_COUNT)
182                 nex_quitrequest = 0;
183 };
184
185 void(void) nex_quit =
186 {
187 /*  entity ent;
188         // choose a quit message
189         nex_quit_choose();
190
191         // change the flags
192         ent = menu_getitem("main");
193         ent.flag = ent.flag | FLAG_CHILDDRAWONLY;
194         ent = menu_getitem("quit");
195         ent.flag = FLAG_NOSELECT;
196         menu_jumptowindow(ent, false);*/
197         entity ent;
198
199         // change the flags
200         ent = menu_getitem("quitbox_ref");
201         ent._child = menu_activewindow;
202         ent = menu_getitem("quitbox");
203         menu_jumptowindow(ent, true);
204 };
205
206 void(void) nex_quit_yes =
207 {
208         cmd("quit\n");
209 };
210
211 void(void) nex_quit_no =
212 {
213 /*  entity ent;
214
215         ent = menu_getitem("quit_msg_0");
216         strunzone(ent.text);
217
218         ent = menu_getitem("quit_msg_1");
219         strunzone(ent.text);
220
221         ent = menu_getitem("quit");
222         ent.flag = FLAG_HIDDEN;
223         ent = menu_getitem("main");
224         ent.flag = ent.flag - FLAG_CHILDDRAWONLY;
225         menu_selectup();*/
226         menu_selectup();
227 };
228
229 float(float keynr, float ascii) nex_quit_key =
230 {
231         if(keynr == K_LEFTARROW)
232                 return false;
233         if(keynr == K_RIGHTARROW)
234                 return false;
235         if(keynr == K_ENTER)
236                 return false;
237         if(keynr == K_MOUSE1)
238                 return false;
239         if(ascii == 'Y' || ascii == 'y')
240                 nex_quit_yes();
241         if(ascii == 'N' || ascii == 'n' || keynr == K_ESCAPE)
242                 nex_quit_no();
243         return true;
244 };
245
246 // options menu
247
248 void(void) nex_display_options =
249 {
250         entity ent;
251
252         ent = menu_getitem( "options" );
253
254         nex_makeonlyvisible( ent );
255         menu_jumptowindow( ent, false );
256 };
257
258 /////////////////
259 // video.menu
260
261 void(void) nex_display_video =
262 {
263         nex_makeonlyvisible( menu_getitem( "video" ) );
264         menu_jumptowindow( menu_getitem( "video" ), false );
265 };
266
267 void(void) nex_video_bpp_reinit =
268 {
269         if(cvar("vid_bitsperpixel") == 32)
270                 self.value = 1;
271         else
272                 self.value = 0;
273 };
274
275 void(void) nex_video_fullscreen_reinit =
276 {
277         self.value = cvar("vid_fullscreen");
278 };
279
280 string nex_video_resolutions;
281
282 void(void) nex_video_resolution_switch_reinit =
283 {
284         float c, i;
285         float pos86;
286
287         c = getaltstringcount(nex_video_resolutions);
288         for(i = 0; i < c; i=i+1)
289         {
290                 string s;
291                 vector t;
292                 s = getaltstring(i,nex_video_resolutions);
293                 s = strcat("'",s,"'");
294                 t = stov(s);
295                 if(t_x == cvar("vid_width") && t_y == cvar("vid_height"))
296                 {
297                         self.value = i;
298                         return;
299                 }
300                 if(t == '800 600 0')
301                         pos86 = i;
302         }
303
304         self.value = pos86;
305 };
306
307 void(void) nex_video_resolution_switch =
308 {
309         var float pos86 = 0;
310         var float counter = 0;
311         vector t;
312
313         nex_video_resolutions = "";
314         self.text = "";
315         self.value = -1;
316
317         while((t = getresolution(counter)) != '0 0 0')
318         {
319                 if(t == '800 600 0')
320                         pos86 = counter;
321                 if(t_x == cvar("vid_width") && t_y == cvar("vid_height"))
322                 {
323                         self.value = counter;
324                 }
325                 counter = counter + 1;
326                 self.text = strcat(self.text,"'",ftos(t_x),"x");
327                 self.text = strcat(self.text,ftos(t_y),"'");
328                 nex_video_resolutions = strcat(nex_video_resolutions,vtos(t));
329         }
330
331         if(self.value == -1)
332                 self.value = pos86;
333
334         self.text = strzone(self.text);
335         nex_video_resolutions = strzone(nex_video_resolutions);
336
337         self.reinit = nex_video_resolution_switch;
338 };
339
340 void(void) nex_video_apply =
341 {
342         vector set, res;
343         float changed;
344         entity tmp;
345
346         changed = false;
347
348         // resolution test
349         res_x = cvar("vid_width");
350         res_y = cvar("vid_height");
351         res_z = 0;
352
353         tmp = menu_getitem("video_resolution_switch");
354         set = stov(getaltstring(tmp.value, nex_video_resolutions));
355         if(set != res)
356         {
357                 cvar_set("vid_width",ftos(set_x));
358                 cvar_set("vid_height",ftos(set_y));
359                 changed = true;
360         }
361         // bpp test
362         tmp = menu_getitem("video_bpp_switch");
363         if((tmp.value+1)*16 != cvar("vid_bitsperpixel"))
364         {
365                 cvar_set("vid_bitsperpixel",ftos((tmp.value+1)*16));
366                 changed = true;
367         }
368         // fullscreen changed
369         tmp = menu_getitem("video_fullscreen_switch");
370         if(tmp.value != cvar("vid_fullscreen"))
371         {
372                 cvar_set("vid_fullscreen",ftos(tmp.value));
373                 changed = true;
374         }
375
376         if(changed)
377         {
378                 cmd("vid_restart\n");
379         }
380 };
381
382 /////////////////
383 // xplayer.menu
384 ///
385
386 float maxfrags;
387 float maxtime;
388 float maxbots;
389 float skilllevel;
390 string hostname;
391 float  maxclients;
392 float  publicserver;
393 float  gamemode;
394
395 entity maps_list;
396 entity maps_current;
397
398 // text = info text
399 // picture = picture filename
400 // name = map name
401 void(entity node) _nex_xp_remove =
402 {
403         strunzone( node.picture );
404         strunzone( node.text );
405         strunzone( node.name );
406         remove( node );
407 }
408
409 void(void) _nex_xp_update =
410 {
411         entity item;
412
413         item = menu_getitem( "creategame_map_name" );
414         item.text = maps_current.name;
415
416         item = menu_getitem( "creategame_map_picture" );
417         item.picture = maps_current.picture;
418
419         item = menu_getitem( "creategame_map_info" );
420         item.text = maps_current.text;
421 };
422
423 void(void) nex_xp_enummaps =
424 {
425         float count;
426         float searchhandle;
427         float counter;
428
429         // remove the old list
430         if( maps_list ) {
431                 entity node;
432
433                 node = maps_list;
434                 while( node._next ) {
435                         node = node._next;
436                         _nex_xp_remove( node._prev );
437                 }
438                 _nex_xp_remove( node );
439         }
440         maps_list = maps_current = null_entity;
441
442         searchhandle = search_begin( "maps/*.bsp", true, true );
443         if( searchhandle == -1 ) {
444                 print( "menu: No maps found!\n" );
445                 return;
446         } else if( searchhandle == -2)
447                 return;
448
449         maps_list = maps_current = spawn();
450         count = search_getsize( searchhandle );
451         for( counter = 0 ; counter < count ; counter = counter + 1 ) {
452                 float file;
453                 string fname;
454
455                 fname = search_getfilename( searchhandle, counter );
456                 fname = substring( fname, 0, strlen( fname ) -  4 );
457                 fname = strzone( fname );
458
459                 //try to find the information text
460                 file = fopen( strcat( fname, ".txt" ), FILE_READ );
461                 if( file == -1 )
462                         maps_current.text = strzone( "--NO INFORMATION AVAILABLE--" );
463                 else {
464                         string temp, old;
465                         maps_current.text = strzone( "" );
466                         do {
467                                 old = maps_current.text;
468                                 temp = fgets( file );
469                                 maps_current.text = strzone( strcat( old, temp, "\n" ) );
470                                 strunzone( old );
471                         } while( validstring( temp ) );
472                         fclose( file );
473                 }
474
475                 //try to find the picture
476                 file = search_begin( strcat( fname, ".jpg" ), true, true );
477                 if( file == -1 )
478                         maps_current.picture = strzone( "gfx/m_nomap" );
479                 else {
480                         maps_current.picture = strzone( strcat( fname, ".jpg" ) );
481                         search_end( file );
482                 }
483
484                 maps_current.name = strzone( substring( fname, 5, strlen( fname ) - 5 ) ); // remove the 'maps/'
485                 strunzone( fname );
486
487                 // create next item and link it with the list
488                 maps_current._next = spawn();
489                 maps_current._next._prev = maps_current;
490                 maps_current = maps_current._next;
491         }
492         // remove the last item
493         maps_current = maps_current._prev;
494         remove( maps_current._next );
495         maps_current._next = null_entity;
496
497         search_end( searchhandle );
498
499         maps_current = maps_list;
500         _nex_xp_update();
501 };
502
503 void(void) nex_xp_prev =
504 {
505         if( maps_current._prev )
506                 maps_current = maps_current._prev;
507         _nex_xp_update();
508 };
509
510 void(void) nex_xp_next =
511 {
512         if( maps_current._next )
513                 maps_current = maps_current._next;
514         _nex_xp_update();
515 };
516
517
518 void(void) nex_display_creategame =
519 {
520         nex_makeonlyvisible( menu_getitem( "creategame" ) );
521         menu_jumptowindow( menu_getitem( "creategame" ), false );
522 };
523
524 void(void) nex_xp_maxfrags =
525 {
526         float x;
527         x = stof(self.text);
528         maxfrags = rint(x);
529
530         strunzone(self.text);
531         self.text = ftos(x);
532         self.text = strzone(self.text);
533 };
534
535 void(void) nex_xp_maxbots =
536 {
537         float x;
538         x = stof(self.text);
539         maxbots = min( fabs(rint(x)), maxclients - 1, 16 ); // 16 is currently max in frikbot - see below
540
541         strunzone(self.text);
542         self.text = ftos(x);
543         self.text = strzone(self.text);
544 };
545
546 void(void) nex_xp_maxtime =
547 {
548         float x;
549         x = stof(self.text);
550         maxtime = rint(x);
551
552         strunzone(self.text);
553         self.text = ftos(maxtime);
554         self.text = strzone(self.text);
555 };
556
557 void(void) nex_xp_hostname =
558 {
559         hostname = self.text;
560 };
561
562 void(void) nex_xp_maxclients =
563 {
564         local float i;
565         i = stof(self.text);
566         maxclients = rint(i);
567
568         strunzone(self.text);
569         self.text = strzone(ftos(maxclients));
570 };
571
572 void(void) nex_xp_publicserv =
573 {
574         publicserver = self.value;
575 };
576
577 void(void) nex_xp_gamemode =
578 {
579         gamemode = self.value;
580 };
581
582 void(void) nex_xp_skilllevel =
583 {
584         skilllevel = self.value;
585 }
586
587 void(void) nex_xp_start =
588 {
589         cvar_set( "fraglimit", ftos( maxfrags ) );
590         cvar_set( "timelimit", ftos( maxtime ) );
591         cvar_set( "deathmatch", "1" );
592
593         cmd( "maxplayers " );
594         cmd( ftos( maxclients ) );
595         cmd( "\n" );
596
597         cvar_set( "sv_public", ftos( publicserver ) );
598         cvar_set( "hostname", hostname );
599
600         // see bot/bot.qc: BotInit
601         cvar_set( "saved1", "1" );
602         cvar_set( "scratch1", ftos( pow( 2, maxbots ) - 1 ) );
603         cvar_set( "scratch2", ftos( skilllevel * (pow(4, min(maxbots, 8)) - 1) / 3) );
604         cvar_set( "scratch3", ftos( skilllevel * (pow(4, min(maxbots - 8, 8)) - 1) / 3) );
605
606         cmd( "map " );
607         cmd( maps_current.name );
608         cmd( "\n" );
609         cmd( "togglemenu\n" );
610 };
611
612 void(void) nex_goto_createserver =
613 {
614         menu_jumptowindow( menu_getitem( "multiplayer_frame"), false );
615 }
616
617 void(void) nex_draw_text =
618 {
619         local vector drawpos;
620         local float cpos, end;
621
622         cpos = 0;
623         drawpos = self.pos;
624         drawpos_y = drawpos_y + self.font_size_y;
625         do {
626                 local string l;
627                 local float i;
628
629                 end = strlen( self.text );
630                 i = cpos;
631                 do {
632                         l = substring( self.text, i, 1 );
633
634                         if( l == "\n" ) {
635                                 end = i;
636                                 break;
637                         }
638
639                         i = i + 1;
640                 } while( l != "" );
641
642                 l = substring( self.text, cpos, end - cpos );
643                 if( l != "" )
644                         menu_drawstring( drawpos, l, self.font_size, self.color, self.alpha, self.drawflag );
645                 drawpos_y = drawpos_y + self.font_size_y;
646
647                 cpos = end + 1;
648         } while( end != strlen( self.text ) );
649 }
650
651 // server list
652 var float slist_selected = 0;
653 var float slist_start   = 0;
654 float slist_estimatedsize;
655
656 void(void) nex_display_serverlist =
657 {
658         if(menu_activewindow.name == "serverlist")
659                 return;
660         menu_jumptowindow(menu_getitem("serverlist"),true);
661         cmd("net_slist\n");
662 };
663
664 // use a ITEM_TEXT as base item for this
665 // we need another item to clip the slist
666 // (another reason for a new menu qc!)
667 void(void) slist_draw =
668 {
669         float c;
670         vector pos;
671         float listsize;
672
673         //print("slist drawing...", ftos(listsize), "\n");
674
675         pos = '0 0 0'; // the upper item sets the origin
676         listsize = gethostcachevalue(SLIST_HOSTCACHECOUNT);
677         if(!listsize)
678         {
679                 menu_drawstring(pos, "No Servers", self.font_size, self.color, self.alpha, self.drawflag);
680                 return;
681         }
682
683         for(c = 0; c < slist_estimatedsize + 1; c = c + 1)
684         {
685                 string line;
686
687                 if(listsize <= slist_start + c)
688                         break;
689
690                 //print("drawing ", ftos(c),"\n");
691
692                 if(slist_selected - slist_start == c)
693                 {
694                         vector s;
695                         s = self.size;
696                         s_y = self.font_size_y * 2;
697
698                         menu_fillarea(pos, s, self.color_selected, self.alpha_selected * (sin(time * 9) + 1) / 2, self.drawflag_selected);
699                 }
700
701                 line = gethostcachestring(SLIST_LINE1, slist_start + c);
702
703                 if( !line || line == "" )
704                         line = strzone( "Empty" );
705                 else
706                         line = strzone( strcat( chr(127), line ) );
707
708                 menu_drawstring(pos, line, self.font_size, self.color, self.alpha, self.drawflag);
709
710                 pos_y = pos_y + self.font_size_y;
711
712                 strunzone( line );
713                 line = gethostcachestring(SLIST_LINE2, slist_start + c);
714
715                 if( !line || line == "" )
716                         line = strzone( "Empty" );
717                 else
718                         line = strzone( strcat( chr(127), line ) );
719
720                 menu_drawstring(pos, line, self.font_size, self.color, self.alpha, self.drawflag);
721                 pos_y = pos_y + self.font_size_y;
722
723                 strunzone( line );
724         }
725 };
726
727 void(void) slist_init =
728 {
729         self.size = self._parent.size;
730         slist_estimatedsize = self.size_y / self.font_size_y / 2;
731 };
732
733 void(void) slist_refresh =
734 {
735         float hostcachesize;
736
737         hostcachesize = gethostcachevalue(SLIST_HOSTCACHECOUNT);
738         if(slist_start >= hostcachesize)
739                 slist_start = ceil(hostcachesize - slist_estimatedsize);
740         if(slist_start < 0)
741                 slist_start = 0;
742         if(slist_selected >= hostcachesize)
743                 slist_selected = hostcachesize;
744 };
745
746 void(void) slist_join =
747 {
748         string cname;
749         cname = gethostcachestring(SLIST_CNAME, slist_selected);
750
751         if(cname != "")
752         {
753                 cmd("connect ");
754                 cmd(cname);
755                 cmd(" ;togglemenu\n");
756         }
757 };
758
759 float(float keynr, float ascii ) slist_key =
760 {
761         float listsize;
762
763         if(keynr == K_UPARROW)
764         {
765                 if(slist_selected > 0)
766                         slist_selected = slist_selected - 1;
767                 if(slist_start > slist_selected)
768                         slist_start = slist_selected;
769                 return TRUE;
770         } else if(keynr == K_DOWNARROW)
771         {
772                 listsize = gethostcachevalue(SLIST_HOSTCACHECOUNT);
773                 if(slist_selected < listsize - 1)
774                         slist_selected = slist_selected + 1;
775                 if(slist_start + slist_estimatedsize - 0.5 < slist_selected)
776                         slist_start = ceil(slist_selected - slist_estimatedsize + 0.5);
777                 return TRUE;
778         } else if(keynr == K_ENTER)
779         {
780                 slist_join();
781                 return TRUE;
782         } else if(keynr == K_SPACE)
783         {
784                 cmd("net_slist\n");
785                 return TRUE;
786         } else if(keynr == K_MOUSE1)
787         {
788                 float pos;
789
790                 listsize = gethostcachevalue(SLIST_HOSTCACHECOUNT);
791                 pos = floor(menu_cursor_y / self.font_size_y / 2);
792
793                  if(pos + slist_start == slist_selected)
794                         slist_join();
795                 else if(pos + slist_start < listsize)
796                         slist_selected = pos;
797                 return TRUE;
798         }
799         return FALSE;
800 };
801
802 void(void) slist_info1 =
803 {
804         float query, reply;
805         string temp;
806
807         query = gethostcachevalue(SLIST_MASTERQUERYCOUNT);
808         reply = gethostcachevalue(SLIST_MASTERREPLYCOUNT);
809
810         if( self.text )
811                 strunzone(self.text);
812
813         temp = strcat(ftos(reply), "/");
814         temp = strcat(temp, ftos(query), " Master Servers");
815
816         self.text = strzone(temp);
817 };
818
819 void(void) slist_info2 =
820 {
821         float query, reply;
822         string temp;
823
824         query = gethostcachevalue(SLIST_SERVERQUERYCOUNT);
825         reply = gethostcachevalue(SLIST_SERVERREPLYCOUNT);
826
827         if( self.text )
828                 strunzone(self.text);
829
830         temp = strcat(ftos(reply), "/");
831         temp = strcat(temp, ftos(query), " Game Servers");
832
833         self.text = strzone(temp);
834 };
835
836 /////////////////
837 // options.menu
838 ///
839
840 // player options
841 var entity mlist_list = null_entity;
842 entity mlist_current;
843 string mlist_saved;
844
845 string player_name;
846
847 string player_model_cvar = "_cl_playermodel";
848 string player_name_cvar = "_cl_name";
849 string player_skin_cvar = "_cl_playerskin";
850 string player_fov_cvar = "player_fov";
851
852 void() nex_player_init =
853 {
854         local entity lEntity;
855
856         mlist_saved = strzone( str_cvar( player_model_cvar ) );
857
858         lEntity = menu_getitem( "options_player_opt_playername_switch" );
859         lEntity.text = strzone( str_cvar( player_name_cvar ) );
860
861 };
862
863 void(void) nex_player_reinit =
864 {
865         entity ent;
866
867         strunzone( mlist_saved );
868         mlist_saved = strzone( str_cvar( player_model_cvar ) );
869
870         ent = menu_getitem( "options_player_opt_playername_switch" );
871         strunzone( ent.text );
872         ent.text = strzone( str_cvar( player_name_cvar ) );
873 };
874
875 void(void) nex_player_name =
876 {
877         player_name = self.text;
878 };
879
880 void(void) nex_player_apply =
881 {
882         cmd( strcat( "playermodel \"", mlist_current.picture_selected, "\"\n" ) );
883         cmd( strcat( "playerskin \"", mlist_current.picture_pressed, "\"\n" ) );
884         cmd( strcat( "name ", player_name, "\n" ) );
885 };
886
887 // name = name
888 // picture_selected = model name
889 // picture_pressed = skin name
890 // picture = picture
891 // text = desc text
892 void(entity e) _nex_player_remove =
893 {
894         strunzone( e.name );
895         strunzone( e.picture_selected );
896         strunzone( e.picture_pressed );
897         strunzone( e.picture );
898         strunzone( e.text );
899
900         remove( e );
901 };
902
903 void() _nex_player_model_update =
904 {
905         entity item;
906
907         if( !mlist_list )
908                 return;
909
910         item = menu_getitem( "options_player_model_name" );
911         item.text = mlist_current.name;
912
913         item = menu_getitem( "options_player_model_picture" );
914         item.picture = mlist_current.picture;
915
916         item = menu_getitem( "options_player_model_info" );
917         item.text = mlist_current.text;
918 };
919
920 /*
921 .mdef file format
922 name
923 picture\n
924 skin filename\n
925 model filename\n
926 rest text*/
927 void(void) nex_player_buildlist =
928 {
929         local float shandle;
930         local float count;
931         local float counter;
932         local float loaded;
933         local entity hit;
934
935         // remove the old player list
936         if( mlist_list ) {
937                 local entity node;
938
939                 // save the old selected model
940                 mlist_saved = strzone( mlist_current.name );
941
942                 node = mlist_list;
943                 while( node._next ) {
944                         node = node._next;
945                         _nex_player_remove( node._prev );
946                 }
947                 _nex_player_remove( node );
948
949                 mlist_list = mlist_current = null_entity;
950         }
951
952         shandle = search_begin( "models/player/*.txt", false, true );
953         if( shandle < 0 )
954                 return;
955
956         count = search_getsize( shandle );
957         mlist_list = mlist_current = spawn();
958         hit = null_entity;
959         loaded = 0;
960         for ( counter = 0 ; counter < count ; counter = counter + 1 ) {
961                 local string dname;
962                 local string dpicture;
963                 local string dskin;
964                 local string dmodel;
965                 local string dtext;
966
967                 local float handle;
968
969                 handle = fopen( search_getfilename( handle, counter ), FILE_READ );
970
971                 if( handle < 0 )
972                         continue;
973
974                 dname = strzone( fgets( handle ) );
975                 dpicture = strzone( fgets( handle ) );
976                 dskin = strzone( fgets( handle ) );
977                 dmodel = strzone( fgets( handle ) );
978                 {
979                         local string ltemp, lold;
980                         dtext = strzone( "" );
981                         do {
982                                 lold = dtext;
983                                 ltemp = fgets( handle );
984                                 dtext = strzone( strcat( lold, ltemp, "\n" ) );
985                                 strunzone( lold );
986                         } while( validstring( ltemp ) );
987                 }
988
989                 if( !dname || !dpicture || !dskin || !dmodel || !dtext ) {
990                         print( "Bad model definition file '", search_getfilename( shandle, counter ), "'\n" );
991
992                         strunzone( dname );
993                         strunzone( dpicture );
994                         strunzone( dskin );
995                         strunzone( dmodel );
996                         //strunzone( dtext );
997
998                         fclose( handle );
999                         continue;
1000                 }
1001
1002                 // is this the previous selected model?
1003                 if( dname == mlist_saved )
1004                         hit = mlist_current;
1005
1006                 mlist_current.name = dname;
1007                 mlist_current.picture = dpicture;
1008                 mlist_current.picture_pressed = dskin;
1009                 mlist_current.picture_selected = dmodel;
1010                 mlist_current.text = dtext;
1011
1012                 loaded = loaded + 1;
1013
1014                 mlist_current._next = spawn();
1015                 mlist_current._next._prev = mlist_current;
1016                 mlist_current = mlist_current._next;
1017
1018                 fclose( handle );
1019         }
1020         mlist_current._prev._next = null_entity;
1021         remove( mlist_current );
1022
1023         search_end( shandle );
1024
1025         if( loaded == 0 ) {
1026                 print( "No model description files found in models/player\n" );
1027                 mlist_list = mlist_current = null_entity;
1028         } else
1029                 print( ftos( loaded ), " model description files loaded from models/player\n" );
1030
1031         if( hit )
1032                 mlist_current = hit;
1033         else
1034                 mlist_current = mlist_list;
1035
1036         _nex_player_model_update();
1037 };
1038
1039 void(void) nex_player_model_next =
1040 {
1041         if( mlist_current._next )
1042                 mlist_current = mlist_current._next;
1043         _nex_player_model_update();
1044 };
1045
1046 void(void) nex_player_model_prev =
1047 {
1048         if( mlist_current._prev )
1049                 mlist_current = mlist_current._prev;
1050         _nex_player_model_update();
1051 };
1052
1053 void(void) nex_player =
1054 {
1055         entity ent;
1056         ent = menu_getitem("options_player");
1057         nex_makeonlyvisible( ent );
1058         menu_jumptowindow(ent, false);
1059 };
1060
1061 // old/other options
1062
1063 void(void) nex_options_alwaysrun_switchchange =
1064 {
1065         if(self.value)
1066         {
1067                 cvar_set("cl_forwardspeed","400");
1068                 cvar_set("cl_backspeed","400");
1069         }
1070         else
1071         {
1072                 cvar_set("cl_forwardspeed","200");
1073                 cvar_set("cl_backspeed","200");
1074         }
1075 };
1076
1077 void(void) nex_options_alwaysrun_refresh =
1078 {
1079         if(cvar("cl_forwardspeed") > 200)
1080                 self.value = 1;
1081         else
1082                 self.value = 0;
1083 };
1084
1085 void(void) nex_options_invmouse_switchchange =
1086 {
1087         float old;
1088         old = 0 - cvar("m_pitch");
1089         cvar_set("m_pitch",ftos(old));
1090 };
1091
1092 void(void) nex_options_invmouse_refresh =
1093 {
1094         if(cvar("m_pitch") > 0)
1095                 self.value = 0;
1096         else
1097                 self.value = 1;
1098 };
1099
1100 void(void) nex_snd =
1101 {
1102         entity ent;
1103         ent = menu_getitem("options_sound");
1104         nex_makeonlyvisible( ent );
1105         menu_jumptowindow(ent, false);
1106 }
1107
1108 void(void) nex_snd_cd_init =
1109 {
1110         if(cvar("cdaudioinitialized"))
1111         {
1112                 self.flag = FLAG_AUTOSETCLICK;
1113                 self.color = ITEM_TEXT_NORMAL_COLOR;
1114         }
1115         else
1116         {
1117                 self.flag = FLAG_NOSELECT | FLAG_DRAWONLY | FLAG_CHILDDRAWONLY;
1118                 self.color = '0.5 0.5 0.5';
1119         }
1120 };
1121
1122 void(void) nex_snd_snd_init =
1123 {
1124         if(cvar("snd_initialized"))
1125         {
1126                 self.flag = FLAG_AUTOSETCLICK;
1127                 self.color = ITEM_TEXT_NORMAL_COLOR;
1128         }
1129         else
1130         {
1131                 self.flag = FLAG_NOSELECT | FLAG_DRAWONLY | FLAG_CHILDDRAWONLY;
1132                 self.color = '0.5 0.5 0.5';
1133         }
1134 };
1135
1136 void(void) nex_cc =
1137 {
1138         entity ent;
1139         ent = menu_getitem("options_cc");
1140         nex_makeonlyvisible( ent );
1141         menu_jumptowindow(ent, false);
1142 }
1143
1144 void(void) nex_cc_reset =
1145 {
1146         cmd(
1147         "v_hwgamma 1;"
1148         "v_gamma 1;"
1149         "v_contrast 1;"
1150         "v_brightness 0;"
1151         "v_color_enable 0;"
1152         "v_color_black_r 0;"
1153         "v_color_black_g 0;"
1154         "v_color_black_b 0;"
1155         "v_color_grey_r 0;"
1156         "v_color_grey_g 0;"
1157         "v_color_grey_b 0;"
1158         "v_color_white_r 1;"
1159         "v_color_white_g 1;"
1160         "v_color_white_b 1;"
1161         "\n");
1162 };
1163
1164 void(void) nex_cc_check_hwgamma =
1165 {
1166         if(cvar("vid_hardwaregammasupported"))
1167         {
1168                 self.flag = FLAG_AUTOSETCLICK;
1169                 self.color = ITEM_TEXT_NORMAL_COLOR;
1170         }
1171         else
1172         {
1173                 self.flag = FLAG_NOSELECT;
1174                 self.color = '0.5 0.5 0.5';
1175         }
1176 };
1177
1178 void(void) nex_cc_check_gamma = // used in key -- BADBAD HACKHACK
1179 {
1180         if(cvar("v_hwgamma") && cvar("vid_hardwaregammasupported") && !cvar("v_color_enable"))
1181         {
1182                 self.flag = FLAG_AUTOSETCLICK;
1183                 self.color = ITEM_TEXT_NORMAL_COLOR;
1184         }
1185         else
1186         {
1187                 self.flag = FLAG_NOSELECT;
1188                 self.color = '0.5 0.5 0.5';
1189         }
1190 };
1191
1192 void(void) nex_cc_check_grey = // used in key -- BADBAD HACKHACK
1193 {
1194         if(cvar("v_hwgamma") && cvar("vid_hardwaregammasupported") && cvar("v_color_enable"))
1195         {
1196                 self.flag = FLAG_AUTOSETCLICK;
1197                 self.color = ITEM_TEXT_NORMAL_COLOR;
1198         }
1199         else
1200         {
1201                 self.flag = FLAG_NOSELECT;
1202                 self.color = '0.5 0.5 0.5';
1203         }
1204 };
1205
1206 void(void) nex_cc_check_ncolor_enable =
1207 {
1208         if(!cvar("v_color_enable"))
1209         {
1210                 self.flag = FLAG_AUTOSETCLICK;
1211                 self.color = ITEM_TEXT_NORMAL_COLOR;
1212         }
1213         else
1214         {
1215                 self.flag = FLAG_NOSELECT;
1216                 self.color = '0.5 0.5 0.5';
1217         }
1218 };
1219
1220 void(void) nex_cc_check_color_enable =
1221 {
1222         if(cvar("v_color_enable"))
1223         {
1224                 self.flag = FLAG_AUTOSETCLICK;
1225                 self.color = ITEM_TEXT_NORMAL_COLOR;
1226         }
1227         else
1228         {
1229                 self.flag = FLAG_NOSELECT;
1230                 self.color = '0.5 0.5 0.5';
1231         }
1232 };
1233
1234 void(void) nex_cc_color_enable =
1235 {
1236         cvar_set("v_color_enable","1");
1237 };
1238
1239 void(void) nex_cc_ncolor_enable =
1240 {
1241         cvar_set("v_color_enable","0");
1242 };
1243
1244 void(void) nex_cc_grey_refresh =
1245 {
1246         self.value = cvar(strcat(self.cvarname,"_r"));
1247         self.value = self.value + cvar(strcat(self.cvarname,"_g"));
1248         self.value = self.value + cvar(strcat(self.cvarname,"_b"));
1249         self.value = self.value / 3;
1250 };
1251
1252
1253 void(void) nex_cc_grey_move =
1254 {
1255         string tmp;
1256         tmp = ftos(self.value);
1257         cvar_set(strcat(self.cvarname,"_r"), tmp);
1258         cvar_set(strcat(self.cvarname,"_g"), tmp);
1259         cvar_set(strcat(self.cvarname,"_b"), tmp);
1260 };
1261
1262 void(void) nex_cc_grey =
1263 {
1264         self.refresh = nex_cc_grey_refresh;
1265         self.slidermove = nex_cc_grey_move;
1266 };
1267
1268 // key control stuff
1269 void(void) nex_cntrl =
1270 {
1271         entity ent;
1272         ent = menu_getitem("options_control");
1273         nex_makeonlyvisible( ent );
1274         menu_jumptowindow(ent, false);
1275 }
1276
1277 const float NUMKEYS = 2;        // visible key count (first and secondary key)
1278 string bindcommand;
1279
1280 void(float keynr, float ascii) nex_con_keyhook =
1281 {
1282         entity ent;
1283
1284         //dprint("nex_con_keyhook called !\n");
1285
1286         if(keynr != K_ESCAPE)
1287         {
1288                 string tmp;
1289                 tmp = bind_getkeylist(bindcommand);
1290                 // remove the binds if we need more space
1291                 bind_limitbinds(NUMKEYS - 1, bindcommand);
1292                 // bind the new key
1293                 bind_bindkey(bind_getstringforkey(keynr), bindcommand);
1294         }
1295
1296         ent = menu_getitem("options_control_statemsg1");
1297         ent.value = 0;
1298
1299         ent = menu_getitem("options_control_statemsg2");
1300         ent.value = 0;
1301
1302         menu_keyhook = null_function;
1303 };
1304
1305 void(void) nex_con_action_key =
1306 {
1307         entity ent;
1308
1309         bindcommand = self.link;
1310
1311         //dprint("action called");
1312
1313         menu_keyhook = nex_con_keyhook;
1314
1315         ent = menu_getitem("options_control_statemsg1");
1316         ent.value = 1;
1317
1318         ent = menu_getitem("options_control_statemsg2");
1319         ent.value = 1;
1320 };
1321
1322 float(float keynr, float ascii) nex_con_key =
1323 {
1324         if(keynr == K_DEL)
1325         {
1326                 // the user wants to unbind this action
1327                 //dprint("Removing binds for '", self.link,"'\n");
1328                 bind_limitbinds(0, self.link);
1329                 return true;
1330         }
1331
1332         return false;
1333 };
1334
1335 void(void) nex_con_update_keys =
1336 {
1337         entity ent;
1338         string keystr;
1339         float num;
1340
1341         if(!self._child)
1342                 return;
1343
1344         keystr = strzone(bind_getkeylist(self.link));
1345
1346         num = 0;
1347
1348         for(ent = self._child; ent != null_entity; ent = ent._next)
1349         {
1350                 float keynr;
1351
1352                 keynr = stof(getaltstring(num, keystr));
1353
1354                 strunzone(ent.text);
1355
1356                 if(keynr == -1 )
1357                         ent.text = strzone("-");
1358                 else
1359                         ent.text = strzone(bind_getstringforkey(keynr));
1360
1361                 num = num + 1;
1362         }
1363
1364         strunzone(keystr);
1365 };
1366
1367 var float numkey = 0;
1368 void(void) CONTROL_KEY =
1369 {
1370         entity key1, key2, desc;
1371         entity temp_desc, temp_key;
1372
1373         temp_desc = menu_getitem("control_desc_template");
1374         temp_key = menu_getitem("control_key_template");
1375
1376         desc = spawn();
1377         copyentity(temp_desc, desc);
1378
1379         key1 = spawn();
1380         copyentity(temp_key, key1);
1381
1382         key2 = spawn();
1383         copyentity(temp_key, key2);
1384
1385         desc.name = self.text;
1386         key1.name = strzone(strcat(self.text, " key1"));
1387         key2.name = strzone(strcat(self.text, " key2"));
1388
1389         desc.pos_y = key1.pos_y = key2.pos_y = temp_desc.pos_y * numkey;
1390         key2.pos_x = 2 * key2.pos_x;
1391
1392         desc.text = self.text;
1393         desc.link = self.link;
1394
1395         key1.text = strzone("-");
1396         key2.text = strzone("-");
1397
1398         desc.alignment = 0;
1399
1400         // set the parents
1401         desc.parent = "options_control";
1402         desc._parent = menu_getitem("options_control");
1403
1404         key1.parent = key2.parent = desc.name;
1405         key1._parent = key2._parent = desc;
1406
1407         //eprint(key1);
1408         //eprint(key2);
1409         //eprint(desc);
1410
1411         numkey = numkey + 1;
1412 };
1413
1414 ////////////////////////////////////////////////////
1415 // Test Stuff
1416 ///
1417 void(void) initbrightness =
1418 {
1419         self.value = cvar("scr_conbrightness");
1420 };
1421
1422 void(void) setbrightness =
1423 {
1424         cvar_set("scr_conbrightness",ftos(self.value));
1425 };
1426
1427 void(void)  nex_main_exit =
1428 {
1429         entity e;
1430         e = menu_getitem("MAIN_MENU");
1431         e.flag = FLAG_NOSELECT + FLAG_CHILDDRAWONLY;
1432         e = menu_getitem("MAIN_EXIT_MENU");
1433         e.flag = FLAG_NOSELECT;
1434         menu_jumptowindow(e, false);
1435 };
1436
1437 void(void) nex_main_exit_no =
1438 {
1439         entity e;
1440         e = menu_getitem("MAIN_EXIT_MENU");
1441         e.flag = FLAG_NOSELECT + FLAG_HIDDEN;
1442         e = menu_getitem("MAIN_MENU");
1443         e.flag = FLAG_NOSELECT;
1444         menu_selectup();
1445 };
1446
1447 void(void) nex_main_exit_yes =
1448 {
1449         cmd("quit\n");
1450 };
1451
1452 float(float keynr, float ascii) nex_main_exit_key =
1453 {
1454         if(keynr == K_ESCAPE)
1455         {
1456                 nex_main_exit_no();
1457                 return true;
1458         }
1459         return false;
1460 }
1461
1462 void(void)  dorestart =
1463 {
1464         cmd("menu_restart\n");
1465 };
1466
1467 void(void) nex_text_cur_x =
1468 {
1469         self.text = ftos(rint(cursor_x));
1470 };
1471
1472 void(void) nex_text_cur_y =
1473 {
1474         self.text = ftos(rint(cursor_y));
1475 };