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