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