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