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