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
9 ============================================================================
13 checkextension(string)
18 sprint(float clientnum,...[string])
19 centerprint(...[string])
20 vector normalize(vector)
22 float vectoyaw(vector)
23 vector vectoangles(vector)
27 cvar_set (string,string)
33 float stof(...[string])
36 entity find(entity start, .string field, string match)
38 entity findfloat(entity start, .float field, float match)
39 entity findentity(entity start, .entity field, entity match)
41 entity findchain(.string field, string match)
43 entity findchainfloat(.string field, float match)
44 entity findchainentity(.string field, entity match)
46 string precache_file(string)
47 string precache_sound (string sample)
55 entity nextent(entity)
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)
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)
74 string strzone(string s)
76 float tokenize(string s)
81 clientcommand(float client, string s) (for client and menu)
82 changelevel(string map)
83 localsound(string sample)
86 loadfromdata(string data)
87 loadfromfile(string file)
88 float mod(float val, float m)
89 const string str_cvar (string)
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)
98 string chr(float ascii)
100 perhaps only : Menu : WriteMsg
101 ===============================
103 WriteByte(float data, float dest, float desto)
104 WriteChar(float data, float dest, float desto)
105 WriteShort(float data, float dest, float desto)
106 WriteLong(float data, float dest, float desto)
107 WriteAngle(float data, float dest, float desto)
108 WriteCoord(float data, float dest, float desto)
109 WriteString(string data, float dest, float desto)
110 WriteEntity(entity data, float dest, float desto)
112 Client & Menu : draw functions
113 ===============================
115 float iscachedpic(string pic)
116 string precache_pic(string pic)
118 float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
119 float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
120 float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
121 float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
122 drawsetcliparea(float x, float y, float width, float height)
124 vector getimagesize(string pic)
127 ==============================================================================
131 setkeydest(float dest)
133 setmousetarget(float target)
134 float getmousetarget(void)
136 callfunction(...,string function_name)
137 writetofile(float fhandle, entity ent)
138 float isfunction(string function_name)
139 vector getresolution(float number)
140 string keynumtostring(float keynum)
141 string findkeysforcommand(string command)
142 float gethostcachevalue(float type)
143 string gethostcachestring(float type, float hostnr)
148 #include "quakedef.h"
149 #include "progdefs.h"
150 #include "clprogdefs.h"
151 #include "mprogdefs.h"
153 //============================================================================
154 // nice helper macros
156 #ifndef VM_NOPARMCHECK
157 #define VM_SAFEPARMCOUNT(p,f) if(prog->argc != p) PRVM_ERROR(#f " wrong parameter count (" #p " expected ) !\n")
159 #define VM_SAFEPARMCOUNT(p,f)
162 #define VM_RETURN_EDICT(e) (((int *)prog->globals)[OFS_RETURN] = PRVM_EDICT_TO_PROG(e))
164 #define VM_STRINGS_MEMPOOL vm_strings_mempool[PRVM_GetProgNr()]
166 #define e10 0,0,0,0,0,0,0,0,0,0
167 #define e100 e10,e10,e10,e10,e10,e10,e10,e10,e10,e10
168 #define e1000 e100,e100,e100,e100,e100,e100,e100,e100,e100,e100
170 //============================================================================
173 // string zone mempool
174 mempool_t *vm_strings_mempool[PRVM_MAXPROGS];
176 // temp string handling
177 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
178 #define VM_STRINGTEMP_BUFFERS 16
179 #define VM_STRINGTEMP_LENGTH 4096
180 static char vm_string_temp[VM_STRINGTEMP_BUFFERS][VM_STRINGTEMP_LENGTH];
181 static int vm_string_tempindex = 0;
184 #define MAX_VMFILES 256
185 #define MAX_PRVMFILES MAX_VMFILES * PRVM_MAXPROGS
186 #define VM_FILES ((qfile_t**)(vm_files + PRVM_GetProgNr() * MAX_VMFILES))
188 qfile_t *vm_files[MAX_PRVMFILES];
190 // qc fs search handling
191 #define MAX_VMSEARCHES 128
192 #define TOTAL_VMSEARCHES MAX_VMSEARCHES * PRVM_MAXPROGS
193 #define VM_SEARCHLIST ((fssearch_t**)(vm_fssearchlist + PRVM_GetProgNr() * MAX_VMSEARCHES))
195 fssearch_t *vm_fssearchlist[TOTAL_VMSEARCHES];
197 static char *VM_GetTempString(void)
200 s = vm_string_temp[vm_string_tempindex];
201 vm_string_tempindex = (vm_string_tempindex + 1) % VM_STRINGTEMP_BUFFERS;
205 void VM_CheckEmptyString (char *s)
208 PRVM_ERROR ("%s: Bad string", PRVM_NAME);
211 //============================================================================
214 void VM_VarString(int first, char *out, int outlength)
220 outend = out + outlength - 1;
221 for (i = first;i < prog->argc && out < outend;i++)
223 s = PRVM_G_STRING((OFS_PARM0+i*3));
224 while (out < outend && *s)
234 returns true if the extension is supported by the server
236 checkextension(extensionname)
240 // kind of helper function
241 static qboolean checkextension(char *name)
247 for (e = prog->extensionstring;*e;e++)
254 while (*e && *e != ' ')
256 if (e - start == len)
257 if (!strncasecmp(start, name, len))
265 void VM_checkextension (void)
267 VM_SAFEPARMCOUNT(1,VM_checkextension);
269 PRVM_G_FLOAT(OFS_RETURN) = checkextension(PRVM_G_STRING(OFS_PARM0));
276 This is a TERMINAL error, which will kill off the entire prog.
285 char string[VM_STRINGTEMP_LENGTH];
287 VM_VarString(0, string, sizeof(string));
288 Con_Printf("======%S ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
291 ed = PRVM_G_EDICT(prog->self->ofs);
295 PRVM_ERROR ("%s: Program error", PRVM_NAME);
302 Dumps out self, then an error message. The program is aborted and self is
303 removed, but the level can continue.
308 void VM_objerror (void)
311 char string[VM_STRINGTEMP_LENGTH];
313 VM_VarString(0, string, sizeof(string));
314 Con_Printf("======%s OBJECT ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
317 ed = PRVM_G_EDICT (prog->self->ofs);
323 // objerror has to display the object fields -> else call
324 PRVM_ERROR ("VM_objecterror: self not defined !\n");
329 VM_print (actually used only by client and menu)
338 char string[VM_STRINGTEMP_LENGTH];
340 VM_VarString(0, string, sizeof(string));
348 broadcast print to everyone on server
353 void VM_bprint (void)
355 char string[VM_STRINGTEMP_LENGTH];
359 Con_Printf("VM_bprint: game is not server(%s) !\n", PRVM_NAME);
363 VM_VarString(0, string, sizeof(string));
364 SV_BroadcastPrint(string);
369 VM_sprint (menu & client but only if server.active == true)
371 single print to a specific client
373 sprint(float clientnum,...[string])
376 void VM_sprint (void)
380 char string[VM_STRINGTEMP_LENGTH];
382 //find client for this entity
383 clientnum = PRVM_G_FLOAT(OFS_PARM0);
384 if (!sv.active || clientnum < 0 || clientnum >= svs.maxclients || !svs.clients[clientnum].active)
386 Con_Printf("VM_sprint: %s: invalid client or server is not active !\n", PRVM_NAME);
390 client = svs.clients + clientnum;
391 if (!client->netconnection)
393 VM_VarString(1, string, sizeof(string));
394 MSG_WriteChar(&client->message,svc_print);
395 MSG_WriteString(&client->message, string);
402 single print to the screen
404 centerprint(clientent, value)
407 void VM_centerprint (void)
409 char string[VM_STRINGTEMP_LENGTH];
411 VM_VarString(0, string, sizeof(string));
412 SCR_CenterPrint(string);
419 vector normalize(vector)
422 void VM_normalize (void)
428 VM_SAFEPARMCOUNT(1,VM_normalize);
430 value1 = PRVM_G_VECTOR(OFS_PARM0);
432 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
436 newvalue[0] = newvalue[1] = newvalue[2] = 0;
440 newvalue[0] = value1[0] * new;
441 newvalue[1] = value1[1] * new;
442 newvalue[2] = value1[2] * new;
445 VectorCopy (newvalue, PRVM_G_VECTOR(OFS_RETURN));
460 VM_SAFEPARMCOUNT(1,VM_vlen);
462 value1 = PRVM_G_VECTOR(OFS_PARM0);
464 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
467 PRVM_G_FLOAT(OFS_RETURN) = new;
474 float vectoyaw(vector)
477 void VM_vectoyaw (void)
482 VM_SAFEPARMCOUNT(1,VM_vectoyaw);
484 value1 = PRVM_G_VECTOR(OFS_PARM0);
486 if (value1[1] == 0 && value1[0] == 0)
490 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
495 PRVM_G_FLOAT(OFS_RETURN) = yaw;
503 vector vectoangles(vector)
506 void VM_vectoangles (void)
512 VM_SAFEPARMCOUNT(1,VM_vectoangles);
514 value1 = PRVM_G_VECTOR(OFS_PARM0);
516 if (value1[1] == 0 && value1[0] == 0)
526 // LordHavoc: optimized a bit
529 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
533 else if (value1[1] > 0)
538 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
539 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
544 PRVM_G_FLOAT(OFS_RETURN+0) = pitch;
545 PRVM_G_FLOAT(OFS_RETURN+1) = yaw;
546 PRVM_G_FLOAT(OFS_RETURN+2) = 0;
553 Returns a number from 0<= num < 1
558 void VM_random (void)
562 VM_SAFEPARMCOUNT(0,VM_random);
564 num = (rand ()&0x7fff) / ((float)0x7fff);
566 PRVM_G_FLOAT(OFS_RETURN) = num;
573 Each entity can have eight independant sound sources, like voice,
576 Channel 0 is an auto-allocate channel, the others override anything
577 already running on that entity/channel pair.
579 An attenuation of 0 will play full volume everywhere in the level.
580 Larger attenuations will drop off.
593 entity = G_EDICT(OFS_PARM0);
594 channel = G_FLOAT(OFS_PARM1);
595 sample = G_STRING(OFS_PARM2);
596 volume = G_FLOAT(OFS_PARM3) * 255;
597 attenuation = G_FLOAT(OFS_PARM4);
599 if (volume < 0 || volume > 255)
600 Host_Error ("SV_StartSound: volume = %i", volume);
602 if (attenuation < 0 || attenuation > 4)
603 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
605 if (channel < 0 || channel > 7)
606 Host_Error ("SV_StartSound: channel = %i", channel);
608 SV_StartSound (entity, channel, sample, volume, attenuation);
616 localsound(string sample)
619 void VM_localsound(void)
623 VM_SAFEPARMCOUNT(1,VM_localsound);
625 s = PRVM_G_STRING(OFS_PARM0);
627 if(!S_LocalSound(s, true))
629 Con_Printf("VM_localsound: Failed to play %s for %s !\n", s, PRVM_NAME);
630 PRVM_G_FLOAT(OFS_RETURN) = -4;
634 PRVM_G_FLOAT(OFS_RETURN) = 1;
646 PRVM_ERROR ("%s: break statement", PRVM_NAME);
649 //============================================================================
655 Sends text over to the client's execution buffer
657 [localcmd (string) or]
661 void VM_localcmd (void)
663 VM_SAFEPARMCOUNT(1,VM_localcmd);
665 Cbuf_AddText(PRVM_G_STRING(OFS_PARM0));
677 VM_SAFEPARMCOUNT(1,VM_cvar);
679 PRVM_G_FLOAT(OFS_RETURN) = Cvar_VariableValue(PRVM_G_STRING(OFS_PARM0));
686 const string str_cvar (string)
689 void VM_str_cvar(void)
692 const char *cvar_string;
693 VM_SAFEPARMCOUNT(1,VM_str_cvar);
695 name = PRVM_G_STRING(OFS_PARM0);
698 PRVM_ERROR("VM_str_cvar: %s: null string\n", PRVM_NAME);
700 VM_CheckEmptyString(name);
702 out = VM_GetTempString();
704 cvar_string = Cvar_VariableString(name);
706 strcpy(out, cvar_string);
708 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(out);
715 void cvar_set (string,string)
718 void VM_cvar_set (void)
720 VM_SAFEPARMCOUNT(2,VM_cvar_set);
722 Cvar_Set(PRVM_G_STRING(OFS_PARM0), PRVM_G_STRING(OFS_PARM1));
732 void VM_dprint (void)
734 char string[VM_STRINGTEMP_LENGTH];
735 if (developer.integer)
737 VM_VarString(0, string, sizeof(string));
738 Con_Printf("%s: %s", PRVM_NAME, string);
755 VM_SAFEPARMCOUNT(1, VM_ftos);
757 v = PRVM_G_FLOAT(OFS_PARM0);
759 s = VM_GetTempString();
760 if ((float)((int)v) == v)
761 sprintf(s, "%i", (int)v);
764 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
779 VM_SAFEPARMCOUNT(1,VM_fabs);
781 v = PRVM_G_FLOAT(OFS_PARM0);
782 PRVM_G_FLOAT(OFS_RETURN) = fabs(v);
797 VM_SAFEPARMCOUNT(1,VM_vtos);
799 s = VM_GetTempString();
800 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]);
801 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
816 VM_SAFEPARMCOUNT(1, VM_etos);
818 s = VM_GetTempString();
819 sprintf (s, "entity %i", PRVM_G_EDICTNUM(OFS_PARM0));
820 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
827 float stof(...[string])
832 char string[VM_STRINGTEMP_LENGTH];
833 VM_VarString(0, string, sizeof(string));
834 PRVM_G_FLOAT(OFS_RETURN) = atof(string);
848 prog->xfunction->builtinsprofile += 20;
849 ed = PRVM_ED_Alloc();
861 void VM_remove (void)
864 prog->xfunction->builtinsprofile += 20;
866 VM_SAFEPARMCOUNT(1, VM_remove);
868 ed = PRVM_G_EDICT(OFS_PARM0);
869 // if (ed == prog->edicts)
870 // PRVM_ERROR ("remove: tried to remove world\n");
871 // if (PRVM_NUM_FOR_EDICT(ed) <= sv.maxclients)
872 // Host_Error("remove: tried to remove a client\n");
880 entity find(entity start, .string field, string match)
891 VM_SAFEPARMCOUNT(3,VM_find);
893 e = PRVM_G_EDICTNUM(OFS_PARM0);
894 f = PRVM_G_INT(OFS_PARM1);
895 s = PRVM_G_STRING(OFS_PARM2);
899 // return reserved edict 0 (could be used for whatever the prog wants)
900 VM_RETURN_EDICT(prog->edicts);
904 for (e++ ; e < prog->num_edicts ; e++)
906 prog->xfunction->builtinsprofile++;
907 ed = PRVM_EDICT_NUM(e);
910 t = PRVM_E_STRING(ed,f);
920 VM_RETURN_EDICT(prog->edicts);
927 entity findfloat(entity start, .float field, float match)
928 entity findentity(entity start, .entity field, entity match)
931 // LordHavoc: added this for searching float, int, and entity reference fields
932 void VM_findfloat (void)
939 VM_SAFEPARMCOUNT(3,VM_findfloat);
941 e = PRVM_G_EDICTNUM(OFS_PARM0);
942 f = PRVM_G_INT(OFS_PARM1);
943 s = PRVM_G_FLOAT(OFS_PARM2);
945 for (e++ ; e < prog->num_edicts ; e++)
947 prog->xfunction->builtinsprofile++;
948 ed = PRVM_EDICT_NUM(e);
951 if (PRVM_E_FLOAT(ed,f) == s)
958 VM_RETURN_EDICT(prog->edicts);
965 entity findchain(.string field, string match)
968 int PRVM_ED_FindFieldOffset(const char *field);
969 // chained search for strings in entity fields
970 // entity(.string field, string match) findchain = #402;
971 void VM_findchain (void)
977 prvm_edict_t *ent, *chain;
979 VM_SAFEPARMCOUNT(2,VM_findchain);
981 // is the same like !(prog->flag & PRVM_FE_CHAIN) - even if the operator precedence is another
982 if(!prog->flag & PRVM_FE_CHAIN)
983 PRVM_ERROR("VM_findchain: %s doesnt have a chain field !\n", PRVM_NAME);
985 chain_of = PRVM_ED_FindFieldOffset ("chain");
987 chain = prog->edicts;
989 f = PRVM_G_INT(OFS_PARM0);
990 s = PRVM_G_STRING(OFS_PARM1);
993 VM_RETURN_EDICT(prog->edicts);
997 ent = PRVM_NEXT_EDICT(prog->edicts);
998 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
1000 prog->xfunction->builtinsprofile++;
1003 t = PRVM_E_STRING(ent,f);
1009 PRVM_E_FLOAT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain);
1013 VM_RETURN_EDICT(chain);
1020 entity findchainfloat(.string field, float match)
1021 entity findchainentity(.string field, entity match)
1024 // LordHavoc: chained search for float, int, and entity reference fields
1025 // entity(.string field, float match) findchainfloat = #403;
1026 void VM_findchainfloat (void)
1032 prvm_edict_t *ent, *chain;
1034 VM_SAFEPARMCOUNT(2, VM_findchainfloat);
1036 if(!prog->flag & PRVM_FE_CHAIN)
1037 PRVM_ERROR("VM_findchainfloat: %s doesnt have a chain field !\n", PRVM_NAME);
1039 chain_of = PRVM_ED_FindFieldOffset ("chain");
1041 chain = (prvm_edict_t *)prog->edicts;
1043 f = PRVM_G_INT(OFS_PARM0);
1044 s = PRVM_G_FLOAT(OFS_PARM1);
1046 ent = PRVM_NEXT_EDICT(prog->edicts);
1047 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
1049 prog->xfunction->builtinsprofile++;
1052 if (E_FLOAT(ent,f) != s)
1055 PRVM_E_FLOAT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain);
1059 VM_RETURN_EDICT(chain);
1066 string precache_file(string)
1069 void VM_precache_file (void)
1070 { // precache_file is only used to copy files with qcc, it does nothing
1071 VM_SAFEPARMCOUNT(1,VM_precache_file);
1073 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1080 used instead of the other VM_precache_* functions in the builtin list
1084 void VM_precache_error (void)
1086 PRVM_ERROR ("PF_Precache_*: Precache can only be done in spawn functions");
1093 string precache_sound (string sample)
1096 void VM_precache_sound (void)
1100 VM_SAFEPARMCOUNT(1, VM_precache_sound);
1102 s = PRVM_G_STRING(OFS_PARM0);
1103 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1104 VM_CheckEmptyString (s);
1106 if(!S_PrecacheSound(s,true, true, true))
1107 Con_Printf("VM_precache_sound: Failed to load %s for %s\n", s, PRVM_NAME);
1117 void VM_coredump (void)
1119 VM_SAFEPARMCOUNT(0,VM_coredump);
1121 Cbuf_AddText("prvm_edicts ");
1122 Cbuf_AddText(PRVM_NAME);
1133 void PRVM_StackTrace(void);
1134 void VM_stackdump (void)
1136 VM_SAFEPARMCOUNT(0, VM_stackdump);
1151 VM_SAFEPARMCOUNT(0, VM_crash);
1153 PRVM_ERROR("Crash called by %s\n",PRVM_NAME);
1163 void VM_traceon (void)
1165 VM_SAFEPARMCOUNT(0,VM_traceon);
1177 void VM_traceoff (void)
1179 VM_SAFEPARMCOUNT(0,VM_traceoff);
1181 prog->trace = false;
1191 void VM_eprint (void)
1193 VM_SAFEPARMCOUNT(1,VM_eprint);
1195 PRVM_ED_PrintNum (PRVM_G_EDICTNUM(OFS_PARM0));
1209 VM_SAFEPARMCOUNT(1,VM_rint);
1211 f = PRVM_G_FLOAT(OFS_PARM0);
1213 PRVM_G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1215 PRVM_G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1225 void VM_floor (void)
1227 VM_SAFEPARMCOUNT(1,VM_floor);
1229 PRVM_G_FLOAT(OFS_RETURN) = floor(PRVM_G_FLOAT(OFS_PARM0));
1241 VM_SAFEPARMCOUNT(1,VM_ceil);
1243 PRVM_G_FLOAT(OFS_RETURN) = ceil(PRVM_G_FLOAT(OFS_PARM0));
1251 entity nextent(entity)
1254 void VM_nextent (void)
1259 i = PRVM_G_EDICTNUM(OFS_PARM0);
1262 prog->xfunction->builtinsprofile++;
1264 if (i == prog->num_edicts)
1266 VM_RETURN_EDICT(prog->edicts);
1269 ent = PRVM_EDICT_NUM(i);
1270 if (!ent->p.e->free)
1272 VM_RETURN_EDICT(ent);
1279 ===============================================================================
1282 used only for client and menu
1283 severs uses VM_SV_...
1285 Write*(* data, float type, float to)
1287 ===============================================================================
1290 #define MSG_BROADCAST 0 // unreliable to all
1291 #define MSG_ONE 1 // reliable to one (msg_entity)
1292 #define MSG_ALL 2 // reliable to all
1293 #define MSG_INIT 3 // write to the init string
1295 sizebuf_t *VM_WriteDest (void)
1301 PRVM_ERROR("VM_WriteDest: game is not server (%s)\n", PRVM_NAME);
1303 dest = G_FLOAT(OFS_PARM1);
1307 return &sv.datagram;
1310 destclient = (int) PRVM_G_FLOAT(OFS_PARM2);
1311 if (destclient < 0 || destclient >= svs.maxclients || !svs.clients[destclient].active)
1312 PRVM_ERROR("VM_clientcommand: %s: invalid client !\n", PRVM_NAME);
1314 return &svs.clients[destclient].message;
1317 return &sv.reliable_datagram;
1323 PRVM_ERROR ("WriteDest: bad destination");
1330 void VM_WriteByte (void)
1332 MSG_WriteByte (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1335 void VM_WriteChar (void)
1337 MSG_WriteChar (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1340 void VM_WriteShort (void)
1342 MSG_WriteShort (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1345 void VM_WriteLong (void)
1347 MSG_WriteLong (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1350 void VM_WriteAngle (void)
1352 MSG_WriteAngle (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0), sv.protocol);
1355 void VM_WriteCoord (void)
1357 MSG_WriteCoord (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0), sv.protocol);
1360 void VM_WriteString (void)
1362 MSG_WriteString (VM_WriteDest(), PRVM_G_STRING(OFS_PARM0));
1365 void VM_WriteEntity (void)
1367 MSG_WriteShort (VM_WriteDest(), PRVM_G_EDICTNUM(OFS_PARM0));
1370 //=============================================================================
1377 changelevel(string map)
1380 void VM_changelevel (void)
1384 VM_SAFEPARMCOUNT(1, VM_changelevel);
1388 Con_Printf("VM_changelevel: game is not server (%s)\n", PRVM_NAME);
1392 // make sure we don't issue two changelevels
1393 if (svs.changelevel_issued)
1395 svs.changelevel_issued = true;
1397 s = G_STRING(OFS_PARM0);
1398 Cbuf_AddText (va("changelevel %s\n",s));
1410 VM_SAFEPARMCOUNT(1,VM_sin);
1411 PRVM_G_FLOAT(OFS_RETURN) = sin(PRVM_G_FLOAT(OFS_PARM0));
1422 VM_SAFEPARMCOUNT(1,VM_cos);
1423 PRVM_G_FLOAT(OFS_RETURN) = cos(PRVM_G_FLOAT(OFS_PARM0));
1435 VM_SAFEPARMCOUNT(1,VM_sqrt);
1436 PRVM_G_FLOAT(OFS_RETURN) = sqrt(PRVM_G_FLOAT(OFS_PARM0));
1443 Returns a vector of length < 1 and > 0
1448 void VM_randomvec (void)
1453 VM_SAFEPARMCOUNT(0, VM_randomvec);
1458 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1459 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1460 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1462 while (DotProduct(temp, temp) >= 1);
1463 VectorCopy (temp, PRVM_G_VECTOR(OFS_RETURN));
1466 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1467 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1468 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1469 // length returned always > 0
1470 length = (rand()&32766 + 1) * (1.0 / 32767.0) / VectorLength(temp);
1471 VectorScale(temp,length, temp);*/
1472 //VectorCopy(temp, PRVM_G_VECTOR(OFS_RETURN));
1475 //=============================================================================
1481 float registercvar (string name, string value, float flags)
1484 void VM_registercvar (void)
1489 VM_SAFEPARMCOUNT(3,VM_registercvar);
1491 name = PRVM_G_STRING(OFS_PARM0);
1492 value = PRVM_G_STRING(OFS_PARM1);
1493 flags = PRVM_G_FLOAT(OFS_PARM2);
1494 PRVM_G_FLOAT(OFS_RETURN) = 0;
1496 if(flags > CVAR_MAXFLAGSVAL)
1499 // first check to see if it has already been defined
1500 if (Cvar_FindVar (name))
1503 // check for overlap with a command
1504 if (Cmd_Exists (name))
1506 Con_Printf("VM_registercvar: %s is a command\n", name);
1510 Cvar_Get(name, value, 0);
1512 PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1519 returns the minimum of two supplied floats
1521 float min(float a, float b, ...[float])
1526 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1527 if (prog->argc == 2)
1528 PRVM_G_FLOAT(OFS_RETURN) = min(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1529 else if (prog->argc >= 3)
1532 float f = PRVM_G_FLOAT(OFS_PARM0);
1533 for (i = 1;i < prog->argc;i++)
1534 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) < f)
1535 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1536 PRVM_G_FLOAT(OFS_RETURN) = f;
1539 PRVM_ERROR("VM_min: %s must supply at least 2 floats\n", PRVM_NAME);
1546 returns the maximum of two supplied floats
1548 float max(float a, float b, ...[float])
1553 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1554 if (prog->argc == 2)
1555 PRVM_G_FLOAT(OFS_RETURN) = max(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1556 else if (prog->argc >= 3)
1559 float f = PRVM_G_FLOAT(OFS_PARM0);
1560 for (i = 1;i < prog->argc;i++)
1561 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) > f)
1562 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1563 G_FLOAT(OFS_RETURN) = f;
1566 PRVM_ERROR("VM_max: %s must supply at least 2 floats\n", PRVM_NAME);
1573 returns number bounded by supplied range
1575 float bound(float min, float value, float max)
1578 void VM_bound (void)
1580 VM_SAFEPARMCOUNT(3,VM_bound);
1581 PRVM_G_FLOAT(OFS_RETURN) = bound(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2));
1588 returns a raised to power b
1590 float pow(float a, float b)
1595 VM_SAFEPARMCOUNT(2,VM_pow);
1596 PRVM_G_FLOAT(OFS_RETURN) = pow(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1603 copies data from one entity to another
1605 copyentity(entity src, entity dst)
1608 void VM_copyentity (void)
1610 prvm_edict_t *in, *out;
1611 VM_SAFEPARMCOUNT(2,VM_copyentity);
1612 in = PRVM_G_EDICT(OFS_PARM0);
1613 out = PRVM_G_EDICT(OFS_PARM1);
1614 memcpy(out->v, in->v, prog->progs->entityfields * 4);
1621 sets the color of a client and broadcasts the update to all connected clients
1623 setcolor(clientent, value)
1626 /*void PF_setcolor (void)
1632 entnum = G_EDICTNUM(OFS_PARM0);
1633 i = G_FLOAT(OFS_PARM1);
1635 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1637 Con_Print("tried to setcolor a non-client\n");
1641 client = svs.clients + entnum-1;
1642 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
1645 client->old_colors = i;
1646 client->edict->v->team = (i & 15) + 1;
1648 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1649 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
1650 MSG_WriteByte (&sv.reliable_datagram, i);
1653 void VM_Files_Init(void)
1655 memset(VM_FILES, 0, sizeof(qfile_t*[MAX_VMFILES]));
1658 void VM_Files_CloseAll(void)
1661 for (i = 0;i < MAX_VMFILES;i++)
1664 FS_Close(VM_FILES[i]);
1665 //VM_FILES[i] = NULL;
1667 memset(VM_FILES,0,sizeof(qfile_t*[MAX_VMFILES])); // this should be faster (is it ?)
1674 float fopen(string filename, float mode)
1677 // float(string filename, float mode) fopen = #110;
1678 // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE),
1679 // returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
1683 char *modestring, *filename;
1685 VM_SAFEPARMCOUNT(2,VM_fopen);
1687 for (filenum = 0;filenum < MAX_VMFILES;filenum++)
1688 if (VM_FILES[filenum] == NULL)
1690 if (filenum >= MAX_VMFILES)
1692 Con_Printf("VM_fopen: %s ran out of file handles (%i)\n", PRVM_NAME, MAX_VMFILES);
1693 PRVM_G_FLOAT(OFS_RETURN) = -2;
1696 mode = PRVM_G_FLOAT(OFS_PARM1);
1699 case 0: // FILE_READ
1702 case 1: // FILE_APPEND
1705 case 2: // FILE_WRITE
1709 Con_Printf("VM_fopen: %s no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", PRVM_NAME, mode);
1710 PRVM_G_FLOAT(OFS_RETURN) = -3;
1713 filename = PRVM_G_STRING(OFS_PARM0);
1714 // .. is parent directory on many platforms
1715 // / is parent directory on Amiga
1716 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
1717 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
1718 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
1720 Con_Printf("VM_fopen: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
1721 PRVM_G_FLOAT(OFS_RETURN) = -4;
1724 VM_FILES[filenum] = FS_Open(va("data/%s", filename), modestring, false);
1725 if (VM_FILES[filenum] == NULL && mode == 0)
1726 VM_FILES[filenum] = FS_Open(va("%s", filename), modestring, false);
1728 if (VM_FILES[filenum] == NULL)
1729 PRVM_G_FLOAT(OFS_RETURN) = -1;
1731 PRVM_G_FLOAT(OFS_RETURN) = filenum;
1738 fclose(float fhandle)
1741 //void(float fhandle) fclose = #111; // closes a file
1742 void VM_fclose(void)
1746 VM_SAFEPARMCOUNT(1,VM_fclose);
1748 filenum = PRVM_G_FLOAT(OFS_PARM0);
1749 if (filenum < 0 || filenum >= MAX_VMFILES)
1751 Con_Printf("VM_fclose: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1754 if (VM_FILES[filenum] == NULL)
1756 Con_Printf("VM_fclose: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1759 FS_Close(VM_FILES[filenum]);
1760 VM_FILES[filenum] = NULL;
1767 string fgets(float fhandle)
1770 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
1774 static char string[VM_STRINGTEMP_LENGTH];
1777 VM_SAFEPARMCOUNT(1,VM_fgets);
1779 filenum = PRVM_G_FLOAT(OFS_PARM0);
1780 if (filenum < 0 || filenum >= MAX_VMFILES)
1782 Con_Printf("VM_fgets: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1785 if (VM_FILES[filenum] == NULL)
1787 Con_Printf("VM_fgets: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1793 c = FS_Getc(VM_FILES[filenum]);
1794 if (c == '\r' || c == '\n' || c < 0)
1796 if (end < VM_STRINGTEMP_LENGTH - 1)
1800 // remove \n following \r
1802 c = FS_Getc(VM_FILES[filenum]);
1803 if (developer.integer)
1804 Con_Printf("fgets: %s: %s\n", PRVM_NAME, string);
1806 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1808 PRVM_G_INT(OFS_RETURN) = 0;
1815 fputs(float fhandle, string s)
1818 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
1822 char string[VM_STRINGTEMP_LENGTH];
1825 VM_SAFEPARMCOUNT(2,VM_fputs);
1827 filenum = PRVM_G_FLOAT(OFS_PARM0);
1828 if (filenum < 0 || filenum >= MAX_VMFILES)
1830 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1833 if (VM_FILES[filenum] == NULL)
1835 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1838 VM_VarString(1, string, sizeof(string));
1839 if ((stringlength = strlen(string)))
1840 FS_Write(VM_FILES[filenum], string, stringlength);
1841 if (developer.integer)
1842 Con_Printf("fputs: %s: %s\n", PRVM_NAME, string);
1849 float strlen(string s)
1852 //float(string s) strlen = #114; // returns how many characters are in a string
1853 void VM_strlen(void)
1857 VM_SAFEPARMCOUNT(1,VM_strlen);
1859 s = PRVM_G_STRING(OFS_PARM0);
1861 PRVM_G_FLOAT(OFS_RETURN) = strlen(s);
1863 PRVM_G_FLOAT(OFS_RETURN) = 0;
1870 string strcat(string,string,...[string])
1873 //string(string s1, string s2) strcat = #115;
1874 // concatenates two strings (for example "abc", "def" would return "abcdef")
1875 // and returns as a tempstring
1876 void VM_strcat(void)
1881 PRVM_ERROR("VM_strcat wrong parameter count (min. 2 expected ) !\n");
1883 s = VM_GetTempString();
1884 VM_VarString(0, s, VM_STRINGTEMP_LENGTH);
1885 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
1892 string substring(string s, float start, float length)
1895 // string(string s, float start, float length) substring = #116;
1896 // returns a section of a string as a tempstring
1897 void VM_substring(void)
1899 int i, start, length;
1902 VM_SAFEPARMCOUNT(3,VM_substring);
1904 string = VM_GetTempString();
1905 s = PRVM_G_STRING(OFS_PARM0);
1906 start = PRVM_G_FLOAT(OFS_PARM1);
1907 length = PRVM_G_FLOAT(OFS_PARM2);
1910 for (i = 0;i < start && *s;i++, s++);
1911 for (i = 0;i < VM_STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
1914 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1921 vector stov(string s)
1924 //vector(string s) stov = #117; // returns vector value from a string
1927 char string[VM_STRINGTEMP_LENGTH];
1929 VM_SAFEPARMCOUNT(1,VM_stov);
1931 VM_VarString(0, string, sizeof(string));
1932 Math_atov(string, PRVM_G_VECTOR(OFS_RETURN));
1939 string strzone(string s)
1942 //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)
1943 void VM_strzone(void)
1947 VM_SAFEPARMCOUNT(1,VM_strzone);
1949 in = PRVM_G_STRING(OFS_PARM0);
1950 out = Mem_Alloc(VM_STRINGS_MEMPOOL, strlen(in) + 1);
1952 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(out);
1962 //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!!!)
1963 void VM_strunzone(void)
1965 VM_SAFEPARMCOUNT(1,VM_strunzone);
1967 Mem_Free(PRVM_G_STRING(OFS_PARM0));
1972 VM_command (used by client and menu)
1974 clientcommand(float client, string s) (for client and menu)
1977 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
1978 //this function originally written by KrimZon, made shorter by LordHavoc
1979 void VM_clcommand (void)
1981 client_t *temp_client;
1984 VM_SAFEPARMCOUNT(2,VM_clcommand);
1986 i = PRVM_G_FLOAT(OFS_PARM0);
1987 if (!sv.active || i < 0 || i >= svs.maxclients || !svs.clients[i].active)
1989 Con_Printf("VM_clientcommand: %s: invalid client/server is not active !\n", PRVM_NAME);
1993 temp_client = host_client;
1994 host_client = svs.clients + i;
1995 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
1996 host_client = temp_client;
2004 float tokenize(string s)
2007 //float(string s) tokenize = #441;
2008 // takes apart a string into individal words (access them with argv), returns how many
2009 // this function originally written by KrimZon, made shorter by LordHavoc
2010 static char **tokens = NULL;
2011 static int max_tokens, num_tokens = 0;
2012 void VM_tokenize (void)
2017 VM_SAFEPARMCOUNT(1,VM_tokenize);
2019 str = PRVM_G_STRING(OFS_PARM0);
2024 for (i=0;i<num_tokens;i++)
2030 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2031 max_tokens = strlen(str);
2033 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2035 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2036 strcpy(tokens[num_tokens], com_token);
2039 PRVM_G_FLOAT(OFS_RETURN) = num_tokens;
2046 string argv(float n)
2049 //string(float n) argv = #442;
2050 // returns a word from the tokenized string (returns nothing for an invalid index)
2051 // this function originally written by KrimZon, made shorter by LordHavoc
2056 VM_SAFEPARMCOUNT(1,VM_argv);
2058 token_num = PRVM_G_FLOAT(OFS_PARM0);
2059 if (token_num >= 0 && token_num < num_tokens)
2060 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tokens[token_num]);
2062 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
2066 //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)
2067 void PF_setattachment (void)
2069 edict_t *e = G_EDICT(OFS_PARM0);
2070 edict_t *tagentity = G_EDICT(OFS_PARM1);
2071 char *tagname = G_STRING(OFS_PARM2);
2076 if (tagentity == NULL)
2077 tagentity = sv.edicts;
2079 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
2081 v->edict = EDICT_TO_PROG(tagentity);
2083 v = GETEDICTFIELDVALUE(e, eval_tag_index);
2086 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
2088 modelindex = (int)tagentity->v->modelindex;
2089 if (modelindex >= 0 && modelindex < MAX_MODELS)
2091 model = sv.models[modelindex];
2092 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
2093 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
2094 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
2096 // FIXME: use a model function to get tag info (need to handle skeletal)
2097 if (v->_float == 0 && model->alias.aliasnum_tags)
2098 for (i = 0;i < model->alias.aliasnum_tags;i++)
2099 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
2102 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);
2105 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));
2116 void VM_isserver(void)
2118 VM_SAFEPARMCOUNT(0,VM_serverstate);
2120 PRVM_G_FLOAT(OFS_RETURN) = sv.active;
2130 void VM_clientcount(void)
2132 VM_SAFEPARMCOUNT(0,VM_clientcount);
2134 PRVM_G_FLOAT(OFS_RETURN) = svs.maxclients;
2144 void VM_clientstate(void)
2146 VM_SAFEPARMCOUNT(0,VM_clientstate);
2148 PRVM_G_FLOAT(OFS_RETURN) = cls.state;
2155 float getostype(void)
2157 */ // not used at the moment -> not included in the common list
2158 void VM_getostype(void)
2160 VM_SAFEPARMCOUNT(0,VM_getostype);
2165 OS_MAC - not supported
2169 PRVM_G_FLOAT(OFS_RETURN) = 0;
2171 PRVM_G_FLOAT(OFS_RETURN) = 2;
2173 PRVM_G_FLOAT(OFS_RETURN) = 1;
2181 vector getmousepos()
2184 void VM_getmousepos(void)
2187 VM_SAFEPARMCOUNT(0,VM_getmousepos);
2189 PRVM_G_VECTOR(OFS_RETURN)[0] = in_mouse_x;
2190 PRVM_G_VECTOR(OFS_RETURN)[1] = in_mouse_y;
2191 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2201 void VM_gettime(void)
2203 VM_SAFEPARMCOUNT(0,VM_gettime);
2205 PRVM_G_FLOAT(OFS_RETURN) = (float) *prog->time;
2212 loadfromdata(string data)
2215 void VM_loadfromdata(void)
2217 VM_SAFEPARMCOUNT(1,VM_loadentsfromfile);
2219 PRVM_ED_LoadFromFile(PRVM_G_STRING(OFS_PARM0));
2226 loadfromfile(string file)
2229 void VM_loadfromfile(void)
2234 VM_SAFEPARMCOUNT(1,VM_loadfromfile);
2236 filename = PRVM_G_STRING(OFS_PARM0);
2237 // .. is parent directory on many platforms
2238 // / is parent directory on Amiga
2239 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2240 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2241 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2243 Con_Printf("VM_loadfromfile: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
2244 PRVM_G_FLOAT(OFS_RETURN) = -4;
2248 // not conform with VM_fopen
2249 data = FS_LoadFile(filename, tempmempool, false);
2251 PRVM_G_FLOAT(OFS_RETURN) = -1;
2253 PRVM_ED_LoadFromFile(data);
2264 float mod(float val, float m)
2267 void VM_modulo(void)
2270 VM_SAFEPARMCOUNT(2,VM_module);
2272 val = (int) PRVM_G_FLOAT(OFS_PARM0);
2273 m = (int) PRVM_G_FLOAT(OFS_PARM1);
2275 PRVM_G_FLOAT(OFS_RETURN) = (float) (val % m);
2278 void VM_Search_Init(void)
2280 memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
2283 void VM_Search_Reset(void)
2286 // reset the fssearch list
2287 for(i = 0; i < MAX_VMSEARCHES; i++)
2288 if(VM_SEARCHLIST[i])
2289 FS_FreeSearch(VM_SEARCHLIST[i]);
2290 memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
2297 float search_begin(string pattern, float caseinsensitive, float quiet)
2300 void VM_search_begin(void)
2304 int caseinsens, quiet;
2306 VM_SAFEPARMCOUNT(3, VM_search_begin);
2308 pattern = PRVM_G_STRING(OFS_PARM0);
2310 VM_CheckEmptyString(pattern);
2312 caseinsens = PRVM_G_FLOAT(OFS_PARM1);
2313 quiet = PRVM_G_FLOAT(OFS_PARM2);
2315 for(handle = 0; handle < MAX_VMSEARCHES; handle++)
2316 if(!VM_SEARCHLIST[handle])
2319 if(handle >= MAX_VMSEARCHES)
2321 Con_Printf("VM_search_begin: %s ran out of search handles (%i)\n", PRVM_NAME, MAX_VMSEARCHES);
2322 PRVM_G_FLOAT(OFS_RETURN) = -2;
2326 if(!(VM_SEARCHLIST[handle] = FS_Search(pattern,caseinsens, quiet)))
2327 PRVM_G_FLOAT(OFS_RETURN) = -1;
2329 PRVM_G_FLOAT(OFS_RETURN) = handle;
2336 void search_end(float handle)
2339 void VM_search_end(void)
2342 VM_SAFEPARMCOUNT(1, VM_search_end);
2344 handle = PRVM_G_FLOAT(OFS_PARM0);
2346 if(handle < 0 || handle >= MAX_VMSEARCHES)
2348 Con_Printf("VM_search_end: invalid handle %i used in %s\n", handle, PRVM_NAME);
2351 if(VM_SEARCHLIST[handle] == NULL)
2353 Con_Printf("VM_search_end: no such handle %i in %s\n", handle, PRVM_NAME);
2357 FS_FreeSearch(VM_SEARCHLIST[handle]);
2358 VM_SEARCHLIST[handle] = NULL;
2365 float search_getsize(float handle)
2368 void VM_search_getsize(void)
2371 VM_SAFEPARMCOUNT(1, VM_M_search_getsize);
2373 handle = PRVM_G_FLOAT(OFS_PARM0);
2375 if(handle < 0 || handle >= MAX_VMSEARCHES)
2377 Con_Printf("VM_search_getsize: invalid handle %i used in %s\n", handle, PRVM_NAME);
2380 if(VM_SEARCHLIST[handle] == NULL)
2382 Con_Printf("VM_search_getsize: no such handle %i in %s\n", handle, PRVM_NAME);
2386 PRVM_G_FLOAT(OFS_RETURN) = VM_SEARCHLIST[handle]->numfilenames;
2391 VM_search_getfilename
2393 string search_getfilename(float handle, float num)
2396 void VM_search_getfilename(void)
2398 int handle, filenum;
2400 VM_SAFEPARMCOUNT(2, VM_search_getfilename);
2402 handle = PRVM_G_FLOAT(OFS_PARM0);
2403 filenum = PRVM_G_FLOAT(OFS_PARM1);
2405 if(handle < 0 || handle >= MAX_VMSEARCHES)
2407 Con_Printf("VM_search_getfilename: invalid handle %i used in %s\n", handle, PRVM_NAME);
2410 if(VM_SEARCHLIST[handle] == NULL)
2412 Con_Printf("VM_search_getfilename: no such handle %i in %s\n", handle, PRVM_NAME);
2415 if(filenum < 0 || filenum >= VM_SEARCHLIST[handle]->numfilenames)
2417 Con_Printf("VM_search_getfilename: invalid filenum %i in %s\n", filenum, PRVM_NAME);
2421 tmp = VM_GetTempString();
2422 strcpy(tmp, VM_SEARCHLIST[handle]->filenames[filenum]);
2424 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
2431 string chr(float ascii)
2437 VM_SAFEPARMCOUNT(1, VM_chr);
2439 tmp = VM_GetTempString();
2440 tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0);
2443 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
2446 //=============================================================================
2447 // Draw builtins (client & menu)
2453 float iscachedpic(string pic)
2456 void VM_iscachedpic(void)
2458 VM_SAFEPARMCOUNT(1,VM_iscachedpic);
2460 // drawq hasnt such a function, thus always return true
2461 PRVM_G_FLOAT(OFS_RETURN) = TRUE;
2468 string precache_pic(string pic)
2471 void VM_precache_pic(void)
2475 VM_SAFEPARMCOUNT(1, VM_precache_pic);
2477 s = PRVM_G_STRING(OFS_PARM0);
2478 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
2481 PRVM_ERROR ("VM_precache_pic: %s: NULL\n", PRVM_NAME);
2483 VM_CheckEmptyString (s);
2485 if(!Draw_CachePic(s))
2486 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
2496 void VM_freepic(void)
2500 VM_SAFEPARMCOUNT(1,VM_freepic);
2502 s = PRVM_G_STRING(OFS_PARM0);
2505 PRVM_ERROR ("VM_freepic: %s: NULL\n");
2507 VM_CheckEmptyString (s);
2516 float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
2519 void VM_drawcharacter(void)
2521 float *pos,*scale,*rgb;
2524 VM_SAFEPARMCOUNT(6,VM_drawcharacter);
2526 character = (char) PRVM_G_FLOAT(OFS_PARM1);
2529 Con_Printf("VM_drawcharacter: %s passed null character !\n",PRVM_NAME);
2530 PRVM_G_FLOAT(OFS_RETURN) = -1;
2534 pos = PRVM_G_VECTOR(OFS_PARM0);
2535 scale = PRVM_G_VECTOR(OFS_PARM2);
2536 rgb = PRVM_G_VECTOR(OFS_PARM3);
2537 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2539 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2541 Con_Printf("VM_drawcharacter: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2542 PRVM_G_FLOAT(OFS_RETURN) = -2;
2546 if(pos[2] || scale[2])
2547 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")));
2549 if(!scale[0] || !scale[1])
2551 Con_Printf("VM_drawcharacter: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2552 PRVM_G_FLOAT(OFS_RETURN) = -3;
2556 DrawQ_String (pos[0], pos[1], &character, 1, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2557 PRVM_G_FLOAT(OFS_RETURN) = 1;
2564 float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
2567 void VM_drawstring(void)
2569 float *pos,*scale,*rgb;
2572 VM_SAFEPARMCOUNT(6,VM_drawstring);
2574 string = PRVM_G_STRING(OFS_PARM1);
2577 Con_Printf("VM_drawstring: %s passed null string !\n",PRVM_NAME);
2578 PRVM_G_FLOAT(OFS_RETURN) = -1;
2582 VM_CheckEmptyString(string);
2584 pos = PRVM_G_VECTOR(OFS_PARM0);
2585 scale = PRVM_G_VECTOR(OFS_PARM2);
2586 rgb = PRVM_G_VECTOR(OFS_PARM3);
2587 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2589 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2591 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2592 PRVM_G_FLOAT(OFS_RETURN) = -2;
2596 if(!scale[0] || !scale[1])
2598 Con_Printf("VM_drawstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2599 PRVM_G_FLOAT(OFS_RETURN) = -3;
2603 if(pos[2] || scale[2])
2604 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")));
2606 DrawQ_String (pos[0], pos[1], string, 0, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2607 PRVM_G_FLOAT(OFS_RETURN) = 1;
2613 float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
2616 void VM_drawpic(void)
2619 float *size, *pos, *rgb;
2622 VM_SAFEPARMCOUNT(6,VM_drawpic);
2624 pic = PRVM_G_STRING(OFS_PARM1);
2628 Con_Printf("VM_drawpic: %s passed null picture name !\n", PRVM_NAME);
2629 PRVM_G_FLOAT(OFS_RETURN) = -1;
2633 VM_CheckEmptyString (pic);
2635 // is pic cached ? no function yet for that
2638 Con_Printf("VM_drawpic: %s: %s not cached !\n", PRVM_NAME, pic);
2639 PRVM_G_FLOAT(OFS_RETURN) = -4;
2643 pos = PRVM_G_VECTOR(OFS_PARM0);
2644 size = PRVM_G_VECTOR(OFS_PARM2);
2645 rgb = PRVM_G_VECTOR(OFS_PARM3);
2646 flag = (int) PRVM_G_FLOAT(OFS_PARM5);
2648 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2650 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2651 PRVM_G_FLOAT(OFS_RETURN) = -2;
2655 if(pos[2] || size[2])
2656 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")));
2658 DrawQ_Pic(pos[0], pos[1], pic, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2659 PRVM_G_FLOAT(OFS_RETURN) = 1;
2666 float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
2669 void VM_drawfill(void)
2671 float *size, *pos, *rgb;
2674 VM_SAFEPARMCOUNT(5,VM_drawfill);
2677 pos = PRVM_G_VECTOR(OFS_PARM0);
2678 size = PRVM_G_VECTOR(OFS_PARM1);
2679 rgb = PRVM_G_VECTOR(OFS_PARM2);
2680 flag = (int) PRVM_G_FLOAT(OFS_PARM4);
2682 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2684 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2685 PRVM_G_FLOAT(OFS_RETURN) = -2;
2689 if(pos[2] || size[2])
2690 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")));
2692 DrawQ_Pic(pos[0], pos[1], 0, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM3), flag);
2693 PRVM_G_FLOAT(OFS_RETURN) = 1;
2700 drawsetcliparea(float x, float y, float width, float height)
2703 void VM_drawsetcliparea(void)
2706 VM_SAFEPARMCOUNT(4,VM_drawsetcliparea);
2708 x = bound(0,PRVM_G_FLOAT(OFS_PARM0),vid.conwidth);
2709 y = bound(0,PRVM_G_FLOAT(OFS_PARM1),vid.conheight);
2710 w = bound(0,PRVM_G_FLOAT(OFS_PARM2),(vid.conwidth - x));
2711 h = bound(0,PRVM_G_FLOAT(OFS_PARM3),(vid.conheight - y));
2713 DrawQ_SetClipArea(x,y,w,h);
2718 VM_drawresetcliparea
2723 void VM_drawresetcliparea(void)
2725 VM_SAFEPARMCOUNT(0,VM_drawresetcliparea);
2727 DrawQ_ResetClipArea();
2734 vector getimagesize(string pic)
2737 void VM_getimagesize(void)
2742 VM_SAFEPARMCOUNT(1,VM_getimagesize);
2744 p = PRVM_G_STRING(OFS_PARM0);
2747 PRVM_ERROR("VM_getimagepos: %s passed null picture name !\n", PRVM_NAME);
2749 VM_CheckEmptyString (p);
2751 pic = Draw_CachePic (p);
2753 PRVM_G_VECTOR(OFS_RETURN)[0] = pic->width;
2754 PRVM_G_VECTOR(OFS_RETURN)[1] = pic->height;
2755 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2758 void VM_Cmd_Init(void)
2760 // only init the stuff for the current prog
2761 VM_STRINGS_MEMPOOL = Mem_AllocPool(va("vm_stringsmempool[%s]",PRVM_NAME), 0, NULL);
2766 void VM_Cmd_Reset(void)
2768 //Mem_EmptyPool(VM_STRINGS_MEMPOOL);
2769 Mem_FreePool(&VM_STRINGS_MEMPOOL);
2771 VM_Files_CloseAll();
2774 //============================================================================
2777 char *vm_sv_extensions =
2780 prvm_builtin_t vm_sv_builtins[] = {
2781 0 // to be consistent with the old vm
2784 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
2786 void VM_SV_Cmd_Init(void)
2790 void VM_SV_Cmd_Reset(void)
2794 //============================================================================
2797 char *vm_cl_extensions =
2800 prvm_builtin_t vm_cl_builtins[] = {
2801 0 // to be consistent with the old vm
2804 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
2806 void VM_CL_Cmd_Init(void)
2810 void VM_CL_Cmd_Reset(void)
2814 //============================================================================
2817 char *vm_m_extensions =
2824 setmousetarget(float target)
2827 void VM_M_setmousetarget(void)
2829 VM_SAFEPARMCOUNT(1, VM_M_setmousetarget);
2831 switch((int)PRVM_G_FLOAT(OFS_PARM0))
2834 in_client_mouse = false;
2837 in_client_mouse = true;
2840 PRVM_ERROR("VM_M_setmousetarget: wrong destination %i !\n",PRVM_G_FLOAT(OFS_PARM0));
2848 float getmousetarget
2851 void VM_M_getmousetarget(void)
2853 VM_SAFEPARMCOUNT(0,VM_M_getmousetarget);
2856 PRVM_G_FLOAT(OFS_RETURN) = 2;
2858 PRVM_G_FLOAT(OFS_RETURN) = 1;
2867 setkeydest(float dest)
2870 void VM_M_setkeydest(void)
2872 VM_SAFEPARMCOUNT(1,VM_M_setkeydest);
2874 switch((int)PRVM_G_FLOAT(OFS_PARM0))
2878 key_dest = key_game;
2882 key_dest = key_menu;
2886 // key_dest = key_message
2889 PRVM_ERROR("VM_M_setkeydest: wrong destination %i !\n",prog->globals[OFS_PARM0]);
2900 void VM_M_getkeydest(void)
2902 VM_SAFEPARMCOUNT(0,VM_M_getkeydest);
2904 // key_game = 0, key_message = 1, key_menu = 2, unknown = 3
2908 PRVM_G_FLOAT(OFS_RETURN) = 0;
2911 PRVM_G_FLOAT(OFS_RETURN) = 2;
2915 // PRVM_G_FLOAT(OFS_RETURN) = 1;
2918 PRVM_G_FLOAT(OFS_RETURN) = 3;
2926 callfunction(...,string function_name)
2929 mfunction_t *PRVM_ED_FindFunction (const char *name);
2930 void VM_M_callfunction(void)
2936 PRVM_ERROR("VM_M_callfunction: 1 parameter is required !\n");
2938 s = PRVM_G_STRING(OFS_PARM0 + (prog->argc - 1));
2941 PRVM_ERROR("VM_M_callfunction: null string !\n");
2943 VM_CheckEmptyString(s);
2945 func = PRVM_ED_FindFunction(s);
2948 PRVM_ERROR("VM_M_callfunciton: function %s not found !\n", s);
2949 else if (func->first_statement < 0)
2951 // negative statements are built in functions
2952 int builtinnumber = -func->first_statement;
2953 prog->xfunction->builtinsprofile++;
2954 if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber])
2955 prog->builtins[builtinnumber]();
2957 PRVM_ERROR("No such builtin #%i in %s", builtinnumber, PRVM_NAME);
2962 PRVM_ExecuteProgram(func - prog->functions,"");
2971 float isfunction(string function_name)
2974 mfunction_t *PRVM_ED_FindFunction (const char *name);
2975 void VM_M_isfunction(void)
2980 VM_SAFEPARMCOUNT(1, VM_M_isfunction);
2982 s = PRVM_G_STRING(OFS_PARM0);
2985 PRVM_ERROR("VM_M_isfunction: null string !\n");
2987 VM_CheckEmptyString(s);
2989 func = PRVM_ED_FindFunction(s);
2992 PRVM_G_FLOAT(OFS_RETURN) = false;
2994 PRVM_G_FLOAT(OFS_RETURN) = true;
3001 writetofile(float fhandle, entity ent)
3004 void VM_M_writetofile(void)
3009 VM_SAFEPARMCOUNT(2, VM_M_writetofile);
3011 filenum = PRVM_G_FLOAT(OFS_PARM0);
3012 if (filenum < 0 || filenum >= MAX_VMFILES)
3014 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
3017 if (VM_FILES[filenum] == NULL)
3019 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
3023 ent = PRVM_G_EDICT(OFS_PARM1);
3026 Con_Printf("VM_M_writetofile: %s: entity %i is free !\n", PRVM_NAME, PRVM_EDICT_NUM(OFS_PARM1));
3030 PRVM_ED_Write (VM_FILES[filenum], ent);
3037 vector getresolution(float number)
3040 extern unsigned short video_resolutions[][2];
3041 void VM_M_getresolution(void)
3044 VM_SAFEPARMCOUNT(1, VM_getresolution);
3046 nr = PRVM_G_FLOAT(OFS_PARM0);
3049 PRVM_G_VECTOR(OFS_RETURN)[0] = video_resolutions[nr][0];
3050 PRVM_G_VECTOR(OFS_RETURN)[1] = video_resolutions[nr][1];
3051 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
3058 string keynumtostring(float keynum)
3061 void VM_M_keynumtostring(void)
3065 VM_SAFEPARMCOUNT(1, VM_M_keynumtostring);
3067 keynum = PRVM_G_FLOAT(OFS_PARM0);
3069 tmp = VM_GetTempString();
3071 strcpy(tmp, Key_KeynumToString(keynum));
3073 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
3078 VM_M_findkeysforcommand
3080 string findkeysforcommand(string command)
3082 the returned string is an altstring
3085 #define NUMKEYS 5 // TODO: merge the constant in keys.c with this one somewhen
3087 void M_FindKeysForCommand(char *command, int *keys);
3088 void VM_M_findkeysforcommand(void)
3094 VM_SAFEPARMCOUNT(1, VM_M_findkeysforcommand);
3096 cmd = PRVM_G_STRING(OFS_PARM0);
3098 VM_CheckEmptyString(cmd);
3100 (ret = VM_GetTempString())[0] = 0;
3102 M_FindKeysForCommand(cmd, keys);
3104 for(i = 0; i < NUMKEYS; i++)
3105 ret = strcat(ret, va(" \'%i\'", keys[i]));
3107 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(ret);
3112 VM_M_gethostcachecount
3114 float gethostcachevalue(float type)
3125 void VM_M_gethostcachevalue( void )
3128 VM_SAFEPARMCOUNT ( 1, VM_M_gethostcachevalue );
3130 PRVM_G_FLOAT( OFS_RETURN ) = 0;
3132 type = PRVM_G_FLOAT( OFS_PARM0 );
3133 if( type < 0 || type > 4 )
3134 Con_Printf( "VM_M_gethostcachevalue: bad type %i!\n", type );
3138 PRVM_G_FLOAT ( OFS_RETURN ) = hostCacheCount;
3141 PRVM_G_FLOAT ( OFS_RETURN ) = masterquerycount;
3144 PRVM_G_FLOAT ( OFS_RETURN ) = masterreplycount;
3147 PRVM_G_FLOAT ( OFS_RETURN ) = serverquerycount;
3150 PRVM_G_FLOAT ( OFS_RETURN ) = serverreplycount;
3157 VM_M_gethostcachestring
3159 string gethostcachestring(float type, float hostnr)
3167 void VM_M_gethostcachestring(void)
3172 VM_SAFEPARMCOUNT(2, VM_M_gethostcachestring);
3174 PRVM_G_INT(OFS_RETURN) = 0;
3176 type = PRVM_G_FLOAT(OFS_PARM0);
3178 if(type < 0 || type > 2)
3180 Con_Print("VM_M_gethostcachestring: bad string type requested!\n");
3184 hostnr = PRVM_G_FLOAT(OFS_PARM1);
3186 if(hostnr < 0 || hostnr >= hostCacheCount)
3188 Con_Print("VM_M_gethostcachestring: bad hostnr passed!\n");
3193 PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( hostcache[hostnr].cname );
3194 else if( type == 1 )
3195 PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( hostcache[hostnr].line1 );
3197 PRVM_G_INT( OFS_RETURN ) = PRVM_SetString( hostcache[hostnr].line2 );
3200 prvm_builtin_t vm_m_builtins[] = {
3201 0, // to be consistent with the old vm
3202 // common builtings (mostly)
3279 VM_search_getfilename, // 77
3295 VM_WriteEntity, // 408
3311 VM_drawresetcliparea,
3312 VM_getimagesize,// 460
3321 VM_M_setmousetarget,
3322 VM_M_getmousetarget,
3327 VM_M_keynumtostring,
3328 VM_M_findkeysforcommand,// 610
3329 VM_M_gethostcachevalue,
3330 VM_M_gethostcachestring // 612
3333 const int vm_m_numbuiltins = sizeof(vm_m_builtins) / sizeof(prvm_builtin_t);
3335 void VM_M_Cmd_Init(void)
3340 void VM_M_Cmd_Reset(void)