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)
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 perhaps only : Menu : WriteMsg
99 ===============================
101 WriteByte(float data, float dest, float desto)
102 WriteChar(float data, float dest, float desto)
103 WriteShort(float data, float dest, float desto)
104 WriteLong(float data, float dest, float desto)
105 WriteAngle(float data, float dest, float desto)
106 WriteCoord(float data, float dest, float desto)
107 WriteString(string data, float dest, float desto)
108 WriteEntity(entity data, float dest, float desto)
110 Client & Menu : draw functions
111 ===============================
113 float iscachedpic(string pic)
114 string precache_pic(string pic)
116 float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
117 float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
118 float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
119 float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
120 drawsetcliparea(float x, float y, float width, float height)
122 vector getimagesize(string pic)
125 ==============================================================================
129 setkeydest(float dest)
131 setmousetarget(float target)
132 float getmousetarget(void)
134 callfunction(...,string function_name)
135 writetofile(float fhandle, entity ent)
136 float isfunction(string function_name)
137 vector getresolution(float number)
138 string keynumtostring(float keynum)
142 #include "quakedef.h"
143 #include "progdefs.h"
144 #include "clprogdefs.h"
145 #include "mprogdefs.h"
147 //============================================================================
148 // nice helper macros
150 #ifndef VM_NOPARMCHECK
151 #define VM_SAFEPARMCOUNT(p,f) if(prog->argc != p) PRVM_ERROR(#f " wrong parameter count (" #p " expected ) !\n")
153 #define VM_SAFEPARMCOUNT(p,f)
156 #define VM_RETURN_EDICT(e) (((int *)prog->globals)[OFS_RETURN] = PRVM_EDICT_TO_PROG(e))
158 #define VM_STRINGS_MEMPOOL vm_strings_mempool[PRVM_GetProgNr()]
160 #define e10 0,0,0,0,0,0,0,0,0,0
161 #define e100 e10,e10,e10,e10,e10,e10,e10,e10,e10,e10
162 #define e1000 e100,e100,e100,e100,e100,e100,e100,e100,e100,e100
164 //============================================================================
167 // string zone mempool
168 mempool_t *vm_strings_mempool[PRVM_MAXPROGS];
170 // temp string handling
171 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
172 #define VM_STRINGTEMP_BUFFERS 16
173 #define VM_STRINGTEMP_LENGTH 4096
174 static char vm_string_temp[VM_STRINGTEMP_BUFFERS][VM_STRINGTEMP_LENGTH];
175 static int vm_string_tempindex = 0;
178 #define MAX_QC_CVARS 128 * PRVM_MAXPROGS
179 cvar_t vm_qc_cvar[MAX_QC_CVARS];
180 int vm_currentqc_cvar;
183 #define MAX_VMFILES 256
184 #define MAX_PRVMFILES MAX_VMFILES * PRVM_MAXPROGS
185 #define VM_FILES ((qfile_t**)(vm_files + PRVM_GetProgNr() * MAX_VMFILES))
187 qfile_t *vm_files[MAX_PRVMFILES];
189 // qc fs search handling
190 #define MAX_VMSEARCHES 128
191 #define TOTAL_VMSEARCHES MAX_VMSEARCHES * PRVM_MAXPROGS
192 #define VM_SEARCHLIST ((fssearch_t**)(vm_fssearchlist + PRVM_GetProgNr() * MAX_VMSEARCHES))
194 fssearch_t *vm_fssearchlist[TOTAL_VMSEARCHES];
196 static char *VM_GetTempString(void)
199 s = vm_string_temp[vm_string_tempindex];
200 vm_string_tempindex = (vm_string_tempindex + 1) % VM_STRINGTEMP_BUFFERS;
204 void VM_CheckEmptyString (char *s)
207 PRVM_ERROR ("%s: Bad string", PRVM_NAME);
210 //============================================================================
213 void VM_VarString(int first, char *out, int outlength)
219 outend = out + outlength - 1;
220 for (i = first;i < prog->argc && out < outend;i++)
222 s = PRVM_G_STRING((OFS_PARM0+i*3));
223 while (out < outend && *s)
233 returns true if the extension is supported by the server
235 checkextension(extensionname)
239 // kind of helper function
240 static qboolean checkextension(char *name)
246 for (e = prog->extensionstring;*e;e++)
253 while (*e && *e != ' ')
255 if (e - start == len)
256 if (!strncasecmp(start, name, len))
264 void VM_checkextension (void)
266 VM_SAFEPARMCOUNT(1,VM_checkextension);
268 PRVM_G_FLOAT(OFS_RETURN) = checkextension(PRVM_G_STRING(OFS_PARM0));
275 This is a TERMINAL error, which will kill off the entire prog.
284 char string[VM_STRINGTEMP_LENGTH];
286 VM_VarString(0, string, sizeof(string));
287 Con_Printf ("======%S ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
290 ed = PRVM_G_EDICT(prog->self->ofs);
294 PRVM_ERROR ("%s: Program error", PRVM_NAME);
301 Dumps out self, then an error message. The program is aborted and self is
302 removed, but the level can continue.
307 void VM_objerror (void)
310 char string[VM_STRINGTEMP_LENGTH];
312 VM_VarString(0, string, sizeof(string));
313 Con_Printf ("======%s OBJECT ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
316 ed = PRVM_G_EDICT (prog->self->ofs);
322 // objerror has to display the object fields -> else call
323 PRVM_ERROR ("VM_objecterror: self not defined !\n");
328 VM_print (actually used only by client and menu)
337 char string[VM_STRINGTEMP_LENGTH];
339 VM_VarString(0, string, sizeof(string));
347 broadcast print to everyone on server
352 void VM_bprint (void)
354 char string[VM_STRINGTEMP_LENGTH];
358 Con_Printf("VM_bprint: game is not server(%s) !", PRVM_NAME);
362 VM_VarString(0, string, sizeof(string));
363 SV_BroadcastPrintf("%s", string);
368 VM_sprint (menu & client but only if server.active == true)
370 single print to a specific client
372 sprint(float clientnum,...[string])
375 void VM_sprint (void)
379 char string[VM_STRINGTEMP_LENGTH];
381 //find client for this entity
382 clientnum = PRVM_G_FLOAT(OFS_PARM0);
383 if (!sv.active || clientnum < 0 || clientnum >= svs.maxclients || !svs.clients[clientnum].active)
385 Con_Printf("VM_sprint: %s: invalid client or server is not active !", PRVM_NAME);
389 client = svs.clients + clientnum;
390 if (!client->netconnection)
392 VM_VarString(1, string, sizeof(string));
393 MSG_WriteChar(&client->message,svc_print);
394 MSG_WriteString(&client->message, string);
401 single print to the screen
403 centerprint(clientent, value)
406 void VM_centerprint (void)
408 char string[VM_STRINGTEMP_LENGTH];
410 VM_VarString(0, string, sizeof(string));
411 SCR_CenterPrint(string);
418 vector normalize(vector)
421 void VM_normalize (void)
427 VM_SAFEPARMCOUNT(1,VM_normalize);
429 value1 = PRVM_G_VECTOR(OFS_PARM0);
431 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
435 newvalue[0] = newvalue[1] = newvalue[2] = 0;
439 newvalue[0] = value1[0] * new;
440 newvalue[1] = value1[1] * new;
441 newvalue[2] = value1[2] * new;
444 VectorCopy (newvalue, PRVM_G_VECTOR(OFS_RETURN));
459 VM_SAFEPARMCOUNT(1,VM_vlen);
461 value1 = PRVM_G_VECTOR(OFS_PARM0);
463 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
466 PRVM_G_FLOAT(OFS_RETURN) = new;
473 float vectoyaw(vector)
476 void VM_vectoyaw (void)
481 VM_SAFEPARMCOUNT(1,VM_vectoyaw);
483 value1 = PRVM_G_VECTOR(OFS_PARM0);
485 if (value1[1] == 0 && value1[0] == 0)
489 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
494 PRVM_G_FLOAT(OFS_RETURN) = yaw;
502 vector vectoangles(vector)
505 void VM_vectoangles (void)
511 VM_SAFEPARMCOUNT(1,VM_vectoangles);
513 value1 = PRVM_G_VECTOR(OFS_PARM0);
515 if (value1[1] == 0 && value1[0] == 0)
525 // LordHavoc: optimized a bit
528 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
532 else if (value1[1] > 0)
537 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
538 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
543 PRVM_G_FLOAT(OFS_RETURN+0) = pitch;
544 PRVM_G_FLOAT(OFS_RETURN+1) = yaw;
545 PRVM_G_FLOAT(OFS_RETURN+2) = 0;
552 Returns a number from 0<= num < 1
557 void VM_random (void)
561 VM_SAFEPARMCOUNT(0,VM_random);
563 num = (rand ()&0x7fff) / ((float)0x7fff);
565 PRVM_G_FLOAT(OFS_RETURN) = num;
572 Each entity can have eight independant sound sources, like voice,
575 Channel 0 is an auto-allocate channel, the others override anything
576 already running on that entity/channel pair.
578 An attenuation of 0 will play full volume everywhere in the level.
579 Larger attenuations will drop off.
592 entity = G_EDICT(OFS_PARM0);
593 channel = G_FLOAT(OFS_PARM1);
594 sample = G_STRING(OFS_PARM2);
595 volume = G_FLOAT(OFS_PARM3) * 255;
596 attenuation = G_FLOAT(OFS_PARM4);
598 if (volume < 0 || volume > 255)
599 Host_Error ("SV_StartSound: volume = %i", volume);
601 if (attenuation < 0 || attenuation > 4)
602 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
604 if (channel < 0 || channel > 7)
605 Host_Error ("SV_StartSound: channel = %i", channel);
607 SV_StartSound (entity, channel, sample, volume, attenuation);
615 localsound(string sample)
618 void VM_localsound(void)
622 VM_SAFEPARMCOUNT(1,VM_localsound);
624 s = PRVM_G_STRING(OFS_PARM0);
628 Con_Printf("VM_localsound: %s : %s not cached !\n", PRVM_NAME, s);
629 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_PARM0) = 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);
1108 Con_Printf("VM_precache_sound: %s already cached (%s)\n", s, PRVM_NAME);
1112 if(!S_PrecacheSound(s,true))
1113 Con_Printf("VM_prache_sound: Failed to load %s for %s\n", s, PRVM_NAME);
1123 void VM_coredump (void)
1125 VM_SAFEPARMCOUNT(0,VM_coredump);
1127 Cbuf_AddText("prvm_edicts ");
1128 Cbuf_AddText(PRVM_NAME);
1139 void PRVM_StackTrace(void);
1140 void VM_stackdump (void)
1142 VM_SAFEPARMCOUNT(0, VM_stackdump);
1157 VM_SAFEPARMCOUNT(0, VM_crash);
1159 PRVM_ERROR("Crash called by %s\n",PRVM_NAME);
1169 void VM_traceon (void)
1171 VM_SAFEPARMCOUNT(0,VM_traceon);
1183 void VM_traceoff (void)
1185 VM_SAFEPARMCOUNT(0,VM_traceoff);
1187 prog->trace = false;
1197 void VM_eprint (void)
1199 VM_SAFEPARMCOUNT(1,VM_eprint);
1201 PRVM_ED_PrintNum (PRVM_G_EDICTNUM(OFS_PARM0));
1215 VM_SAFEPARMCOUNT(1,VM_rint);
1217 f = PRVM_G_FLOAT(OFS_PARM0);
1219 PRVM_G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1221 PRVM_G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1231 void VM_floor (void)
1233 VM_SAFEPARMCOUNT(1,VM_floor);
1235 PRVM_G_FLOAT(OFS_RETURN) = floor(PRVM_G_FLOAT(OFS_PARM0));
1247 VM_SAFEPARMCOUNT(1,VM_ceil);
1249 PRVM_G_FLOAT(OFS_RETURN) = ceil(PRVM_G_FLOAT(OFS_PARM0));
1257 entity nextent(entity)
1260 void VM_nextent (void)
1265 i = PRVM_G_EDICTNUM(OFS_PARM0);
1268 prog->xfunction->builtinsprofile++;
1270 if (i == prog->num_edicts)
1272 VM_RETURN_EDICT(prog->edicts);
1275 ent = PRVM_EDICT_NUM(i);
1278 VM_RETURN_EDICT(ent);
1285 ===============================================================================
1288 used only for client and menu
1289 severs uses VM_SV_...
1291 Write*(* data, float type, float to)
1293 ===============================================================================
1296 #define MSG_BROADCAST 0 // unreliable to all
1297 #define MSG_ONE 1 // reliable to one (msg_entity)
1298 #define MSG_ALL 2 // reliable to all
1299 #define MSG_INIT 3 // write to the init string
1301 sizebuf_t *VM_WriteDest (void)
1307 PRVM_ERROR("VM_WriteDest: game is not server (%s)\n", PRVM_NAME);
1309 dest = G_FLOAT(OFS_PARM1);
1313 return &sv.datagram;
1316 destclient = (int) PRVM_G_FLOAT(OFS_PARM2);
1317 if (destclient < 0 || destclient >= svs.maxclients || !svs.clients[destclient].active)
1318 PRVM_ERROR("VM_clientcommand: %s: invalid client !\n", PRVM_NAME);
1320 return &svs.clients[destclient].message;
1323 return &sv.reliable_datagram;
1329 PRVM_ERROR ("WriteDest: bad destination");
1336 void VM_WriteByte (void)
1338 MSG_WriteByte (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1341 void VM_WriteChar (void)
1343 MSG_WriteChar (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1346 void VM_WriteShort (void)
1348 MSG_WriteShort (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1351 void VM_WriteLong (void)
1353 MSG_WriteLong (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1356 void VM_WriteAngle (void)
1358 MSG_WriteAngle (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1361 void VM_WriteCoord (void)
1363 MSG_WriteDPCoord (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1366 void VM_WriteString (void)
1368 MSG_WriteString (VM_WriteDest(), PRVM_G_STRING(OFS_PARM0));
1371 void VM_WriteEntity (void)
1373 MSG_WriteShort (VM_WriteDest(), PRVM_G_EDICTNUM(OFS_PARM0));
1376 //=============================================================================
1383 changelevel(string map)
1386 void VM_changelevel (void)
1390 VM_SAFEPARMCOUNT(1, VM_changelevel);
1394 Con_Printf("VM_changelevel: game is not server (%s)\n", PRVM_NAME);
1398 // make sure we don't issue two changelevels
1399 if (svs.changelevel_issued)
1401 svs.changelevel_issued = true;
1403 s = G_STRING(OFS_PARM0);
1404 Cbuf_AddText (va("changelevel %s\n",s));
1416 VM_SAFEPARMCOUNT(1,VM_sin);
1417 PRVM_G_FLOAT(OFS_RETURN) = sin(PRVM_G_FLOAT(OFS_PARM0));
1428 VM_SAFEPARMCOUNT(1,VM_cos);
1429 PRVM_G_FLOAT(OFS_RETURN) = cos(PRVM_G_FLOAT(OFS_PARM0));
1441 VM_SAFEPARMCOUNT(1,VM_sqrt);
1442 PRVM_G_FLOAT(OFS_RETURN) = sqrt(PRVM_G_FLOAT(OFS_PARM0));
1449 Returns a vector of length < 1 and > 0
1454 void VM_randomvec (void)
1459 VM_SAFEPARMCOUNT(0, VM_randomvec);
1464 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1465 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1466 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1468 while (DotProduct(temp, temp) >= 1);
1469 VectorCopy (temp, PRVM_G_VECTOR(OFS_RETURN));
1472 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1473 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1474 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1475 // length returned always > 0
1476 length = (rand()&32766 + 1) * (1.0 / 32767.0) / VectorLength(temp);
1477 VectorScale(temp,length, temp);*/
1478 //VectorCopy(temp, PRVM_G_VECTOR(OFS_RETURN));
1481 //=============================================================================
1487 float registercvar (string name, string value)
1490 void VM_registercvar (void)
1495 VM_SAFEPARMCOUNT(2,VM_registercvar);
1497 name = PRVM_G_STRING(OFS_PARM0);
1498 value = PRVM_G_STRING(OFS_PARM1);
1499 PRVM_G_FLOAT(OFS_RETURN) = 0;
1500 // first check to see if it has already been defined
1501 if (Cvar_FindVar (name))
1504 // check for overlap with a command
1505 if (Cmd_Exists (name))
1507 Con_Printf ("VM_registercvar: %s is a command\n", name);
1511 if (vm_currentqc_cvar >= MAX_QC_CVARS)
1512 PRVM_ERROR ("VM_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1514 // copy the name and value
1515 variable = &vm_qc_cvar[vm_currentqc_cvar++];
1516 variable->name = Z_Malloc (strlen(name)+1);
1517 strcpy (variable->name, name);
1518 variable->string = Z_Malloc (strlen(value)+1);
1519 strcpy (variable->string, value);
1520 variable->value = atof (value);
1522 Cvar_RegisterVariable(variable);
1523 PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1530 returns the minimum of two supplied floats
1532 float min(float a, float b, ...[float])
1537 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1538 if (prog->argc == 2)
1539 PRVM_G_FLOAT(OFS_RETURN) = min(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1540 else if (prog->argc >= 3)
1543 float f = PRVM_G_FLOAT(OFS_PARM0);
1544 for (i = 1;i < prog->argc;i++)
1545 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) < f)
1546 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1547 PRVM_G_FLOAT(OFS_RETURN) = f;
1550 PRVM_ERROR("VM_min: %s must supply at least 2 floats\n", PRVM_NAME);
1557 returns the maximum of two supplied floats
1559 float max(float a, float b, ...[float])
1564 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1565 if (prog->argc == 2)
1566 PRVM_G_FLOAT(OFS_RETURN) = max(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1567 else if (prog->argc >= 3)
1570 float f = PRVM_G_FLOAT(OFS_PARM0);
1571 for (i = 1;i < prog->argc;i++)
1572 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) > f)
1573 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1574 G_FLOAT(OFS_RETURN) = f;
1577 PRVM_ERROR("VM_max: %s must supply at least 2 floats\n", PRVM_NAME);
1584 returns number bounded by supplied range
1586 float bound(float min, float value, float max)
1589 void VM_bound (void)
1591 VM_SAFEPARMCOUNT(3,VM_bound);
1592 PRVM_G_FLOAT(OFS_RETURN) = bound(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2));
1599 returns a raised to power b
1601 float pow(float a, float b)
1606 VM_SAFEPARMCOUNT(2,VM_pow);
1607 PRVM_G_FLOAT(OFS_RETURN) = pow(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1614 copies data from one entity to another
1616 copyentity(entity src, entity dst)
1619 void VM_copyentity (void)
1621 prvm_edict_t *in, *out;
1622 VM_SAFEPARMCOUNT(2,VM_copyentity);
1623 in = PRVM_G_EDICT(OFS_PARM0);
1624 out = PRVM_G_EDICT(OFS_PARM1);
1625 memcpy(out->v, in->v, prog->progs->entityfields * 4);
1632 sets the color of a client and broadcasts the update to all connected clients
1634 setcolor(clientent, value)
1637 /*void PF_setcolor (void)
1643 entnum = G_EDICTNUM(OFS_PARM0);
1644 i = G_FLOAT(OFS_PARM1);
1646 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1648 Con_Printf ("tried to setcolor a non-client\n");
1652 client = svs.clients + entnum-1;
1653 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
1656 client->old_colors = i;
1657 client->edict->v->team = (i & 15) + 1;
1659 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1660 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
1661 MSG_WriteByte (&sv.reliable_datagram, i);
1664 void VM_Files_Init(void)
1666 memset(VM_FILES, 0, sizeof(qfile_t*[MAX_VMFILES]));
1669 void VM_Files_CloseAll(void)
1672 for (i = 0;i < MAX_VMFILES;i++)
1675 FS_Close(VM_FILES[i]);
1676 //VM_FILES[i] = NULL;
1678 memset(VM_FILES,0,sizeof(qfile_t*[MAX_VMFILES])); // this should be faster (is it ?)
1685 float fopen(string filename, float mode)
1688 // float(string filename, float mode) fopen = #110;
1689 // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE),
1690 // returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
1694 char *modestring, *filename;
1696 VM_SAFEPARMCOUNT(2,VM_fopen);
1698 for (filenum = 0;filenum < MAX_VMFILES;filenum++)
1699 if (VM_FILES[filenum] == NULL)
1701 if (filenum >= MAX_VMFILES)
1703 Con_Printf("VM_fopen: %s ran out of file handles (%i)\n", PRVM_NAME, MAX_VMFILES);
1704 PRVM_G_FLOAT(OFS_RETURN) = -2;
1707 mode = PRVM_G_FLOAT(OFS_PARM1);
1710 case 0: // FILE_READ
1713 case 1: // FILE_APPEND
1716 case 2: // FILE_WRITE
1720 Con_Printf ("VM_fopen: %s no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", PRVM_NAME, mode);
1721 PRVM_G_FLOAT(OFS_RETURN) = -3;
1724 filename = PRVM_G_STRING(OFS_PARM0);
1725 // .. is parent directory on many platforms
1726 // / is parent directory on Amiga
1727 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
1728 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
1729 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
1731 Con_Printf("VM_fopen: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
1732 PRVM_G_FLOAT(OFS_RETURN) = -4;
1735 VM_FILES[filenum] = FS_Open(va("data/%s", filename), modestring, false);
1736 if (VM_FILES[filenum] == NULL)
1737 PRVM_G_FLOAT(OFS_RETURN) = -1;
1739 PRVM_G_FLOAT(OFS_RETURN) = filenum;
1746 fclose(float fhandle)
1749 //void(float fhandle) fclose = #111; // closes a file
1750 void VM_fclose(void)
1754 VM_SAFEPARMCOUNT(1,VM_fclose);
1756 filenum = PRVM_G_FLOAT(OFS_PARM0);
1757 if (filenum < 0 || filenum >= MAX_VMFILES)
1759 Con_Printf("VM_fclose: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1762 if (VM_FILES[filenum] == NULL)
1764 Con_Printf("VM_fclose: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1767 FS_Close(VM_FILES[filenum]);
1768 VM_FILES[filenum] = NULL;
1775 string fgets(float fhandle)
1778 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
1782 static char string[VM_STRINGTEMP_LENGTH];
1785 VM_SAFEPARMCOUNT(1,VM_fgets);
1787 filenum = PRVM_G_FLOAT(OFS_PARM0);
1788 if (filenum < 0 || filenum >= MAX_VMFILES)
1790 Con_Printf("VM_fgets: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1793 if (VM_FILES[filenum] == NULL)
1795 Con_Printf("VM_fgets: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1801 c = FS_Getc(VM_FILES[filenum]);
1802 if (c == '\r' || c == '\n' || c < 0)
1804 if (end < VM_STRINGTEMP_LENGTH - 1)
1808 // remove \n following \r
1810 c = FS_Getc(VM_FILES[filenum]);
1811 if (developer.integer)
1812 Con_Printf("fgets: %s: %s\n", PRVM_NAME, string);
1814 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1816 PRVM_G_INT(OFS_RETURN) = 0;
1823 fputs(float fhandle, string s)
1826 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
1830 char string[VM_STRINGTEMP_LENGTH];
1833 VM_SAFEPARMCOUNT(2,VM_fputs);
1835 filenum = PRVM_G_FLOAT(OFS_PARM0);
1836 if (filenum < 0 || filenum >= MAX_VMFILES)
1838 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1841 if (VM_FILES[filenum] == NULL)
1843 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1846 VM_VarString(1, string, sizeof(string));
1847 if ((stringlength = strlen(string)))
1848 FS_Write(VM_FILES[filenum], string, stringlength);
1849 if (developer.integer)
1850 Con_Printf("fputs: %s: %s\n", PRVM_NAME, string);
1857 float strlen(string s)
1860 //float(string s) strlen = #114; // returns how many characters are in a string
1861 void VM_strlen(void)
1865 VM_SAFEPARMCOUNT(1,VM_strlen);
1867 s = PRVM_G_STRING(OFS_PARM0);
1869 PRVM_G_FLOAT(OFS_RETURN) = strlen(s);
1871 PRVM_G_FLOAT(OFS_RETURN) = 0;
1878 string strcat(string,string,...[string])
1881 //string(string s1, string s2) strcat = #115;
1882 // concatenates two strings (for example "abc", "def" would return "abcdef")
1883 // and returns as a tempstring
1884 void VM_strcat(void)
1889 PRVM_ERROR("VM_strcat wrong parameter count (min. 2 expected ) !\n");
1891 s = VM_GetTempString();
1892 VM_VarString(0, s, VM_STRINGTEMP_LENGTH);
1893 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
1900 string substring(string s, float start, float length)
1903 // string(string s, float start, float length) substring = #116;
1904 // returns a section of a string as a tempstring
1905 void VM_substring(void)
1907 int i, start, length;
1910 VM_SAFEPARMCOUNT(3,VM_substring);
1912 string = VM_GetTempString();
1913 s = PRVM_G_STRING(OFS_PARM0);
1914 start = PRVM_G_FLOAT(OFS_PARM1);
1915 length = PRVM_G_FLOAT(OFS_PARM2);
1918 for (i = 0;i < start && *s;i++, s++);
1919 for (i = 0;i < VM_STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
1922 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1929 vector stov(string s)
1932 //vector(string s) stov = #117; // returns vector value from a string
1935 char string[VM_STRINGTEMP_LENGTH];
1937 VM_SAFEPARMCOUNT(1,VM_stov);
1939 VM_VarString(0, string, sizeof(string));
1940 Math_atov(string, PRVM_G_VECTOR(OFS_RETURN));
1947 string strzone(string s)
1950 //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)
1951 void VM_strzone(void)
1955 VM_SAFEPARMCOUNT(1,VM_strzone);
1957 in = PRVM_G_STRING(OFS_PARM0);
1958 out = Mem_Alloc(VM_STRINGS_MEMPOOL, strlen(in) + 1);
1960 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(out);
1970 //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!!!)
1971 void VM_strunzone(void)
1973 VM_SAFEPARMCOUNT(1,VM_strunzone);
1975 Mem_Free(PRVM_G_STRING(OFS_PARM0));
1980 VM_command (used by client and menu)
1982 clientcommand(float client, string s) (for client and menu)
1985 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
1986 //this function originally written by KrimZon, made shorter by LordHavoc
1987 void VM_clcommand (void)
1989 client_t *temp_client;
1992 VM_SAFEPARMCOUNT(2,VM_clcommand);
1994 i = PRVM_G_FLOAT(OFS_PARM0);
1995 if (!sv.active || i < 0 || i >= svs.maxclients || !svs.clients[i].active)
1997 Con_Printf("VM_clientcommand: %s: invalid client/server is not active !", PRVM_NAME);
2001 temp_client = host_client;
2002 host_client = svs.clients + i;
2003 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2004 host_client = temp_client;
2012 float tokenize(string s)
2015 //float(string s) tokenize = #441;
2016 // takes apart a string into individal words (access them with argv), returns how many
2017 // this function originally written by KrimZon, made shorter by LordHavoc
2018 static char **tokens = NULL;
2019 static int max_tokens, num_tokens = 0;
2020 void VM_tokenize (void)
2025 VM_SAFEPARMCOUNT(1,VM_tokenize);
2027 str = PRVM_G_STRING(OFS_PARM0);
2032 for (i=0;i<num_tokens;i++)
2038 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2039 max_tokens = strlen(str);
2041 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2043 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2044 strcpy(tokens[num_tokens], com_token);
2047 PRVM_G_FLOAT(OFS_RETURN) = num_tokens;
2054 string argv(float n)
2057 //string(float n) argv = #442;
2058 // returns a word from the tokenized string (returns nothing for an invalid index)
2059 // this function originally written by KrimZon, made shorter by LordHavoc
2064 VM_SAFEPARMCOUNT(1,VM_argv);
2066 token_num = PRVM_G_FLOAT(OFS_PARM0);
2067 if (token_num >= 0 && token_num < num_tokens)
2068 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tokens[token_num]);
2070 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
2074 //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)
2075 void PF_setattachment (void)
2077 edict_t *e = G_EDICT(OFS_PARM0);
2078 edict_t *tagentity = G_EDICT(OFS_PARM1);
2079 char *tagname = G_STRING(OFS_PARM2);
2084 if (tagentity == NULL)
2085 tagentity = sv.edicts;
2087 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
2089 v->edict = EDICT_TO_PROG(tagentity);
2091 v = GETEDICTFIELDVALUE(e, eval_tag_index);
2094 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
2096 modelindex = (int)tagentity->v->modelindex;
2097 if (modelindex >= 0 && modelindex < MAX_MODELS)
2099 model = sv.models[modelindex];
2100 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
2101 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
2102 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
2104 if (v->_float == 0 && model->alias.aliasnum_tags)
2105 for (i = 0;i < model->alias.aliasnum_tags;i++)
2106 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
2109 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);
2112 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));
2123 void VM_isserver(void)
2125 VM_SAFEPARMCOUNT(0,VM_serverstate);
2127 PRVM_G_FLOAT(OFS_RETURN) = sv.active;
2137 void VM_clientcount(void)
2139 VM_SAFEPARMCOUNT(0,VM_clientcount);
2141 PRVM_G_FLOAT(OFS_RETURN) = svs.maxclients;
2151 void VM_clientstate(void)
2153 VM_SAFEPARMCOUNT(0,VM_clientstate);
2155 PRVM_G_FLOAT(OFS_RETURN) = cls.state;
2162 float getostype(void)
2164 */ // not used at the moment -> not included in the common list
2165 void VM_getostype(void)
2167 VM_SAFEPARMCOUNT(0,VM_getostype);
2172 OS_MAC - not supported
2176 PRVM_G_FLOAT(OFS_RETURN) = 0;
2178 PRVM_G_FLOAT(OFS_RETURN) = 2;
2180 PRVM_G_FLOAT(OFS_RETURN) = 1;
2188 vector getmousepos()
2191 void VM_getmousepos(void)
2194 VM_SAFEPARMCOUNT(0,VM_getmousepos);
2196 PRVM_G_VECTOR(OFS_RETURN)[0] = in_mouse_x;
2197 PRVM_G_VECTOR(OFS_RETURN)[1] = in_mouse_y;
2198 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2208 void VM_gettime(void)
2210 VM_SAFEPARMCOUNT(0,VM_gettime);
2212 PRVM_G_FLOAT(OFS_RETURN) = (float) *prog->time;
2219 loadfromdata(string data)
2222 void VM_loadfromdata(void)
2224 VM_SAFEPARMCOUNT(1,VM_loadentsfromfile);
2226 PRVM_ED_LoadFromFile(PRVM_G_STRING(OFS_PARM0));
2233 loadfromfile(string file)
2236 void VM_loadfromfile(void)
2241 VM_SAFEPARMCOUNT(1,VM_loadfromfile);
2243 filename = PRVM_G_STRING(OFS_PARM0);
2244 // .. is parent directory on many platforms
2245 // / is parent directory on Amiga
2246 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2247 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2248 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2250 Con_Printf("VM_loadfromfile: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
2251 PRVM_G_FLOAT(OFS_RETURN) = -4;
2255 // not conform with VM_fopen
2256 data = FS_LoadFile(filename, false);
2258 PRVM_G_FLOAT(OFS_RETURN) = -1;
2260 PRVM_ED_LoadFromFile(data);
2271 float mod(float val, float m)
2274 void VM_modulo(void)
2277 VM_SAFEPARMCOUNT(2,VM_module);
2279 val = (int) PRVM_G_FLOAT(OFS_PARM0);
2280 m = (int) PRVM_G_FLOAT(OFS_PARM1);
2282 PRVM_G_FLOAT(OFS_RETURN) = (float) (val % m);
2285 void VM_Search_Init(void)
2287 memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
2290 void VM_Search_Reset(void)
2293 // reset the fssearch list
2294 for(i = 0; i < MAX_VMSEARCHES; i++)
2295 if(VM_SEARCHLIST[i])
2296 FS_FreeSearch(VM_SEARCHLIST[i]);
2297 memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
2304 float search_begin(string pattern, float caseinsensitive, float quiet)
2307 void VM_search_begin(void)
2311 int caseinsens, quiet;
2313 VM_SAFEPARMCOUNT(3, VM_search_begin);
2315 pattern = PRVM_G_STRING(OFS_PARM0);
2317 VM_CheckEmptyString(pattern);
2319 caseinsens = PRVM_G_FLOAT(OFS_PARM1);
2320 quiet = PRVM_G_FLOAT(OFS_PARM2);
2322 for(handle = 0; handle < MAX_VMSEARCHES; handle++)
2323 if(!VM_SEARCHLIST[handle])
2326 if(handle >= MAX_VMSEARCHES)
2328 Con_Printf("VM_search_begin: %s ran out of search handles (%i)\n", PRVM_NAME, MAX_VMSEARCHES);
2329 PRVM_G_FLOAT(OFS_RETURN) = -2;
2333 if(!(VM_SEARCHLIST[handle] = FS_Search(pattern,caseinsens, quiet)))
2334 PRVM_G_FLOAT(OFS_RETURN) = -1;
2336 PRVM_G_FLOAT(OFS_RETURN) = handle;
2343 void search_end(float handle)
2346 void VM_search_end(void)
2349 VM_SAFEPARMCOUNT(1, VM_search_end);
2351 handle = PRVM_G_FLOAT(OFS_PARM0);
2353 if(handle < 0 || handle >= MAX_VMSEARCHES)
2355 Con_Printf("VM_search_end: invalid handle %i used in %s\n", handle, PRVM_NAME);
2358 if(VM_SEARCHLIST[handle] == NULL)
2360 Con_Printf("VM_search_end: no such handle %i in %s\n", handle, PRVM_NAME);
2364 FS_FreeSearch(VM_SEARCHLIST[handle]);
2365 VM_SEARCHLIST[handle] = NULL;
2372 float search_getsize(float handle)
2375 void VM_search_getsize(void)
2378 VM_SAFEPARMCOUNT(1, VM_M_search_getsize);
2380 handle = PRVM_G_FLOAT(OFS_PARM0);
2382 if(handle < 0 || handle >= MAX_VMSEARCHES)
2384 Con_Printf("VM_search_getsize: invalid handle %i used in %s\n", handle, PRVM_NAME);
2387 if(VM_SEARCHLIST[handle] == NULL)
2389 Con_Printf("VM_search_getsize: no such handle %i in %s\n", handle, PRVM_NAME);
2393 PRVM_G_FLOAT(OFS_RETURN) = VM_SEARCHLIST[handle]->numfilenames;
2398 VM_search_getfilename
2400 string search_getfilename(float handle, float num)
2403 void VM_search_getfilename(void)
2405 int handle, filenum;
2407 VM_SAFEPARMCOUNT(2, VM_search_getfilename);
2409 handle = PRVM_G_FLOAT(OFS_PARM0);
2410 filenum = PRVM_G_FLOAT(OFS_PARM1);
2412 if(handle < 0 || handle >= MAX_VMSEARCHES)
2414 Con_Printf("VM_search_getfilename: invalid handle %i used in %s\n", handle, PRVM_NAME);
2417 if(VM_SEARCHLIST[handle] == NULL)
2419 Con_Printf("VM_search_getfilename: no such handle %i in %s\n", handle, PRVM_NAME);
2422 if(filenum < 0 || filenum >= VM_SEARCHLIST[handle]->numfilenames)
2424 Con_Printf("VM_search_getfilename: invalid filenum %i in %s\n", filenum, PRVM_NAME);
2428 tmp = VM_GetTempString();
2429 strcpy(tmp, VM_SEARCHLIST[handle]->filenames[filenum]);
2431 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
2434 //=============================================================================
2435 // Draw builtins (client & menu)
2441 float iscachedpic(string pic)
2444 void VM_iscachedpic(void)
2446 VM_SAFEPARMCOUNT(1,VM_iscachedpic);
2448 // drawq hasnt such a function, thus always return true
2449 PRVM_G_FLOAT(OFS_RETURN) = TRUE;
2456 string precache_pic(string pic)
2459 void VM_precache_pic(void)
2463 VM_SAFEPARMCOUNT(1, VM_precache_pic);
2465 s = PRVM_G_STRING(OFS_PARM0);
2466 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
2469 PRVM_ERROR ("VM_precache_pic: %s: NULL\n", PRVM_NAME);
2471 VM_CheckEmptyString (s);
2473 if(!Draw_CachePic(s))
2474 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
2484 void VM_freepic(void)
2488 VM_SAFEPARMCOUNT(1,VM_freepic);
2490 s = PRVM_G_STRING(OFS_PARM0);
2493 PRVM_ERROR ("VM_freepic: %s: NULL\n");
2495 VM_CheckEmptyString (s);
2504 float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
2507 void VM_drawcharacter(void)
2509 float *pos,*scale,*rgb;
2512 VM_SAFEPARMCOUNT(6,VM_drawcharacter);
2514 character = (char) PRVM_G_FLOAT(OFS_PARM1);
2517 Con_Printf("VM_drawcharacter: %s passed null character !\n",PRVM_NAME);
2518 PRVM_G_FLOAT(OFS_RETURN) = -1;
2522 pos = PRVM_G_VECTOR(OFS_PARM0);
2523 scale = PRVM_G_VECTOR(OFS_PARM2);
2524 rgb = PRVM_G_VECTOR(OFS_PARM3);
2525 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2527 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2529 Con_Printf("VM_drawcharacter: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2530 PRVM_G_FLOAT(OFS_RETURN) = -2;
2534 if(pos[2] || scale[2])
2535 Con_Printf("VM_drawcharacter: z value%c from %s discarded",(pos[2] && scale[2]) ? 's' : 0,((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale")));
2537 if(!scale[0] || !scale[1])
2539 Con_Printf("VM_drawcharacter: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2540 PRVM_G_FLOAT(OFS_RETURN) = -3;
2544 DrawQ_String (pos[0], pos[1], &character, 1, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2545 PRVM_G_FLOAT(OFS_RETURN) = 1;
2552 float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
2555 void VM_drawstring(void)
2557 float *pos,*scale,*rgb;
2560 VM_SAFEPARMCOUNT(6,VM_drawstring);
2562 string = PRVM_G_STRING(OFS_PARM1);
2565 Con_Printf("VM_drawstring: %s passed null string !\n",PRVM_NAME);
2566 PRVM_G_FLOAT(OFS_RETURN) = -1;
2570 VM_CheckEmptyString(string);
2572 pos = PRVM_G_VECTOR(OFS_PARM0);
2573 scale = PRVM_G_VECTOR(OFS_PARM2);
2574 rgb = PRVM_G_VECTOR(OFS_PARM3);
2575 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2577 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2579 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2580 PRVM_G_FLOAT(OFS_RETURN) = -2;
2584 if(!scale[0] || !scale[1])
2586 Con_Printf("VM_drawstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2587 PRVM_G_FLOAT(OFS_RETURN) = -3;
2591 if(pos[2] || scale[2])
2592 Con_Printf("VM_drawstring: z value%c from %s discarded",(pos[2] && scale[2]) ? 's' : 0,((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale")));
2594 DrawQ_String (pos[0], pos[1], string, 0, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2595 PRVM_G_FLOAT(OFS_RETURN) = 1;
2601 float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
2604 void VM_drawpic(void)
2607 float *size, *pos, *rgb;
2610 VM_SAFEPARMCOUNT(6,VM_drawpic);
2612 pic = PRVM_G_STRING(OFS_PARM1);
2616 Con_Printf("VM_drawpic: %s passed null picture name !\n", PRVM_NAME);
2617 PRVM_G_FLOAT(OFS_RETURN) = -1;
2621 VM_CheckEmptyString (pic);
2623 // is pic cached ? no function yet for that
2626 Con_Printf("VM_drawpic: %s: %s not cached !\n", PRVM_NAME, pic);
2627 PRVM_G_FLOAT(OFS_RETURN) = -4;
2631 pos = PRVM_G_VECTOR(OFS_PARM0);
2632 size = PRVM_G_VECTOR(OFS_PARM2);
2633 rgb = PRVM_G_VECTOR(OFS_PARM3);
2634 flag = (int) PRVM_G_FLOAT(OFS_PARM5);
2636 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2638 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2639 PRVM_G_FLOAT(OFS_RETURN) = -2;
2643 if(pos[2] || size[2])
2644 Con_Printf("VM_drawstring: z value%c from %s discarded",(pos[2] && size[2]) ? 's' : 0,((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size")));
2646 DrawQ_Pic(pos[0], pos[1], pic, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2647 PRVM_G_FLOAT(OFS_RETURN) = 1;
2654 float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
2657 void VM_drawfill(void)
2659 float *size, *pos, *rgb;
2662 VM_SAFEPARMCOUNT(5,VM_drawfill);
2665 pos = PRVM_G_VECTOR(OFS_PARM0);
2666 size = PRVM_G_VECTOR(OFS_PARM1);
2667 rgb = PRVM_G_VECTOR(OFS_PARM2);
2668 flag = (int) PRVM_G_FLOAT(OFS_PARM4);
2670 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2672 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2673 PRVM_G_FLOAT(OFS_RETURN) = -2;
2677 if(pos[2] || size[2])
2678 Con_Printf("VM_drawstring: z value%c from %s discarded",(pos[2] && size[2]) ? 's' : 0,((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size")));
2680 DrawQ_Pic(pos[0], pos[1], 0, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM3), flag);
2681 PRVM_G_FLOAT(OFS_RETURN) = 1;
2688 drawsetcliparea(float x, float y, float width, float height)
2691 void VM_drawsetcliparea(void)
2694 VM_SAFEPARMCOUNT(4,VM_drawsetcliparea);
2696 x = bound(0,PRVM_G_FLOAT(OFS_PARM0),vid.conwidth);
2697 y = bound(0,PRVM_G_FLOAT(OFS_PARM1),vid.conheight);
2698 w = bound(0,PRVM_G_FLOAT(OFS_PARM2),(vid.conwidth - x));
2699 h = bound(0,PRVM_G_FLOAT(OFS_PARM3),(vid.conheight - y));
2701 DrawQ_SetClipArea(x,y,w,h);
2706 VM_drawresetcliparea
2711 void VM_drawresetcliparea(void)
2713 VM_SAFEPARMCOUNT(0,VM_drawresetcliparea);
2715 DrawQ_ResetClipArea();
2722 vector getimagesize(string pic)
2725 void VM_getimagesize(void)
2730 VM_SAFEPARMCOUNT(1,VM_getimagesize);
2732 p = PRVM_G_STRING(OFS_PARM0);
2735 PRVM_ERROR("VM_getimagepos: %s passed null picture name !\n", PRVM_NAME);
2737 VM_CheckEmptyString (p);
2739 pic = Draw_CachePic (p);
2741 PRVM_G_VECTOR(OFS_RETURN)[0] = pic->width;
2742 PRVM_G_VECTOR(OFS_RETURN)[1] = pic->height;
2743 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2746 void VM_Cmd_Init(void)
2748 // only init the stuff for the current prog
2749 VM_STRINGS_MEMPOOL = Mem_AllocPool(va("vm_stringsmempool[%s]",PRVM_NAME));
2754 void VM_Cmd_Reset(void)
2756 //Mem_EmptyPool(VM_STRINGS_MEMPOOL);
2757 Mem_FreePool(&VM_STRINGS_MEMPOOL);
2759 VM_Files_CloseAll();
2762 //============================================================================
2765 char *vm_sv_extensions =
2768 prvm_builtin_t vm_sv_builtins[] = {
2769 0 // to be consistent with the old vm
2772 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
2774 void VM_SV_Cmd_Init(void)
2778 void VM_SV_Cmd_Reset(void)
2782 //============================================================================
2785 char *vm_cl_extensions =
2788 prvm_builtin_t vm_cl_builtins[] = {
2789 0 // to be consistent with the old vm
2792 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
2794 void VM_CL_Cmd_Init(void)
2798 void VM_CL_Cmd_Reset(void)
2802 //============================================================================
2805 char *vm_m_extensions =
2812 setmousetarget(float target)
2815 void VM_M_setmousetarget(void)
2817 VM_SAFEPARMCOUNT(1, VM_M_setmousetarget);
2819 switch((int)PRVM_G_FLOAT(OFS_PARM0))
2822 in_client_mouse = false;
2825 in_client_mouse = true;
2828 PRVM_ERROR("VM_M_setmousetarget: wrong destination %i !\n",PRVM_G_FLOAT(OFS_PARM0));
2836 float getmousetarget
2839 void VM_M_getmousetarget(void)
2841 VM_SAFEPARMCOUNT(0,VM_M_getmousetarget);
2844 PRVM_G_FLOAT(OFS_RETURN) = 2;
2846 PRVM_G_FLOAT(OFS_RETURN) = 1;
2855 setkeydest(float dest)
2858 void VM_M_setkeydest(void)
2860 VM_SAFEPARMCOUNT(1,VM_M_setkeydest);
2862 switch((int)PRVM_G_FLOAT(OFS_PARM0))
2866 key_dest = key_game;
2870 key_dest = key_menu;
2874 // key_dest = key_message
2877 PRVM_ERROR("VM_M_setkeydest: wrong destination %i !\n",prog->globals[OFS_PARM0]);
2888 void VM_M_getkeydest(void)
2890 VM_SAFEPARMCOUNT(0,VM_M_getkeydest);
2892 // key_game = 0, key_message = 1, key_menu = 2, unknown = 3
2896 PRVM_G_FLOAT(OFS_RETURN) = 0;
2899 PRVM_G_FLOAT(OFS_RETURN) = 2;
2903 // PRVM_G_FLOAT(OFS_RETURN) = 1;
2906 PRVM_G_FLOAT(OFS_RETURN) = 3;
2914 callfunction(...,string function_name)
2917 mfunction_t *PRVM_ED_FindFunction (const char *name);
2918 void VM_M_callfunction(void)
2924 PRVM_ERROR("VM_M_callfunction: 1 parameter is required !\n");
2926 s = PRVM_G_STRING(OFS_PARM0 + (prog->argc - 1));
2929 PRVM_ERROR("VM_M_callfunction: null string !\n");
2931 VM_CheckEmptyString(s);
2933 func = PRVM_ED_FindFunction(s);
2936 PRVM_ERROR("VM_M_callfunciton: function %s not found !\n", s);
2937 else if (func->first_statement < 0)
2939 // negative statements are built in functions
2940 int builtinnumber = -func->first_statement;
2941 prog->xfunction->builtinsprofile++;
2942 if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber])
2943 prog->builtins[builtinnumber]();
2945 PRVM_ERROR("No such builtin #%i in %s", builtinnumber, PRVM_NAME);
2950 PRVM_ExecuteProgram(func - prog->functions,"");
2959 float isfunction(string function_name)
2962 mfunction_t *PRVM_ED_FindFunction (const char *name);
2963 void VM_M_isfunction(void)
2968 VM_SAFEPARMCOUNT(1, VM_M_isfunction);
2970 s = PRVM_G_STRING(OFS_PARM0);
2973 PRVM_ERROR("VM_M_isfunction: null string !\n");
2975 VM_CheckEmptyString(s);
2977 func = PRVM_ED_FindFunction(s);
2980 PRVM_G_FLOAT(OFS_RETURN) = false;
2982 PRVM_G_FLOAT(OFS_RETURN) = true;
2989 writetofile(float fhandle, entity ent)
2992 void VM_M_writetofile(void)
2997 VM_SAFEPARMCOUNT(2, VM_M_writetofile);
2999 filenum = PRVM_G_FLOAT(OFS_PARM0);
3000 if (filenum < 0 || filenum >= MAX_VMFILES)
3002 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
3005 if (VM_FILES[filenum] == NULL)
3007 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
3011 ent = PRVM_G_EDICT(OFS_PARM1);
3014 Con_Printf("VM_M_writetofile: %s: entity %i is free !\n", PRVM_NAME, PRVM_EDICT_NUM(OFS_PARM1));
3018 PRVM_ED_Write (VM_FILES[filenum], ent);
3025 vector getresolution(float number)
3028 extern unsigned short video_resolutions[][2];
3029 void VM_M_getresolution(void)
3032 VM_SAFEPARMCOUNT(1, VM_getresolution);
3034 nr = PRVM_G_FLOAT(OFS_PARM0);
3037 PRVM_G_VECTOR(OFS_RETURN)[0] = video_resolutions[nr][0];
3038 PRVM_G_VECTOR(OFS_RETURN)[1] = video_resolutions[nr][1];
3039 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
3046 string keynumtostring(float keynum)
3049 void VM_M_keynumtostring(void)
3053 VM_SAFEPARMCOUNT(1, VM_M_keynumtostring);
3055 keynum = PRVM_G_FLOAT(OFS_PARM0);
3057 tmp = VM_GetTempString();
3059 strcpy(tmp, Key_KeynumToString(keynum));
3061 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
3064 prvm_builtin_t vm_m_builtins[] = {
3065 0, // to be consistent with the old vm
3066 // common builtings (mostly)
3143 VM_search_getfilename, // 77
3158 VM_WriteEntity, // 408
3174 VM_drawresetcliparea,
3175 VM_getimagesize,// 460
3184 VM_M_setmousetarget,
3185 VM_M_getmousetarget,
3190 VM_M_keynumtostring // 609
3193 const int vm_m_numbuiltins = sizeof(vm_m_builtins) / sizeof(prvm_builtin_t);
3195 void VM_M_Cmd_Init(void)
3200 void VM_M_Cmd_Reset(void)