cl_capturevideo_raw* modes now use O_NONBLOCKING file access for more performance
[xonotic/darkplaces.git] / prvm_cmds.c
1 // AK
2 // Basically every vm builtin cmd should be in here.
3 // All 3 builtin and extension lists can be found here
4 // cause large (I think they will) parts are from pr_cmds the same copyright like in pr_cmds
5 // also applies here
6
7
8 /*
9 ============================================================================
10 common cmd list:
11 =================
12
13                 checkextension(string)
14                 error(...[string])
15                 objerror(...[string)
16                 print(...[strings])
17                 bprint(...[string])
18                 sprint(float clientnum,...[string])
19                 centerprint(...[string])
20 vector  normalize(vector)
21 float   vlen(vector)
22 float   vectoyaw(vector)
23 vector  vectoangles(vector)
24 float   random()
25                 cmd(string)
26                 float cvar (string)
27                 cvar_set (string,string)
28                 dprint(...[string])
29 string  ftos(float)
30 float   fabs(float)
31 string  vtos(vector)
32 string  etos(entity)
33 float   stof(...[string])
34 entity  spawn()
35                 remove(entity e)
36 entity  find(entity start, .string field, string match)
37
38 entity  findfloat(entity start, .float field, float match)
39 entity  findentity(entity start, .entity field, entity match)
40
41 entity  findchain(.string field, string match)
42
43 entity  findchainfloat(.string field, float match)
44 entity  findchainentity(.string field, entity match)
45
46 string  precache_file(string)
47 string  precache_sound (string sample)
48                 coredump()
49                 traceon()
50                 traceoff()
51                 eprint(entity e)
52 float   rint(float)
53 float   floor(float)
54 float   ceil(float)
55 entity  nextent(entity)
56 float   sin(float)
57 float   cos(float)
58 float   sqrt(float)
59 vector  randomvec()
60 float   registercvar (string name, string value, float flags)
61 float   min(float a, float b, ...[float])
62 float   max(float a, float b, ...[float])
63 float   bound(float min, float value, float max)
64 float   pow(float a, float b)
65                 copyentity(entity src, entity dst)
66 float   fopen(string filename, float mode)
67                 fclose(float fhandle)
68 string  fgets(float fhandle)
69                 fputs(float fhandle, string s)
70 float   strlen(string s)
71 string  strcat(string,string,...[string])
72 string  substring(string s, float start, float length)
73 vector  stov(string s)
74 string  strzone(string s)
75                 strunzone(string s)
76 float   tokenize(string s)
77 string  argv(float n)
78 float   isserver()
79 float   clientcount()
80 float   clientstate()
81                 clientcommand(float client, string s) (for client and menu)
82                 changelevel(string map)
83                 localsound(string sample)
84 vector  getmousepos()
85 float   gettime()
86                 loadfromdata(string data)
87                 loadfromfile(string file)
88 float   mod(float val, float m)
89 const string    str_cvar (string)
90                 crash()
91                 stackdump()
92
93 float   search_begin(string pattern, float caseinsensitive, float quiet)
94 void    search_end(float handle)
95 float   search_getsize(float handle)
96 string  search_getfilename(float handle, float num)
97
98 string  chr(float ascii)
99
100 float   itof(intt ent)
101 intt    ftoi(float num)
102
103 float   altstr_count(string)
104 string  altstr_prepare(string)
105 string  altstr_get(string,float)
106 string  altstr_set(string altstr, float num, string set)
107
108 perhaps only : Menu : WriteMsg
109 ===============================
110
111                 WriteByte(float data, float dest, float desto)
112                 WriteChar(float data, float dest, float desto)
113                 WriteShort(float data, float dest, float desto)
114                 WriteLong(float data, float dest, float desto)
115                 WriteAngle(float data, float dest, float desto)
116                 WriteCoord(float data, float dest, float desto)
117                 WriteString(string data, float dest, float desto)
118                 WriteEntity(entity data, float dest, float desto)
119
120 Client & Menu : draw functions & video functions
121 ===================================================
122
123 float   iscachedpic(string pic)
124 string  precache_pic(string pic)
125                 freepic(string s)
126 float   drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
127 float   drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
128 float   drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
129 float   drawfill(vector position, vector size, vector rgb, float alpha, float flag)
130                 drawsetcliparea(float x, float y, float width, float height)
131                 drawresetcliparea()
132 vector  getimagesize(string pic)
133
134 float   cin_open(string file, string name)
135 void    cin_close(string name)
136 void    cin_setstate(string name, float type)
137 float   cin_getstate(string name)
138 void    cin_restart(string name)
139
140 ==============================================================================
141 menu cmd list:
142 ===============
143
144                 setkeydest(float dest)
145 float   getkeydest()
146                 setmousetarget(float target)
147 float   getmousetarget()
148
149                 callfunction(...,string function_name)
150                 writetofile(float fhandle, entity ent)
151 float   isfunction(string function_name)
152 vector  getresolution(float number)
153 string  keynumtostring(float keynum)
154 string  findkeysforcommand(string command)
155 float   gethostcachestat(float type)
156 string  gethostcachestring(float fld, float hostnr)
157
158                 parseentitydata(entity ent, string data)
159
160 float   stringtokeynum(string key)
161
162                 resethostcachemasks()
163                 sethostcachemaskstring(float mask, float fld, string str)
164                 sethostcachemasknumber(float mask, float fld, float num, float op)
165                 resorthostcache()
166                 sethostcachesort(float field, float descending)
167                 refreshhostcache()
168 float   gethostcachenumber(float fld, float hostnr)
169 float   gethostcacheindexforkey(string key)
170                 addwantedhostcachekey(string key)
171 */
172
173 #include "quakedef.h"
174 #include "progdefs.h"
175 #include "progsvm.h"
176 #include "clprogdefs.h"
177 #include "mprogdefs.h"
178
179 #include "cl_video.h"
180
181 //============================================================================
182 // nice helper macros
183
184 #ifndef VM_NOPARMCHECK
185 #define VM_SAFEPARMCOUNT(p,f)   if(prog->argc != p) PRVM_ERROR(#f " wrong parameter count (" #p " expected ) !\n")
186 #else
187 #define VM_SAFEPARMCOUNT(p,f)
188 #endif
189
190 #define VM_RETURN_EDICT(e)              (((int *)prog->globals)[OFS_RETURN] = PRVM_EDICT_TO_PROG(e))
191
192 #define VM_STRINGS_MEMPOOL              vm_strings_mempool[PRVM_GetProgNr()]
193
194 #define e10 0,0,0,0,0,0,0,0,0,0
195 #define e100 e10,e10,e10,e10,e10,e10,e10,e10,e10,e10
196 #define e1000 e100,e100,e100,e100,e100,e100,e100,e100,e100,e100
197
198 //============================================================================
199 // Common
200
201 // string zone mempool
202 mempool_t *vm_strings_mempool[PRVM_MAXPROGS];
203
204 // temp string handling
205 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
206 #define VM_STRINGTEMP_BUFFERS 16
207 #define VM_STRINGTEMP_LENGTH 4096
208 static char vm_string_temp[VM_STRINGTEMP_BUFFERS][VM_STRINGTEMP_LENGTH];
209 static int vm_string_tempindex = 0;
210
211 // qc file handling
212 #define MAX_VMFILES             256
213 #define MAX_PRVMFILES   MAX_VMFILES * PRVM_MAXPROGS
214 #define VM_FILES ((qfile_t**)(vm_files + PRVM_GetProgNr() * MAX_VMFILES))
215
216 qfile_t *vm_files[MAX_PRVMFILES];
217
218 // qc fs search handling
219 #define MAX_VMSEARCHES 128
220 #define TOTAL_VMSEARCHES MAX_VMSEARCHES * PRVM_MAXPROGS
221 #define VM_SEARCHLIST ((fssearch_t**)(vm_fssearchlist + PRVM_GetProgNr() * MAX_VMSEARCHES))
222
223 fssearch_t *vm_fssearchlist[TOTAL_VMSEARCHES];
224
225 static char *VM_GetTempString(void)
226 {
227         char *s;
228         s = vm_string_temp[vm_string_tempindex];
229         vm_string_tempindex = (vm_string_tempindex + 1) % VM_STRINGTEMP_BUFFERS;
230         return s;
231 }
232
233 void VM_CheckEmptyString (char *s)
234 {
235         if (s[0] <= ' ')
236                 PRVM_ERROR ("%s: Bad string", PRVM_NAME);
237 }
238
239 //============================================================================
240 //BUILT-IN FUNCTIONS
241
242 void VM_VarString(int first, char *out, int outlength)
243 {
244         int i;
245         const char *s;
246         char *outend;
247
248         outend = out + outlength - 1;
249         for (i = first;i < prog->argc && out < outend;i++)
250         {
251                 s = PRVM_G_STRING((OFS_PARM0+i*3));
252                 while (out < outend && *s)
253                         *out++ = *s++;
254         }
255         *out++ = 0;
256 }
257
258 /*
259 =================
260 VM_checkextension
261
262 returns true if the extension is supported by the server
263
264 checkextension(extensionname)
265 =================
266 */
267
268 // kind of helper function
269 static qboolean checkextension(char *name)
270 {
271         int len;
272         char *e, *start;
273         len = strlen(name);
274
275         for (e = prog->extensionstring;*e;e++)
276         {
277                 while (*e == ' ')
278                         e++;
279                 if (!*e)
280                         break;
281                 start = e;
282                 while (*e && *e != ' ')
283                         e++;
284                 if (e - start == len)
285                         if (!strncasecmp(start, name, len))
286                         {
287                                 return true;
288                         }
289         }
290         return false;
291 }
292
293 void VM_checkextension (void)
294 {
295         VM_SAFEPARMCOUNT(1,VM_checkextension);
296
297         PRVM_G_FLOAT(OFS_RETURN) = checkextension(PRVM_G_STRING(OFS_PARM0));
298 }
299
300 /*
301 =================
302 VM_error
303
304 This is a TERMINAL error, which will kill off the entire prog.
305 Dumps self.
306
307 error(value)
308 =================
309 */
310 void VM_error (void)
311 {
312         prvm_edict_t    *ed;
313         char string[VM_STRINGTEMP_LENGTH];
314
315         VM_VarString(0, string, sizeof(string));
316         Con_Printf("======%S ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
317         if(prog->self)
318         {
319                 ed = PRVM_G_EDICT(prog->self->ofs);
320                 PRVM_ED_Print(ed);
321         }
322
323         PRVM_ERROR ("%s: Program error", PRVM_NAME);
324 }
325
326 /*
327 =================
328 VM_objerror
329
330 Dumps out self, then an error message.  The program is aborted and self is
331 removed, but the level can continue.
332
333 objerror(value)
334 =================
335 */
336 void VM_objerror (void)
337 {
338         prvm_edict_t    *ed;
339         char string[VM_STRINGTEMP_LENGTH];
340
341         VM_VarString(0, string, sizeof(string));
342         Con_Printf("======%s OBJECT ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
343         if(prog->self)
344         {
345                 ed = PRVM_G_EDICT (prog->self->ofs);
346                 PRVM_ED_Print(ed);
347
348                 PRVM_ED_Free (ed);
349         }
350         else
351                 // objerror has to display the object fields -> else call
352                 PRVM_ERROR ("VM_objecterror: self not defined !\n");
353 }
354
355 /*
356 =================
357 VM_print (actually used only by client and menu)
358
359 print to console
360
361 print(string)
362 =================
363 */
364 void VM_print (void)
365 {
366         char string[VM_STRINGTEMP_LENGTH];
367
368         VM_VarString(0, string, sizeof(string));
369         Con_Print(string);
370 }
371
372 /*
373 =================
374 VM_bprint
375
376 broadcast print to everyone on server
377
378 bprint(...[string])
379 =================
380 */
381 void VM_bprint (void)
382 {
383         char string[VM_STRINGTEMP_LENGTH];
384
385         if(!sv.active)
386         {
387                 Con_Printf("VM_bprint: game is not server(%s) !\n", PRVM_NAME);
388                 return;
389         }
390
391         VM_VarString(0, string, sizeof(string));
392         SV_BroadcastPrint(string);
393 }
394
395 /*
396 =================
397 VM_sprint (menu & client but only if server.active == true)
398
399 single print to a specific client
400
401 sprint(float clientnum,...[string])
402 =================
403 */
404 void VM_sprint (void)
405 {
406         client_t        *client;
407         int                     clientnum;
408         char string[VM_STRINGTEMP_LENGTH];
409
410         //find client for this entity
411         clientnum = PRVM_G_FLOAT(OFS_PARM0);
412         if (!sv.active  || clientnum < 0 || clientnum >= svs.maxclients || !svs.clients[clientnum].active)
413         {
414                 Con_Printf("VM_sprint: %s: invalid client or server is not active !\n", PRVM_NAME);
415                 return;
416         }
417
418         client = svs.clients + clientnum;
419         VM_VarString(1, string, sizeof(string));
420         MSG_WriteChar(&client->message,svc_print);
421         MSG_WriteString(&client->message, string);
422 }
423
424 /*
425 =================
426 VM_centerprint
427
428 single print to the screen
429
430 centerprint(clientent, value)
431 =================
432 */
433 void VM_centerprint (void)
434 {
435         char string[VM_STRINGTEMP_LENGTH];
436
437         VM_VarString(0, string, sizeof(string));
438         SCR_CenterPrint(string);
439 }
440
441 /*
442 =================
443 VM_normalize
444
445 vector normalize(vector)
446 =================
447 */
448 void VM_normalize (void)
449 {
450         float   *value1;
451         vec3_t  newvalue;
452         float   new;
453
454         VM_SAFEPARMCOUNT(1,VM_normalize);
455
456         value1 = PRVM_G_VECTOR(OFS_PARM0);
457
458         new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
459         new = sqrt(new);
460
461         if (new == 0)
462                 newvalue[0] = newvalue[1] = newvalue[2] = 0;
463         else
464         {
465                 new = 1/new;
466                 newvalue[0] = value1[0] * new;
467                 newvalue[1] = value1[1] * new;
468                 newvalue[2] = value1[2] * new;
469         }
470
471         VectorCopy (newvalue, PRVM_G_VECTOR(OFS_RETURN));
472 }
473
474 /*
475 =================
476 VM_vlen
477
478 scalar vlen(vector)
479 =================
480 */
481 void VM_vlen (void)
482 {
483         float   *value1;
484         float   new;
485
486         VM_SAFEPARMCOUNT(1,VM_vlen);
487
488         value1 = PRVM_G_VECTOR(OFS_PARM0);
489
490         new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
491         new = sqrt(new);
492
493         PRVM_G_FLOAT(OFS_RETURN) = new;
494 }
495
496 /*
497 =================
498 VM_vectoyaw
499
500 float vectoyaw(vector)
501 =================
502 */
503 void VM_vectoyaw (void)
504 {
505         float   *value1;
506         float   yaw;
507
508         VM_SAFEPARMCOUNT(1,VM_vectoyaw);
509
510         value1 = PRVM_G_VECTOR(OFS_PARM0);
511
512         if (value1[1] == 0 && value1[0] == 0)
513                 yaw = 0;
514         else
515         {
516                 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
517                 if (yaw < 0)
518                         yaw += 360;
519         }
520
521         PRVM_G_FLOAT(OFS_RETURN) = yaw;
522 }
523
524
525 /*
526 =================
527 VM_vectoangles
528
529 vector vectoangles(vector)
530 =================
531 */
532 void VM_vectoangles (void)
533 {
534         float   *value1;
535         float   forward;
536         float   yaw, pitch;
537
538         VM_SAFEPARMCOUNT(1,VM_vectoangles);
539
540         value1 = PRVM_G_VECTOR(OFS_PARM0);
541
542         if (value1[1] == 0 && value1[0] == 0)
543         {
544                 yaw = 0;
545                 if (value1[2] > 0)
546                         pitch = 90;
547                 else
548                         pitch = 270;
549         }
550         else
551         {
552                 // LordHavoc: optimized a bit
553                 if (value1[0])
554                 {
555                         yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
556                         if (yaw < 0)
557                                 yaw += 360;
558                 }
559                 else if (value1[1] > 0)
560                         yaw = 90;
561                 else
562                         yaw = 270;
563
564                 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
565                 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
566                 if (pitch < 0)
567                         pitch += 360;
568         }
569
570         PRVM_G_FLOAT(OFS_RETURN+0) = pitch;
571         PRVM_G_FLOAT(OFS_RETURN+1) = yaw;
572         PRVM_G_FLOAT(OFS_RETURN+2) = 0;
573 }
574
575 /*
576 =================
577 VM_random
578
579 Returns a number from 0<= num < 1
580
581 float random()
582 =================
583 */
584 void VM_random (void)
585 {
586         VM_SAFEPARMCOUNT(0,VM_random);
587
588         PRVM_G_FLOAT(OFS_RETURN) = lhrandom(0, 1);
589 }
590
591 /*
592 =================
593 PF_sound
594
595 Each entity can have eight independant sound sources, like voice,
596 weapon, feet, etc.
597
598 Channel 0 is an auto-allocate channel, the others override anything
599 already running on that entity/channel pair.
600
601 An attenuation of 0 will play full volume everywhere in the level.
602 Larger attenuations will drop off.
603
604 =================
605 */
606 /*
607 void PF_sound (void)
608 {
609         char            *sample;
610         int                     channel;
611         edict_t         *entity;
612         int             volume;
613         float attenuation;
614
615         entity = G_EDICT(OFS_PARM0);
616         channel = G_FLOAT(OFS_PARM1);
617         sample = G_STRING(OFS_PARM2);
618         volume = G_FLOAT(OFS_PARM3) * 255;
619         attenuation = G_FLOAT(OFS_PARM4);
620
621         if (volume < 0 || volume > 255)
622                 Host_Error ("SV_StartSound: volume = %i", volume);
623
624         if (attenuation < 0 || attenuation > 4)
625                 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
626
627         if (channel < 0 || channel > 7)
628                 Host_Error ("SV_StartSound: channel = %i", channel);
629
630         SV_StartSound (entity, channel, sample, volume, attenuation);
631 }
632 */
633
634 /*
635 =========
636 VM_localsound
637
638 localsound(string sample)
639 =========
640 */
641 void VM_localsound(void)
642 {
643         char *s;
644
645         VM_SAFEPARMCOUNT(1,VM_localsound);
646
647         s = PRVM_G_STRING(OFS_PARM0);
648
649         if(!S_LocalSound (s))
650         {
651                 Con_Printf("VM_localsound: Failed to play %s for %s !\n", s, PRVM_NAME);
652                 PRVM_G_FLOAT(OFS_RETURN) = -4;
653                 return;
654         }
655
656         PRVM_G_FLOAT(OFS_RETURN) = 1;
657 }
658
659 /*
660 =================
661 VM_break
662
663 break()
664 =================
665 */
666 void VM_break (void)
667 {
668         PRVM_ERROR ("%s: break statement", PRVM_NAME);
669 }
670
671 //============================================================================
672
673 /*
674 =================
675 VM_localcmd
676
677 Sends text over to the client's execution buffer
678
679 [localcmd (string) or]
680 cmd (string)
681 =================
682 */
683 void VM_localcmd (void)
684 {
685         VM_SAFEPARMCOUNT(1,VM_localcmd);
686
687         Cbuf_AddText(PRVM_G_STRING(OFS_PARM0));
688 }
689
690 /*
691 =================
692 VM_cvar
693
694 float cvar (string)
695 =================
696 */
697 void VM_cvar (void)
698 {
699         VM_SAFEPARMCOUNT(1,VM_cvar);
700
701         PRVM_G_FLOAT(OFS_RETURN) = Cvar_VariableValue(PRVM_G_STRING(OFS_PARM0));
702 }
703
704 /*
705 =================
706 VM_str_cvar
707
708 const string    str_cvar (string)
709 =================
710 */
711 void VM_str_cvar(void)
712 {
713         char *out, *name;
714         const char *cvar_string;
715         VM_SAFEPARMCOUNT(1,VM_str_cvar);
716
717         name = PRVM_G_STRING(OFS_PARM0);
718
719         if(!name)
720                 PRVM_ERROR("VM_str_cvar: %s: null string\n", PRVM_NAME);
721
722         VM_CheckEmptyString(name);
723
724         out = VM_GetTempString();
725
726         cvar_string = Cvar_VariableString(name);
727
728         strcpy(out, cvar_string);
729
730         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(out);
731 }
732
733 /*
734 =================
735 VM_cvar_set
736
737 void cvar_set (string,string)
738 =================
739 */
740 void VM_cvar_set (void)
741 {
742         VM_SAFEPARMCOUNT(2,VM_cvar_set);
743
744         Cvar_Set(PRVM_G_STRING(OFS_PARM0), PRVM_G_STRING(OFS_PARM1));
745 }
746
747 /*
748 =========
749 VM_dprint
750
751 dprint(...[string])
752 =========
753 */
754 void VM_dprint (void)
755 {
756         char string[VM_STRINGTEMP_LENGTH];
757         if (developer.integer)
758         {
759                 VM_VarString(0, string, sizeof(string));
760                 Con_Printf("%s: %s", PRVM_NAME, string);
761         }
762 }
763
764 /*
765 =========
766 VM_ftos
767
768 string  ftos(float)
769 =========
770 */
771
772 void VM_ftos (void)
773 {
774         float v;
775         char *s;
776
777         VM_SAFEPARMCOUNT(1, VM_ftos);
778
779         v = PRVM_G_FLOAT(OFS_PARM0);
780
781         s = VM_GetTempString();
782         if ((float)((int)v) == v)
783                 sprintf(s, "%i", (int)v);
784         else
785                 sprintf(s, "%f", v);
786         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
787 }
788
789 /*
790 =========
791 VM_fabs
792
793 float   fabs(float)
794 =========
795 */
796
797 void VM_fabs (void)
798 {
799         float   v;
800
801         VM_SAFEPARMCOUNT(1,VM_fabs);
802
803         v = PRVM_G_FLOAT(OFS_PARM0);
804         PRVM_G_FLOAT(OFS_RETURN) = fabs(v);
805 }
806
807 /*
808 =========
809 VM_vtos
810
811 string  vtos(vector)
812 =========
813 */
814
815 void VM_vtos (void)
816 {
817         char *s;
818
819         VM_SAFEPARMCOUNT(1,VM_vtos);
820
821         s = VM_GetTempString();
822         sprintf (s, "'%5.1f %5.1f %5.1f'", PRVM_G_VECTOR(OFS_PARM0)[0], PRVM_G_VECTOR(OFS_PARM0)[1], PRVM_G_VECTOR(OFS_PARM0)[2]);
823         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
824 }
825
826 /*
827 =========
828 VM_etos
829
830 string  etos(entity)
831 =========
832 */
833
834 void VM_etos (void)
835 {
836         char *s;
837
838         VM_SAFEPARMCOUNT(1, VM_etos);
839
840         s = VM_GetTempString();
841         sprintf (s, "entity %i", PRVM_G_EDICTNUM(OFS_PARM0));
842         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
843 }
844
845 /*
846 =========
847 VM_stof
848
849 float stof(...[string])
850 =========
851 */
852 void VM_stof(void)
853 {
854         char string[VM_STRINGTEMP_LENGTH];
855         VM_VarString(0, string, sizeof(string));
856         PRVM_G_FLOAT(OFS_RETURN) = atof(string);
857 }
858
859 /*
860 ========================
861 VM_itof
862
863 float itof(intt ent)
864 ========================
865 */
866 void VM_itof(void)
867 {
868         VM_SAFEPARMCOUNT(1, VM_itof);
869         PRVM_G_FLOAT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
870 }
871
872 /*
873 ========================
874 VM_itoe
875
876 intt ftoi(float num)
877 ========================
878 */
879 void VM_ftoi(void)
880 {
881         int ent;
882         VM_SAFEPARMCOUNT(1, VM_ftoi);
883
884         ent = PRVM_G_FLOAT(OFS_PARM0);
885         if(PRVM_PROG_TO_EDICT(ent)->p.e->free)
886                 PRVM_ERROR ("VM_ftoe: %s tried to access a freed entity (entity %i)!\n", PRVM_NAME, ent);
887
888         PRVM_G_INT(OFS_RETURN) = ent;
889 }
890
891 /*
892 =========
893 VM_spawn
894
895 entity spawn()
896 =========
897 */
898
899 void VM_spawn (void)
900 {
901         prvm_edict_t    *ed;
902         prog->xfunction->builtinsprofile += 20;
903         ed = PRVM_ED_Alloc();
904         VM_RETURN_EDICT(ed);
905 }
906
907 /*
908 =========
909 VM_remove
910
911 remove(entity e)
912 =========
913 */
914
915 void VM_remove (void)
916 {
917         prvm_edict_t    *ed;
918         prog->xfunction->builtinsprofile += 20;
919
920         VM_SAFEPARMCOUNT(1, VM_remove);
921
922         ed = PRVM_G_EDICT(OFS_PARM0);
923 //      if (ed == prog->edicts)
924 //              PRVM_ERROR ("remove: tried to remove world\n");
925 //      if (PRVM_NUM_FOR_EDICT(ed) <= sv.maxclients)
926 //              Host_Error("remove: tried to remove a client\n");
927         PRVM_ED_Free (ed);
928 }
929
930 /*
931 =========
932 VM_find
933
934 entity  find(entity start, .string field, string match)
935 =========
936 */
937
938 void VM_find (void)
939 {
940         int             e;
941         int             f;
942         char    *s, *t;
943         prvm_edict_t    *ed;
944
945         VM_SAFEPARMCOUNT(3,VM_find);
946
947         e = PRVM_G_EDICTNUM(OFS_PARM0);
948         f = PRVM_G_INT(OFS_PARM1);
949         s = PRVM_G_STRING(OFS_PARM2);
950
951         if (!s || !s[0])
952         {
953                 // return reserved edict 0 (could be used for whatever the prog wants)
954                 VM_RETURN_EDICT(prog->edicts);
955                 return;
956         }
957
958         for (e++ ; e < prog->num_edicts ; e++)
959         {
960                 prog->xfunction->builtinsprofile++;
961                 ed = PRVM_EDICT_NUM(e);
962                 if (ed->p.e->free)
963                         continue;
964                 t = PRVM_E_STRING(ed,f);
965                 if (!t)
966                         continue;
967                 if (!strcmp(t,s))
968                 {
969                         VM_RETURN_EDICT(ed);
970                         return;
971                 }
972         }
973
974         VM_RETURN_EDICT(prog->edicts);
975 }
976
977 /*
978 =========
979 VM_findfloat
980
981   entity        findfloat(entity start, .float field, float match)
982   entity        findentity(entity start, .entity field, entity match)
983 =========
984 */
985 // LordHavoc: added this for searching float, int, and entity reference fields
986 void VM_findfloat (void)
987 {
988         int             e;
989         int             f;
990         float   s;
991         prvm_edict_t    *ed;
992
993         VM_SAFEPARMCOUNT(3,VM_findfloat);
994
995         e = PRVM_G_EDICTNUM(OFS_PARM0);
996         f = PRVM_G_INT(OFS_PARM1);
997         s = PRVM_G_FLOAT(OFS_PARM2);
998
999         for (e++ ; e < prog->num_edicts ; e++)
1000         {
1001                 prog->xfunction->builtinsprofile++;
1002                 ed = PRVM_EDICT_NUM(e);
1003                 if (ed->p.e->free)
1004                         continue;
1005                 if (PRVM_E_FLOAT(ed,f) == s)
1006                 {
1007                         VM_RETURN_EDICT(ed);
1008                         return;
1009                 }
1010         }
1011
1012         VM_RETURN_EDICT(prog->edicts);
1013 }
1014
1015 /*
1016 =========
1017 VM_findchain
1018
1019 entity  findchain(.string field, string match)
1020 =========
1021 */
1022 int PRVM_ED_FindFieldOffset(const char *field);
1023 // chained search for strings in entity fields
1024 // entity(.string field, string match) findchain = #402;
1025 void VM_findchain (void)
1026 {
1027         int             i;
1028         int             f;
1029         int             chain_of;
1030         char    *s, *t;
1031         prvm_edict_t    *ent, *chain;
1032
1033         VM_SAFEPARMCOUNT(2,VM_findchain);
1034
1035         // is the same like !(prog->flag & PRVM_FE_CHAIN) - even if the operator precedence is another
1036         if(!prog->flag & PRVM_FE_CHAIN)
1037                 PRVM_ERROR("VM_findchain: %s doesnt have a chain field !\n", PRVM_NAME);
1038
1039         chain_of = PRVM_ED_FindFieldOffset ("chain");
1040
1041         chain = prog->edicts;
1042
1043         f = PRVM_G_INT(OFS_PARM0);
1044         s = PRVM_G_STRING(OFS_PARM1);
1045         if (!s || !s[0])
1046         {
1047                 VM_RETURN_EDICT(prog->edicts);
1048                 return;
1049         }
1050
1051         ent = PRVM_NEXT_EDICT(prog->edicts);
1052         for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
1053         {
1054                 prog->xfunction->builtinsprofile++;
1055                 if (ent->p.e->free)
1056                         continue;
1057                 t = PRVM_E_STRING(ent,f);
1058                 if (!t)
1059                         continue;
1060                 if (strcmp(t,s))
1061                         continue;
1062
1063                 PRVM_E_INT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain);
1064                 chain = ent;
1065         }
1066
1067         VM_RETURN_EDICT(chain);
1068 }
1069
1070 /*
1071 =========
1072 VM_findchainfloat
1073
1074 entity  findchainfloat(.string field, float match)
1075 entity  findchainentity(.string field, entity match)
1076 =========
1077 */
1078 // LordHavoc: chained search for float, int, and entity reference fields
1079 // entity(.string field, float match) findchainfloat = #403;
1080 void VM_findchainfloat (void)
1081 {
1082         int             i;
1083         int             f;
1084         int             chain_of;
1085         float   s;
1086         prvm_edict_t    *ent, *chain;
1087
1088         VM_SAFEPARMCOUNT(2, VM_findchainfloat);
1089
1090         if(!prog->flag & PRVM_FE_CHAIN)
1091                 PRVM_ERROR("VM_findchainfloat: %s doesnt have a chain field !\n", PRVM_NAME);
1092
1093         chain_of = PRVM_ED_FindFieldOffset ("chain");
1094
1095         chain = (prvm_edict_t *)prog->edicts;
1096
1097         f = PRVM_G_INT(OFS_PARM0);
1098         s = PRVM_G_FLOAT(OFS_PARM1);
1099
1100         ent = PRVM_NEXT_EDICT(prog->edicts);
1101         for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
1102         {
1103                 prog->xfunction->builtinsprofile++;
1104                 if (ent->p.e->free)
1105                         continue;
1106                 if (PRVM_E_FLOAT(ent,f) != s)
1107                         continue;
1108
1109                 PRVM_E_INT(ent,chain_of) = PRVM_EDICT_TO_PROG(chain);
1110                 chain = ent;
1111         }
1112
1113         VM_RETURN_EDICT(chain);
1114 }
1115
1116 /*
1117 =========
1118 VM_precache_file
1119
1120 string  precache_file(string)
1121 =========
1122 */
1123 void VM_precache_file (void)
1124 {       // precache_file is only used to copy files with qcc, it does nothing
1125         VM_SAFEPARMCOUNT(1,VM_precache_file);
1126
1127         PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1128 }
1129
1130 /*
1131 =========
1132 VM_preache_error
1133
1134 used instead of the other VM_precache_* functions in the builtin list
1135 =========
1136 */
1137
1138 void VM_precache_error (void)
1139 {
1140         PRVM_ERROR ("PF_Precache_*: Precache can only be done in spawn functions");
1141 }
1142
1143 /*
1144 =========
1145 VM_precache_sound
1146
1147 string  precache_sound (string sample)
1148 =========
1149 */
1150 void VM_precache_sound (void)
1151 {
1152         char    *s;
1153
1154         VM_SAFEPARMCOUNT(1, VM_precache_sound);
1155
1156         s = PRVM_G_STRING(OFS_PARM0);
1157         PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1158         VM_CheckEmptyString (s);
1159
1160         if(snd_initialized.integer && !S_PrecacheSound (s,true, true))
1161                 Con_Printf("VM_precache_sound: Failed to load %s for %s\n", s, PRVM_NAME);
1162 }
1163
1164 /*
1165 =========
1166 VM_coredump
1167
1168 coredump()
1169 =========
1170 */
1171 void VM_coredump (void)
1172 {
1173         VM_SAFEPARMCOUNT(0,VM_coredump);
1174
1175         Cbuf_AddText("prvm_edicts ");
1176         Cbuf_AddText(PRVM_NAME);
1177         Cbuf_AddText("\n");
1178 }
1179
1180 /*
1181 =========
1182 VM_stackdump
1183
1184 stackdump()
1185 =========
1186 */
1187 void PRVM_StackTrace(void);
1188 void VM_stackdump (void)
1189 {
1190         VM_SAFEPARMCOUNT(0, VM_stackdump);
1191
1192         PRVM_StackTrace();
1193 }
1194
1195 /*
1196 =========
1197 VM_crash
1198
1199 crash()
1200 =========
1201 */
1202
1203 void VM_crash(void)
1204 {
1205         VM_SAFEPARMCOUNT(0, VM_crash);
1206
1207         PRVM_ERROR("Crash called by %s\n",PRVM_NAME);
1208 }
1209
1210 /*
1211 =========
1212 VM_traceon
1213
1214 traceon()
1215 =========
1216 */
1217 void VM_traceon (void)
1218 {
1219         VM_SAFEPARMCOUNT(0,VM_traceon);
1220
1221         prog->trace = true;
1222 }
1223
1224 /*
1225 =========
1226 VM_traceoff
1227
1228 traceoff()
1229 =========
1230 */
1231 void VM_traceoff (void)
1232 {
1233         VM_SAFEPARMCOUNT(0,VM_traceoff);
1234
1235         prog->trace = false;
1236 }
1237
1238 /*
1239 =========
1240 VM_eprint
1241
1242 eprint(entity e)
1243 =========
1244 */
1245 void VM_eprint (void)
1246 {
1247         VM_SAFEPARMCOUNT(1,VM_eprint);
1248
1249         PRVM_ED_PrintNum (PRVM_G_EDICTNUM(OFS_PARM0));
1250 }
1251
1252 /*
1253 =========
1254 VM_rint
1255
1256 float   rint(float)
1257 =========
1258 */
1259 void VM_rint (void)
1260 {
1261         float   f;
1262
1263         VM_SAFEPARMCOUNT(1,VM_rint);
1264
1265         f = PRVM_G_FLOAT(OFS_PARM0);
1266         if (f > 0)
1267                 PRVM_G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1268         else
1269                 PRVM_G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1270 }
1271
1272 /*
1273 =========
1274 VM_floor
1275
1276 float   floor(float)
1277 =========
1278 */
1279 void VM_floor (void)
1280 {
1281         VM_SAFEPARMCOUNT(1,VM_floor);
1282
1283         PRVM_G_FLOAT(OFS_RETURN) = floor(PRVM_G_FLOAT(OFS_PARM0));
1284 }
1285
1286 /*
1287 =========
1288 VM_ceil
1289
1290 float   ceil(float)
1291 =========
1292 */
1293 void VM_ceil (void)
1294 {
1295         VM_SAFEPARMCOUNT(1,VM_ceil);
1296
1297         PRVM_G_FLOAT(OFS_RETURN) = ceil(PRVM_G_FLOAT(OFS_PARM0));
1298 }
1299
1300
1301 /*
1302 =============
1303 VM_nextent
1304
1305 entity  nextent(entity)
1306 =============
1307 */
1308 void VM_nextent (void)
1309 {
1310         int             i;
1311         prvm_edict_t    *ent;
1312
1313         i = PRVM_G_EDICTNUM(OFS_PARM0);
1314         while (1)
1315         {
1316                 prog->xfunction->builtinsprofile++;
1317                 i++;
1318                 if (i == prog->num_edicts)
1319                 {
1320                         VM_RETURN_EDICT(prog->edicts);
1321                         return;
1322                 }
1323                 ent = PRVM_EDICT_NUM(i);
1324                 if (!ent->p.e->free)
1325                 {
1326                         VM_RETURN_EDICT(ent);
1327                         return;
1328                 }
1329         }
1330 }
1331
1332 /*
1333 ===============================================================================
1334 MESSAGE WRITING
1335
1336 used only for client and menu
1337 severs uses VM_SV_...
1338
1339 Write*(* data, float type, float to)
1340
1341 ===============================================================================
1342 */
1343
1344 #define MSG_BROADCAST   0               // unreliable to all
1345 #define MSG_ONE                 1               // reliable to one (msg_entity)
1346 #define MSG_ALL                 2               // reliable to all
1347 #define MSG_INIT                3               // write to the init string
1348
1349 sizebuf_t *VM_WriteDest (void)
1350 {
1351         int             dest;
1352         int             destclient;
1353
1354         if(!sv.active)
1355                 PRVM_ERROR("VM_WriteDest: game is not server (%s)\n", PRVM_NAME);
1356
1357         dest = G_FLOAT(OFS_PARM1);
1358         switch (dest)
1359         {
1360         case MSG_BROADCAST:
1361                 return &sv.datagram;
1362
1363         case MSG_ONE:
1364                 destclient = (int) PRVM_G_FLOAT(OFS_PARM2);
1365                 if (destclient < 0 || destclient >= svs.maxclients || !svs.clients[destclient].active)
1366                         PRVM_ERROR("VM_clientcommand: %s: invalid client !\n", PRVM_NAME);
1367
1368                 return &svs.clients[destclient].message;
1369
1370         case MSG_ALL:
1371                 return &sv.reliable_datagram;
1372
1373         case MSG_INIT:
1374                 return &sv.signon;
1375
1376         default:
1377                 PRVM_ERROR ("WriteDest: bad destination");
1378                 break;
1379         }
1380
1381         return NULL;
1382 }
1383
1384 void VM_WriteByte (void)
1385 {
1386         MSG_WriteByte (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1387 }
1388
1389 void VM_WriteChar (void)
1390 {
1391         MSG_WriteChar (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1392 }
1393
1394 void VM_WriteShort (void)
1395 {
1396         MSG_WriteShort (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1397 }
1398
1399 void VM_WriteLong (void)
1400 {
1401         MSG_WriteLong (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1402 }
1403
1404 void VM_WriteAngle (void)
1405 {
1406         MSG_WriteAngle (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0), sv.protocol);
1407 }
1408
1409 void VM_WriteCoord (void)
1410 {
1411         MSG_WriteCoord (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0), sv.protocol);
1412 }
1413
1414 void VM_WriteString (void)
1415 {
1416         MSG_WriteString (VM_WriteDest(), PRVM_G_STRING(OFS_PARM0));
1417 }
1418
1419 void VM_WriteEntity (void)
1420 {
1421         MSG_WriteShort (VM_WriteDest(), PRVM_G_EDICTNUM(OFS_PARM0));
1422 }
1423
1424 //=============================================================================
1425
1426 /*
1427 ==============
1428 VM_changelevel
1429 server and menu
1430
1431 changelevel(string map)
1432 ==============
1433 */
1434 void VM_changelevel (void)
1435 {
1436         char    *s;
1437
1438         VM_SAFEPARMCOUNT(1, VM_changelevel);
1439
1440         if(!sv.active)
1441         {
1442                 Con_Printf("VM_changelevel: game is not server (%s)\n", PRVM_NAME);
1443                 return;
1444         }
1445
1446 // make sure we don't issue two changelevels
1447         if (svs.changelevel_issued)
1448                 return;
1449         svs.changelevel_issued = true;
1450
1451         s = G_STRING(OFS_PARM0);
1452         Cbuf_AddText (va("changelevel %s\n",s));
1453 }
1454
1455 /*
1456 =========
1457 VM_sin
1458
1459 float   sin(float)
1460 =========
1461 */
1462 void VM_sin (void)
1463 {
1464         VM_SAFEPARMCOUNT(1,VM_sin);
1465         PRVM_G_FLOAT(OFS_RETURN) = sin(PRVM_G_FLOAT(OFS_PARM0));
1466 }
1467
1468 /*
1469 =========
1470 VM_cos
1471 float   cos(float)
1472 =========
1473 */
1474 void VM_cos (void)
1475 {
1476         VM_SAFEPARMCOUNT(1,VM_cos);
1477         PRVM_G_FLOAT(OFS_RETURN) = cos(PRVM_G_FLOAT(OFS_PARM0));
1478 }
1479
1480 /*
1481 =========
1482 VM_sqrt
1483
1484 float   sqrt(float)
1485 =========
1486 */
1487 void VM_sqrt (void)
1488 {
1489         VM_SAFEPARMCOUNT(1,VM_sqrt);
1490         PRVM_G_FLOAT(OFS_RETURN) = sqrt(PRVM_G_FLOAT(OFS_PARM0));
1491 }
1492
1493 /*
1494 =================
1495 VM_randomvec
1496
1497 Returns a vector of length < 1 and > 0
1498
1499 vector randomvec()
1500 =================
1501 */
1502 void VM_randomvec (void)
1503 {
1504         vec3_t          temp;
1505         //float         length;
1506
1507         VM_SAFEPARMCOUNT(0, VM_randomvec);
1508
1509         //// WTF ??
1510         do
1511         {
1512                 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1513                 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1514                 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1515         }
1516         while (DotProduct(temp, temp) >= 1);
1517         VectorCopy (temp, PRVM_G_VECTOR(OFS_RETURN));
1518
1519         /*
1520         temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1521         temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1522         temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1523         // length returned always > 0
1524         length = (rand()&32766 + 1) * (1.0 / 32767.0) / VectorLength(temp);
1525         VectorScale(temp,length, temp);*/
1526         //VectorCopy(temp, PRVM_G_VECTOR(OFS_RETURN));
1527 }
1528
1529 //=============================================================================
1530
1531 /*
1532 =========
1533 VM_registercvar
1534
1535 float   registercvar (string name, string value, float flags)
1536 =========
1537 */
1538 void VM_registercvar (void)
1539 {
1540         char *name, *value;
1541         int     flags;
1542
1543         VM_SAFEPARMCOUNT(3,VM_registercvar);
1544
1545         name = PRVM_G_STRING(OFS_PARM0);
1546         value = PRVM_G_STRING(OFS_PARM1);
1547         flags = PRVM_G_FLOAT(OFS_PARM2);
1548         PRVM_G_FLOAT(OFS_RETURN) = 0;
1549
1550         if(flags > CVAR_MAXFLAGSVAL)
1551                 return;
1552
1553 // first check to see if it has already been defined
1554         if (Cvar_FindVar (name))
1555                 return;
1556
1557 // check for overlap with a command
1558         if (Cmd_Exists (name))
1559         {
1560                 Con_Printf("VM_registercvar: %s is a command\n", name);
1561                 return;
1562         }
1563
1564         Cvar_Get(name, value, flags);
1565
1566         PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1567 }
1568
1569 /*
1570 =================
1571 VM_min
1572
1573 returns the minimum of two supplied floats
1574
1575 float min(float a, float b, ...[float])
1576 =================
1577 */
1578 void VM_min (void)
1579 {
1580         // LordHavoc: 3+ argument enhancement suggested by FrikaC
1581         if (prog->argc == 2)
1582                 PRVM_G_FLOAT(OFS_RETURN) = min(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1583         else if (prog->argc >= 3)
1584         {
1585                 int i;
1586                 float f = PRVM_G_FLOAT(OFS_PARM0);
1587                 for (i = 1;i < prog->argc;i++)
1588                         if (PRVM_G_FLOAT((OFS_PARM0+i*3)) < f)
1589                                 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1590                 PRVM_G_FLOAT(OFS_RETURN) = f;
1591         }
1592         else
1593                 PRVM_ERROR("VM_min: %s must supply at least 2 floats\n", PRVM_NAME);
1594 }
1595
1596 /*
1597 =================
1598 VM_max
1599
1600 returns the maximum of two supplied floats
1601
1602 float   max(float a, float b, ...[float])
1603 =================
1604 */
1605 void VM_max (void)
1606 {
1607         // LordHavoc: 3+ argument enhancement suggested by FrikaC
1608         if (prog->argc == 2)
1609                 PRVM_G_FLOAT(OFS_RETURN) = max(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1610         else if (prog->argc >= 3)
1611         {
1612                 int i;
1613                 float f = PRVM_G_FLOAT(OFS_PARM0);
1614                 for (i = 1;i < prog->argc;i++)
1615                         if (PRVM_G_FLOAT((OFS_PARM0+i*3)) > f)
1616                                 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1617                 PRVM_G_FLOAT(OFS_RETURN) = f;
1618         }
1619         else
1620                 PRVM_ERROR("VM_max: %s must supply at least 2 floats\n", PRVM_NAME);
1621 }
1622
1623 /*
1624 =================
1625 VM_bound
1626
1627 returns number bounded by supplied range
1628
1629 float   bound(float min, float value, float max)
1630 =================
1631 */
1632 void VM_bound (void)
1633 {
1634         VM_SAFEPARMCOUNT(3,VM_bound);
1635         PRVM_G_FLOAT(OFS_RETURN) = bound(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2));
1636 }
1637
1638 /*
1639 =================
1640 VM_pow
1641
1642 returns a raised to power b
1643
1644 float   pow(float a, float b)
1645 =================
1646 */
1647 void VM_pow (void)
1648 {
1649         VM_SAFEPARMCOUNT(2,VM_pow);
1650         PRVM_G_FLOAT(OFS_RETURN) = pow(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1651 }
1652
1653 /*
1654 =================
1655 VM_copyentity
1656
1657 copies data from one entity to another
1658
1659 copyentity(entity src, entity dst)
1660 =================
1661 */
1662 void VM_copyentity (void)
1663 {
1664         prvm_edict_t *in, *out;
1665         VM_SAFEPARMCOUNT(2,VM_copyentity);
1666         in = PRVM_G_EDICT(OFS_PARM0);
1667         out = PRVM_G_EDICT(OFS_PARM1);
1668         memcpy(out->v, in->v, prog->progs->entityfields * 4);
1669 }
1670
1671 /*
1672 =================
1673 VM_setcolor
1674
1675 sets the color of a client and broadcasts the update to all connected clients
1676
1677 setcolor(clientent, value)
1678 =================
1679 */
1680 /*void PF_setcolor (void)
1681 {
1682         client_t *client;
1683         int entnum, i;
1684         eval_t *val;
1685
1686         entnum = G_EDICTNUM(OFS_PARM0);
1687         i = G_FLOAT(OFS_PARM1);
1688
1689         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1690         {
1691                 Con_Print("tried to setcolor a non-client\n");
1692                 return;
1693         }
1694
1695         client = svs.clients + entnum-1;
1696         if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
1697                 val->_float = i;
1698         client->colors = i;
1699         client->old_colors = i;
1700         client->edict->v->team = (i & 15) + 1;
1701
1702         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1703         MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
1704         MSG_WriteByte (&sv.reliable_datagram, i);
1705 }*/
1706
1707 void VM_Files_Init(void)
1708 {
1709         memset(VM_FILES, 0, sizeof(qfile_t*[MAX_VMFILES]));
1710 }
1711
1712 void VM_Files_CloseAll(void)
1713 {
1714         int i;
1715         for (i = 0;i < MAX_VMFILES;i++)
1716         {
1717                 if (VM_FILES[i])
1718                         FS_Close(VM_FILES[i]);
1719                 //VM_FILES[i] = NULL;
1720         }
1721         memset(VM_FILES,0,sizeof(qfile_t*[MAX_VMFILES])); // this should be faster (is it ?)
1722 }
1723
1724 /*
1725 =========
1726 VM_fopen
1727
1728 float   fopen(string filename, float mode)
1729 =========
1730 */
1731 // float(string filename, float mode) fopen = #110;
1732 // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE),
1733 // returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
1734 void VM_fopen(void)
1735 {
1736         int filenum, mode;
1737         char *modestring, *filename;
1738
1739         VM_SAFEPARMCOUNT(2,VM_fopen);
1740
1741         for (filenum = 0;filenum < MAX_VMFILES;filenum++)
1742                 if (VM_FILES[filenum] == NULL)
1743                         break;
1744         if (filenum >= MAX_VMFILES)
1745         {
1746                 Con_Printf("VM_fopen: %s ran out of file handles (%i)\n", PRVM_NAME, MAX_VMFILES);
1747                 PRVM_G_FLOAT(OFS_RETURN) = -2;
1748                 return;
1749         }
1750         mode = PRVM_G_FLOAT(OFS_PARM1);
1751         switch(mode)
1752         {
1753         case 0: // FILE_READ
1754                 modestring = "rb";
1755                 break;
1756         case 1: // FILE_APPEND
1757                 modestring = "ab";
1758                 break;
1759         case 2: // FILE_WRITE
1760                 modestring = "wb";
1761                 break;
1762         default:
1763                 Con_Printf("VM_fopen: %s no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", PRVM_NAME, mode);
1764                 PRVM_G_FLOAT(OFS_RETURN) = -3;
1765                 return;
1766         }
1767         filename = PRVM_G_STRING(OFS_PARM0);
1768         // .. is parent directory on many platforms
1769         // / is parent directory on Amiga
1770         // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
1771         // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
1772         if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
1773         {
1774                 Con_Printf("VM_fopen: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
1775                 PRVM_G_FLOAT(OFS_RETURN) = -4;
1776                 return;
1777         }
1778         VM_FILES[filenum] = FS_Open(va("data/%s", filename), modestring, false, false);
1779         if (VM_FILES[filenum] == NULL && mode == 0)
1780                 VM_FILES[filenum] = FS_Open(va("%s", filename), modestring, false, false);
1781
1782         if (VM_FILES[filenum] == NULL)
1783                 PRVM_G_FLOAT(OFS_RETURN) = -1;
1784         else
1785                 PRVM_G_FLOAT(OFS_RETURN) = filenum;
1786 }
1787
1788 /*
1789 =========
1790 VM_fclose
1791
1792 fclose(float fhandle)
1793 =========
1794 */
1795 //void(float fhandle) fclose = #111; // closes a file
1796 void VM_fclose(void)
1797 {
1798         int filenum;
1799
1800         VM_SAFEPARMCOUNT(1,VM_fclose);
1801
1802         filenum = PRVM_G_FLOAT(OFS_PARM0);
1803         if (filenum < 0 || filenum >= MAX_VMFILES)
1804         {
1805                 Con_Printf("VM_fclose: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1806                 return;
1807         }
1808         if (VM_FILES[filenum] == NULL)
1809         {
1810                 Con_Printf("VM_fclose: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1811                 return;
1812         }
1813         FS_Close(VM_FILES[filenum]);
1814         VM_FILES[filenum] = NULL;
1815 }
1816
1817 /*
1818 =========
1819 VM_fgets
1820
1821 string  fgets(float fhandle)
1822 =========
1823 */
1824 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
1825 void VM_fgets(void)
1826 {
1827         int c, end;
1828         static char string[VM_STRINGTEMP_LENGTH];
1829         int filenum;
1830
1831         VM_SAFEPARMCOUNT(1,VM_fgets);
1832
1833         filenum = PRVM_G_FLOAT(OFS_PARM0);
1834         if (filenum < 0 || filenum >= MAX_VMFILES)
1835         {
1836                 Con_Printf("VM_fgets: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1837                 return;
1838         }
1839         if (VM_FILES[filenum] == NULL)
1840         {
1841                 Con_Printf("VM_fgets: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1842                 return;
1843         }
1844         end = 0;
1845         for (;;)
1846         {
1847                 c = FS_Getc(VM_FILES[filenum]);
1848                 if (c == '\r' || c == '\n' || c < 0)
1849                         break;
1850                 if (end < VM_STRINGTEMP_LENGTH - 1)
1851                         string[end++] = c;
1852         }
1853         string[end] = 0;
1854         // remove \n following \r
1855         if (c == '\r')
1856         {
1857                 c = FS_Getc(VM_FILES[filenum]);
1858                 if (c != '\n')
1859                         FS_UnGetc(VM_FILES[filenum], (unsigned char)c);
1860         }
1861         if (developer.integer >= 3)
1862                 Con_Printf("fgets: %s: %s\n", PRVM_NAME, string);
1863         if (c >= 0 || end)
1864                 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1865         else
1866                 PRVM_G_INT(OFS_RETURN) = 0;
1867 }
1868
1869 /*
1870 =========
1871 VM_fputs
1872
1873 fputs(float fhandle, string s)
1874 =========
1875 */
1876 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
1877 void VM_fputs(void)
1878 {
1879         int stringlength;
1880         char string[VM_STRINGTEMP_LENGTH];
1881         int filenum;
1882
1883         VM_SAFEPARMCOUNT(2,VM_fputs);
1884
1885         filenum = PRVM_G_FLOAT(OFS_PARM0);
1886         if (filenum < 0 || filenum >= MAX_VMFILES)
1887         {
1888                 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1889                 return;
1890         }
1891         if (VM_FILES[filenum] == NULL)
1892         {
1893                 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1894                 return;
1895         }
1896         VM_VarString(1, string, sizeof(string));
1897         if ((stringlength = strlen(string)))
1898                 FS_Write(VM_FILES[filenum], string, stringlength);
1899         if (developer.integer)
1900                 Con_Printf("fputs: %s: %s\n", PRVM_NAME, string);
1901 }
1902
1903 /*
1904 =========
1905 VM_strlen
1906
1907 float   strlen(string s)
1908 =========
1909 */
1910 //float(string s) strlen = #114; // returns how many characters are in a string
1911 void VM_strlen(void)
1912 {
1913         char *s;
1914
1915         VM_SAFEPARMCOUNT(1,VM_strlen);
1916
1917         s = PRVM_G_STRING(OFS_PARM0);
1918         if (s)
1919                 PRVM_G_FLOAT(OFS_RETURN) = strlen(s);
1920         else
1921                 PRVM_G_FLOAT(OFS_RETURN) = 0;
1922 }
1923
1924 /*
1925 =========
1926 VM_strcat
1927
1928 string strcat(string,string,...[string])
1929 =========
1930 */
1931 //string(string s1, string s2) strcat = #115;
1932 // concatenates two strings (for example "abc", "def" would return "abcdef")
1933 // and returns as a tempstring
1934 void VM_strcat(void)
1935 {
1936         char *s;
1937
1938         if(prog->argc < 1)
1939                 PRVM_ERROR("VM_strcat wrong parameter count (min. 1 expected ) !\n");
1940
1941         s = VM_GetTempString();
1942         VM_VarString(0, s, VM_STRINGTEMP_LENGTH);
1943         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
1944 }
1945
1946 /*
1947 =========
1948 VM_substring
1949
1950 string  substring(string s, float start, float length)
1951 =========
1952 */
1953 // string(string s, float start, float length) substring = #116;
1954 // returns a section of a string as a tempstring
1955 void VM_substring(void)
1956 {
1957         int i, start, length;
1958         char *s, *string;
1959
1960         VM_SAFEPARMCOUNT(3,VM_substring);
1961
1962         string = VM_GetTempString();
1963         s = PRVM_G_STRING(OFS_PARM0);
1964         start = PRVM_G_FLOAT(OFS_PARM1);
1965         length = PRVM_G_FLOAT(OFS_PARM2);
1966         if (!s)
1967                 s = "";
1968         for (i = 0;i < start && *s;i++, s++);
1969         for (i = 0;i < VM_STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
1970                 string[i] = *s;
1971         string[i] = 0;
1972         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1973 }
1974
1975 /*
1976 =========
1977 VM_stov
1978
1979 vector  stov(string s)
1980 =========
1981 */
1982 //vector(string s) stov = #117; // returns vector value from a string
1983 void VM_stov(void)
1984 {
1985         char string[VM_STRINGTEMP_LENGTH];
1986
1987         VM_SAFEPARMCOUNT(1,VM_stov);
1988
1989         VM_VarString(0, string, sizeof(string));
1990         Math_atov(string, PRVM_G_VECTOR(OFS_RETURN));
1991 }
1992
1993 /*
1994 =========
1995 VM_strzone
1996
1997 string  strzone(string s)
1998 =========
1999 */
2000 //string(string s) strzone = #118; // makes a copy of a string into the string zone and returns it, this is often used to keep around a tempstring for longer periods of time (tempstrings are replaced often)
2001 void VM_strzone(void)
2002 {
2003         char *in, *out;
2004
2005         VM_SAFEPARMCOUNT(1,VM_strzone);
2006
2007         in = PRVM_G_STRING(OFS_PARM0);
2008         out = Mem_Alloc(VM_STRINGS_MEMPOOL, strlen(in) + 1);
2009         strcpy(out, in);
2010         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(out);
2011 }
2012
2013 /*
2014 =========
2015 VM_strunzone
2016
2017 strunzone(string s)
2018 =========
2019 */
2020 //void(string s) strunzone = #119; // removes a copy of a string from the string zone (you can not use that string again or it may crash!!!)
2021 void VM_strunzone(void)
2022 {
2023         char *str;
2024         VM_SAFEPARMCOUNT(1,VM_strunzone);
2025
2026         str = PRVM_G_STRING(OFS_PARM0);
2027         if( developer.integer && !Mem_IsAllocated( VM_STRINGS_MEMPOOL, str ) )
2028                 PRVM_ERROR( "VM_strunzone: Zone string already freed in %s!", PRVM_NAME );
2029         else
2030                 Mem_Free( str );
2031 }
2032
2033 /*
2034 =========
2035 VM_command (used by client and menu)
2036
2037 clientcommand(float client, string s) (for client and menu)
2038 =========
2039 */
2040 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2041 //this function originally written by KrimZon, made shorter by LordHavoc
2042 void VM_clcommand (void)
2043 {
2044         client_t *temp_client;
2045         int i;
2046
2047         VM_SAFEPARMCOUNT(2,VM_clcommand);
2048
2049         i = PRVM_G_FLOAT(OFS_PARM0);
2050         if (!sv.active  || i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2051         {
2052                 Con_Printf("VM_clientcommand: %s: invalid client/server is not active !\n", PRVM_NAME);
2053                 return;
2054         }
2055
2056         temp_client = host_client;
2057         host_client = svs.clients + i;
2058         Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2059         host_client = temp_client;
2060 }
2061
2062
2063 /*
2064 =========
2065 VM_tokenize
2066
2067 float tokenize(string s)
2068 =========
2069 */
2070 //float(string s) tokenize = #441;
2071 // takes apart a string into individal words (access them with argv), returns how many
2072 // this function originally written by KrimZon, made shorter by LordHavoc
2073 static char **tokens = NULL;
2074 static int    max_tokens, num_tokens = 0;
2075 void VM_tokenize (void)
2076 {
2077         const char *p;
2078         char *str;
2079
2080         VM_SAFEPARMCOUNT(1,VM_tokenize);
2081
2082         str = PRVM_G_STRING(OFS_PARM0);
2083
2084         if (tokens != NULL)
2085         {
2086                 int i;
2087                 for (i=0;i<num_tokens;i++)
2088                         Z_Free(tokens[i]);
2089                 Z_Free(tokens);
2090                 num_tokens = 0;
2091         }
2092
2093         tokens = Z_Malloc(strlen(str) * sizeof(char *));
2094         max_tokens = strlen(str);
2095
2096         for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2097         {
2098                 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2099                 strcpy(tokens[num_tokens], com_token);
2100         }
2101
2102         PRVM_G_FLOAT(OFS_RETURN) = num_tokens;
2103 }
2104
2105 /*
2106 =========
2107 VM_argv
2108
2109 string argv(float n)
2110 =========
2111 */
2112 //string(float n) argv = #442;
2113 // returns a word from the tokenized string (returns nothing for an invalid index)
2114 // this function originally written by KrimZon, made shorter by LordHavoc
2115 void VM_argv (void)
2116 {
2117         int token_num;
2118
2119         VM_SAFEPARMCOUNT(1,VM_argv);
2120
2121         token_num = PRVM_G_FLOAT(OFS_PARM0);
2122         if (token_num >= 0 && token_num < num_tokens)
2123                 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tokens[token_num]);
2124         else
2125                 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
2126 }
2127
2128 /*
2129 //void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag)
2130 void PF_setattachment (void)
2131 {
2132         edict_t *e = G_EDICT(OFS_PARM0);
2133         edict_t *tagentity = G_EDICT(OFS_PARM1);
2134         char *tagname = G_STRING(OFS_PARM2);
2135         eval_t *v;
2136         int i, modelindex;
2137         model_t *model;
2138
2139         if (tagentity == NULL)
2140                 tagentity = sv.edicts;
2141
2142         v = GETEDICTFIELDVALUE(e, eval_tag_entity);
2143         if (v)
2144                 v->edict = EDICT_TO_PROG(tagentity);
2145
2146         v = GETEDICTFIELDVALUE(e, eval_tag_index);
2147         if (v)
2148                 v->_float = 0;
2149         if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
2150         {
2151                 modelindex = (int)tagentity->v->modelindex;
2152                 if (modelindex >= 0 && modelindex < MAX_MODELS)
2153                 {
2154                         model = sv.models[modelindex];
2155                         if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
2156                                 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
2157                                         if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
2158                                                 v->_float = i + 1;
2159                         // FIXME: use a model function to get tag info (need to handle skeletal)
2160                         if (v->_float == 0 && model->alias.aliasnum_tags)
2161                                 for (i = 0;i < model->alias.aliasnum_tags;i++)
2162                                         if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
2163                                                 v->_float = i + 1;
2164                         if (v->_float == 0)
2165                                 Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity), model->name);
2166                 }
2167                 else
2168                         Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", NUM_FOR_EDICT(e), NUM_FOR_EDICT(tagentity), tagname, tagname, NUM_FOR_EDICT(tagentity));
2169         }
2170 }*/
2171
2172 /*
2173 =========
2174 VM_isserver
2175
2176 float   isserver()
2177 =========
2178 */
2179 void VM_isserver(void)
2180 {
2181         VM_SAFEPARMCOUNT(0,VM_serverstate);
2182
2183         PRVM_G_FLOAT(OFS_RETURN) = sv.active;
2184 }
2185
2186 /*
2187 =========
2188 VM_clientcount
2189
2190 float   clientcount()
2191 =========
2192 */
2193 void VM_clientcount(void)
2194 {
2195         VM_SAFEPARMCOUNT(0,VM_clientcount);
2196
2197         PRVM_G_FLOAT(OFS_RETURN) = svs.maxclients;
2198 }
2199
2200 /*
2201 =========
2202 VM_clientstate
2203
2204 float   clientstate()
2205 =========
2206 */
2207 void VM_clientstate(void)
2208 {
2209         VM_SAFEPARMCOUNT(0,VM_clientstate);
2210
2211         PRVM_G_FLOAT(OFS_RETURN) = cls.state;
2212 }
2213
2214 /*
2215 =========
2216 VM_getostype
2217
2218 float   getostype(void)
2219 =========
2220 */ // not used at the moment -> not included in the common list
2221 void VM_getostype(void)
2222 {
2223         VM_SAFEPARMCOUNT(0,VM_getostype);
2224
2225         /*
2226         OS_WINDOWS
2227         OS_LINUX
2228         OS_MAC - not supported
2229         */
2230
2231 #ifdef _WIN32
2232         PRVM_G_FLOAT(OFS_RETURN) = 0;
2233 #elif defined _MAC
2234         PRVM_G_FLOAT(OFS_RETURN) = 2;
2235 #else
2236         PRVM_G_FLOAT(OFS_RETURN) = 1;
2237 #endif
2238 }
2239
2240 /*
2241 =========
2242 VM_getmousepos
2243
2244 vector  getmousepos()
2245 =========
2246 */
2247 void VM_getmousepos(void)
2248 {
2249
2250         VM_SAFEPARMCOUNT(0,VM_getmousepos);
2251
2252         PRVM_G_VECTOR(OFS_RETURN)[0] = in_mouse_x;
2253         PRVM_G_VECTOR(OFS_RETURN)[1] = in_mouse_y;
2254         PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2255 }
2256
2257 /*
2258 =========
2259 VM_gettime
2260
2261 float   gettime(void)
2262 =========
2263 */
2264 void VM_gettime(void)
2265 {
2266         VM_SAFEPARMCOUNT(0,VM_gettime);
2267
2268         PRVM_G_FLOAT(OFS_RETURN) = (float) *prog->time;
2269 }
2270
2271 /*
2272 =========
2273 VM_loadfromdata
2274
2275 loadfromdata(string data)
2276 =========
2277 */
2278 void VM_loadfromdata(void)
2279 {
2280         VM_SAFEPARMCOUNT(1,VM_loadentsfromfile);
2281
2282         PRVM_ED_LoadFromFile(PRVM_G_STRING(OFS_PARM0));
2283 }
2284
2285 /*
2286 ========================
2287 VM_M_parseentitydata
2288
2289 parseentitydata(entity ent, string data)
2290 ========================
2291 */
2292 void VM_M_parseentitydata(void)
2293 {
2294         prvm_edict_t *ent;
2295         const char *data;
2296
2297         VM_SAFEPARMCOUNT(2, VM_parseentitydata);
2298
2299     // get edict and test it
2300         ent = PRVM_G_EDICT(OFS_PARM0);
2301         if (ent->p.e->free)
2302                 PRVM_ERROR ("VM_parseentitydata: %s: Can only set already spawned entities (entity %i is free)!\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ent));
2303
2304         data = PRVM_G_STRING(OFS_PARM1);
2305
2306     // parse the opening brace
2307         if (!COM_ParseToken(&data, false) || com_token[0] != '{' )
2308                 PRVM_ERROR ("VM_parseentitydata: %s: Couldn't parse entity data:\n%s\n", PRVM_NAME, data );
2309
2310         PRVM_ED_ParseEdict (data, ent);
2311 }
2312
2313 /*
2314 =========
2315 VM_loadfromfile
2316
2317 loadfromfile(string file)
2318 =========
2319 */
2320 void VM_loadfromfile(void)
2321 {
2322         char *filename;
2323         qbyte *data;
2324
2325         VM_SAFEPARMCOUNT(1,VM_loadfromfile);
2326
2327         filename = PRVM_G_STRING(OFS_PARM0);
2328         // .. is parent directory on many platforms
2329         // / is parent directory on Amiga
2330         // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2331         // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2332         if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2333         {
2334                 Con_Printf("VM_loadfromfile: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
2335                 PRVM_G_FLOAT(OFS_RETURN) = -4;
2336                 return;
2337         }
2338
2339         // not conform with VM_fopen
2340         data = FS_LoadFile(filename, tempmempool, false);
2341         if (data == NULL)
2342                 PRVM_G_FLOAT(OFS_RETURN) = -1;
2343
2344         PRVM_ED_LoadFromFile(data);
2345
2346         if(data)
2347                 Mem_Free(data);
2348 }
2349
2350
2351 /*
2352 =========
2353 VM_modulo
2354
2355 float   mod(float val, float m)
2356 =========
2357 */
2358 void VM_modulo(void)
2359 {
2360         int val, m;
2361         VM_SAFEPARMCOUNT(2,VM_module);
2362
2363         val = (int) PRVM_G_FLOAT(OFS_PARM0);
2364         m       = (int) PRVM_G_FLOAT(OFS_PARM1);
2365
2366         PRVM_G_FLOAT(OFS_RETURN) = (float) (val % m);
2367 }
2368
2369 void VM_Search_Init(void)
2370 {
2371         memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
2372 }
2373
2374 void VM_Search_Reset(void)
2375 {
2376         int i;
2377         // reset the fssearch list
2378         for(i = 0; i < MAX_VMSEARCHES; i++)
2379                 if(VM_SEARCHLIST[i])
2380                         FS_FreeSearch(VM_SEARCHLIST[i]);
2381         memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
2382 }
2383
2384 /*
2385 =========
2386 VM_search_begin
2387
2388 float search_begin(string pattern, float caseinsensitive, float quiet)
2389 =========
2390 */
2391 void VM_search_begin(void)
2392 {
2393         int handle;
2394         char *pattern;
2395         int caseinsens, quiet;
2396
2397         VM_SAFEPARMCOUNT(3, VM_search_begin);
2398
2399         pattern = PRVM_G_STRING(OFS_PARM0);
2400
2401         VM_CheckEmptyString(pattern);
2402
2403         caseinsens = PRVM_G_FLOAT(OFS_PARM1);
2404         quiet = PRVM_G_FLOAT(OFS_PARM2);
2405
2406         for(handle = 0; handle < MAX_VMSEARCHES; handle++)
2407                 if(!VM_SEARCHLIST[handle])
2408                         break;
2409
2410         if(handle >= MAX_VMSEARCHES)
2411         {
2412                 Con_Printf("VM_search_begin: %s ran out of search handles (%i)\n", PRVM_NAME, MAX_VMSEARCHES);
2413                 PRVM_G_FLOAT(OFS_RETURN) = -2;
2414                 return;
2415         }
2416
2417         if(!(VM_SEARCHLIST[handle] = FS_Search(pattern,caseinsens, quiet)))
2418                 PRVM_G_FLOAT(OFS_RETURN) = -1;
2419         else
2420                 PRVM_G_FLOAT(OFS_RETURN) = handle;
2421 }
2422
2423 /*
2424 =========
2425 VM_search_end
2426
2427 void    search_end(float handle)
2428 =========
2429 */
2430 void VM_search_end(void)
2431 {
2432         int handle;
2433         VM_SAFEPARMCOUNT(1, VM_search_end);
2434
2435         handle = PRVM_G_FLOAT(OFS_PARM0);
2436
2437         if(handle < 0 || handle >= MAX_VMSEARCHES)
2438         {
2439                 Con_Printf("VM_search_end: invalid handle %i used in %s\n", handle, PRVM_NAME);
2440                 return;
2441         }
2442         if(VM_SEARCHLIST[handle] == NULL)
2443         {
2444                 Con_Printf("VM_search_end: no such handle %i in %s\n", handle, PRVM_NAME);
2445                 return;
2446         }
2447
2448         FS_FreeSearch(VM_SEARCHLIST[handle]);
2449         VM_SEARCHLIST[handle] = NULL;
2450 }
2451
2452 /*
2453 =========
2454 VM_search_getsize
2455
2456 float   search_getsize(float handle)
2457 =========
2458 */
2459 void VM_search_getsize(void)
2460 {
2461         int handle;
2462         VM_SAFEPARMCOUNT(1, VM_M_search_getsize);
2463
2464         handle = PRVM_G_FLOAT(OFS_PARM0);
2465
2466         if(handle < 0 || handle >= MAX_VMSEARCHES)
2467         {
2468                 Con_Printf("VM_search_getsize: invalid handle %i used in %s\n", handle, PRVM_NAME);
2469                 return;
2470         }
2471         if(VM_SEARCHLIST[handle] == NULL)
2472         {
2473                 Con_Printf("VM_search_getsize: no such handle %i in %s\n", handle, PRVM_NAME);
2474                 return;
2475         }
2476
2477         PRVM_G_FLOAT(OFS_RETURN) = VM_SEARCHLIST[handle]->numfilenames;
2478 }
2479
2480 /*
2481 =========
2482 VM_search_getfilename
2483
2484 string  search_getfilename(float handle, float num)
2485 =========
2486 */
2487 void VM_search_getfilename(void)
2488 {
2489         int handle, filenum;
2490         char *tmp;
2491         VM_SAFEPARMCOUNT(2, VM_search_getfilename);
2492
2493         handle = PRVM_G_FLOAT(OFS_PARM0);
2494         filenum = PRVM_G_FLOAT(OFS_PARM1);
2495
2496         if(handle < 0 || handle >= MAX_VMSEARCHES)
2497         {
2498                 Con_Printf("VM_search_getfilename: invalid handle %i used in %s\n", handle, PRVM_NAME);
2499                 return;
2500         }
2501         if(VM_SEARCHLIST[handle] == NULL)
2502         {
2503                 Con_Printf("VM_search_getfilename: no such handle %i in %s\n", handle, PRVM_NAME);
2504                 return;
2505         }
2506         if(filenum < 0 || filenum >= VM_SEARCHLIST[handle]->numfilenames)
2507         {
2508                 Con_Printf("VM_search_getfilename: invalid filenum %i in %s\n", filenum, PRVM_NAME);
2509                 return;
2510         }
2511
2512         tmp = VM_GetTempString();
2513         strcpy(tmp, VM_SEARCHLIST[handle]->filenames[filenum]);
2514
2515         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
2516 }
2517
2518 /*
2519 =========
2520 VM_chr
2521
2522 string  chr(float ascii)
2523 =========
2524 */
2525 void VM_chr(void)
2526 {
2527         char *tmp;
2528         VM_SAFEPARMCOUNT(1, VM_chr);
2529
2530         tmp = VM_GetTempString();
2531         tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0);
2532         tmp[1] = 0;
2533
2534         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
2535 }
2536
2537 //=============================================================================
2538 // Draw builtins (client & menu)
2539
2540 /*
2541 =========
2542 VM_iscachedpic
2543
2544 float   iscachedpic(string pic)
2545 =========
2546 */
2547 void VM_iscachedpic(void)
2548 {
2549         VM_SAFEPARMCOUNT(1,VM_iscachedpic);
2550
2551         // drawq hasnt such a function, thus always return true
2552         PRVM_G_FLOAT(OFS_RETURN) = false;
2553 }
2554
2555 /*
2556 =========
2557 VM_precache_pic
2558
2559 string  precache_pic(string pic)
2560 =========
2561 */
2562 void VM_precache_pic(void)
2563 {
2564         char    *s;
2565
2566         VM_SAFEPARMCOUNT(1, VM_precache_pic);
2567
2568         s = PRVM_G_STRING(OFS_PARM0);
2569         PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
2570
2571         if(!s)
2572                 PRVM_ERROR ("VM_precache_pic: %s: NULL\n", PRVM_NAME);
2573
2574         VM_CheckEmptyString (s);
2575
2576         if(!Draw_CachePic(s))
2577                 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
2578 }
2579
2580 /*
2581 =========
2582 VM_freepic
2583
2584 freepic(string s)
2585 =========
2586 */
2587 void VM_freepic(void)
2588 {
2589         char *s;
2590
2591         VM_SAFEPARMCOUNT(1,VM_freepic);
2592
2593         s = PRVM_G_STRING(OFS_PARM0);
2594
2595         if(!s)
2596                 PRVM_ERROR ("VM_freepic: %s: NULL\n");
2597
2598         VM_CheckEmptyString (s);
2599
2600         Draw_FreePic(s);
2601 }
2602
2603 /*
2604 =========
2605 VM_drawcharacter
2606
2607 float   drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
2608 =========
2609 */
2610 void VM_drawcharacter(void)
2611 {
2612         float *pos,*scale,*rgb;
2613         char   character;
2614         int flag;
2615         VM_SAFEPARMCOUNT(6,VM_drawcharacter);
2616
2617         character = (char) PRVM_G_FLOAT(OFS_PARM1);
2618         if(character == 0)
2619         {
2620                 Con_Printf("VM_drawcharacter: %s passed null character !\n",PRVM_NAME);
2621                 PRVM_G_FLOAT(OFS_RETURN) = -1;
2622                 return;
2623         }
2624
2625         pos = PRVM_G_VECTOR(OFS_PARM0);
2626         scale = PRVM_G_VECTOR(OFS_PARM2);
2627         rgb = PRVM_G_VECTOR(OFS_PARM3);
2628         flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2629
2630         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2631         {
2632                 Con_Printf("VM_drawcharacter: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2633                 PRVM_G_FLOAT(OFS_RETURN) = -2;
2634                 return;
2635         }
2636
2637         if(pos[2] || scale[2])
2638                 Con_Printf("VM_drawcharacter: z value%c from %s discarded\n",(pos[2] && scale[2]) ? 's' : 0,((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale")));
2639
2640         if(!scale[0] || !scale[1])
2641         {
2642                 Con_Printf("VM_drawcharacter: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2643                 PRVM_G_FLOAT(OFS_RETURN) = -3;
2644                 return;
2645         }
2646
2647         DrawQ_String (pos[0], pos[1], &character, 1, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2648         PRVM_G_FLOAT(OFS_RETURN) = 1;
2649 }
2650
2651 /*
2652 =========
2653 VM_drawstring
2654
2655 float   drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
2656 =========
2657 */
2658 void VM_drawstring(void)
2659 {
2660         float *pos,*scale,*rgb;
2661         char  *string;
2662         int flag;
2663         VM_SAFEPARMCOUNT(6,VM_drawstring);
2664
2665         string = PRVM_G_STRING(OFS_PARM1);
2666         if(!string)
2667         {
2668                 Con_Printf("VM_drawstring: %s passed null string !\n",PRVM_NAME);
2669                 PRVM_G_FLOAT(OFS_RETURN) = -1;
2670                 return;
2671         }
2672
2673         //VM_CheckEmptyString(string); Why should it be checked - perhaps the menu wants to support the precolored letters, too?
2674
2675         pos = PRVM_G_VECTOR(OFS_PARM0);
2676         scale = PRVM_G_VECTOR(OFS_PARM2);
2677         rgb = PRVM_G_VECTOR(OFS_PARM3);
2678         flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2679
2680         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2681         {
2682                 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2683                 PRVM_G_FLOAT(OFS_RETURN) = -2;
2684                 return;
2685         }
2686
2687         if(!scale[0] || !scale[1])
2688         {
2689                 Con_Printf("VM_drawstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2690                 PRVM_G_FLOAT(OFS_RETURN) = -3;
2691                 return;
2692         }
2693
2694         if(pos[2] || scale[2])
2695                 Con_Printf("VM_drawstring: z value%c from %s discarded\n",(pos[2] && scale[2]) ? 's' : 0,((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale")));
2696
2697         DrawQ_String (pos[0], pos[1], string, 0, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2698         PRVM_G_FLOAT(OFS_RETURN) = 1;
2699 }
2700 /*
2701 =========
2702 VM_drawpic
2703
2704 float   drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
2705 =========
2706 */
2707 void VM_drawpic(void)
2708 {
2709         char *pic;
2710         float *size, *pos, *rgb;
2711         int flag;
2712
2713         VM_SAFEPARMCOUNT(6,VM_drawpic);
2714
2715         pic = PRVM_G_STRING(OFS_PARM1);
2716
2717         if(!pic)
2718         {
2719                 Con_Printf("VM_drawpic: %s passed null picture name !\n", PRVM_NAME);
2720                 PRVM_G_FLOAT(OFS_RETURN) = -1;
2721                 return;
2722         }
2723
2724         VM_CheckEmptyString (pic);
2725
2726         // is pic cached ? no function yet for that
2727         if(!1)
2728         {
2729                 Con_Printf("VM_drawpic: %s: %s not cached !\n", PRVM_NAME, pic);
2730                 PRVM_G_FLOAT(OFS_RETURN) = -4;
2731                 return;
2732         }
2733
2734         pos = PRVM_G_VECTOR(OFS_PARM0);
2735         size = PRVM_G_VECTOR(OFS_PARM2);
2736         rgb = PRVM_G_VECTOR(OFS_PARM3);
2737         flag = (int) PRVM_G_FLOAT(OFS_PARM5);
2738
2739         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2740         {
2741                 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2742                 PRVM_G_FLOAT(OFS_RETURN) = -2;
2743                 return;
2744         }
2745
2746         if(pos[2] || size[2])
2747                 Con_Printf("VM_drawstring: z value%c from %s discarded\n",(pos[2] && size[2]) ? 's' : 0,((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size")));
2748
2749         DrawQ_Pic(pos[0], pos[1], pic, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2750         PRVM_G_FLOAT(OFS_RETURN) = 1;
2751 }
2752
2753 /*
2754 =========
2755 VM_drawfill
2756
2757 float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
2758 =========
2759 */
2760 void VM_drawfill(void)
2761 {
2762         float *size, *pos, *rgb;
2763         int flag;
2764
2765         VM_SAFEPARMCOUNT(5,VM_drawfill);
2766
2767
2768         pos = PRVM_G_VECTOR(OFS_PARM0);
2769         size = PRVM_G_VECTOR(OFS_PARM1);
2770         rgb = PRVM_G_VECTOR(OFS_PARM2);
2771         flag = (int) PRVM_G_FLOAT(OFS_PARM4);
2772
2773         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2774         {
2775                 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2776                 PRVM_G_FLOAT(OFS_RETURN) = -2;
2777                 return;
2778         }
2779
2780         if(pos[2] || size[2])
2781                 Con_Printf("VM_drawstring: z value%c from %s discarded\n",(pos[2] && size[2]) ? 's' : 0,((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size")));
2782
2783         DrawQ_Pic(pos[0], pos[1], 0, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM3), flag);
2784         PRVM_G_FLOAT(OFS_RETURN) = 1;
2785 }
2786
2787 /*
2788 =========
2789 VM_drawsetcliparea
2790
2791 drawsetcliparea(float x, float y, float width, float height)
2792 =========
2793 */
2794 void VM_drawsetcliparea(void)
2795 {
2796         float x,y,w,h;
2797         VM_SAFEPARMCOUNT(4,VM_drawsetcliparea);
2798
2799         x = bound(0, PRVM_G_FLOAT(OFS_PARM0), vid.conwidth);
2800         y = bound(0, PRVM_G_FLOAT(OFS_PARM1), vid.conheight);
2801         w = bound(0, PRVM_G_FLOAT(OFS_PARM2) + PRVM_G_FLOAT(OFS_PARM0) - x, (vid.conwidth  - x));
2802         h = bound(0, PRVM_G_FLOAT(OFS_PARM3) + PRVM_G_FLOAT(OFS_PARM1) - y, (vid.conheight - y));
2803
2804         DrawQ_SetClipArea(x, y, w, h);
2805 }
2806
2807 /*
2808 =========
2809 VM_drawresetcliparea
2810
2811 drawresetcliparea()
2812 =========
2813 */
2814 void VM_drawresetcliparea(void)
2815 {
2816         VM_SAFEPARMCOUNT(0,VM_drawresetcliparea);
2817
2818         DrawQ_ResetClipArea();
2819 }
2820
2821 /*
2822 =========
2823 VM_getimagesize
2824
2825 vector  getimagesize(string pic)
2826 =========
2827 */
2828 void VM_getimagesize(void)
2829 {
2830         char *p;
2831         cachepic_t *pic;
2832
2833         VM_SAFEPARMCOUNT(1,VM_getimagesize);
2834
2835         p = PRVM_G_STRING(OFS_PARM0);
2836
2837         if(!p)
2838                 PRVM_ERROR("VM_getimagepos: %s passed null picture name !\n", PRVM_NAME);
2839
2840         VM_CheckEmptyString (p);
2841
2842         pic = Draw_CachePic (p);
2843
2844         PRVM_G_VECTOR(OFS_RETURN)[0] = pic->width;
2845         PRVM_G_VECTOR(OFS_RETURN)[1] = pic->height;
2846         PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2847 }
2848
2849 // CL_Video interface functions
2850
2851 /*
2852 ========================
2853 VM_cin_open
2854
2855 float cin_open(string file, string name)
2856 ========================
2857 */
2858 void VM_cin_open( void )
2859 {
2860         char *file;
2861         char *name;
2862
2863         VM_SAFEPARMCOUNT( 2, VM_cin_open );
2864
2865         file = PRVM_G_STRING( OFS_PARM0 );
2866         name = PRVM_G_STRING( OFS_PARM1 );
2867
2868         VM_CheckEmptyString( file );
2869     VM_CheckEmptyString( name );
2870
2871         if( CL_OpenVideo( file, name, MENUOWNER ) )
2872                 PRVM_G_FLOAT( OFS_RETURN ) = 1;
2873         else
2874                 PRVM_G_FLOAT( OFS_RETURN ) = 0;
2875 }
2876
2877 /*
2878 ========================
2879 VM_cin_close
2880
2881 void cin_close(string name)
2882 ========================
2883 */
2884 void VM_cin_close( void )
2885 {
2886         char *name;
2887
2888         VM_SAFEPARMCOUNT( 1, VM_cin_close );
2889
2890         name = PRVM_G_STRING( OFS_PARM0 );
2891         VM_CheckEmptyString( name );
2892
2893         CL_CloseVideo( CL_GetVideo( name ) );
2894 }
2895
2896 /*
2897 ========================
2898 VM_cin_setstate
2899 void cin_setstate(string name, float type)
2900 ========================
2901 */
2902 void VM_cin_setstate( void )
2903 {
2904         char *name;
2905         clvideostate_t  state;
2906         clvideo_t               *video;
2907
2908         VM_SAFEPARMCOUNT( 2, VM_cin_netstate );
2909
2910         name = PRVM_G_STRING( OFS_PARM0 );
2911         VM_CheckEmptyString( name );
2912
2913         state = PRVM_G_FLOAT( OFS_PARM1 );
2914
2915         video = CL_GetVideo( name );
2916         if( video && state > CLVIDEO_UNUSED && state < CLVIDEO_STATECOUNT )
2917                 CL_SetVideoState( video, state );
2918 }
2919
2920 /*
2921 ========================
2922 VM_cin_getstate
2923
2924 float cin_getstate(string name)
2925 ========================
2926 */
2927 void VM_cin_getstate( void )
2928 {
2929         char *name;
2930         clvideo_t               *video;
2931
2932         VM_SAFEPARMCOUNT( 1, VM_cin_getstate );
2933
2934         name = PRVM_G_STRING( OFS_PARM0 );
2935         VM_CheckEmptyString( name );
2936
2937         video = CL_GetVideo( name );
2938         if( video )
2939                 PRVM_G_FLOAT( OFS_RETURN ) = (int)video->state;
2940         else
2941                 PRVM_G_FLOAT( OFS_RETURN ) = 0;
2942 }
2943
2944 /*
2945 ========================
2946 VM_cin_restart
2947
2948 void cin_restart(string name)
2949 ========================
2950 */
2951 void VM_cin_restart( void )
2952 {
2953         char *name;
2954         clvideo_t               *video;
2955
2956         VM_SAFEPARMCOUNT( 1, VM_cin_restart );
2957
2958         name = PRVM_G_STRING( OFS_PARM0 );
2959         VM_CheckEmptyString( name );
2960
2961         video = CL_GetVideo( name );
2962         if( video )
2963                 CL_RestartVideo( video );
2964 }
2965
2966 ////////////////////////////////////////
2967 // AltString functions
2968 ////////////////////////////////////////
2969
2970 /*
2971 ========================
2972 VM_altstr_count
2973
2974 float altstr_count(string)
2975 ========================
2976 */
2977 void VM_altstr_count( void )
2978 {
2979         char *altstr, *pos;
2980         int     count;
2981
2982         VM_SAFEPARMCOUNT( 1, VM_altstr_count );
2983
2984         altstr = PRVM_G_STRING( OFS_PARM0 );
2985         //VM_CheckEmptyString( altstr );
2986
2987         for( count = 0, pos = altstr ; *pos ; pos++ )
2988                 if( *pos == '\\' && !*++pos )
2989                                 break;
2990                 else if( *pos == '\'' )
2991                         count++;
2992
2993         PRVM_G_FLOAT( OFS_RETURN ) = (float) (count / 2);
2994 }
2995
2996 /*
2997 ========================
2998 VM_altstr_prepare
2999
3000 string altstr_prepare(string)
3001 ========================
3002 */
3003 void VM_altstr_prepare( void )
3004 {
3005         char *outstr, *out;
3006         char *instr, *in;
3007         int size;
3008
3009         VM_SAFEPARMCOUNT( 1, VM_altstr_prepare );
3010
3011         instr = PRVM_G_STRING( OFS_PARM0 );
3012         //VM_CheckEmptyString( instr );
3013         outstr = VM_GetTempString();
3014
3015         for( out = outstr, in = instr, size = VM_STRINGTEMP_LENGTH - 1 ; size && *in ; size--, in++, out++ )
3016                 if( *in == '\'' ) {
3017                         *out++ = '\\';
3018                         *out = '\'';
3019                         size--;
3020                 } else
3021                         *out = *in;
3022         *out = 0;
3023
3024         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( outstr );
3025 }
3026
3027 /*
3028 ========================
3029 VM_altstr_get
3030
3031 string altstr_get(string, float)
3032 ========================
3033 */
3034 void VM_altstr_get( void )
3035 {
3036         char *altstr, *pos, *outstr, *out;
3037         int count, size;
3038
3039         VM_SAFEPARMCOUNT( 2, VM_altstr_get );
3040
3041         altstr = PRVM_G_STRING( OFS_PARM0 );
3042         //VM_CheckEmptyString( altstr );
3043
3044         count = PRVM_G_FLOAT( OFS_PARM1 );
3045         count = count * 2 + 1;
3046
3047         for( pos = altstr ; *pos && count ; pos++ )
3048                 if( *pos == '\\' && !*++pos )
3049                         break;
3050                 else if( *pos == '\'' )
3051                         count--;
3052
3053         if( !*pos ) {
3054                 PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( "" );
3055                 return;
3056         }
3057
3058     outstr = VM_GetTempString();
3059         for( out = outstr, size = VM_STRINGTEMP_LENGTH - 1 ; size && *pos ; size--, pos++, out++ )
3060                 if( *pos == '\\' ) {
3061                         if( !*++pos )
3062                                 break;
3063                         *out = *pos;
3064                         size--;
3065                 } else if( *pos == '\'' )
3066                         break;
3067                 else
3068                         *out = *pos;
3069
3070         *out = 0;
3071         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( outstr );
3072 }
3073
3074 /*
3075 ========================
3076 VM_altstr_set
3077
3078 string altstr_set(string altstr, float num, string set)
3079 ========================
3080 */
3081 void VM_altstr_set( void )
3082 {
3083     int num;
3084         char *altstr, *str;
3085         char *in;
3086         char *outstr, *out;
3087
3088         VM_SAFEPARMCOUNT( 3, VM_altstr_set );
3089
3090         altstr = PRVM_G_STRING( OFS_PARM0 );
3091         //VM_CheckEmptyString( altstr );
3092
3093         num = PRVM_G_FLOAT( OFS_PARM1 );
3094
3095         str = PRVM_G_STRING( OFS_PARM2 );
3096         //VM_CheckEmptyString( str );
3097
3098         outstr = out = VM_GetTempString();
3099         for( num = num * 2 + 1, in = altstr; *in && num; *out++ = *in++ )
3100                 if( *in == '\\' && !*++in )
3101                         break;
3102                 else if( *in == '\'' )
3103                         num--;
3104
3105         if( !in ) {
3106                 PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( "" );
3107                 return;
3108         }
3109         // copy set in
3110         for( ; *str; *out++ = *str++ );
3111         // now jump over the old contents
3112         for( ; *in ; in++ )
3113                 if( *in == '\'' || (*in == '\\' && !*++in) )
3114                         break;
3115
3116         if( !in ) {
3117                 PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( "" );
3118                 return;
3119         }
3120
3121         strcpy( out, in );
3122         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( outstr );
3123 }
3124
3125 void VM_Cmd_Init(void)
3126 {
3127         // only init the stuff for the current prog
3128         VM_STRINGS_MEMPOOL = Mem_AllocPool(va("vm_stringsmempool[%s]",PRVM_NAME), 0, NULL);
3129         VM_Files_Init();
3130         VM_Search_Init();
3131 }
3132
3133 void VM_Cmd_Reset(void)
3134 {
3135         //Mem_EmptyPool(VM_STRINGS_MEMPOOL);
3136         if( developer.integer >= 2 && VM_STRINGS_MEMPOOL ) {
3137                 memheader_t *header;
3138                 int     i;
3139
3140                 for( i = 0, header = VM_STRINGS_MEMPOOL->chain ; header ; header = header->next, i++ )
3141                         Con_DPrintf( "Leaked string %i (size: %i): %.*s\n", i, header->size, header->size, ((char*)header) + sizeof( memheader_t ) );
3142         }
3143
3144         Mem_FreePool(&VM_STRINGS_MEMPOOL);
3145         CL_PurgeOwner( MENUOWNER );
3146         VM_Search_Reset();
3147         VM_Files_CloseAll();
3148 }
3149
3150 //============================================================================
3151 // Server
3152
3153 char *vm_sv_extensions =
3154 "";
3155
3156 prvm_builtin_t vm_sv_builtins[] = {
3157 0  // to be consistent with the old vm
3158 };
3159
3160 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
3161
3162 void VM_SV_Cmd_Init(void)
3163 {
3164 }
3165
3166 void VM_SV_Cmd_Reset(void)
3167 {
3168 }
3169
3170 //============================================================================
3171 // Client
3172
3173 char *vm_cl_extensions =
3174 "";
3175
3176 prvm_builtin_t vm_cl_builtins[] = {
3177 0  // to be consistent with the old vm
3178 };
3179
3180 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3181
3182 void VM_CL_Cmd_Init(void)
3183 {
3184 }
3185
3186 void VM_CL_Cmd_Reset(void)
3187 {
3188 }
3189
3190 //============================================================================
3191 // Menu
3192
3193 char *vm_m_extensions =
3194 "DP_CINEMATIC_DPV";
3195
3196 /*
3197 =========
3198 VM_M_setmousetarget
3199
3200 setmousetarget(float target)
3201 =========
3202 */
3203 void VM_M_setmousetarget(void)
3204 {
3205         VM_SAFEPARMCOUNT(1, VM_M_setmousetarget);
3206
3207         switch((int)PRVM_G_FLOAT(OFS_PARM0))
3208         {
3209         case 1:
3210                 in_client_mouse = false;
3211                 break;
3212         case 2:
3213                 in_client_mouse = true;
3214                 break;
3215         default:
3216                 PRVM_ERROR("VM_M_setmousetarget: wrong destination %i !\n",PRVM_G_FLOAT(OFS_PARM0));
3217         }
3218 }
3219
3220 /*
3221 =========
3222 VM_M_getmousetarget
3223
3224 float   getmousetarget
3225 =========
3226 */
3227 void VM_M_getmousetarget(void)
3228 {
3229         VM_SAFEPARMCOUNT(0,VM_M_getmousetarget);
3230
3231         if(in_client_mouse)
3232                 PRVM_G_FLOAT(OFS_RETURN) = 2;
3233         else
3234                 PRVM_G_FLOAT(OFS_RETURN) = 1;
3235 }
3236
3237
3238
3239 /*
3240 =========
3241 VM_M_setkeydest
3242
3243 setkeydest(float dest)
3244 =========
3245 */
3246 void VM_M_setkeydest(void)
3247 {
3248         VM_SAFEPARMCOUNT(1,VM_M_setkeydest);
3249
3250         switch((int)PRVM_G_FLOAT(OFS_PARM0))
3251         {
3252         case 0:
3253                 // key_game
3254                 key_dest = key_game;
3255                 break;
3256         case 2:
3257                 // key_menu
3258                 key_dest = key_menu;
3259                 break;
3260         case 1:
3261                 // key_message
3262                 // key_dest = key_message
3263                 // break;
3264         default:
3265                 PRVM_ERROR("VM_M_setkeydest: wrong destination %i !\n",prog->globals[OFS_PARM0]);
3266         }
3267 }
3268
3269 /*
3270 =========
3271 VM_M_getkeydest
3272
3273 float   getkeydest
3274 =========
3275 */
3276 void VM_M_getkeydest(void)
3277 {
3278         VM_SAFEPARMCOUNT(0,VM_M_getkeydest);
3279
3280         // key_game = 0, key_message = 1, key_menu = 2, unknown = 3
3281         switch(key_dest)
3282         {
3283         case key_game:
3284                 PRVM_G_FLOAT(OFS_RETURN) = 0;
3285                 break;
3286         case key_menu:
3287                 PRVM_G_FLOAT(OFS_RETURN) = 2;
3288                 break;
3289         case key_message:
3290                 // not supported
3291                 // PRVM_G_FLOAT(OFS_RETURN) = 1;
3292                 // break;
3293         default:
3294                 PRVM_G_FLOAT(OFS_RETURN) = 3;
3295         }
3296 }
3297
3298 /*
3299 =========
3300 VM_M_callfunction
3301
3302         callfunction(...,string function_name)
3303 Extension: pass
3304 =========
3305 */
3306 mfunction_t *PRVM_ED_FindFunction (const char *name);
3307 void VM_M_callfunction(void)
3308 {
3309         mfunction_t *func;
3310         char *s;
3311
3312         if(prog->argc == 0)
3313                 PRVM_ERROR("VM_M_callfunction: 1 parameter is required !\n");
3314
3315         s = PRVM_G_STRING(OFS_PARM0 + (prog->argc - 1));
3316
3317         if(!s)
3318                 PRVM_ERROR("VM_M_callfunction: null string !\n");
3319
3320         VM_CheckEmptyString(s);
3321
3322         func = PRVM_ED_FindFunction(s);
3323
3324         if(!func)
3325                 PRVM_ERROR("VM_M_callfunciton: function %s not found !\n", s);
3326         else if (func->first_statement < 0)
3327         {
3328                 // negative statements are built in functions
3329                 int builtinnumber = -func->first_statement;
3330                 prog->xfunction->builtinsprofile++;
3331                 if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber])
3332                         prog->builtins[builtinnumber]();
3333                 else
3334                         PRVM_ERROR("No such builtin #%i in %s", builtinnumber, PRVM_NAME);
3335         }
3336         else if(func > 0)
3337         {
3338                 prog->argc--;
3339                 PRVM_ExecuteProgram(func - prog->functions,"");
3340                 prog->argc++;
3341         }
3342 }
3343
3344 /*
3345 =========
3346 VM_M_isfunction
3347
3348 float   isfunction(string function_name)
3349 =========
3350 */
3351 mfunction_t *PRVM_ED_FindFunction (const char *name);
3352 void VM_M_isfunction(void)
3353 {
3354         mfunction_t *func;
3355         char *s;
3356
3357         VM_SAFEPARMCOUNT(1, VM_M_isfunction);
3358
3359         s = PRVM_G_STRING(OFS_PARM0);
3360
3361         if(!s)
3362                 PRVM_ERROR("VM_M_isfunction: null string !\n");
3363
3364         VM_CheckEmptyString(s);
3365
3366         func = PRVM_ED_FindFunction(s);
3367
3368         if(!func)
3369                 PRVM_G_FLOAT(OFS_RETURN) = false;
3370         else
3371                 PRVM_G_FLOAT(OFS_RETURN) = true;
3372 }
3373
3374 /*
3375 =========
3376 VM_M_writetofile
3377
3378         writetofile(float fhandle, entity ent)
3379 =========
3380 */
3381 void VM_M_writetofile(void)
3382 {
3383         prvm_edict_t * ent;
3384         int filenum;
3385
3386         VM_SAFEPARMCOUNT(2, VM_M_writetofile);
3387
3388         filenum = PRVM_G_FLOAT(OFS_PARM0);
3389         if (filenum < 0 || filenum >= MAX_VMFILES)
3390         {
3391                 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
3392                 return;
3393         }
3394         if (VM_FILES[filenum] == NULL)
3395         {
3396                 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
3397                 return;
3398         }
3399
3400         ent = PRVM_G_EDICT(OFS_PARM1);
3401         if(ent->p.e->free)
3402         {
3403                 Con_Printf("VM_M_writetofile: %s: entity %i is free !\n", PRVM_NAME, PRVM_EDICT_NUM(OFS_PARM1));
3404                 return;
3405         }
3406
3407         PRVM_ED_Write (VM_FILES[filenum], ent);
3408 }
3409
3410 /*
3411 =========
3412 VM_M_getresolution
3413
3414 vector  getresolution(float number)
3415 =========
3416 */
3417 extern unsigned short video_resolutions[][2];
3418 void VM_M_getresolution(void)
3419 {
3420         int nr;
3421         VM_SAFEPARMCOUNT(1, VM_getresolution);
3422
3423         nr = PRVM_G_FLOAT(OFS_PARM0);
3424
3425
3426         PRVM_G_VECTOR(OFS_RETURN)[0] = video_resolutions[nr][0];
3427         PRVM_G_VECTOR(OFS_RETURN)[1] = video_resolutions[nr][1];
3428         PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
3429 }
3430
3431 /*
3432 =========
3433 VM_M_keynumtostring
3434
3435 string keynumtostring(float keynum)
3436 =========
3437 */
3438 void VM_M_keynumtostring(void)
3439 {
3440         int keynum;
3441         char *tmp;
3442         VM_SAFEPARMCOUNT(1, VM_M_keynumtostring);
3443
3444         keynum = PRVM_G_FLOAT(OFS_PARM0);
3445
3446         tmp = VM_GetTempString();
3447
3448         strcpy(tmp, Key_KeynumToString(keynum));
3449
3450         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
3451 }
3452
3453 /*
3454 =========
3455 VM_M_stringtokeynum
3456
3457 float stringtokeynum(string key)
3458 =========
3459 */
3460 void VM_M_stringtokeynum( void )
3461 {
3462         char *str;
3463         VM_SAFEPARMCOUNT( 1, VM_M_keynumtostring );
3464
3465         str = PRVM_G_STRING( OFS_PARM0 );
3466
3467         PRVM_G_INT(OFS_RETURN) = Key_StringToKeynum( str );
3468 }
3469
3470 /*
3471 =========
3472 VM_M_findkeysforcommand
3473
3474 string  findkeysforcommand(string command)
3475
3476 the returned string is an altstring
3477 =========
3478 */
3479 #define NUMKEYS 5 // TODO: merge the constant in keys.c with this one somewhen
3480
3481 void M_FindKeysForCommand(char *command, int *keys);
3482 void VM_M_findkeysforcommand(void)
3483 {
3484         char *cmd, *ret;
3485         int keys[NUMKEYS];
3486         int i;
3487
3488         VM_SAFEPARMCOUNT(1, VM_M_findkeysforcommand);
3489
3490         cmd = PRVM_G_STRING(OFS_PARM0);
3491
3492         VM_CheckEmptyString(cmd);
3493
3494         (ret = VM_GetTempString())[0] = 0;
3495
3496         M_FindKeysForCommand(cmd, keys);
3497
3498         for(i = 0; i < NUMKEYS; i++)
3499                 ret = strcat(ret, va(" \'%i\'", keys[i]));
3500
3501         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(ret);
3502 }
3503
3504 /*
3505 =========
3506 VM_M_gethostcachestat
3507
3508 float   gethostcachestat(float type)
3509 =========
3510 */
3511 /*
3512         type:
3513 0       hostcache_viewcount
3514 1   hostcache_totalcount
3515 2       masterquerycount
3516 3       masterreplycount
3517 4       serverquerycount
3518 5       serverreplycount
3519 6       sortfield
3520 7       sortdescending
3521 */
3522 void VM_M_gethostcachestat( void )
3523 {
3524         int type;
3525         VM_SAFEPARMCOUNT ( 1, VM_M_gethostcachestat );
3526
3527         PRVM_G_FLOAT( OFS_RETURN ) = 0;
3528
3529         type = PRVM_G_FLOAT( OFS_PARM0 );
3530         switch(type)
3531         {
3532         case 0:
3533                 PRVM_G_FLOAT ( OFS_RETURN ) = hostcache_viewcount;
3534                 return;
3535         case 1:
3536                 PRVM_G_FLOAT ( OFS_RETURN ) = hostcache_cachecount;
3537         case 2:
3538                 PRVM_G_FLOAT ( OFS_RETURN ) = masterquerycount;
3539                 return;
3540         case 3:
3541                 PRVM_G_FLOAT ( OFS_RETURN ) = masterreplycount;
3542                 return;
3543         case 4:
3544                 PRVM_G_FLOAT ( OFS_RETURN ) = serverquerycount;
3545                 return;
3546         case 5:
3547                 PRVM_G_FLOAT ( OFS_RETURN ) = serverreplycount;
3548                 return;
3549         case 6:
3550                 PRVM_G_FLOAT ( OFS_RETURN ) = hostcache_sortbyfield;
3551                 return;
3552         case 7:
3553                 PRVM_G_FLOAT ( OFS_RETURN ) = hostcache_sortdescending;
3554                 return;
3555         default:
3556                 Con_Printf( "VM_M_gethostcachestat: bad type %i!\n", type );
3557         }
3558 }
3559
3560 /*
3561 ========================
3562 VM_M_resethostcachemasks
3563
3564 resethostcachemasks()
3565 ========================
3566 */
3567 void VM_M_resethostcachemasks( void )
3568 {
3569         HostCache_ResetMasks();
3570 }
3571
3572
3573 /*
3574 ========================
3575 VM_M_sethostcachemaskstring
3576
3577 sethostcachemaskstring(float mask, float fld, string str, float op)
3578 0-511           and
3579 512 - 1024      or
3580 ========================
3581 */
3582 void VM_M_sethostcachemaskstring( void )
3583 {
3584         char *str;
3585         int masknr;
3586         hostcache_mask_t *mask;
3587         int field;
3588
3589         VM_SAFEPARMCOUNT( 4, VM_M_sethostcachemaskstring );
3590         str = PRVM_G_STRING( OFS_PARM1 );
3591         if( !str )
3592                 PRVM_ERROR( "VM_M_sethostcachemaskstring: null string passed!" );
3593
3594         masknr = PRVM_G_FLOAT( OFS_PARM0 );
3595         if( masknr >= 0 && masknr <= HOSTCACHE_ANDMASKCOUNT )
3596                 mask = &hostcache_andmasks[masknr];
3597         else if( masknr >= 512 && masknr - 512 <= HOSTCACHE_ORMASKCOUNT )
3598                 mask = &hostcache_ormasks[masknr - 512 ];
3599         else {
3600                 Con_Printf( "VM_M_sethostcachemaskstring: invalid mask number %i\n", masknr );
3601                 return;
3602         }
3603
3604         field = (int) PRVM_G_FLOAT( OFS_PARM1 );
3605
3606         switch( field ) {
3607                 case HCIF_CNAME:
3608                         strncpy( mask->info.cname, PRVM_G_STRING( OFS_PARM2 ), sizeof(mask->info.cname) );
3609                         break;
3610                 case HCIF_NAME:
3611                         strncpy( mask->info.name, PRVM_G_STRING( OFS_PARM2 ), sizeof(mask->info.name)  );
3612                         break;
3613                 case HCIF_MAP:
3614                         strncpy( mask->info.map, PRVM_G_STRING( OFS_PARM2 ), sizeof(mask->info.map)  );
3615                         break;
3616                 case HCIF_MOD:
3617                         strncpy( mask->info.mod, PRVM_G_STRING( OFS_PARM2 ), sizeof(mask->info.mod)  );
3618                         break;
3619                 case HCIF_GAME:
3620                         strncpy( mask->info.game, PRVM_G_STRING( OFS_PARM2 ), sizeof(mask->info.game)  );
3621                         break;
3622                 default:
3623                         Con_Printf( "VM_M_sethostcachemaskstring: Bad field number %i passed!\n", field );
3624                         return;
3625         }
3626
3627         mask->active = true;
3628         mask->tests[field] = (int) PRVM_G_FLOAT( OFS_PARM3 );
3629 }
3630
3631 /*
3632 ========================
3633 VM_M_sethostcachemasknumber
3634
3635 sethostcachemasknumber(float mask, float fld, float num, float op)
3636
3637 0-511           and
3638 512 - 1024      or
3639 ========================
3640 */
3641 void VM_M_sethostcachemasknumber( void )
3642 {
3643         int number;
3644         hostcache_mask_t *mask;
3645         int     masknr;
3646         int field;
3647         VM_SAFEPARMCOUNT( 4, VM_M_sethostcachemasknumber );
3648
3649         masknr = PRVM_G_FLOAT( OFS_PARM0 );
3650         if( masknr >= 0 && masknr <= HOSTCACHE_ANDMASKCOUNT )
3651                 mask = &hostcache_andmasks[masknr];
3652         else if( masknr >= 512 && masknr - 512 <= HOSTCACHE_ORMASKCOUNT )
3653                 mask = &hostcache_ormasks[masknr - 512 ];
3654         else {
3655                 Con_Printf( "VM_M_sethostcachemasknumber: invalid mask number %i\n", masknr );
3656                 return;
3657         }
3658
3659         number = PRVM_G_FLOAT( OFS_PARM2 );
3660         field = (int) PRVM_G_FLOAT( OFS_PARM1 );
3661
3662         switch( field ) {
3663                 case HCIF_MAXPLAYERS:
3664                         mask->info.maxplayers = number;
3665                         break;
3666                 case HCIF_NUMPLAYERS:
3667                         mask->info.numplayers = number;
3668                         break;
3669                 case HCIF_PING:
3670                         mask->info.ping = number;
3671                         break;
3672                 case HCIF_PROTOCOL:
3673                         mask->info.protocol = number;
3674                         break;
3675                 default:
3676                         Con_Printf( "VM_M_sethostcachemasknumber: Bad field number %i passed!\n", field );
3677                         return;
3678         }
3679
3680         mask->active = true;
3681         mask->tests[field] = (int) PRVM_G_FLOAT( OFS_PARM3 );
3682 }
3683
3684
3685 /*
3686 ========================
3687 VM_M_resorthostcache
3688
3689 resorthostcache
3690 ========================
3691 */
3692 void VM_M_resorthostcache( void )
3693 {
3694         HostCache_RebuildViewSet();
3695 }
3696
3697 /*
3698 =========
3699 VM_M_gethostcachestring
3700
3701 string  gethostcachestring(float field, float hostnr)
3702 =========
3703 */
3704 void VM_M_gethostcachestring(void)
3705 {
3706         hostcache_t *cache;
3707         int hostnr;
3708
3709         VM_SAFEPARMCOUNT(2, VM_M_gethostcachestring);
3710
3711         PRVM_G_INT(OFS_RETURN) = 0;
3712
3713         hostnr = PRVM_G_FLOAT(OFS_PARM1);
3714
3715         if(hostnr < 0 || hostnr >= hostcache_viewcount)
3716         {
3717                 Con_Print("VM_M_gethostcachestring: bad hostnr passed!\n");
3718                 return;
3719         }
3720         cache = hostcache_viewset[hostnr];
3721         switch( (int) PRVM_G_FLOAT(OFS_PARM0) ) {
3722                 case HCIF_CNAME:
3723                         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->info.cname );
3724                         break;
3725                 case HCIF_NAME:
3726                         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->info.name );
3727                         break;
3728                 case HCIF_GAME:
3729                         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->info.game );
3730                         break;
3731                 case HCIF_MOD:
3732                         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->info.mod );
3733                         break;
3734                 case HCIF_MAP:
3735                         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->info.map );
3736                         break;
3737                 // TODO remove this again
3738                 case 1024:
3739                         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->line1 );
3740                         break;
3741                 case 1025:
3742                         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->line2 );
3743                         break;
3744                 default:
3745                         Con_Print("VM_M_gethostcachestring: bad field number passed!\n");
3746         }
3747 }
3748
3749 /*
3750 =========
3751 VM_M_gethostcachenumber
3752
3753 float   gethostcachenumber(float field, float hostnr)
3754 =========
3755 */
3756 void VM_M_gethostcachenumber(void)
3757 {
3758         hostcache_t *cache;
3759         int hostnr;
3760
3761         VM_SAFEPARMCOUNT(2, VM_M_gethostcachestring);
3762
3763         PRVM_G_INT(OFS_RETURN) = 0;
3764
3765         hostnr = PRVM_G_FLOAT(OFS_PARM1);
3766
3767         if(hostnr < 0 || hostnr >= hostcache_viewcount)
3768         {
3769                 Con_Print("VM_M_gethostcachestring: bad hostnr passed!\n");
3770                 return;
3771         }
3772         cache = hostcache_viewset[hostnr];
3773         switch( (int) PRVM_G_FLOAT(OFS_PARM0) ) {
3774                 case HCIF_MAXPLAYERS:
3775                         PRVM_G_FLOAT( OFS_RETURN ) = cache->info.maxplayers;
3776                         break;
3777                 case HCIF_NUMPLAYERS:
3778                         PRVM_G_FLOAT( OFS_RETURN ) = cache->info.numplayers;
3779                         break;
3780                 case HCIF_PING:
3781                         PRVM_G_FLOAT( OFS_RETURN ) = cache->info.ping;
3782                         break;
3783                 case HCIF_PROTOCOL:
3784                         PRVM_G_FLOAT( OFS_RETURN ) = cache->info.protocol;
3785                         break;
3786                 default:
3787                         Con_Print("VM_M_gethostcachenumber: bad field number passed!\n");
3788         }
3789 }
3790
3791 /*
3792 ========================
3793 VM_M_sethostcachesort
3794
3795 sethostcachesort(float field, float descending)
3796 ========================
3797 */
3798 void VM_M_sethostcachesort( void )
3799 {
3800         VM_SAFEPARMCOUNT( 2, VM_M_sethostcachesort );
3801
3802         hostcache_sortbyfield = (int) PRVM_G_FLOAT( OFS_PARM0 );
3803         hostcache_sortdescending = (qboolean) PRVM_G_FLOAT( OFS_PARM1 );
3804 }
3805
3806 /*
3807 ========================
3808 VM_M_refreshhostcache
3809
3810 refreshhostcache()
3811 ========================
3812 */
3813 void VM_M_refreshhostcache( void )
3814 {
3815         VM_SAFEPARMCOUNT( 0, VM_M_refreshhostcache );
3816         HostCache_QueryList();
3817 }
3818
3819 /*
3820 ========================
3821 VM_M_gethostcacheindexforkey
3822
3823 float gethostcacheindexforkey(string key)
3824 ========================
3825 */
3826 void VM_M_gethostcacheindexforkey( void )
3827 {
3828         char *key;
3829         VM_SAFEPARMCOUNT( 1, VM_M_gethostcacheindexforkey );
3830
3831         key = PRVM_G_STRING( OFS_PARM0 );
3832         VM_CheckEmptyString( key );
3833
3834         if( !strcmp( key, "cname" ) )
3835                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_CNAME;
3836         else if( !strcmp( key, "ping" ) )
3837                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_PING;
3838         else if( !strcmp( key, "game" ) )
3839                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_GAME;
3840         else if( !strcmp( key, "mod" ) )
3841                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_MOD;
3842         else if( !strcmp( key, "map" ) )
3843                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_MAP;
3844         else if( !strcmp( key, "name" ) )
3845                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_NAME;
3846         else if( !strcmp( key, "maxplayers" ) )
3847                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_MAXPLAYERS;
3848         else if( !strcmp( key, "numplayers" ) )
3849                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_NUMPLAYERS;
3850         else if( !strcmp( key, "protocol" ) )
3851                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_PROTOCOL;
3852         else
3853                 PRVM_G_FLOAT( OFS_RETURN ) = -1;
3854 }
3855
3856 /*
3857 ========================
3858 VM_M_addwantedhostcachekey
3859
3860 addwantedhostcachekey(string key)
3861 ========================
3862 */
3863 void VM_M_addwantedhostcachekey( void )
3864 {
3865         VM_SAFEPARMCOUNT( 1, VM_M_addwantedhostcachekey );
3866 }
3867
3868 prvm_builtin_t vm_m_builtins[] = {
3869         0, // to be consistent with the old vm
3870         // common builtings (mostly)
3871         VM_checkextension,
3872         VM_error,
3873         VM_objerror,
3874         VM_print,
3875         VM_bprint,
3876         VM_sprint,
3877         VM_centerprint,
3878         VM_normalize,
3879         VM_vlen,
3880         VM_vectoyaw,    // #10
3881         VM_vectoangles,
3882         VM_random,
3883         VM_localcmd,
3884         VM_cvar,
3885         VM_cvar_set,
3886         VM_dprint,
3887         VM_ftos,
3888         VM_fabs,
3889         VM_vtos,
3890         VM_etos,                // 20
3891         VM_stof,
3892         VM_spawn,
3893         VM_remove,
3894         VM_find,
3895         VM_findfloat,
3896         VM_findchain,
3897         VM_findchainfloat,
3898         VM_precache_file,
3899         VM_precache_sound,
3900         VM_coredump,    // 30
3901         VM_traceon,
3902         VM_traceoff,
3903         VM_eprint,
3904         VM_rint,
3905         VM_floor,
3906         VM_ceil,
3907         VM_nextent,
3908         VM_sin,
3909         VM_cos,
3910         VM_sqrt,                // 40
3911         VM_randomvec,