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