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