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