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