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