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