]> icculus.org git repositories - divverent/darkplaces.git/blob - prvm_cmds.c
Added support for 16 joystick buttons.
[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 || end)
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                         // FIXME: use a model function to get tag info (need to handle skeletal)
2121                         if (v->_float == 0 && model->alias.aliasnum_tags)
2122                                 for (i = 0;i < model->alias.aliasnum_tags;i++)
2123                                         if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
2124                                                 v->_float = i + 1;
2125                         if (v->_float == 0)
2126                                 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);
2127                 }
2128                 else
2129                         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));
2130         }
2131 }*/
2132
2133 /*
2134 =========
2135 VM_isserver
2136
2137 float   isserver()
2138 =========
2139 */
2140 void VM_isserver(void)
2141 {
2142         VM_SAFEPARMCOUNT(0,VM_serverstate);
2143
2144         PRVM_G_FLOAT(OFS_RETURN) = sv.active;
2145 }
2146
2147 /*
2148 =========
2149 VM_clientcount
2150
2151 float   clientcount()
2152 =========
2153 */
2154 void VM_clientcount(void)
2155 {
2156         VM_SAFEPARMCOUNT(0,VM_clientcount);
2157
2158         PRVM_G_FLOAT(OFS_RETURN) = svs.maxclients;
2159 }
2160
2161 /*
2162 =========
2163 VM_clientstate
2164
2165 float   clientstate()
2166 =========
2167 */
2168 void VM_clientstate(void)
2169 {
2170         VM_SAFEPARMCOUNT(0,VM_clientstate);
2171
2172         PRVM_G_FLOAT(OFS_RETURN) = cls.state;
2173 }
2174
2175 /*
2176 =========
2177 VM_getostype
2178
2179 float   getostype(void)
2180 =========
2181 */ // not used at the moment -> not included in the common list
2182 void VM_getostype(void)
2183 {
2184         VM_SAFEPARMCOUNT(0,VM_getostype);
2185
2186         /*
2187         OS_WINDOWS
2188         OS_LINUX
2189         OS_MAC - not supported
2190         */
2191
2192 #ifdef _WIN32
2193         PRVM_G_FLOAT(OFS_RETURN) = 0;
2194 #elif defined _MAC
2195         PRVM_G_FLOAT(OFS_RETURN) = 2;
2196 #else
2197         PRVM_G_FLOAT(OFS_RETURN) = 1;
2198 #endif
2199 }
2200
2201 /*
2202 =========
2203 VM_getmousepos
2204
2205 vector  getmousepos()
2206 =========
2207 */
2208 void VM_getmousepos(void)
2209 {
2210
2211         VM_SAFEPARMCOUNT(0,VM_getmousepos);
2212         
2213         PRVM_G_VECTOR(OFS_RETURN)[0] = in_mouse_x;
2214         PRVM_G_VECTOR(OFS_RETURN)[1] = in_mouse_y;
2215         PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2216 }
2217
2218 /*
2219 =========
2220 VM_gettime
2221
2222 float   gettime(void)
2223 =========
2224 */
2225 void VM_gettime(void)
2226 {
2227         VM_SAFEPARMCOUNT(0,VM_gettime);
2228
2229         PRVM_G_FLOAT(OFS_RETURN) = (float) *prog->time;
2230 }
2231
2232 /*
2233 =========
2234 VM_loadfromdata
2235
2236 loadfromdata(string data)
2237 =========
2238 */
2239 void VM_loadfromdata(void)
2240 {
2241         VM_SAFEPARMCOUNT(1,VM_loadentsfromfile);
2242
2243         PRVM_ED_LoadFromFile(PRVM_G_STRING(OFS_PARM0));
2244 }
2245
2246 /*
2247 =========
2248 VM_loadfromfile
2249
2250 loadfromfile(string file)
2251 =========
2252 */
2253 void VM_loadfromfile(void)
2254 {
2255         char *filename;
2256         qbyte *data;
2257         
2258         VM_SAFEPARMCOUNT(1,VM_loadfromfile);
2259         
2260         filename = PRVM_G_STRING(OFS_PARM0);
2261         // .. is parent directory on many platforms
2262         // / is parent directory on Amiga
2263         // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2264         // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2265         if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2266         {
2267                 Con_Printf("VM_loadfromfile: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
2268                 PRVM_G_FLOAT(OFS_RETURN) = -4;
2269                 return;
2270         }
2271
2272         // not conform with VM_fopen
2273         data = FS_LoadFile(filename, tempmempool, false);
2274         if (data == NULL)
2275                 PRVM_G_FLOAT(OFS_RETURN) = -1;
2276         
2277         PRVM_ED_LoadFromFile(data);
2278
2279         if(data)
2280                 Mem_Free(data);
2281 }
2282
2283
2284 /*
2285 =========
2286 VM_modulo
2287
2288 float   mod(float val, float m)
2289 =========
2290 */
2291 void VM_modulo(void)
2292 {
2293         int val, m;
2294         VM_SAFEPARMCOUNT(2,VM_module);
2295
2296         val = (int) PRVM_G_FLOAT(OFS_PARM0);
2297         m       = (int) PRVM_G_FLOAT(OFS_PARM1);
2298
2299         PRVM_G_FLOAT(OFS_RETURN) = (float) (val % m);
2300 }
2301
2302 void VM_Search_Init(void)
2303 {
2304         memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
2305 }
2306
2307 void VM_Search_Reset(void)
2308 {
2309         int i;
2310         // reset the fssearch list
2311         for(i = 0; i < MAX_VMSEARCHES; i++)
2312                 if(VM_SEARCHLIST[i])
2313                         FS_FreeSearch(VM_SEARCHLIST[i]);
2314         memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
2315 }
2316
2317 /*
2318 =========
2319 VM_search_begin
2320
2321 float search_begin(string pattern, float caseinsensitive, float quiet)
2322 =========
2323 */
2324 void VM_search_begin(void)
2325 {
2326         int handle;
2327         char *pattern;
2328         int caseinsens, quiet;
2329
2330         VM_SAFEPARMCOUNT(3, VM_search_begin);
2331
2332         pattern = PRVM_G_STRING(OFS_PARM0);
2333
2334         VM_CheckEmptyString(pattern);
2335
2336         caseinsens = PRVM_G_FLOAT(OFS_PARM1);
2337         quiet = PRVM_G_FLOAT(OFS_PARM2);
2338         
2339         for(handle = 0; handle < MAX_VMSEARCHES; handle++)
2340                 if(!VM_SEARCHLIST[handle])
2341                         break;
2342
2343         if(handle >= MAX_VMSEARCHES)
2344         {
2345                 Con_Printf("VM_search_begin: %s ran out of search handles (%i)\n", PRVM_NAME, MAX_VMSEARCHES);
2346                 PRVM_G_FLOAT(OFS_RETURN) = -2;
2347                 return;
2348         }
2349
2350         if(!(VM_SEARCHLIST[handle] = FS_Search(pattern,caseinsens, quiet)))
2351                 PRVM_G_FLOAT(OFS_RETURN) = -1;
2352         else
2353                 PRVM_G_FLOAT(OFS_RETURN) = handle;
2354 }
2355
2356 /*
2357 =========
2358 VM_search_end
2359
2360 void    search_end(float handle)
2361 =========
2362 */
2363 void VM_search_end(void)
2364 {
2365         int handle;
2366         VM_SAFEPARMCOUNT(1, VM_search_end);
2367
2368         handle = PRVM_G_FLOAT(OFS_PARM0);
2369         
2370         if(handle < 0 || handle >= MAX_VMSEARCHES)
2371         {
2372                 Con_Printf("VM_search_end: invalid handle %i used in %s\n", handle, PRVM_NAME);
2373                 return;
2374         }
2375         if(VM_SEARCHLIST[handle] == NULL)
2376         {
2377                 Con_Printf("VM_search_end: no such handle %i in %s\n", handle, PRVM_NAME);
2378                 return;
2379         }
2380
2381         FS_FreeSearch(VM_SEARCHLIST[handle]);
2382         VM_SEARCHLIST[handle] = NULL;
2383 }
2384
2385 /*
2386 =========
2387 VM_search_getsize
2388
2389 float   search_getsize(float handle)
2390 =========
2391 */
2392 void VM_search_getsize(void)
2393 {
2394         int handle;
2395         VM_SAFEPARMCOUNT(1, VM_M_search_getsize);
2396
2397         handle = PRVM_G_FLOAT(OFS_PARM0);
2398
2399         if(handle < 0 || handle >= MAX_VMSEARCHES)
2400         {
2401                 Con_Printf("VM_search_getsize: invalid handle %i used in %s\n", handle, PRVM_NAME);
2402                 return;
2403         }
2404         if(VM_SEARCHLIST[handle] == NULL)
2405         {
2406                 Con_Printf("VM_search_getsize: no such handle %i in %s\n", handle, PRVM_NAME);
2407                 return;
2408         }
2409         
2410         PRVM_G_FLOAT(OFS_RETURN) = VM_SEARCHLIST[handle]->numfilenames;
2411 }
2412
2413 /*
2414 =========
2415 VM_search_getfilename
2416
2417 string  search_getfilename(float handle, float num)
2418 =========
2419 */
2420 void VM_search_getfilename(void)
2421 {
2422         int handle, filenum;
2423         char *tmp;
2424         VM_SAFEPARMCOUNT(2, VM_search_getfilename);
2425
2426         handle = PRVM_G_FLOAT(OFS_PARM0);
2427         filenum = PRVM_G_FLOAT(OFS_PARM1);
2428
2429         if(handle < 0 || handle >= MAX_VMSEARCHES)
2430         {
2431                 Con_Printf("VM_search_getfilename: invalid handle %i used in %s\n", handle, PRVM_NAME);
2432                 return;
2433         }
2434         if(VM_SEARCHLIST[handle] == NULL)
2435         {
2436                 Con_Printf("VM_search_getfilename: no such handle %i in %s\n", handle, PRVM_NAME);
2437                 return;
2438         }
2439         if(filenum < 0 || filenum >= VM_SEARCHLIST[handle]->numfilenames)
2440         {
2441                 Con_Printf("VM_search_getfilename: invalid filenum %i in %s\n", filenum, PRVM_NAME);
2442                 return;
2443         }
2444         
2445         tmp = VM_GetTempString();
2446         strcpy(tmp, VM_SEARCHLIST[handle]->filenames[filenum]);
2447
2448         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
2449 }
2450
2451 /*
2452 =========
2453 VM_chr
2454
2455 string  chr(float ascii)
2456 =========
2457 */
2458 void VM_chr(void)
2459 {
2460         char *tmp;
2461         VM_SAFEPARMCOUNT(1, VM_chr);
2462
2463         tmp = VM_GetTempString();
2464         tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0);
2465         tmp[1] = 0;
2466
2467         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
2468 }
2469
2470 //=============================================================================
2471 // Draw builtins (client & menu)
2472
2473 /*
2474 =========
2475 VM_iscachedpic
2476
2477 float   iscachedpic(string pic)
2478 =========
2479 */
2480 void VM_iscachedpic(void)
2481 {
2482         VM_SAFEPARMCOUNT(1,VM_iscachedpic);
2483
2484         // drawq hasnt such a function, thus always return true 
2485         PRVM_G_FLOAT(OFS_RETURN) = TRUE;
2486 }
2487
2488 /*
2489 =========
2490 VM_precache_pic
2491
2492 string  precache_pic(string pic) 
2493 =========
2494 */
2495 void VM_precache_pic(void)
2496 {
2497         char    *s;
2498         
2499         VM_SAFEPARMCOUNT(1, VM_precache_pic);
2500         
2501         s = PRVM_G_STRING(OFS_PARM0);
2502         PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
2503         
2504         if(!s)
2505                 PRVM_ERROR ("VM_precache_pic: %s: NULL\n", PRVM_NAME);
2506
2507         VM_CheckEmptyString (s);
2508         
2509         if(!Draw_CachePic(s))
2510                 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(""); 
2511 }
2512
2513 /*
2514 =========
2515 VM_freepic
2516
2517 freepic(string s)
2518 =========
2519 */
2520 void VM_freepic(void)
2521 {
2522         char *s;
2523
2524         VM_SAFEPARMCOUNT(1,VM_freepic);
2525
2526         s = PRVM_G_STRING(OFS_PARM0);
2527         
2528         if(!s)
2529                 PRVM_ERROR ("VM_freepic: %s: NULL\n");
2530         
2531         VM_CheckEmptyString (s);
2532         
2533         Draw_FreePic(s);
2534 }
2535
2536 /*
2537 =========
2538 VM_drawcharacter
2539
2540 float   drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
2541 =========
2542 */
2543 void VM_drawcharacter(void)
2544 {
2545         float *pos,*scale,*rgb;
2546         char   character;
2547         int flag;
2548         VM_SAFEPARMCOUNT(6,VM_drawcharacter);
2549
2550         character = (char) PRVM_G_FLOAT(OFS_PARM1);
2551         if(character == 0)
2552         {
2553                 Con_Printf("VM_drawcharacter: %s passed null character !\n",PRVM_NAME);
2554                 PRVM_G_FLOAT(OFS_RETURN) = -1;
2555                 return;
2556         }
2557         
2558         pos = PRVM_G_VECTOR(OFS_PARM0);
2559         scale = PRVM_G_VECTOR(OFS_PARM2);
2560         rgb = PRVM_G_VECTOR(OFS_PARM3);
2561         flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2562         
2563         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2564         {
2565                 Con_Printf("VM_drawcharacter: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2566                 PRVM_G_FLOAT(OFS_RETURN) = -2;
2567                 return;
2568         }
2569         
2570         if(pos[2] || scale[2])
2571                 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"))); 
2572
2573         if(!scale[0] || !scale[1])
2574         {
2575                 Con_Printf("VM_drawcharacter: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2576                 PRVM_G_FLOAT(OFS_RETURN) = -3;
2577                 return;
2578         }
2579
2580         DrawQ_String (pos[0], pos[1], &character, 1, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2581         PRVM_G_FLOAT(OFS_RETURN) = 1;
2582 }       
2583
2584 /*
2585 =========
2586 VM_drawstring
2587
2588 float   drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
2589 =========
2590 */
2591 void VM_drawstring(void)
2592 {
2593         float *pos,*scale,*rgb;
2594         char  *string;
2595         int flag;
2596         VM_SAFEPARMCOUNT(6,VM_drawstring);
2597         
2598         string = PRVM_G_STRING(OFS_PARM1);
2599         if(!string)
2600         {
2601                 Con_Printf("VM_drawstring: %s passed null string !\n",PRVM_NAME);
2602                 PRVM_G_FLOAT(OFS_RETURN) = -1;
2603                 return;
2604         }
2605         
2606         VM_CheckEmptyString(string);
2607         
2608         pos = PRVM_G_VECTOR(OFS_PARM0);
2609         scale = PRVM_G_VECTOR(OFS_PARM2);
2610         rgb = PRVM_G_VECTOR(OFS_PARM3);
2611         flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2612         
2613         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2614         {
2615                 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2616                 PRVM_G_FLOAT(OFS_RETURN) = -2;
2617                 return;
2618         }
2619         
2620         if(!scale[0] || !scale[1])
2621         {
2622                 Con_Printf("VM_drawstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2623                 PRVM_G_FLOAT(OFS_RETURN) = -3;
2624                 return;
2625         }
2626
2627         if(pos[2] || scale[2])
2628                 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"))); 
2629         
2630         DrawQ_String (pos[0], pos[1], string, 0, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2631         PRVM_G_FLOAT(OFS_RETURN) = 1;
2632 }
2633 /*
2634 =========
2635 VM_drawpic
2636
2637 float   drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
2638 =========
2639 */
2640 void VM_drawpic(void)
2641 {
2642         char *pic;
2643         float *size, *pos, *rgb;
2644         int flag;
2645
2646         VM_SAFEPARMCOUNT(6,VM_drawpic);
2647
2648         pic = PRVM_G_STRING(OFS_PARM1);
2649
2650         if(!pic)
2651         {
2652                 Con_Printf("VM_drawpic: %s passed null picture name !\n", PRVM_NAME);
2653                 PRVM_G_FLOAT(OFS_RETURN) = -1;  
2654                 return;
2655         }
2656
2657         VM_CheckEmptyString (pic);
2658
2659         // is pic cached ? no function yet for that
2660         if(!1)
2661         {
2662                 Con_Printf("VM_drawpic: %s: %s not cached !\n", PRVM_NAME, pic);
2663                 PRVM_G_FLOAT(OFS_RETURN) = -4;
2664                 return;
2665         }
2666         
2667         pos = PRVM_G_VECTOR(OFS_PARM0);
2668         size = PRVM_G_VECTOR(OFS_PARM2);
2669         rgb = PRVM_G_VECTOR(OFS_PARM3);
2670         flag = (int) PRVM_G_FLOAT(OFS_PARM5);
2671
2672         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2673         {
2674                 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2675                 PRVM_G_FLOAT(OFS_RETURN) = -2;
2676                 return;
2677         }
2678
2679         if(pos[2] || size[2])
2680                 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"))); 
2681         
2682         DrawQ_Pic(pos[0], pos[1], pic, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2683         PRVM_G_FLOAT(OFS_RETURN) = 1;
2684 }
2685
2686 /*
2687 =========
2688 VM_drawfill
2689
2690 float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
2691 =========
2692 */
2693 void VM_drawfill(void)
2694 {
2695         float *size, *pos, *rgb;
2696         int flag;
2697         
2698         VM_SAFEPARMCOUNT(5,VM_drawfill);
2699         
2700         
2701         pos = PRVM_G_VECTOR(OFS_PARM0);
2702         size = PRVM_G_VECTOR(OFS_PARM1);
2703         rgb = PRVM_G_VECTOR(OFS_PARM2);
2704         flag = (int) PRVM_G_FLOAT(OFS_PARM4);
2705         
2706         if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2707         {
2708                 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2709                 PRVM_G_FLOAT(OFS_RETURN) = -2;
2710                 return;
2711         }
2712         
2713         if(pos[2] || size[2])
2714                 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"))); 
2715         
2716         DrawQ_Pic(pos[0], pos[1], 0, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM3), flag);
2717         PRVM_G_FLOAT(OFS_RETURN) = 1;
2718 }
2719
2720 /*
2721 =========
2722 VM_drawsetcliparea
2723
2724 drawsetcliparea(float x, float y, float width, float height)
2725 =========
2726 */
2727 void VM_drawsetcliparea(void)
2728 {
2729         float x,y,w,h;
2730         VM_SAFEPARMCOUNT(4,VM_drawsetcliparea);
2731
2732         x = bound(0,PRVM_G_FLOAT(OFS_PARM0),vid.conwidth);
2733         y = bound(0,PRVM_G_FLOAT(OFS_PARM1),vid.conheight);
2734         w = bound(0,PRVM_G_FLOAT(OFS_PARM2),(vid.conwidth  - x));
2735         h = bound(0,PRVM_G_FLOAT(OFS_PARM3),(vid.conheight - y)); 
2736
2737         DrawQ_SetClipArea(x,y,w,h);
2738 }
2739
2740 /*
2741 =========
2742 VM_drawresetcliparea
2743
2744 drawresetcliparea()
2745 =========
2746 */
2747 void VM_drawresetcliparea(void)
2748 {
2749         VM_SAFEPARMCOUNT(0,VM_drawresetcliparea);
2750
2751         DrawQ_ResetClipArea();
2752 }
2753
2754 /*
2755 =========
2756 VM_getimagesize
2757
2758 vector  getimagesize(string pic)
2759 =========
2760 */
2761 void VM_getimagesize(void)
2762 {
2763         char *p;
2764         cachepic_t *pic;
2765
2766         VM_SAFEPARMCOUNT(1,VM_getimagesize);
2767         
2768         p = PRVM_G_STRING(OFS_PARM0);
2769
2770         if(!p)
2771                 PRVM_ERROR("VM_getimagepos: %s passed null picture name !\n", PRVM_NAME);
2772         
2773         VM_CheckEmptyString (p);
2774
2775         pic = Draw_CachePic (p);
2776
2777         PRVM_G_VECTOR(OFS_RETURN)[0] = pic->width;
2778         PRVM_G_VECTOR(OFS_RETURN)[1] = pic->height;
2779         PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2780 }
2781
2782 void VM_Cmd_Init(void)
2783 {
2784         // only init the stuff for the current prog
2785         VM_STRINGS_MEMPOOL = Mem_AllocPool(va("vm_stringsmempool[%s]",PRVM_NAME), 0, NULL);
2786         VM_Files_Init();
2787         VM_Search_Init();
2788 }
2789
2790 void VM_Cmd_Reset(void)
2791 {
2792         //Mem_EmptyPool(VM_STRINGS_MEMPOOL);
2793         Mem_FreePool(&VM_STRINGS_MEMPOOL);
2794         VM_Search_Reset();
2795         VM_Files_CloseAll();
2796 }
2797
2798 //============================================================================
2799 // Server
2800
2801 char *vm_sv_extensions =
2802 "";
2803
2804 prvm_builtin_t vm_sv_builtins[] = {
2805 0  // to be consistent with the old vm
2806 };
2807
2808 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
2809
2810 void VM_SV_Cmd_Init(void)
2811 {
2812 }
2813
2814 void VM_SV_Cmd_Reset(void)
2815 {
2816 }
2817
2818 //============================================================================
2819 // Client
2820
2821 char *vm_cl_extensions =
2822 "";
2823
2824 prvm_builtin_t vm_cl_builtins[] = {
2825 0  // to be consistent with the old vm
2826 };
2827
2828 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
2829
2830 void VM_CL_Cmd_Init(void)
2831 {
2832 }
2833
2834 void VM_CL_Cmd_Reset(void)
2835 {
2836 }
2837
2838 //============================================================================
2839 // Menu
2840
2841 char *vm_m_extensions =
2842 "";
2843
2844 /*
2845 =========
2846 VM_M_setmousetarget
2847
2848 setmousetarget(float target)
2849 =========
2850 */
2851 void VM_M_setmousetarget(void)
2852 {
2853         VM_SAFEPARMCOUNT(1, VM_M_setmousetarget);
2854
2855         switch((int)PRVM_G_FLOAT(OFS_PARM0))
2856         {
2857         case 1:
2858                 in_client_mouse = false;
2859                 break;
2860         case 2:
2861                 in_client_mouse = true;
2862                 break;
2863         default:
2864                 PRVM_ERROR("VM_M_setmousetarget: wrong destination %i !\n",PRVM_G_FLOAT(OFS_PARM0));
2865         }
2866 }
2867
2868 /*
2869 =========
2870 VM_M_getmousetarget
2871
2872 float   getmousetarget
2873 =========
2874 */
2875 void VM_M_getmousetarget(void)
2876 {
2877         VM_SAFEPARMCOUNT(0,VM_M_getmousetarget);
2878
2879         if(in_client_mouse)
2880                 PRVM_G_FLOAT(OFS_RETURN) = 2;
2881         else
2882                 PRVM_G_FLOAT(OFS_RETURN) = 1;
2883 }
2884         
2885
2886
2887 /*
2888 =========
2889 VM_M_setkeydest
2890
2891 setkeydest(float dest)
2892 =========
2893 */
2894 void VM_M_setkeydest(void)
2895 {
2896         VM_SAFEPARMCOUNT(1,VM_M_setkeydest);
2897
2898         switch((int)PRVM_G_FLOAT(OFS_PARM0))
2899         {
2900         case 0:
2901                 // key_game
2902                 key_dest = key_game;
2903                 break;
2904         case 2:
2905                 // key_menu
2906                 key_dest = key_menu;
2907                 break;
2908         case 1:
2909                 // key_message
2910                 // key_dest = key_message
2911                 // break;
2912         default:
2913                 PRVM_ERROR("VM_M_setkeydest: wrong destination %i !\n",prog->globals[OFS_PARM0]);
2914         }
2915 }
2916
2917 /*
2918 =========
2919 VM_M_getkeydest
2920
2921 float   getkeydest
2922 =========
2923 */
2924 void VM_M_getkeydest(void)
2925 {
2926         VM_SAFEPARMCOUNT(0,VM_M_getkeydest);
2927
2928         // key_game = 0, key_message = 1, key_menu = 2, unknown = 3
2929         switch(key_dest)
2930         {
2931         case key_game:
2932                 PRVM_G_FLOAT(OFS_RETURN) = 0;
2933                 break;
2934         case key_menu:
2935                 PRVM_G_FLOAT(OFS_RETURN) = 2;
2936                 break;
2937         case key_message:
2938                 // not supported
2939                 // PRVM_G_FLOAT(OFS_RETURN) = 1;
2940                 // break;
2941         default:
2942                 PRVM_G_FLOAT(OFS_RETURN) = 3;
2943         }
2944 }
2945
2946 /*
2947 =========
2948 VM_M_callfunction
2949
2950         callfunction(...,string function_name)
2951 =========
2952 */
2953 mfunction_t *PRVM_ED_FindFunction (const char *name);
2954 void VM_M_callfunction(void)
2955 {
2956         mfunction_t *func;
2957         char *s;
2958
2959         if(prog->argc == 0)
2960                 PRVM_ERROR("VM_M_callfunction: 1 parameter is required !\n");
2961
2962         s = PRVM_G_STRING(OFS_PARM0 + (prog->argc - 1));
2963
2964         if(!s)
2965                 PRVM_ERROR("VM_M_callfunction: null string !\n");
2966
2967         VM_CheckEmptyString(s); 
2968
2969         func = PRVM_ED_FindFunction(s);
2970
2971         if(!func)
2972                 PRVM_ERROR("VM_M_callfunciton: function %s not found !\n", s);
2973         else if (func->first_statement < 0)
2974         {
2975                 // negative statements are built in functions
2976                 int builtinnumber = -func->first_statement;
2977                 prog->xfunction->builtinsprofile++;
2978                 if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber])
2979                         prog->builtins[builtinnumber]();
2980                 else
2981                         PRVM_ERROR("No such builtin #%i in %s", builtinnumber, PRVM_NAME);
2982         }
2983         else if(func > 0)
2984         {
2985                 prog->argc--;
2986                 PRVM_ExecuteProgram(func - prog->functions,"");
2987                 prog->argc++;
2988         }
2989 }       
2990
2991 /*
2992 =========
2993 VM_M_isfunction
2994
2995 float   isfunction(string function_name)
2996 =========
2997 */
2998 mfunction_t *PRVM_ED_FindFunction (const char *name);
2999 void VM_M_isfunction(void)
3000 {
3001         mfunction_t *func;
3002         char *s;
3003         
3004         VM_SAFEPARMCOUNT(1, VM_M_isfunction);
3005         
3006         s = PRVM_G_STRING(OFS_PARM0);
3007         
3008         if(!s)
3009                 PRVM_ERROR("VM_M_isfunction: null string !\n");
3010         
3011         VM_CheckEmptyString(s); 
3012         
3013         func = PRVM_ED_FindFunction(s);
3014
3015         if(!func)
3016                 PRVM_G_FLOAT(OFS_RETURN) = false;
3017         else
3018                 PRVM_G_FLOAT(OFS_RETURN) = true;
3019 }
3020
3021 /*
3022 =========
3023 VM_M_writetofile
3024
3025         writetofile(float fhandle, entity ent)
3026 =========
3027 */
3028 void VM_M_writetofile(void)
3029 {
3030         prvm_edict_t * ent;
3031         int filenum;
3032
3033         VM_SAFEPARMCOUNT(2, VM_M_writetofile);
3034
3035         filenum = PRVM_G_FLOAT(OFS_PARM0);
3036         if (filenum < 0 || filenum >= MAX_VMFILES)
3037         {
3038                 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
3039                 return;
3040         }
3041         if (VM_FILES[filenum] == NULL)
3042         {
3043                 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
3044                 return;
3045         }
3046
3047         ent = PRVM_G_EDICT(OFS_PARM1);  
3048         if(ent->e->free)
3049         {
3050                 Con_Printf("VM_M_writetofile: %s: entity %i is free !\n", PRVM_NAME, PRVM_EDICT_NUM(OFS_PARM1));
3051                 return;
3052         }
3053
3054         PRVM_ED_Write (VM_FILES[filenum], ent);
3055 }
3056
3057 /*
3058 =========
3059 VM_M_getresolution
3060
3061 vector  getresolution(float number)
3062 =========
3063 */
3064 extern unsigned short video_resolutions[][2];
3065 void VM_M_getresolution(void)
3066 {
3067         int nr;
3068         VM_SAFEPARMCOUNT(1, VM_getresolution);
3069
3070         nr = PRVM_G_FLOAT(OFS_PARM0);
3071
3072
3073         PRVM_G_VECTOR(OFS_RETURN)[0] = video_resolutions[nr][0];
3074         PRVM_G_VECTOR(OFS_RETURN)[1] = video_resolutions[nr][1];
3075         PRVM_G_VECTOR(OFS_RETURN)[2] = 0;       
3076 }
3077
3078 /*
3079 =========
3080 VM_M_keynumtostring
3081
3082 string keynumtostring(float keynum)
3083 =========
3084 */
3085 void VM_M_keynumtostring(void)
3086 {
3087         int keynum;
3088         char *tmp;
3089         VM_SAFEPARMCOUNT(1, VM_M_keynumtostring);
3090
3091         keynum = PRVM_G_FLOAT(OFS_PARM0);
3092
3093         tmp = VM_GetTempString();
3094         
3095         strcpy(tmp, Key_KeynumToString(keynum));
3096
3097         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
3098 }
3099
3100 /*
3101 =========
3102 VM_M_findkeysforcommand
3103
3104 string  findkeysforcommand(string command)
3105
3106 the returned string is an altstring
3107 =========
3108 */
3109 #define NUMKEYS 5 // TODO: merge the constant in keys.c with this one somewhen
3110
3111 void M_FindKeysForCommand(char *command, int *keys);
3112 void VM_M_findkeysforcommand(void)
3113 {
3114         char *cmd, *ret;
3115         int keys[NUMKEYS];
3116         int i;
3117
3118         VM_SAFEPARMCOUNT(1, VM_M_findkeysforcommand);
3119
3120         cmd = PRVM_G_STRING(OFS_PARM0);
3121         
3122         VM_CheckEmptyString(cmd);
3123
3124         (ret = VM_GetTempString())[0] = 0;
3125         
3126         M_FindKeysForCommand(cmd, keys);
3127
3128         for(i = 0; i < NUMKEYS; i++)
3129                 ret = strcat(ret, va(" \'%i\'", keys[i]));
3130
3131         PRVM_G_INT(OFS_RETURN) = PRVM_SetString(ret);
3132 }
3133
3134 /*
3135 =========
3136 VM_M_gethostcachecount
3137
3138 float   gethostcachevalue(float type)
3139 =========
3140 */
3141 /*
3142         type:
3143 0       hostcachecount
3144 1       masterquerycount
3145 2       masterreplycount
3146 3       serverquerycount
3147 4       serverreplycount
3148 */
3149 void VM_M_gethostcachevalue( void )
3150 {
3151         int type;
3152         VM_SAFEPARMCOUNT ( 1, VM_M_gethostcachevalue );
3153
3154         PRVM_G_FLOAT( OFS_RETURN ) = 0;
3155
3156         type = PRVM_G_FLOAT( OFS_PARM0 );
3157         if( type < 0 || type > 4 )
3158                 Con_Printf( "VM_M_gethostcachevalue: bad type %i!\n", type );
3159         else switch(type)
3160         {
3161         case 0:
3162                 PRVM_G_FLOAT ( OFS_RETURN ) = hostCacheCount;
3163                 return;
3164         case 1:
3165                 PRVM_G_FLOAT ( OFS_RETURN ) = masterquerycount;
3166                 return;
3167         case 2:
3168                 PRVM_G_FLOAT ( OFS_RETURN ) = masterreplycount;
3169                 return;
3170         case 3:
3171                 PRVM_G_FLOAT ( OFS_RETURN ) = serverquerycount;
3172                 return;
3173         case 4:
3174                 PRVM_G_FLOAT ( OFS_RETURN ) = serverreplycount;
3175                 return;
3176         }
3177 }
3178
3179 /*
3180 =========
3181 VM_M_gethostcachestring
3182
3183 string  gethostcachestring(float type, float hostnr)
3184 =========
3185 */
3186 /*
3187 0       Get CName
3188 1       Get line1
3189 2       Get line2 
3190 */
3191 void VM_M_gethostcachestring(void)
3192 {
3193         int type;
3194         int hostnr;
3195
3196         VM_SAFEPARMCOUNT(2, VM_M_gethostcachestring);
3197
3198         PRVM_G_INT(OFS_RETURN) = 0;
3199
3200         type = PRVM_G_FLOAT(OFS_PARM0);
3201         
3202         if(type < 0 || type > 2)
3203         {
3204                 Con_Print("VM_M_gethostcachestring: bad string type requested!\n");
3205                 return;
3206         }
3207
3208         hostnr = PRVM_G_FLOAT(OFS_PARM1);
3209
3210         if(hostnr < 0 || hostnr >= hostCacheCount)
3211         {
3212                 Con_Print("VM_M_gethostcachestring: bad hostnr passed!\n");
3213                 return;
3214         }
3215
3216         if( type == 0 )
3217                 PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( hostcache[hostnr].cname );
3218         else if( type == 1 )
3219                 PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( hostcache[hostnr].line1 );
3220         else
3221                 PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( hostcache[hostnr].line2 );
3222 }
3223
3224 prvm_builtin_t vm_m_builtins[] = {
3225         0, // to be consistent with the old vm
3226         // common builtings (mostly)
3227         VM_checkextension,
3228         VM_error,
3229         VM_objerror,
3230         VM_print,
3231         VM_bprint,
3232         VM_sprint,
3233         VM_centerprint,
3234         VM_normalize,
3235         VM_vlen,
3236         VM_vectoyaw,    // #10
3237         VM_vectoangles,
3238         VM_random,
3239         VM_localcmd,
3240         VM_cvar,
3241         VM_cvar_set,
3242         VM_dprint,
3243         VM_ftos,
3244         VM_fabs,
3245         VM_vtos,
3246         VM_etos,                // 20
3247         VM_stof,
3248         VM_spawn,
3249         VM_remove,
3250         VM_find,
3251         VM_findfloat,
3252         VM_findchain,
3253         VM_findchainfloat,
3254         VM_precache_file,
3255         VM_precache_sound,
3256         VM_coredump,    // 30
3257         VM_traceon,
3258         VM_traceoff,
3259         VM_eprint,
3260         VM_rint,
3261         VM_floor,
3262         VM_ceil,
3263         VM_nextent,
3264         VM_sin,
3265         VM_cos,
3266         VM_sqrt,                // 40
3267         VM_randomvec,
3268         VM_registercvar,
3269         VM_min,
3270         VM_max,
3271         VM_bound,
3272         VM_pow,
3273         VM_copyentity,
3274         VM_fopen,
3275         VM_fclose,
3276         VM_fgets,               // 50
3277         VM_fputs,
3278         VM_strlen,
3279         VM_strcat,
3280         VM_substring,
3281         VM_stov,
3282         VM_strzone,
3283         VM_strunzone,
3284         VM_tokenize,
3285         VM_argv,
3286         VM_isserver,    // 60
3287         VM_clientcount, 
3288         VM_clientstate, 
3289         VM_clcommand,
3290         VM_changelevel,
3291         VM_localsound,  
3292         VM_getmousepos,
3293         VM_gettime,
3294         VM_loadfromdata,
3295         VM_loadfromfile,
3296         VM_modulo,              // 70
3297         VM_str_cvar,    
3298         VM_crash,
3299         VM_stackdump,   // 73
3300         VM_search_begin,
3301         VM_search_end,
3302         VM_search_getsize,
3303         VM_search_getfilename, // 77
3304         VM_chr, //78
3305         0,0,// 80
3306         e10,                    // 90
3307         e10,                    // 100
3308         e100,                   // 200
3309         e100,                   // 300
3310         e100,                   // 400
3311         // msg functions
3312         VM_WriteByte,
3313         VM_WriteChar,
3314         VM_WriteShort,
3315         VM_WriteLong,
3316         VM_WriteAngle,
3317         VM_WriteCoord,
3318         VM_WriteString,
3319         VM_WriteEntity, // 408
3320         0,
3321         0,                              // 410
3322         e10,                    // 420
3323         e10,                    // 430
3324         e10,                    // 440
3325         e10,                    // 450
3326         // draw functions
3327         VM_iscachedpic,
3328         VM_precache_pic,
3329         VM_freepic,
3330         VM_drawcharacter,
3331         VM_drawstring,
3332         VM_drawpic,
3333         VM_drawfill,    
3334         VM_drawsetcliparea,
3335         VM_drawresetcliparea,
3336         VM_getimagesize,// 460
3337         e10,                    // 470
3338         e10,                    // 480
3339         e10,                    // 490
3340         e10,                    // 500
3341         e100,                   // 600
3342         // menu functions
3343         VM_M_setkeydest,
3344         VM_M_getkeydest,
3345         VM_M_setmousetarget,
3346         VM_M_getmousetarget,
3347         VM_M_callfunction,
3348         VM_M_writetofile,
3349         VM_M_isfunction,
3350         VM_M_getresolution,
3351         VM_M_keynumtostring,
3352         VM_M_findkeysforcommand,// 610
3353         VM_M_gethostcachevalue,
3354         VM_M_gethostcachestring // 612 
3355 };
3356
3357 const int vm_m_numbuiltins = sizeof(vm_m_builtins) / sizeof(prvm_builtin_t);
3358
3359 void VM_M_Cmd_Init(void)
3360 {
3361         VM_Cmd_Init();
3362 }
3363
3364 void VM_M_Cmd_Reset(void)
3365 {
3366         //VM_Cmd_Init();
3367         VM_Cmd_Reset();
3368 }