-Added 2 builtins to make the hostcache stuff easier extensible.
[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);
1779         if (VM_FILES[filenum] == NULL && mode == 0)
1780                 VM_FILES[filenum] = FS_Open(va("%s", filename), modestring, 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                 c = FS_Getc(VM_FILES[filenum]);
1857         if (developer.integer >= 3)
1858                 Con_Printf("fgets: %s: %s\n", PRVM_NAME, string);
1859         if (c >= 0 || end)
1860                 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1861         else
1862                 PRVM_G_INT(OFS_RETURN) = 0;
1863 }
1864
1865 /*
1866 =========
1867 VM_fputs
1868
1869 fputs(float fhandle, string s)
1870 =========
1871 */
1872 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
1873 void VM_fputs(void)
1874 {
1875         int stringlength;
1876         char string[VM_STRINGTEMP_LENGTH];
1877         int filenum;
1878
1879         VM_SAFEPARMCOUNT(2,VM_fputs);
1880
1881         filenum = PRVM_G_FLOAT(OFS_PARM0);
1882         if (filenum < 0 || filenum >= MAX_VMFILES)
1883         {
1884                 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1885                 return;
1886         }
1887         if (VM_FILES[filenum] == NULL)
1888         {
1889                 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1890                 return;
1891         }
1892         VM_VarString(1, string, sizeof(string));
1893         if ((stringlength = strlen(string)))
1894                 FS_Write(VM_FILES[filenum], string, stringlength);
1895         if (developer.integer)
1896                 Con_Printf("fputs: %s: %s\n", PRVM_NAME, string);
1897 }
1898
1899 /*
1900 =========
1901 VM_strlen
1902
1903 float   strlen(string s)
1904 =========
1905 */
1906 //float(string s) strlen = #114; // returns how many characters are in a string
1907 void VM_strlen(void)
1908 {
1909         char *s;
1910
1911         VM_SAFEPARMCOUNT(1,VM_strlen);
1912
1913         s = PRVM_G_STRING(OFS_PARM0);
1914         if (s)
1915                 PRVM_G_FLOAT(OFS_RETURN) = strlen(s);
1916         else
1917                 PRVM_G_FLOAT(OFS_RETURN) = 0;
1918 }
1919
1920 /*
1921 =========
1922 VM_strcat
1923
1924 string strcat(string,string,...[string])
1925 =========
1926 */
1927 //string(string s1, string s2) strcat = #115;
1928 // concatenates two strings (for example "abc", "def" would return "abcdef")
1929 // and returns as a tempstring
1930 void VM_strcat(void)
1931 {
1932         char *s;
1933
1934         if(prog->argc < 1) 
1935                 PRVM_ERROR("VM_strcat wrong parameter count (min. 1 expected ) !\n");
1936         
1937         s = VM_GetTempString();
1938         VM_VarString(0, s, VM_STRINGTEMP_LENGTH);
1939         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
1940 }
1941
1942 /*
1943 =========
1944 VM_substring
1945
1946 string  substring(string s, float start, float length)
1947 =========
1948 */
1949 // string(string s, float start, float length) substring = #116;
1950 // returns a section of a string as a tempstring
1951 void VM_substring(void)
1952 {
1953         int i, start, length;
1954         char *s, *string;
1955
1956         VM_SAFEPARMCOUNT(3,VM_substring);
1957
1958         string = VM_GetTempString();
1959         s = PRVM_G_STRING(OFS_PARM0);
1960         start = PRVM_G_FLOAT(OFS_PARM1);
1961         length = PRVM_G_FLOAT(OFS_PARM2);
1962         if (!s)
1963                 s = "";
1964         for (i = 0;i < start && *s;i++, s++);
1965         for (i = 0;i < VM_STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
1966                 string[i] = *s;
1967         string[i] = 0;
1968         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1969 }
1970
1971 /*
1972 =========
1973 VM_stov
1974
1975 vector  stov(string s)
1976 =========
1977 */
1978 //vector(string s) stov = #117; // returns vector value from a string
1979 void VM_stov(void)
1980 {
1981         char string[VM_STRINGTEMP_LENGTH];
1982
1983         VM_SAFEPARMCOUNT(1,VM_stov);
1984
1985         VM_VarString(0, string, sizeof(string));
1986         Math_atov(string, PRVM_G_VECTOR(OFS_RETURN));
1987 }
1988
1989 /*
1990 =========
1991 VM_strzone
1992
1993 string  strzone(string s)
1994 =========
1995 */
1996 //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)
1997 void VM_strzone(void)
1998 {
1999         char *in, *out;
2000
2001         VM_SAFEPARMCOUNT(1,VM_strzone);
2002
2003         in = PRVM_G_STRING(OFS_PARM0);
2004         out = Mem_Alloc(VM_STRINGS_MEMPOOL, strlen(in) + 1);
2005         strcpy(out, in);
2006         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(out);
2007 }
2008
2009 /*
2010 =========
2011 VM_strunzone
2012
2013 strunzone(string s)
2014 =========
2015 */
2016 //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!!!)
2017 void VM_strunzone(void)
2018 {
2019         char *str;
2020         VM_SAFEPARMCOUNT(1,VM_strunzone);
2021
2022         str = PRVM_G_STRING(OFS_PARM0);
2023         if( developer.integer && !Mem_IsAllocated( VM_STRINGS_MEMPOOL, str ) )
2024                 PRVM_ERROR( "VM_strunzone: Zone string already freed in %s!", PRVM_NAME );
2025         else
2026                 Mem_Free( str );
2027 }
2028
2029 /*
2030 =========
2031 VM_command (used by client and menu)
2032
2033 clientcommand(float client, string s) (for client and menu)
2034 =========
2035 */
2036 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2037 //this function originally written by KrimZon, made shorter by LordHavoc
2038 void VM_clcommand (void)
2039 {
2040         client_t *temp_client;
2041         int i;
2042
2043         VM_SAFEPARMCOUNT(2,VM_clcommand);
2044
2045         i = PRVM_G_FLOAT(OFS_PARM0);
2046         if (!sv.active  || i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2047         {
2048                 Con_Printf("VM_clientcommand: %s: invalid client/server is not active !\n", PRVM_NAME);
2049                 return;
2050         }
2051
2052         temp_client = host_client;
2053         host_client = svs.clients + i;
2054         Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2055         host_client = temp_client;
2056 }
2057
2058
2059 /*
2060 =========
2061 VM_tokenize
2062
2063 float tokenize(string s)
2064 =========
2065 */
2066 //float(string s) tokenize = #441;
2067 // takes apart a string into individal words (access them with argv), returns how many
2068 // this function originally written by KrimZon, made shorter by LordHavoc
2069 static char **tokens = NULL;
2070 static int    max_tokens, num_tokens = 0;
2071 void VM_tokenize (void)
2072 {
2073         const char *p;
2074         char *str;
2075
2076         VM_SAFEPARMCOUNT(1,VM_tokenize);
2077
2078         str = PRVM_G_STRING(OFS_PARM0);
2079
2080         if (tokens != NULL)
2081         {
2082                 int i;
2083                 for (i=0;i<num_tokens;i++)
2084                         Z_Free(tokens[i]);
2085                 Z_Free(tokens);
2086                 num_tokens = 0;
2087         }
2088
2089         tokens = Z_Malloc(strlen(str) * sizeof(char *));
2090         max_tokens = strlen(str);
2091
2092         for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2093         {
2094                 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2095                 strcpy(tokens[num_tokens], com_token);
2096         }
2097
2098         PRVM_G_FLOAT(OFS_RETURN) = num_tokens;
2099 }
2100
2101 /*
2102 =========
2103 VM_argv
2104
2105 string argv(float n)
2106 =========
2107 */
2108 //string(float n) argv = #442;
2109 // returns a word from the tokenized string (returns nothing for an invalid index)
2110 // this function originally written by KrimZon, made shorter by LordHavoc
2111 void VM_argv (void)
2112 {
2113         int token_num;
2114
2115         VM_SAFEPARMCOUNT(1,VM_argv);
2116
2117         token_num = PRVM_G_FLOAT(OFS_PARM0);
2118         if (token_num >= 0 && token_num < num_tokens)
2119                 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tokens[token_num]);
2120         else
2121                 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
2122 }
2123
2124 /*
2125 //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)
2126 void PF_setattachment (void)
2127 {
2128         edict_t *e = G_EDICT(OFS_PARM0);
2129         edict_t *tagentity = G_EDICT(OFS_PARM1);
2130         char *tagname = G_STRING(OFS_PARM2);
2131         eval_t *v;
2132         int i, modelindex;
2133         model_t *model;
2134
2135         if (tagentity == NULL)
2136                 tagentity = sv.edicts;
2137
2138         v = GETEDICTFIELDVALUE(e, eval_tag_entity);
2139         if (v)
2140                 v->edict = EDICT_TO_PROG(tagentity);
2141
2142         v = GETEDICTFIELDVALUE(e, eval_tag_index);
2143         if (v)
2144                 v->_float = 0;
2145         if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
2146         {
2147                 modelindex = (int)tagentity->v->modelindex;
2148                 if (modelindex >= 0 && modelindex < MAX_MODELS)
2149                 {
2150                         model = sv.models[modelindex];
2151                         if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
2152                                 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
2153                                         if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
2154                                                 v->_float = i + 1;
2155                         // FIXME: use a model function to get tag info (need to handle skeletal)
2156                         if (v->_float == 0 && model->alias.aliasnum_tags)
2157                                 for (i = 0;i < model->alias.aliasnum_tags;i++)
2158                                         if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
2159                                                 v->_float = i + 1;
2160                         if (v->_float == 0)
2161                                 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);
2162                 }
2163                 else
2164                         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));
2165         }
2166 }*/
2167
2168 /*
2169 =========
2170 VM_isserver
2171
2172 float   isserver()
2173 =========
2174 */
2175 void VM_isserver(void)
2176 {
2177         VM_SAFEPARMCOUNT(0,VM_serverstate);
2178
2179         PRVM_G_FLOAT(OFS_RETURN) = sv.active;
2180 }
2181
2182 /*
2183 =========
2184 VM_clientcount
2185
2186 float   clientcount()
2187 =========
2188 */
2189 void VM_clientcount(void)
2190 {
2191         VM_SAFEPARMCOUNT(0,VM_clientcount);
2192
2193         PRVM_G_FLOAT(OFS_RETURN) = svs.maxclients;
2194 }
2195
2196 /*
2197 =========
2198 VM_clientstate
2199
2200 float   clientstate()
2201 =========
2202 */
2203 void VM_clientstate(void)
2204 {
2205         VM_SAFEPARMCOUNT(0,VM_clientstate);
2206
2207         PRVM_G_FLOAT(OFS_RETURN) = cls.state;
2208 }
2209
2210 /*
2211 =========
2212 VM_getostype
2213
2214 float   getostype(void)
2215 =========
2216 */ // not used at the moment -> not included in the common list
2217 void VM_getostype(void)
2218 {
2219         VM_SAFEPARMCOUNT(0,VM_getostype);
2220
2221         /*
2222         OS_WINDOWS
2223         OS_LINUX
2224         OS_MAC - not supported
2225         */
2226
2227 #ifdef _WIN32
2228         PRVM_G_FLOAT(OFS_RETURN) = 0;
2229 #elif defined _MAC
2230         PRVM_G_FLOAT(OFS_RETURN) = 2;
2231 #else
2232         PRVM_G_FLOAT(OFS_RETURN) = 1;
2233 #endif
2234 }
2235
2236 /*
2237 =========
2238 VM_getmousepos
2239
2240 vector  getmousepos()
2241 =========
2242 */
2243 void VM_getmousepos(void)
2244 {
2245
2246         VM_SAFEPARMCOUNT(0,VM_getmousepos);
2247         
2248         PRVM_G_VECTOR(OFS_RETURN)[0] = in_mouse_x;
2249         PRVM_G_VECTOR(OFS_RETURN)[1] = in_mouse_y;
2250         PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2251 }
2252
2253 /*
2254 =========
2255 VM_gettime
2256
2257 float   gettime(void)
2258 =========
2259 */
2260 void VM_gettime(void)
2261 {
2262         VM_SAFEPARMCOUNT(0,VM_gettime);
2263
2264         PRVM_G_FLOAT(OFS_RETURN) = (float) *prog->time;
2265 }
2266
2267 /*
2268 =========
2269 VM_loadfromdata
2270
2271 loadfromdata(string data)
2272 =========
2273 */
2274 void VM_loadfromdata(void)
2275 {
2276         VM_SAFEPARMCOUNT(1,VM_loadentsfromfile);
2277
2278         PRVM_ED_LoadFromFile(PRVM_G_STRING(OFS_PARM0));
2279 }
2280
2281 /*
2282 ========================
2283 VM_M_parseentitydata
2284
2285 parseentitydata(entity ent, string data)
2286 ========================
2287 */
2288 void VM_M_parseentitydata(void)
2289 {
2290         prvm_edict_t *ent;
2291         const char *data;
2292
2293         VM_SAFEPARMCOUNT(2, VM_parseentitydata);
2294     
2295     // get edict and test it
2296         ent = PRVM_G_EDICT(OFS_PARM0);
2297         if (ent->p.e->free)
2298                 PRVM_ERROR ("VM_parseentitydata: %s: Can only set already spawned entities (entity %i is free)!\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ent));
2299
2300         data = PRVM_G_STRING(OFS_PARM1);
2301
2302     // parse the opening brace
2303         if (!COM_ParseToken(&data, false) || com_token[0] != '{' )
2304                 PRVM_ERROR ("VM_parseentitydata: %s: Couldn't parse entity data:\n%s\n", PRVM_NAME, data );
2305
2306         PRVM_ED_ParseEdict (data, ent);
2307 }
2308
2309 /*
2310 =========
2311 VM_loadfromfile
2312
2313 loadfromfile(string file)
2314 =========
2315 */
2316 void VM_loadfromfile(void)
2317 {
2318         char *filename;
2319         qbyte *data;
2320         
2321         VM_SAFEPARMCOUNT(1,VM_loadfromfile);
2322         
2323         filename = PRVM_G_STRING(OFS_PARM0);
2324         // .. is parent directory on many platforms
2325         // / is parent directory on Amiga
2326         // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2327         // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2328         if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2329         {
2330                 Con_Printf("VM_loadfromfile: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
2331                 PRVM_G_FLOAT(OFS_RETURN) = -4;
2332                 return;
2333         }
2334
2335         // not conform with VM_fopen
2336         data = FS_LoadFile(filename, tempmempool, false);
2337         if (data == NULL)
2338                 PRVM_G_FLOAT(OFS_RETURN) = -1;
2339         
2340         PRVM_ED_LoadFromFile(data);
2341
2342         if(data)
2343                 Mem_Free(data);
2344 }
2345
2346
2347 /*
2348 =========
2349 VM_modulo
2350
2351 float   mod(float val, float m)
2352 =========
2353 */
2354 void VM_modulo(void)
2355 {
2356         int val, m;
2357         VM_SAFEPARMCOUNT(2,VM_module);
2358
2359         val = (int) PRVM_G_FLOAT(OFS_PARM0);
2360         m       = (int) PRVM_G_FLOAT(OFS_PARM1);
2361
2362         PRVM_G_FLOAT(OFS_RETURN) = (float) (val % m);
2363 }
2364
2365 void VM_Search_Init(void)
2366 {
2367         memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
2368 }
2369
2370 void VM_Search_Reset(void)
2371 {
2372         int i;
2373         // reset the fssearch list
2374         for(i = 0; i < MAX_VMSEARCHES; i++)
2375                 if(VM_SEARCHLIST[i])
2376                         FS_FreeSearch(VM_SEARCHLIST[i]);
2377         memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
2378 }
2379
2380 /*
2381 =========
2382 VM_search_begin
2383
2384 float search_begin(string pattern, float caseinsensitive, float quiet)
2385 =========
2386 */
2387 void VM_search_begin(void)
2388 {
2389         int handle;
2390         char *pattern;
2391         int caseinsens, quiet;
2392
2393         VM_SAFEPARMCOUNT(3, VM_search_begin);
2394
2395         pattern = PRVM_G_STRING(OFS_PARM0);
2396
2397         VM_CheckEmptyString(pattern);
2398
2399         caseinsens = PRVM_G_FLOAT(OFS_PARM1);
2400         quiet = PRVM_G_FLOAT(OFS_PARM2);
2401         
2402         for(handle = 0; handle < MAX_VMSEARCHES; handle++)
2403                 if(!VM_SEARCHLIST[handle])
2404                         break;
2405
2406         if(handle >= MAX_VMSEARCHES)
2407         {
2408                 Con_Printf("VM_search_begin: %s ran out of search handles (%i)\n", PRVM_NAME, MAX_VMSEARCHES);
2409                 PRVM_G_FLOAT(OFS_RETURN) = -2;
2410                 return;
2411         }
2412
2413         if(!(VM_SEARCHLIST[handle] = FS_Search(pattern,caseinsens, quiet)))
2414                 PRVM_G_FLOAT(OFS_RETURN) = -1;
2415         else
2416                 PRVM_G_FLOAT(OFS_RETURN) = handle;
2417 }
2418
2419 /*
2420 =========
2421 VM_search_end
2422
2423 void    search_end(float handle)
2424 =========
2425 */
2426 void VM_search_end(void)
2427 {
2428         int handle;
2429         VM_SAFEPARMCOUNT(1, VM_search_end);
2430
2431         handle = PRVM_G_FLOAT(OFS_PARM0);
2432         
2433         if(handle < 0 || handle >= MAX_VMSEARCHES)
2434         {
2435                 Con_Printf("VM_search_end: invalid handle %i used in %s\n", handle, PRVM_NAME);
2436                 return;
2437         }
2438         if(VM_SEARCHLIST[handle] == NULL)
2439         {
2440                 Con_Printf("VM_search_end: no such handle %i in %s\n", handle, PRVM_NAME);
2441                 return;
2442         }
2443
2444         FS_FreeSearch(VM_SEARCHLIST[handle]);
2445         VM_SEARCHLIST[handle] = NULL;
2446 }
2447
2448 /*
2449 =========
2450 VM_search_getsize
2451
2452 float   search_getsize(float handle)
2453 =========
2454 */
2455 void VM_search_getsize(void)
2456 {
2457         int handle;
2458         VM_SAFEPARMCOUNT(1, VM_M_search_getsize);
2459
2460         handle = PRVM_G_FLOAT(OFS_PARM0);
2461
2462         if(handle < 0 || handle >= MAX_VMSEARCHES)
2463         {
2464                 Con_Printf("VM_search_getsize: invalid handle %i used in %s\n", handle, PRVM_NAME);
2465                 return;
2466         }
2467         if(VM_SEARCHLIST[handle] == NULL)
2468         {
2469                 Con_Printf("VM_search_getsize: no such handle %i in %s\n", handle, PRVM_NAME);
2470                 return;
2471         }
2472         
2473         PRVM_G_FLOAT(OFS_RETURN) = VM_SEARCHLIST[handle]->numfilenames;
2474 }
2475
2476 /*
2477 =========
2478 VM_search_getfilename
2479
2480 string  search_getfilename(float handle, float num)
2481 =========
2482 */
2483 void VM_search_getfilename(void)
2484 {
2485         int handle, filenum;
2486         char *tmp;
2487         VM_SAFEPARMCOUNT(2, VM_search_getfilename);
2488
2489         handle = PRVM_G_FLOAT(OFS_PARM0);
2490         filenum = PRVM_G_FLOAT(OFS_PARM1);
2491
2492         if(handle < 0 || handle >= MAX_VMSEARCHES)
2493         {
2494                 Con_Printf("VM_search_getfilename: invalid handle %i used in %s\n", handle, PRVM_NAME);
2495                 return;
2496         }
2497         if(VM_SEARCHLIST[handle] == NULL)
2498         {
2499                 Con_Printf("VM_search_getfilename: no such handle %i in %s\n", handle, PRVM_NAME);
2500                 return;
2501         }
2502         if(filenum < 0 || filenum >= VM_SEARCHLIST[handle]->numfilenames)
2503         {
2504                 Con_Printf("VM_search_getfilename: invalid filenum %i in %s\n", filenum, PRVM_NAME);
2505                 return;
2506         }
2507         
2508         tmp = VM_GetTempString();
2509         strcpy(tmp, VM_SEARCHLIST[handle]->filenames[filenum]);
2510
2511         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
2512 }
2513
2514 /*
2515 =========
2516 VM_chr
2517
2518 string  chr(float ascii)
2519 =========
2520 */
2521 void VM_chr(void)
2522 {
2523         char *tmp;
2524         VM_SAFEPARMCOUNT(1, VM_chr);
2525
2526         tmp = VM_GetTempString();
2527         tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0);
2528         tmp[1] = 0;
2529
2530         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
2531 }
2532
2533 //=============================================================================
2534 // Draw builtins (client & menu)
2535
2536 /*
2537 =========
2538 VM_iscachedpic
2539
2540 float   iscachedpic(string pic)
2541 =========
2542 */
2543 void VM_iscachedpic(void)
2544 {
2545         VM_SAFEPARMCOUNT(1,VM_iscachedpic);
2546
2547         // drawq hasnt such a function, thus always return true 
2548         PRVM_G_FLOAT(OFS_RETURN) = false;
2549 }
2550
2551 /*
2552 =========
2553 VM_precache_pic
2554
2555 string  precache_pic(string pic) 
2556 =========
2557 */
2558 void VM_precache_pic(void)
2559 {
2560         char    *s;
2561         
2562         VM_SAFEPARMCOUNT(1, VM_precache_pic);
2563         
2564         s = PRVM_G_STRING(OFS_PARM0);
2565         PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
2566         
2567         if(!s)
2568                 PRVM_ERROR ("VM_precache_pic: %s: NULL\n", PRVM_NAME);
2569
2570         VM_CheckEmptyString (s);
2571         
2572         if(!Draw_CachePic(s))
2573                 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(""); 
2574 }
2575
2576 /*
2577 =========
2578 VM_freepic
2579
2580 freepic(string s)
2581 =========
2582 */
2583 void VM_freepic(void)
2584 {
2585         char *s;
2586
2587         VM_SAFEPARMCOUNT(1,VM_freepic);
2588
2589         s = PRVM_G_STRING(OFS_PARM0);
2590         
2591         if(!s)
2592                 PRVM_ERROR ("VM_freepic: %s: NULL\n");
2593         
2594         VM_CheckEmptyString (s);
2595         
2596         Draw_FreePic(s);
2597 }
2598
2599 /*
2600 =========
2601 VM_drawcharacter
2602
2603 float   drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
2604 =========
2605 */
2606 void VM_drawcharacter(void)
2607 {
2608         float *pos,*scale,*rgb;
2609         char   character;
2610         int flag;
2611         VM_SAFEPARMCOUNT(6,VM_drawcharacter);
2612
2613         character = (char) PRVM_G_FLOAT(OFS_PARM1);
2614         if(character == 0)
2615         {
2616                 Con_Printf("VM_drawcharacter: %s passed null character !\n",PRVM_NAME);
2617                 PRVM_G_FLOAT(OFS_RETURN) = -1;
2618                 return;
2619         }
2620         
2621         pos = PRVM_G_VECTOR(OFS_PARM0);
2622         scale = PRVM_G_VECTOR(OFS_PARM2);
2623         rgb = PRVM_G_VECTOR(OFS_PARM3);
2624         flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2625         
2626         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2627         {
2628                 Con_Printf("VM_drawcharacter: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2629                 PRVM_G_FLOAT(OFS_RETURN) = -2;
2630                 return;
2631         }
2632         
2633         if(pos[2] || scale[2])
2634                 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"))); 
2635
2636         if(!scale[0] || !scale[1])
2637         {
2638                 Con_Printf("VM_drawcharacter: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2639                 PRVM_G_FLOAT(OFS_RETURN) = -3;
2640                 return;
2641         }
2642
2643         DrawQ_String (pos[0], pos[1], &character, 1, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2644         PRVM_G_FLOAT(OFS_RETURN) = 1;
2645 }       
2646
2647 /*
2648 =========
2649 VM_drawstring
2650
2651 float   drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
2652 =========
2653 */
2654 void VM_drawstring(void)
2655 {
2656         float *pos,*scale,*rgb;
2657         char  *string;
2658         int flag;
2659         VM_SAFEPARMCOUNT(6,VM_drawstring);
2660         
2661         string = PRVM_G_STRING(OFS_PARM1);
2662         if(!string)
2663         {
2664                 Con_Printf("VM_drawstring: %s passed null string !\n",PRVM_NAME);
2665                 PRVM_G_FLOAT(OFS_RETURN) = -1;
2666                 return;
2667         }
2668         
2669         //VM_CheckEmptyString(string); Why should it be checked - perhaps the menu wants to support the precolored letters, too?
2670         
2671         pos = PRVM_G_VECTOR(OFS_PARM0);
2672         scale = PRVM_G_VECTOR(OFS_PARM2);
2673         rgb = PRVM_G_VECTOR(OFS_PARM3);
2674         flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2675         
2676         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2677         {
2678                 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2679                 PRVM_G_FLOAT(OFS_RETURN) = -2;
2680                 return;
2681         }
2682         
2683         if(!scale[0] || !scale[1])
2684         {
2685                 Con_Printf("VM_drawstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2686                 PRVM_G_FLOAT(OFS_RETURN) = -3;
2687                 return;
2688         }
2689
2690         if(pos[2] || scale[2])
2691                 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"))); 
2692         
2693         DrawQ_String (pos[0], pos[1], string, 0, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2694         PRVM_G_FLOAT(OFS_RETURN) = 1;
2695 }
2696 /*
2697 =========
2698 VM_drawpic
2699
2700 float   drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
2701 =========
2702 */
2703 void VM_drawpic(void)
2704 {
2705         char *pic;
2706         float *size, *pos, *rgb;
2707         int flag;
2708
2709         VM_SAFEPARMCOUNT(6,VM_drawpic);
2710
2711         pic = PRVM_G_STRING(OFS_PARM1);
2712
2713         if(!pic)
2714         {
2715                 Con_Printf("VM_drawpic: %s passed null picture name !\n", PRVM_NAME);
2716                 PRVM_G_FLOAT(OFS_RETURN) = -1;  
2717                 return;
2718         }
2719
2720         VM_CheckEmptyString (pic);
2721
2722         // is pic cached ? no function yet for that
2723         if(!1)
2724         {
2725                 Con_Printf("VM_drawpic: %s: %s not cached !\n", PRVM_NAME, pic);
2726                 PRVM_G_FLOAT(OFS_RETURN) = -4;
2727                 return;
2728         }
2729         
2730         pos = PRVM_G_VECTOR(OFS_PARM0);
2731         size = PRVM_G_VECTOR(OFS_PARM2);
2732         rgb = PRVM_G_VECTOR(OFS_PARM3);
2733         flag = (int) PRVM_G_FLOAT(OFS_PARM5);
2734
2735         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2736         {
2737                 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2738                 PRVM_G_FLOAT(OFS_RETURN) = -2;
2739                 return;
2740         }
2741
2742         if(pos[2] || size[2])
2743                 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"))); 
2744         
2745         DrawQ_Pic(pos[0], pos[1], pic, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2746         PRVM_G_FLOAT(OFS_RETURN) = 1;
2747 }
2748
2749 /*
2750 =========
2751 VM_drawfill
2752
2753 float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
2754 =========
2755 */
2756 void VM_drawfill(void)
2757 {
2758         float *size, *pos, *rgb;
2759         int flag;
2760         
2761         VM_SAFEPARMCOUNT(5,VM_drawfill);
2762         
2763         
2764         pos = PRVM_G_VECTOR(OFS_PARM0);
2765         size = PRVM_G_VECTOR(OFS_PARM1);
2766         rgb = PRVM_G_VECTOR(OFS_PARM2);
2767         flag = (int) PRVM_G_FLOAT(OFS_PARM4);
2768         
2769         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2770         {
2771                 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2772                 PRVM_G_FLOAT(OFS_RETURN) = -2;
2773                 return;
2774         }
2775         
2776         if(pos[2] || size[2])
2777                 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"))); 
2778         
2779         DrawQ_Pic(pos[0], pos[1], 0, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM3), flag);
2780         PRVM_G_FLOAT(OFS_RETURN) = 1;
2781 }
2782
2783 /*
2784 =========
2785 VM_drawsetcliparea
2786
2787 drawsetcliparea(float x, float y, float width, float height)
2788 =========
2789 */
2790 void VM_drawsetcliparea(void)
2791 {
2792         float x,y,w,h;
2793         VM_SAFEPARMCOUNT(4,VM_drawsetcliparea);
2794
2795         x = bound(0, PRVM_G_FLOAT(OFS_PARM0), vid.conwidth);
2796         y = bound(0, PRVM_G_FLOAT(OFS_PARM1), vid.conheight);
2797         w = bound(0, PRVM_G_FLOAT(OFS_PARM2) + PRVM_G_FLOAT(OFS_PARM0) - x, (vid.conwidth  - x));
2798         h = bound(0, PRVM_G_FLOAT(OFS_PARM3) + PRVM_G_FLOAT(OFS_PARM1) - y, (vid.conheight - y)); 
2799
2800         DrawQ_SetClipArea(x, y, w, h);
2801 }
2802
2803 /*
2804 =========
2805 VM_drawresetcliparea
2806
2807 drawresetcliparea()
2808 =========
2809 */
2810 void VM_drawresetcliparea(void)
2811 {
2812         VM_SAFEPARMCOUNT(0,VM_drawresetcliparea);
2813
2814         DrawQ_ResetClipArea();
2815 }
2816
2817 /*
2818 =========
2819 VM_getimagesize
2820
2821 vector  getimagesize(string pic)
2822 =========
2823 */
2824 void VM_getimagesize(void)
2825 {
2826         char *p;
2827         cachepic_t *pic;
2828
2829         VM_SAFEPARMCOUNT(1,VM_getimagesize);
2830         
2831         p = PRVM_G_STRING(OFS_PARM0);
2832
2833         if(!p)
2834                 PRVM_ERROR("VM_getimagepos: %s passed null picture name !\n", PRVM_NAME);
2835         
2836         VM_CheckEmptyString (p);
2837
2838         pic = Draw_CachePic (p);
2839
2840         PRVM_G_VECTOR(OFS_RETURN)[0] = pic->width;
2841         PRVM_G_VECTOR(OFS_RETURN)[1] = pic->height;
2842         PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2843 }
2844
2845 // CL_Video interface functions
2846
2847 /*
2848 ========================
2849 VM_cin_open
2850
2851 float cin_open(string file, string name)
2852 ========================
2853 */
2854 void VM_cin_open( void )
2855 {
2856         char *file;
2857         char *name;
2858         
2859         VM_SAFEPARMCOUNT( 2, VM_cin_open );
2860         
2861         file = PRVM_G_STRING( OFS_PARM0 );
2862         name = PRVM_G_STRING( OFS_PARM1 );
2863
2864         VM_CheckEmptyString( file );
2865     VM_CheckEmptyString( name );
2866
2867         if( CL_OpenVideo( file, name, MENUOWNER ) )
2868                 PRVM_G_FLOAT( OFS_RETURN ) = 1;
2869         else
2870                 PRVM_G_FLOAT( OFS_RETURN ) = 0;
2871 }
2872
2873 /*
2874 ========================
2875 VM_cin_close
2876
2877 void cin_close(string name)
2878 ========================
2879 */
2880 void VM_cin_close( void )
2881 {
2882         char *name;
2883
2884         VM_SAFEPARMCOUNT( 1, VM_cin_close );
2885
2886         name = PRVM_G_STRING( OFS_PARM0 );
2887         VM_CheckEmptyString( name );
2888
2889         CL_CloseVideo( CL_GetVideo( name ) ); 
2890 }
2891
2892 /*
2893 ========================
2894 VM_cin_setstate
2895 void cin_setstate(string name, float type)
2896 ========================
2897 */
2898 void VM_cin_setstate( void )
2899 {
2900         char *name;
2901         clvideostate_t  state;
2902         clvideo_t               *video;
2903
2904         VM_SAFEPARMCOUNT( 2, VM_cin_netstate );
2905
2906         name = PRVM_G_STRING( OFS_PARM0 );
2907         VM_CheckEmptyString( name );
2908
2909         state = PRVM_G_FLOAT( OFS_PARM1 );
2910
2911         video = CL_GetVideo( name );
2912         if( video && state > CLVIDEO_UNUSED && state < CLVIDEO_STATECOUNT )
2913                 CL_SetVideoState( video, state );               
2914 }
2915
2916 /*
2917 ========================
2918 VM_cin_getstate
2919
2920 float cin_getstate(string name)
2921 ========================
2922 */
2923 void VM_cin_getstate( void )
2924 {
2925         char *name;
2926         clvideo_t               *video;
2927
2928         VM_SAFEPARMCOUNT( 1, VM_cin_getstate );
2929
2930         name = PRVM_G_STRING( OFS_PARM0 );
2931         VM_CheckEmptyString( name );
2932
2933         video = CL_GetVideo( name );
2934         if( video )
2935                 PRVM_G_FLOAT( OFS_RETURN ) = (int)video->state;
2936         else
2937                 PRVM_G_FLOAT( OFS_RETURN ) = 0;
2938 }
2939
2940 /*
2941 ========================
2942 VM_cin_restart
2943
2944 void cin_restart(string name)
2945 ========================
2946 */
2947 void VM_cin_restart( void )
2948 {
2949         char *name;
2950         clvideo_t               *video;
2951
2952         VM_SAFEPARMCOUNT( 1, VM_cin_restart );
2953
2954         name = PRVM_G_STRING( OFS_PARM0 );
2955         VM_CheckEmptyString( name );
2956
2957         video = CL_GetVideo( name );
2958         if( video )
2959                 CL_RestartVideo( video );
2960 }
2961
2962 ////////////////////////////////////////
2963 // AltString functions
2964 ////////////////////////////////////////
2965
2966 /*
2967 ========================
2968 VM_altstr_count
2969
2970 float altstr_count(string)
2971 ========================
2972 */
2973 void VM_altstr_count( void )
2974 {
2975         char *altstr, *pos;
2976         int     count;
2977
2978         VM_SAFEPARMCOUNT( 1, VM_altstr_count );
2979
2980         altstr = PRVM_G_STRING( OFS_PARM0 );
2981         //VM_CheckEmptyString( altstr );
2982
2983         for( count = 0, pos = altstr ; *pos ; pos++ )
2984                 if( *pos == '\\' && !*++pos )
2985                                 break;
2986                 else if( *pos == '\'' )
2987                         count++;
2988
2989         PRVM_G_FLOAT( OFS_RETURN ) = (float) (count / 2);
2990 }
2991
2992 /*
2993 ========================
2994 VM_altstr_prepare
2995
2996 string altstr_prepare(string)
2997 ========================
2998 */
2999 void VM_altstr_prepare( void )
3000 {
3001         char *outstr, *out;
3002         char *instr, *in;
3003         int size;
3004
3005         VM_SAFEPARMCOUNT( 1, VM_altstr_prepare );
3006
3007         instr = PRVM_G_STRING( OFS_PARM0 );
3008         //VM_CheckEmptyString( instr );
3009         outstr = VM_GetTempString();
3010
3011         for( out = outstr, in = instr, size = VM_STRINGTEMP_LENGTH - 1 ; size && *in ; size--, in++, out++ )
3012                 if( *in == '\'' ) {
3013                         *out++ = '\\';
3014                         *out = '\'';
3015                         size--;
3016                 } else
3017                         *out = *in;
3018         *out = 0;
3019
3020         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( outstr );
3021 }
3022
3023 /*
3024 ========================
3025 VM_altstr_get
3026
3027 string altstr_get(string, float)
3028 ========================
3029 */
3030 void VM_altstr_get( void )
3031 {
3032         char *altstr, *pos, *outstr, *out;
3033         int count, size;
3034
3035         VM_SAFEPARMCOUNT( 2, VM_altstr_get );
3036
3037         altstr = PRVM_G_STRING( OFS_PARM0 );
3038         //VM_CheckEmptyString( altstr );
3039
3040         count = PRVM_G_FLOAT( OFS_PARM1 );
3041         count = count * 2 + 1;
3042
3043         for( pos = altstr ; *pos && count ; pos++ )
3044                 if( *pos == '\\' && !*++pos )
3045                         break;                          
3046                 else if( *pos == '\'' )
3047                         count--;
3048
3049         if( !*pos ) {
3050                 PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( "" );
3051                 return;
3052         }
3053
3054     outstr = VM_GetTempString();
3055         for( out = outstr, size = VM_STRINGTEMP_LENGTH - 1 ; size && *pos ; size--, pos++, out++ )
3056                 if( *pos == '\\' ) {
3057                         if( !*++pos )
3058                                 break;
3059                         *out = *pos;
3060                         size--;
3061                 } else if( *pos == '\'' )
3062                         break;
3063                 else
3064                         *out = *pos;
3065
3066         *out = 0;
3067         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( outstr );
3068 }
3069
3070 /*
3071 ========================
3072 VM_altstr_set
3073
3074 string altstr_set(string altstr, float num, string set)
3075 ========================
3076 */
3077 void VM_altstr_set( void )
3078 {
3079     int num;
3080         char *altstr, *str;
3081         char *in;
3082         char *outstr, *out;
3083
3084         VM_SAFEPARMCOUNT( 3, VM_altstr_set );
3085
3086         altstr = PRVM_G_STRING( OFS_PARM0 );
3087         //VM_CheckEmptyString( altstr );
3088
3089         num = PRVM_G_FLOAT( OFS_PARM1 );
3090
3091         str = PRVM_G_STRING( OFS_PARM2 );
3092         //VM_CheckEmptyString( str );
3093
3094         outstr = out = VM_GetTempString();
3095         for( num = num * 2 + 1, in = altstr; *in && num; *out++ = *in++ )
3096                 if( *in == '\\' && !*++in )
3097                         break;
3098                 else if( *in == '\'' )
3099                         num--;
3100
3101         if( !in ) {
3102                 PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( "" );
3103                 return;
3104         }
3105         // copy set in
3106         for( ; *str; *out++ = *str++ );
3107         // now jump over the old contents
3108         for( ; *in ; in++ )
3109                 if( *in == '\'' || *in == '\\' && !*++in )
3110                         break;
3111         
3112         if( !in ) {
3113                 PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( "" );
3114                 return;
3115         }
3116
3117         strcpy( out, in );
3118         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( outstr );
3119 }
3120
3121 void VM_Cmd_Init(void)
3122 {
3123         // only init the stuff for the current prog
3124         VM_STRINGS_MEMPOOL = Mem_AllocPool(va("vm_stringsmempool[%s]",PRVM_NAME), 0, NULL);
3125         VM_Files_Init();
3126         VM_Search_Init();
3127 }
3128
3129 void VM_Cmd_Reset(void)
3130 {
3131         //Mem_EmptyPool(VM_STRINGS_MEMPOOL);
3132         if( developer.integer >= 2 && VM_STRINGS_MEMPOOL ) {
3133                 memheader_t *header;
3134                 int     i;
3135
3136                 for( i = 0, header = VM_STRINGS_MEMPOOL->chain ; header ; header = header->next, i++ )
3137                         Con_DPrintf( "Leaked string %i (size: %i): %.*s\n", i, header->size, header->size, ((char*)header) + sizeof( memheader_t ) );
3138         }
3139
3140         Mem_FreePool(&VM_STRINGS_MEMPOOL);
3141         CL_PurgeOwner( MENUOWNER );
3142         VM_Search_Reset();
3143         VM_Files_CloseAll();
3144 }
3145
3146 //============================================================================
3147 // Server
3148
3149 char *vm_sv_extensions =
3150 "";
3151
3152 prvm_builtin_t vm_sv_builtins[] = {
3153 0  // to be consistent with the old vm
3154 };
3155
3156 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
3157
3158 void VM_SV_Cmd_Init(void)
3159 {
3160 }
3161
3162 void VM_SV_Cmd_Reset(void)
3163 {
3164 }
3165
3166 //============================================================================
3167 // Client
3168
3169 char *vm_cl_extensions =
3170 "";
3171
3172 prvm_builtin_t vm_cl_builtins[] = {
3173 0  // to be consistent with the old vm
3174 };
3175
3176 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3177
3178 void VM_CL_Cmd_Init(void)
3179 {
3180 }
3181
3182 void VM_CL_Cmd_Reset(void)
3183 {
3184 }
3185
3186 //============================================================================
3187 // Menu
3188
3189 char *vm_m_extensions =
3190 "DP_CINEMATIC_DPV";
3191
3192 /*
3193 =========
3194 VM_M_setmousetarget
3195
3196 setmousetarget(float target)
3197 =========
3198 */
3199 void VM_M_setmousetarget(void)
3200 {
3201         VM_SAFEPARMCOUNT(1, VM_M_setmousetarget);
3202
3203         switch((int)PRVM_G_FLOAT(OFS_PARM0))
3204         {
3205         case 1:
3206                 in_client_mouse = false;
3207                 break;
3208         case 2:
3209                 in_client_mouse = true;
3210                 break;
3211         default:
3212                 PRVM_ERROR("VM_M_setmousetarget: wrong destination %i !\n",PRVM_G_FLOAT(OFS_PARM0));
3213         }
3214 }
3215
3216 /*
3217 =========
3218 VM_M_getmousetarget
3219
3220 float   getmousetarget
3221 =========
3222 */
3223 void VM_M_getmousetarget(void)
3224 {
3225         VM_SAFEPARMCOUNT(0,VM_M_getmousetarget);
3226
3227         if(in_client_mouse)
3228                 PRVM_G_FLOAT(OFS_RETURN) = 2;
3229         else
3230                 PRVM_G_FLOAT(OFS_RETURN) = 1;
3231 }
3232         
3233
3234
3235 /*
3236 =========
3237 VM_M_setkeydest
3238
3239 setkeydest(float dest)
3240 =========
3241 */
3242 void VM_M_setkeydest(void)
3243 {
3244         VM_SAFEPARMCOUNT(1,VM_M_setkeydest);
3245
3246         switch((int)PRVM_G_FLOAT(OFS_PARM0))
3247         {
3248         case 0:
3249                 // key_game
3250                 key_dest = key_game;
3251                 break;
3252         case 2:
3253                 // key_menu
3254                 key_dest = key_menu;
3255                 break;
3256         case 1:
3257                 // key_message
3258                 // key_dest = key_message
3259                 // break;
3260         default:
3261                 PRVM_ERROR("VM_M_setkeydest: wrong destination %i !\n",prog->globals[OFS_PARM0]);
3262         }
3263 }
3264
3265 /*
3266 =========
3267 VM_M_getkeydest
3268
3269 float   getkeydest
3270 =========
3271 */
3272 void VM_M_getkeydest(void)
3273 {
3274         VM_SAFEPARMCOUNT(0,VM_M_getkeydest);
3275
3276         // key_game = 0, key_message = 1, key_menu = 2, unknown = 3
3277         switch(key_dest)
3278         {
3279         case key_game:
3280                 PRVM_G_FLOAT(OFS_RETURN) = 0;
3281                 break;
3282         case key_menu:
3283                 PRVM_G_FLOAT(OFS_RETURN) = 2;
3284                 break;
3285         case key_message:
3286                 // not supported
3287                 // PRVM_G_FLOAT(OFS_RETURN) = 1;
3288                 // break;
3289         default:
3290                 PRVM_G_FLOAT(OFS_RETURN) = 3;
3291         }
3292 }
3293
3294 /*
3295 =========
3296 VM_M_callfunction
3297
3298         callfunction(...,string function_name)
3299 Extension: pass 
3300 =========
3301 */
3302 mfunction_t *PRVM_ED_FindFunction (const char *name);
3303 void VM_M_callfunction(void)
3304 {
3305         mfunction_t *func;
3306         char *s;
3307
3308         if(prog->argc == 0)
3309                 PRVM_ERROR("VM_M_callfunction: 1 parameter is required !\n");
3310
3311         s = PRVM_G_STRING(OFS_PARM0 + (prog->argc - 1));
3312
3313         if(!s)
3314                 PRVM_ERROR("VM_M_callfunction: null string !\n");
3315
3316         VM_CheckEmptyString(s); 
3317
3318         func = PRVM_ED_FindFunction(s);
3319
3320         if(!func)
3321                 PRVM_ERROR("VM_M_callfunciton: function %s not found !\n", s);
3322         else if (func->first_statement < 0)
3323         {
3324                 // negative statements are built in functions
3325                 int builtinnumber = -func->first_statement;
3326                 prog->xfunction->builtinsprofile++;
3327                 if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber])
3328                         prog->builtins[builtinnumber]();
3329                 else
3330                         PRVM_ERROR("No such builtin #%i in %s", builtinnumber, PRVM_NAME);
3331         }
3332         else if(func > 0)
3333         {
3334                 prog->argc--;
3335                 PRVM_ExecuteProgram(func - prog->functions,"");
3336                 prog->argc++;
3337         }
3338 }       
3339
3340 /*
3341 =========
3342 VM_M_isfunction
3343
3344 float   isfunction(string function_name)
3345 =========
3346 */
3347 mfunction_t *PRVM_ED_FindFunction (const char *name);
3348 void VM_M_isfunction(void)
3349 {
3350         mfunction_t *func;
3351         char *s;
3352         
3353         VM_SAFEPARMCOUNT(1, VM_M_isfunction);
3354         
3355         s = PRVM_G_STRING(OFS_PARM0);
3356         
3357         if(!s)
3358                 PRVM_ERROR("VM_M_isfunction: null string !\n");
3359         
3360         VM_CheckEmptyString(s); 
3361         
3362         func = PRVM_ED_FindFunction(s);
3363
3364         if(!func)
3365                 PRVM_G_FLOAT(OFS_RETURN) = false;
3366         else
3367                 PRVM_G_FLOAT(OFS_RETURN) = true;
3368 }
3369
3370 /*
3371 =========
3372 VM_M_writetofile
3373
3374         writetofile(float fhandle, entity ent)
3375 =========
3376 */
3377 void VM_M_writetofile(void)
3378 {
3379         prvm_edict_t * ent;
3380         int filenum;
3381
3382         VM_SAFEPARMCOUNT(2, VM_M_writetofile);
3383
3384         filenum = PRVM_G_FLOAT(OFS_PARM0);
3385         if (filenum < 0 || filenum >= MAX_VMFILES)
3386         {
3387                 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
3388                 return;
3389         }
3390         if (VM_FILES[filenum] == NULL)
3391         {
3392                 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
3393                 return;
3394         }
3395
3396         ent = PRVM_G_EDICT(OFS_PARM1);  
3397         if(ent->p.e->free)
3398         {
3399                 Con_Printf("VM_M_writetofile: %s: entity %i is free !\n", PRVM_NAME, PRVM_EDICT_NUM(OFS_PARM1));
3400                 return;
3401         }
3402
3403         PRVM_ED_Write (VM_FILES[filenum], ent);
3404 }
3405
3406 /*
3407 =========
3408 VM_M_getresolution
3409
3410 vector  getresolution(float number)
3411 =========
3412 */
3413 extern unsigned short video_resolutions[][2];
3414 void VM_M_getresolution(void)
3415 {
3416         int nr;
3417         VM_SAFEPARMCOUNT(1, VM_getresolution);
3418
3419         nr = PRVM_G_FLOAT(OFS_PARM0);
3420
3421
3422         PRVM_G_VECTOR(OFS_RETURN)[0] = video_resolutions[nr][0];
3423         PRVM_G_VECTOR(OFS_RETURN)[1] = video_resolutions[nr][1];
3424         PRVM_G_VECTOR(OFS_RETURN)[2] = 0;       
3425 }
3426
3427 /*
3428 =========
3429 VM_M_keynumtostring
3430
3431 string keynumtostring(float keynum)
3432 =========
3433 */
3434 void VM_M_keynumtostring(void)
3435 {
3436         int keynum;
3437         char *tmp;
3438         VM_SAFEPARMCOUNT(1, VM_M_keynumtostring);
3439
3440         keynum = PRVM_G_FLOAT(OFS_PARM0);
3441
3442         tmp = VM_GetTempString();
3443         
3444         strcpy(tmp, Key_KeynumToString(keynum));
3445
3446         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
3447 }
3448
3449 /*
3450 =========
3451 VM_M_stringtokeynum
3452
3453 float stringtokeynum(string key)
3454 =========
3455 */
3456 void VM_M_stringtokeynum( void )
3457 {
3458         char *str;
3459         VM_SAFEPARMCOUNT( 1, VM_M_keynumtostring );
3460
3461         str = PRVM_G_STRING( OFS_PARM0 );
3462
3463         PRVM_G_INT(OFS_RETURN) = Key_StringToKeynum( str );
3464 }
3465
3466 /*
3467 =========
3468 VM_M_findkeysforcommand
3469
3470 string  findkeysforcommand(string command)
3471
3472 the returned string is an altstring
3473 =========
3474 */
3475 #define NUMKEYS 5 // TODO: merge the constant in keys.c with this one somewhen
3476
3477 void M_FindKeysForCommand(char *command, int *keys);
3478 void VM_M_findkeysforcommand(void)
3479 {
3480         char *cmd, *ret;
3481         int keys[NUMKEYS];
3482         int i;
3483
3484         VM_SAFEPARMCOUNT(1, VM_M_findkeysforcommand);
3485
3486         cmd = PRVM_G_STRING(OFS_PARM0);
3487         
3488         VM_CheckEmptyString(cmd);
3489
3490         (ret = VM_GetTempString())[0] = 0;
3491         
3492         M_FindKeysForCommand(cmd, keys);
3493
3494         for(i = 0; i < NUMKEYS; i++)
3495                 ret = strcat(ret, va(" \'%i\'", keys[i]));
3496
3497         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(ret);
3498 }
3499
3500 /*
3501 =========
3502 VM_M_gethostcachestat
3503
3504 float   gethostcachestat(float type)
3505 =========
3506 */
3507 /*
3508         type:
3509 0       hostcache_viewcount
3510 1   hostcache_totalcount
3511 2       masterquerycount
3512 3       masterreplycount
3513 4       serverquerycount
3514 5       serverreplycount
3515 6       sortfield
3516 7       sortdescending
3517 */
3518 void VM_M_gethostcachestat( void )
3519 {
3520         int type;
3521         VM_SAFEPARMCOUNT ( 1, VM_M_gethostcachestat );
3522
3523         PRVM_G_FLOAT( OFS_RETURN ) = 0;
3524
3525         type = PRVM_G_FLOAT( OFS_PARM0 );
3526         switch(type)
3527         {
3528         case 0:
3529                 PRVM_G_FLOAT ( OFS_RETURN ) = hostcache_viewcount;
3530                 return;
3531         case 1:
3532                 PRVM_G_FLOAT ( OFS_RETURN ) = hostcache_cachecount; 
3533         case 2:
3534                 PRVM_G_FLOAT ( OFS_RETURN ) = masterquerycount;
3535                 return;
3536         case 3:
3537                 PRVM_G_FLOAT ( OFS_RETURN ) = masterreplycount;
3538                 return;
3539         case 4:
3540                 PRVM_G_FLOAT ( OFS_RETURN ) = serverquerycount;
3541                 return;
3542         case 5:
3543                 PRVM_G_FLOAT ( OFS_RETURN ) = serverreplycount;
3544                 return;
3545         case 6:
3546                 PRVM_G_FLOAT ( OFS_RETURN ) = hostcache_sortbyfield;
3547                 return;
3548         case 7:
3549                 PRVM_G_FLOAT ( OFS_RETURN ) = hostcache_sortdescending;
3550                 return;
3551         default:
3552                 Con_Printf( "VM_M_gethostcachestat: bad type %i!\n", type );
3553         }
3554 }
3555
3556 /*
3557 ========================
3558 VM_M_resethostcachemasks
3559
3560 resethostcachemasks()
3561 ========================
3562 */
3563 void VM_M_resethostcachemasks( void )
3564 {
3565         HostCache_ResetMasks();
3566 }
3567
3568
3569 /*
3570 ========================
3571 VM_M_sethostcachemaskstring
3572
3573 sethostcachemaskstring(float mask, float fld, string str, float op)
3574 0-511           and
3575 512 - 1024      or
3576 ========================
3577 */
3578 void VM_M_sethostcachemaskstring( void )
3579 {
3580         char *str;
3581         int masknr;
3582         hostcache_mask_t *mask;
3583         int field;
3584
3585         VM_SAFEPARMCOUNT( 4, VM_M_sethostcachemaskstring );
3586         str = PRVM_G_STRING( OFS_PARM1 );
3587         if( !str )
3588                 PRVM_ERROR( "VM_M_sethostcachemaskstring: null string passed!" );
3589
3590         masknr = PRVM_G_FLOAT( OFS_PARM0 );
3591         if( masknr >= 0 && masknr <= HOSTCACHE_ANDMASKCOUNT )
3592                 mask = &hostcache_andmasks[masknr];
3593         else if( masknr >= 512 && masknr - 512 <= HOSTCACHE_ORMASKCOUNT )
3594                 mask = &hostcache_ormasks[masknr - 512 ];
3595         else {
3596                 Con_Printf( "VM_M_sethostcachemaskstring: invalid mask number %i\n", masknr );
3597                 return;
3598         }
3599
3600         field = (int) PRVM_G_FLOAT( OFS_PARM1 );
3601         
3602         switch( field ) {
3603                 case HCIF_CNAME:
3604                         strncpy( mask->info.cname, PRVM_G_STRING( OFS_PARM2 ), sizeof(mask->info.cname) );
3605                         break;
3606                 case HCIF_NAME:
3607                         strncpy( mask->info.name, PRVM_G_STRING( OFS_PARM2 ), sizeof(mask->info.name)  );
3608                         break;
3609                 case HCIF_MAP:
3610                         strncpy( mask->info.map, PRVM_G_STRING( OFS_PARM2 ), sizeof(mask->info.map)  );
3611                         break;
3612                 case HCIF_MOD:
3613                         strncpy( mask->info.mod, PRVM_G_STRING( OFS_PARM2 ), sizeof(mask->info.mod)  );
3614                         break;
3615                 case HCIF_GAME:
3616                         strncpy( mask->info.game, PRVM_G_STRING( OFS_PARM2 ), sizeof(mask->info.game)  );
3617                         break;
3618                 default:
3619                         Con_Printf( "VM_M_sethostcachemaskstring: Bad field number %i passed!\n", field );
3620                         return;
3621         }
3622
3623         mask->active = true;
3624         mask->tests[field] = (int) PRVM_G_FLOAT( OFS_PARM3 );
3625 }    
3626
3627 /*
3628 ========================
3629 VM_M_sethostcachemasknumber
3630
3631 sethostcachemasknumber(float mask, float fld, float num, float op)
3632
3633 0-511           and
3634 512 - 1024      or
3635 ========================
3636 */
3637 void VM_M_sethostcachemasknumber( void )
3638 {
3639         int number;
3640         hostcache_mask_t *mask;
3641         int     masknr;
3642         int field;
3643         VM_SAFEPARMCOUNT( 4, VM_M_sethostcachemasknumber );
3644
3645         masknr = PRVM_G_FLOAT( OFS_PARM0 );
3646         if( masknr >= 0 && masknr <= HOSTCACHE_ANDMASKCOUNT )
3647                 mask = &hostcache_andmasks[masknr];
3648         else if( masknr >= 512 && masknr - 512 <= HOSTCACHE_ORMASKCOUNT )
3649                 mask = &hostcache_ormasks[masknr - 512 ];
3650         else {
3651                 Con_Printf( "VM_M_sethostcachemasknumber: invalid mask number %i\n", masknr );
3652                 return;
3653         }
3654
3655         number = PRVM_G_FLOAT( OFS_PARM2 );
3656         field = (int) PRVM_G_FLOAT( OFS_PARM1 );
3657
3658         switch( field ) {
3659                 case HCIF_MAXPLAYERS:
3660                         mask->info.maxplayers = number;
3661                         break;
3662                 case HCIF_NUMPLAYERS:
3663                         mask->info.numplayers = number;
3664                         break;
3665                 case HCIF_PING:
3666                         mask->info.ping = number;
3667                         break;
3668                 case HCIF_PROTOCOL:
3669                         mask->info.protocol = number;
3670                         break;
3671                 default:
3672                         Con_Printf( "VM_M_sethostcachemasknumber: Bad field number %i passed!\n", field );
3673                         return;
3674         }
3675
3676         mask->active = true;
3677         mask->tests[field] = (int) PRVM_G_FLOAT( OFS_PARM3 );
3678 }
3679
3680
3681 /*
3682 ========================
3683 VM_M_resorthostcache
3684
3685 resorthostcache
3686 ========================
3687 */
3688 void VM_M_resorthostcache( void )
3689 {
3690         HostCache_RebuildViewSet();
3691 }
3692
3693 /*
3694 =========
3695 VM_M_gethostcachestring
3696
3697 string  gethostcachestring(float field, float hostnr)
3698 =========
3699 */
3700 void VM_M_gethostcachestring(void)
3701 {
3702         hostcache_t *cache;
3703         int hostnr;
3704
3705         VM_SAFEPARMCOUNT(2, VM_M_gethostcachestring);
3706
3707         PRVM_G_INT(OFS_RETURN) = 0;
3708
3709         hostnr = PRVM_G_FLOAT(OFS_PARM1);
3710
3711         if(hostnr < 0 || hostnr >= hostcache_viewcount)
3712         {
3713                 Con_Print("VM_M_gethostcachestring: bad hostnr passed!\n");
3714                 return;
3715         }
3716         cache = hostcache_viewset[hostnr];
3717         switch( (int) PRVM_G_FLOAT(OFS_PARM0) ) {
3718                 case HCIF_CNAME:
3719                         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->info.cname );
3720                         break;
3721                 case HCIF_NAME:
3722                         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->info.name );
3723                         break;
3724                 case HCIF_GAME:
3725                         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->info.game );
3726                         break;
3727                 case HCIF_MOD:
3728                         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->info.mod );
3729                         break;
3730                 case HCIF_MAP:
3731                         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->info.map );
3732                         break;
3733                 // TODO remove this again
3734                 case 1024:
3735                         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->line1 );
3736                         break;
3737                 case 1025:
3738                         PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( cache->line2 );
3739                         break;
3740                 default:
3741                         Con_Print("VM_M_gethostcachestring: bad field number passed!\n");
3742         }
3743 }
3744
3745 /*
3746 =========
3747 VM_M_gethostcachenumber
3748
3749 float   gethostcachenumber(float field, float hostnr)
3750 =========
3751 */
3752 void VM_M_gethostcachenumber(void)
3753 {
3754         hostcache_t *cache;
3755         int hostnr;
3756
3757         VM_SAFEPARMCOUNT(2, VM_M_gethostcachestring);
3758
3759         PRVM_G_INT(OFS_RETURN) = 0;
3760
3761         hostnr = PRVM_G_FLOAT(OFS_PARM1);
3762
3763         if(hostnr < 0 || hostnr >= hostcache_viewcount)
3764         {
3765                 Con_Print("VM_M_gethostcachestring: bad hostnr passed!\n");
3766                 return;
3767         }
3768         cache = hostcache_viewset[hostnr];
3769         switch( (int) PRVM_G_FLOAT(OFS_PARM0) ) {
3770                 case HCIF_MAXPLAYERS:
3771                         PRVM_G_FLOAT( OFS_RETURN ) = cache->info.maxplayers;
3772                         break;
3773                 case HCIF_NUMPLAYERS:
3774                         PRVM_G_FLOAT( OFS_RETURN ) = cache->info.numplayers;
3775                         break;
3776                 case HCIF_PING:
3777                         PRVM_G_FLOAT( OFS_RETURN ) = cache->info.ping;
3778                         break;
3779                 case HCIF_PROTOCOL:
3780                         PRVM_G_FLOAT( OFS_RETURN ) = cache->info.protocol;
3781                         break;
3782                 default:
3783                         Con_Print("VM_M_gethostcachenumber: bad field number passed!\n");
3784         }
3785 }
3786
3787 /*
3788 ========================
3789 VM_M_sethostcachesort
3790
3791 sethostcachesort(float field, float descending)
3792 ========================
3793 */
3794 void VM_M_sethostcachesort( void )
3795 {
3796         VM_SAFEPARMCOUNT( 2, VM_M_sethostcachesort );
3797
3798         hostcache_sortbyfield = (int) PRVM_G_FLOAT( OFS_PARM0 );
3799         hostcache_sortdescending = (qboolean) PRVM_G_FLOAT( OFS_PARM1 );
3800 }
3801
3802 /*
3803 ========================
3804 VM_M_refreshhostcache
3805
3806 refreshhostcache()
3807 ========================
3808 */
3809 void VM_M_refreshhostcache( void )
3810 {
3811         VM_SAFEPARMCOUNT( 0, VM_M_refreshhostcache );
3812         HostCache_QueryList();
3813 }
3814
3815 /*
3816 ========================
3817 VM_M_gethostcacheindexforkey
3818
3819 float gethostcacheindexforkey(string key)
3820 ========================
3821 */
3822 void VM_M_gethostcacheindexforkey( void )
3823 {
3824         char *key;
3825         VM_SAFEPARMCOUNT( 1, VM_M_gethostcacheindexforkey );
3826
3827         key = PRVM_G_STRING( OFS_PARM0 );
3828         VM_CheckEmptyString( key );
3829         
3830         if( !strcmp( key, "cname" ) )
3831                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_CNAME;
3832         else if( !strcmp( key, "ping" ) )
3833                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_PING;
3834         else if( !strcmp( key, "game" ) )
3835                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_GAME;
3836         else if( !strcmp( key, "mod" ) )
3837                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_MOD;
3838         else if( !strcmp( key, "map" ) )
3839                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_MAP;
3840         else if( !strcmp( key, "name" ) )
3841                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_NAME;
3842         else if( !strcmp( key, "maxplayers" ) )
3843                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_MAXPLAYERS;
3844         else if( !strcmp( key, "numplayers" ) )
3845                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_NUMPLAYERS;
3846         else if( !strcmp( key, "protocol" ) )
3847                 PRVM_G_FLOAT( OFS_RETURN ) = HCIF_PROTOCOL;
3848         else
3849                 PRVM_G_FLOAT( OFS_RETURN ) = -1;
3850 }
3851
3852 /*
3853 ========================
3854 VM_M_addwantedhostcachekey
3855
3856 addwantedhostcachekey(string key)
3857 ========================
3858 */
3859 void VM_M_addwantedhostcachekey( void )
3860 {
3861         VM_SAFEPARMCOUNT( 1, VM_M_addwantedhostcachekey );
3862 }
3863
3864 prvm_builtin_t vm_m_builtins[] = {
3865         0, // to be consistent with the old vm
3866         // common builtings (mostly)
3867         VM_checkextension,
3868         VM_error,
3869         VM_objerror,
3870         VM_print,
3871         VM_bprint,
3872         VM_sprint,
3873         VM_centerprint,
3874         VM_normalize,
3875         VM_vlen,
3876         VM_vectoyaw,    // #10
3877         VM_vectoangles,
3878         VM_random,
3879         VM_localcmd,
3880         VM_cvar,
3881         VM_cvar_set,
3882         VM_dprint,
3883         VM_ftos,
3884         VM_fabs,
3885         VM_vtos,
3886         VM_etos,                // 20
3887         VM_stof,
3888         VM_spawn,
3889         VM_remove,
3890         VM_find,
3891         VM_findfloat,
3892         VM_findchain,
3893         VM_findchainfloat,
3894         VM_precache_file,
3895         VM_precache_sound,
3896         VM_coredump,    // 30
3897         VM_traceon,
3898         VM_traceoff,
3899         VM_eprint,
3900         VM_rint,
3901         VM_floor,
3902         VM_ceil,
3903         VM_nextent,
3904         VM_sin,
3905         VM_cos,
3906         VM_sqrt,                // 40
3907         VM_randomvec,
3908         VM_registercvar,
3909         VM_min,
3910         VM_max,
3911         VM_bound,
3912         VM_pow,
3913         VM_copyentity,
3914         VM_fopen,
3915         VM_fclose,
3916         VM_fgets,               // 50
3917         VM_fputs,
3918         VM_strlen,
3919         VM_strcat,
3920         VM_substring,
3921         VM_stov,
3922         VM_strzone,
3923         VM_strunzone,
3924         VM_tokenize,
3925         VM_argv,
3926         VM_isserver,    // 60
3927         VM_clientcount, 
3928         VM_clientstate, 
3929         VM_clcommand,
3930         VM_changelevel,
3931         VM_localsound,  
3932         VM_getmousepos,
3933         VM_gettime,
3934         VM_loadfromdata,
3935         VM_loadfromfile,
3936         VM_modulo,              // 70
3937         VM_str_cvar,    
3938         VM_crash,
3939         VM_stackdump,   // 73
3940         VM_search_begin,
3941         VM_search_end,
3942         VM_search_getsize,
3943         VM_search_getfilename, // 77
3944         VM_chr, 
3945         VM_itof,
3946         VM_ftoi,                // 80
3947         VM_itof,                // isString
3948         VM_altstr_count,
3949         VM_altstr_prepare,
3950         VM_altstr_get,
3951         VM_altstr_set,  // 85
3952         0,0,0,0,0,      // 90
3953         e10,                    // 100
3954         e100,                   // 200
3955         e100,                   // 300
3956         e100,                   // 400
3957         // msg functions
3958         VM_WriteByte,
3959         VM_WriteChar,
3960         VM_WriteShort,
3961         VM_WriteLong,
3962         VM_WriteAngle,
3963         VM_WriteCoord,
3964         VM_WriteString,
3965         VM_WriteEntity, // 408
3966         0,
3967         0,                              // 410
3968         e10,                    // 420
3969         e10,                    // 430
3970         e10,                    // 440
3971         e10,                    // 450
3972         // draw functions
3973         VM_iscachedpic,
3974         VM_precache_pic,
3975         VM_freepic,
3976         VM_drawcharacter,
3977         VM_drawstring,
3978         VM_drawpic,
3979         VM_drawfill,    
3980         VM_drawsetcliparea,
3981         VM_drawresetcliparea,
3982         VM_getimagesize,// 460
3983         VM_cin_open,
3984         VM_cin_close,
3985         VM_cin_setstate,        
3986         VM_cin_getstate,
3987         VM_cin_restart, // 465
3988         0,0,0,0,0,      // 470
3989         e10,                    // 480
3990         e10,                    // 490
3991         e10,                    // 500
3992         e100,                   // 600
3993         // menu functions
3994         VM_M_setkeydest,
3995         VM_M_getkeydest,
3996         VM_M_setmousetarget,
3997         VM_M_getmousetarget,
3998         VM_M_callfunction,
3999         VM_M_writetofile,
4000         VM_M_isfunction,
4001         VM_M_getresolution,
4002         VM_M_keynumtostring,
4003         VM_M_findkeysforcommand,// 610
4004         VM_M_gethostcachestat,
4005         VM_M_gethostcachestring,
4006         VM_M_parseentitydata,
4007         VM_M_stringtokeynum,
4008         VM_M_resethostcachemasks,
4009         VM_M_sethostcachemaskstring,
4010         VM_M_sethostcachemasknumber,
4011         VM_M_resorthostcache,
4012         VM_M_sethostcachesort,
4013         VM_M_refreshhostcache,
4014         VM_M_gethostcachenumber,
4015         VM_M_gethostcacheindexforkey, 
4016         VM_M_addwantedhostcachekey // 623
4017 };
4018
4019 const int vm_m_numbuiltins = sizeof(vm_m_builtins) / sizeof(prvm_builtin_t);
4020
4021 void VM_M_Cmd_Init(void)
4022 {
4023         VM_Cmd_Init();
4024 }
4025
4026 void VM_M_Cmd_Reset(void)
4027 {
4028         //VM_Cmd_Init();
4029         VM_Cmd_Reset();
4030 }