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