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