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