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