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 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)
146 #include "quakedef.h"
147 #include "progdefs.h"
148 #include "clprogdefs.h"
149 #include "mprogdefs.h"
151 //============================================================================
152 // nice helper macros
154 #ifndef VM_NOPARMCHECK
155 #define VM_SAFEPARMCOUNT(p,f) if(prog->argc != p) PRVM_ERROR(#f " wrong parameter count (" #p " expected ) !\n")
157 #define VM_SAFEPARMCOUNT(p,f)
160 #define VM_RETURN_EDICT(e) (((int *)prog->globals)[OFS_RETURN] = PRVM_EDICT_TO_PROG(e))
162 #define VM_STRINGS_MEMPOOL vm_strings_mempool[PRVM_GetProgNr()]
164 #define e10 0,0,0,0,0,0,0,0,0,0
165 #define e100 e10,e10,e10,e10,e10,e10,e10,e10,e10,e10
166 #define e1000 e100,e100,e100,e100,e100,e100,e100,e100,e100,e100
168 //============================================================================
171 // string zone mempool
172 mempool_t *vm_strings_mempool[PRVM_MAXPROGS];
174 // temp string handling
175 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
176 #define VM_STRINGTEMP_BUFFERS 16
177 #define VM_STRINGTEMP_LENGTH 4096
178 static char vm_string_temp[VM_STRINGTEMP_BUFFERS][VM_STRINGTEMP_LENGTH];
179 static int vm_string_tempindex = 0;
182 #define MAX_QC_CVARS 128 * PRVM_MAXPROGS
183 cvar_t vm_qc_cvar[MAX_QC_CVARS];
184 int vm_currentqc_cvar;
187 #define MAX_VMFILES 256
188 #define MAX_PRVMFILES MAX_VMFILES * PRVM_MAXPROGS
189 #define VM_FILES ((qfile_t**)(vm_files + PRVM_GetProgNr() * MAX_VMFILES))
191 qfile_t *vm_files[MAX_PRVMFILES];
193 // qc fs search handling
194 #define MAX_VMSEARCHES 128
195 #define TOTAL_VMSEARCHES MAX_VMSEARCHES * PRVM_MAXPROGS
196 #define VM_SEARCHLIST ((fssearch_t**)(vm_fssearchlist + PRVM_GetProgNr() * MAX_VMSEARCHES))
198 fssearch_t *vm_fssearchlist[TOTAL_VMSEARCHES];
200 static char *VM_GetTempString(void)
203 s = vm_string_temp[vm_string_tempindex];
204 vm_string_tempindex = (vm_string_tempindex + 1) % VM_STRINGTEMP_BUFFERS;
208 void VM_CheckEmptyString (char *s)
211 PRVM_ERROR ("%s: Bad string", PRVM_NAME);
214 //============================================================================
217 void VM_VarString(int first, char *out, int outlength)
223 outend = out + outlength - 1;
224 for (i = first;i < prog->argc && out < outend;i++)
226 s = PRVM_G_STRING((OFS_PARM0+i*3));
227 while (out < outend && *s)
237 returns true if the extension is supported by the server
239 checkextension(extensionname)
243 // kind of helper function
244 static qboolean checkextension(char *name)
250 for (e = prog->extensionstring;*e;e++)
257 while (*e && *e != ' ')
259 if (e - start == len)
260 if (!strncasecmp(start, name, len))
268 void VM_checkextension (void)
270 VM_SAFEPARMCOUNT(1,VM_checkextension);
272 PRVM_G_FLOAT(OFS_RETURN) = checkextension(PRVM_G_STRING(OFS_PARM0));
279 This is a TERMINAL error, which will kill off the entire prog.
288 char string[VM_STRINGTEMP_LENGTH];
290 VM_VarString(0, string, sizeof(string));
291 Con_Printf ("======%S ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
294 ed = PRVM_G_EDICT(prog->self->ofs);
298 PRVM_ERROR ("%s: Program error", PRVM_NAME);
305 Dumps out self, then an error message. The program is aborted and self is
306 removed, but the level can continue.
311 void VM_objerror (void)
314 char string[VM_STRINGTEMP_LENGTH];
316 VM_VarString(0, string, sizeof(string));
317 Con_Printf ("======%s OBJECT ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
320 ed = PRVM_G_EDICT (prog->self->ofs);
326 // objerror has to display the object fields -> else call
327 PRVM_ERROR ("VM_objecterror: self not defined !\n");
332 VM_print (actually used only by client and menu)
341 char string[VM_STRINGTEMP_LENGTH];
343 VM_VarString(0, string, sizeof(string));
351 broadcast print to everyone on server
356 void VM_bprint (void)
358 char string[VM_STRINGTEMP_LENGTH];
362 Con_Printf("VM_bprint: game is not server(%s) !", PRVM_NAME);
366 VM_VarString(0, string, sizeof(string));
367 SV_BroadcastPrintf("%s", string);
372 VM_sprint (menu & client but only if server.active == true)
374 single print to a specific client
376 sprint(float clientnum,...[string])
379 void VM_sprint (void)
383 char string[VM_STRINGTEMP_LENGTH];
385 //find client for this entity
386 clientnum = PRVM_G_FLOAT(OFS_PARM0);
387 if (!sv.active || clientnum < 0 || clientnum >= svs.maxclients || !svs.clients[clientnum].active)
389 Con_Printf("VM_sprint: %s: invalid client or server is not active !", PRVM_NAME);
393 client = svs.clients + clientnum;
394 if (!client->netconnection)
396 VM_VarString(1, string, sizeof(string));
397 MSG_WriteChar(&client->message,svc_print);
398 MSG_WriteString(&client->message, string);
405 single print to the screen
407 centerprint(clientent, value)
410 void VM_centerprint (void)
412 char string[VM_STRINGTEMP_LENGTH];
414 VM_VarString(0, string, sizeof(string));
415 SCR_CenterPrint(string);
422 vector normalize(vector)
425 void VM_normalize (void)
431 VM_SAFEPARMCOUNT(1,VM_normalize);
433 value1 = PRVM_G_VECTOR(OFS_PARM0);
435 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
439 newvalue[0] = newvalue[1] = newvalue[2] = 0;
443 newvalue[0] = value1[0] * new;
444 newvalue[1] = value1[1] * new;
445 newvalue[2] = value1[2] * new;
448 VectorCopy (newvalue, PRVM_G_VECTOR(OFS_RETURN));
463 VM_SAFEPARMCOUNT(1,VM_vlen);
465 value1 = PRVM_G_VECTOR(OFS_PARM0);
467 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
470 PRVM_G_FLOAT(OFS_RETURN) = new;
477 float vectoyaw(vector)
480 void VM_vectoyaw (void)
485 VM_SAFEPARMCOUNT(1,VM_vectoyaw);
487 value1 = PRVM_G_VECTOR(OFS_PARM0);
489 if (value1[1] == 0 && value1[0] == 0)
493 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
498 PRVM_G_FLOAT(OFS_RETURN) = yaw;
506 vector vectoangles(vector)
509 void VM_vectoangles (void)
515 VM_SAFEPARMCOUNT(1,VM_vectoangles);
517 value1 = PRVM_G_VECTOR(OFS_PARM0);
519 if (value1[1] == 0 && value1[0] == 0)
529 // LordHavoc: optimized a bit
532 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
536 else if (value1[1] > 0)
541 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
542 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
547 PRVM_G_FLOAT(OFS_RETURN+0) = pitch;
548 PRVM_G_FLOAT(OFS_RETURN+1) = yaw;
549 PRVM_G_FLOAT(OFS_RETURN+2) = 0;
556 Returns a number from 0<= num < 1
561 void VM_random (void)
565 VM_SAFEPARMCOUNT(0,VM_random);
567 num = (rand ()&0x7fff) / ((float)0x7fff);
569 PRVM_G_FLOAT(OFS_RETURN) = num;
576 Each entity can have eight independant sound sources, like voice,
579 Channel 0 is an auto-allocate channel, the others override anything
580 already running on that entity/channel pair.
582 An attenuation of 0 will play full volume everywhere in the level.
583 Larger attenuations will drop off.
596 entity = G_EDICT(OFS_PARM0);
597 channel = G_FLOAT(OFS_PARM1);
598 sample = G_STRING(OFS_PARM2);
599 volume = G_FLOAT(OFS_PARM3) * 255;
600 attenuation = G_FLOAT(OFS_PARM4);
602 if (volume < 0 || volume > 255)
603 Host_Error ("SV_StartSound: volume = %i", volume);
605 if (attenuation < 0 || attenuation > 4)
606 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
608 if (channel < 0 || channel > 7)
609 Host_Error ("SV_StartSound: channel = %i", channel);
611 SV_StartSound (entity, channel, sample, volume, attenuation);
619 localsound(string sample)
622 void VM_localsound(void)
626 VM_SAFEPARMCOUNT(1,VM_localsound);
628 s = PRVM_G_STRING(OFS_PARM0);
632 Con_Printf("VM_localsound: %s : %s not cached !\n", PRVM_NAME, s);
633 PRVM_G_FLOAT(OFS_RETURN) = -4;
638 PRVM_G_FLOAT(OFS_RETURN) = 1;
650 PRVM_ERROR ("%s: break statement", PRVM_NAME);
653 //============================================================================
659 Sends text over to the client's execution buffer
661 [localcmd (string) or]
665 void VM_localcmd (void)
667 VM_SAFEPARMCOUNT(1,VM_localcmd);
669 Cbuf_AddText(PRVM_G_STRING(OFS_PARM0));
681 VM_SAFEPARMCOUNT(1,VM_cvar);
683 PRVM_G_FLOAT(OFS_RETURN) = Cvar_VariableValue(PRVM_G_STRING(OFS_PARM0));
690 const string str_cvar (string)
693 void VM_str_cvar(void)
696 const char *cvar_string;
697 VM_SAFEPARMCOUNT(1,VM_str_cvar);
699 name = PRVM_G_STRING(OFS_PARM0);
702 PRVM_ERROR("VM_str_cvar: %s: null string\n", PRVM_NAME);
704 VM_CheckEmptyString(name);
706 out = VM_GetTempString();
708 cvar_string = Cvar_VariableString(name);
710 strcpy(out, cvar_string);
712 PRVM_G_INT(OFS_PARM0) = PRVM_SetString(out);
719 void cvar_set (string,string)
722 void VM_cvar_set (void)
724 VM_SAFEPARMCOUNT(2,VM_cvar_set);
726 Cvar_Set(PRVM_G_STRING(OFS_PARM0), PRVM_G_STRING(OFS_PARM1));
736 void VM_dprint (void)
738 char string[VM_STRINGTEMP_LENGTH];
739 if (developer.integer)
741 VM_VarString(0, string, sizeof(string));
742 Con_Printf("%s: %s", PRVM_NAME, string);
759 VM_SAFEPARMCOUNT(1, VM_ftos);
761 v = PRVM_G_FLOAT(OFS_PARM0);
763 s = VM_GetTempString();
764 if ((float)((int)v) == v)
765 sprintf(s, "%i", (int)v);
768 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
783 VM_SAFEPARMCOUNT(1,VM_fabs);
785 v = PRVM_G_FLOAT(OFS_PARM0);
786 PRVM_G_FLOAT(OFS_RETURN) = fabs(v);
801 VM_SAFEPARMCOUNT(1,VM_vtos);
803 s = VM_GetTempString();
804 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]);
805 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
820 VM_SAFEPARMCOUNT(1, VM_etos);
822 s = VM_GetTempString();
823 sprintf (s, "entity %i", PRVM_G_EDICTNUM(OFS_PARM0));
824 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
831 float stof(...[string])
836 char string[VM_STRINGTEMP_LENGTH];
837 VM_VarString(0, string, sizeof(string));
838 PRVM_G_FLOAT(OFS_RETURN) = atof(string);
852 prog->xfunction->builtinsprofile += 20;
853 ed = PRVM_ED_Alloc();
865 void VM_remove (void)
868 prog->xfunction->builtinsprofile += 20;
870 VM_SAFEPARMCOUNT(1, VM_remove);
872 ed = PRVM_G_EDICT(OFS_PARM0);
873 // if (ed == prog->edicts)
874 // PRVM_ERROR ("remove: tried to remove world\n");
875 // if (PRVM_NUM_FOR_EDICT(ed) <= sv.maxclients)
876 // Host_Error("remove: tried to remove a client\n");
884 entity find(entity start, .string field, string match)
895 VM_SAFEPARMCOUNT(3,VM_find);
897 e = PRVM_G_EDICTNUM(OFS_PARM0);
898 f = PRVM_G_INT(OFS_PARM1);
899 s = PRVM_G_STRING(OFS_PARM2);
903 // return reserved edict 0 (could be used for whatever the prog wants)
904 VM_RETURN_EDICT(prog->edicts);
908 for (e++ ; e < prog->num_edicts ; e++)
910 prog->xfunction->builtinsprofile++;
911 ed = PRVM_EDICT_NUM(e);
914 t = PRVM_E_STRING(ed,f);
924 VM_RETURN_EDICT(prog->edicts);
931 entity findfloat(entity start, .float field, float match)
932 entity findentity(entity start, .entity field, entity match)
935 // LordHavoc: added this for searching float, int, and entity reference fields
936 void VM_findfloat (void)
943 VM_SAFEPARMCOUNT(3,VM_findfloat);
945 e = PRVM_G_EDICTNUM(OFS_PARM0);
946 f = PRVM_G_INT(OFS_PARM1);
947 s = PRVM_G_FLOAT(OFS_PARM2);
949 for (e++ ; e < prog->num_edicts ; e++)
951 prog->xfunction->builtinsprofile++;
952 ed = PRVM_EDICT_NUM(e);
955 if (PRVM_E_FLOAT(ed,f) == s)
962 VM_RETURN_EDICT(prog->edicts);
969 entity findchain(.string field, string match)
972 int PRVM_ED_FindFieldOffset(const char *field);
973 // chained search for strings in entity fields
974 // entity(.string field, string match) findchain = #402;
975 void VM_findchain (void)
981 prvm_edict_t *ent, *chain;
983 VM_SAFEPARMCOUNT(2,VM_findchain);
985 // is the same like !(prog->flag & PRVM_FE_CHAIN) - even if the operator precedence is another
986 if(!prog->flag & PRVM_FE_CHAIN)
987 PRVM_ERROR("VM_findchain: %s doesnt have a chain field !\n", PRVM_NAME);
989 chain_of = PRVM_ED_FindFieldOffset ("chain");
991 chain = prog->edicts;
993 f = PRVM_G_INT(OFS_PARM0);
994 s = PRVM_G_STRING(OFS_PARM1);
997 VM_RETURN_EDICT(prog->edicts);
1001 ent = PRVM_NEXT_EDICT(prog->edicts);
1002 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
1004 prog->xfunction->builtinsprofile++;
1007 t = PRVM_E_STRING(ent,f);
1013 PRVM_E_FLOAT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain);
1017 VM_RETURN_EDICT(chain);
1024 entity findchainfloat(.string field, float match)
1025 entity findchainentity(.string field, entity match)
1028 // LordHavoc: chained search for float, int, and entity reference fields
1029 // entity(.string field, float match) findchainfloat = #403;
1030 void VM_findchainfloat (void)
1036 prvm_edict_t *ent, *chain;
1038 VM_SAFEPARMCOUNT(2, VM_findchainfloat);
1040 if(!prog->flag & PRVM_FE_CHAIN)
1041 PRVM_ERROR("VM_findchainfloat: %s doesnt have a chain field !\n", PRVM_NAME);
1043 chain_of = PRVM_ED_FindFieldOffset ("chain");
1045 chain = (prvm_edict_t *)prog->edicts;
1047 f = PRVM_G_INT(OFS_PARM0);
1048 s = PRVM_G_FLOAT(OFS_PARM1);
1050 ent = PRVM_NEXT_EDICT(prog->edicts);
1051 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
1053 prog->xfunction->builtinsprofile++;
1056 if (E_FLOAT(ent,f) != s)
1059 PRVM_E_FLOAT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain);
1063 VM_RETURN_EDICT(chain);
1070 string precache_file(string)
1073 void VM_precache_file (void)
1074 { // precache_file is only used to copy files with qcc, it does nothing
1075 VM_SAFEPARMCOUNT(1,VM_precache_file);
1077 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1084 used instead of the other VM_precache_* functions in the builtin list
1088 void VM_precache_error (void)
1090 PRVM_ERROR ("PF_Precache_*: Precache can only be done in spawn functions");
1097 string precache_sound (string sample)
1100 void VM_precache_sound (void)
1104 VM_SAFEPARMCOUNT(1, VM_precache_sound);
1106 s = PRVM_G_STRING(OFS_PARM0);
1107 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1108 VM_CheckEmptyString (s);
1112 Con_Printf("VM_precache_sound: %s already cached (%s)\n", s, PRVM_NAME);
1116 if(!S_PrecacheSound(s,true))
1117 Con_Printf("VM_prache_sound: Failed to load %s for %s\n", s, PRVM_NAME);
1127 void VM_coredump (void)
1129 VM_SAFEPARMCOUNT(0,VM_coredump);
1131 Cbuf_AddText("prvm_edicts ");
1132 Cbuf_AddText(PRVM_NAME);
1143 void PRVM_StackTrace(void);
1144 void VM_stackdump (void)
1146 VM_SAFEPARMCOUNT(0, VM_stackdump);
1161 VM_SAFEPARMCOUNT(0, VM_crash);
1163 PRVM_ERROR("Crash called by %s\n",PRVM_NAME);
1173 void VM_traceon (void)
1175 VM_SAFEPARMCOUNT(0,VM_traceon);
1187 void VM_traceoff (void)
1189 VM_SAFEPARMCOUNT(0,VM_traceoff);
1191 prog->trace = false;
1201 void VM_eprint (void)
1203 VM_SAFEPARMCOUNT(1,VM_eprint);
1205 PRVM_ED_PrintNum (PRVM_G_EDICTNUM(OFS_PARM0));
1219 VM_SAFEPARMCOUNT(1,VM_rint);
1221 f = PRVM_G_FLOAT(OFS_PARM0);
1223 PRVM_G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1225 PRVM_G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1235 void VM_floor (void)
1237 VM_SAFEPARMCOUNT(1,VM_floor);
1239 PRVM_G_FLOAT(OFS_RETURN) = floor(PRVM_G_FLOAT(OFS_PARM0));
1251 VM_SAFEPARMCOUNT(1,VM_ceil);
1253 PRVM_G_FLOAT(OFS_RETURN) = ceil(PRVM_G_FLOAT(OFS_PARM0));
1261 entity nextent(entity)
1264 void VM_nextent (void)
1269 i = PRVM_G_EDICTNUM(OFS_PARM0);
1272 prog->xfunction->builtinsprofile++;
1274 if (i == prog->num_edicts)
1276 VM_RETURN_EDICT(prog->edicts);
1279 ent = PRVM_EDICT_NUM(i);
1282 VM_RETURN_EDICT(ent);
1289 ===============================================================================
1292 used only for client and menu
1293 severs uses VM_SV_...
1295 Write*(* data, float type, float to)
1297 ===============================================================================
1300 #define MSG_BROADCAST 0 // unreliable to all
1301 #define MSG_ONE 1 // reliable to one (msg_entity)
1302 #define MSG_ALL 2 // reliable to all
1303 #define MSG_INIT 3 // write to the init string
1305 sizebuf_t *VM_WriteDest (void)
1311 PRVM_ERROR("VM_WriteDest: game is not server (%s)\n", PRVM_NAME);
1313 dest = G_FLOAT(OFS_PARM1);
1317 return &sv.datagram;
1320 destclient = (int) PRVM_G_FLOAT(OFS_PARM2);
1321 if (destclient < 0 || destclient >= svs.maxclients || !svs.clients[destclient].active)
1322 PRVM_ERROR("VM_clientcommand: %s: invalid client !\n", PRVM_NAME);
1324 return &svs.clients[destclient].message;
1327 return &sv.reliable_datagram;
1333 PRVM_ERROR ("WriteDest: bad destination");
1340 void VM_WriteByte (void)
1342 MSG_WriteByte (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1345 void VM_WriteChar (void)
1347 MSG_WriteChar (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1350 void VM_WriteShort (void)
1352 MSG_WriteShort (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1355 void VM_WriteLong (void)
1357 MSG_WriteLong (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1360 void VM_WriteAngle (void)
1362 MSG_WriteAngle (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1365 void VM_WriteCoord (void)
1367 MSG_WriteDPCoord (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1370 void VM_WriteString (void)
1372 MSG_WriteString (VM_WriteDest(), PRVM_G_STRING(OFS_PARM0));
1375 void VM_WriteEntity (void)
1377 MSG_WriteShort (VM_WriteDest(), PRVM_G_EDICTNUM(OFS_PARM0));
1380 //=============================================================================
1387 changelevel(string map)
1390 void VM_changelevel (void)
1394 VM_SAFEPARMCOUNT(1, VM_changelevel);
1398 Con_Printf("VM_changelevel: game is not server (%s)\n", PRVM_NAME);
1402 // make sure we don't issue two changelevels
1403 if (svs.changelevel_issued)
1405 svs.changelevel_issued = true;
1407 s = G_STRING(OFS_PARM0);
1408 Cbuf_AddText (va("changelevel %s\n",s));
1420 VM_SAFEPARMCOUNT(1,VM_sin);
1421 PRVM_G_FLOAT(OFS_RETURN) = sin(PRVM_G_FLOAT(OFS_PARM0));
1432 VM_SAFEPARMCOUNT(1,VM_cos);
1433 PRVM_G_FLOAT(OFS_RETURN) = cos(PRVM_G_FLOAT(OFS_PARM0));
1445 VM_SAFEPARMCOUNT(1,VM_sqrt);
1446 PRVM_G_FLOAT(OFS_RETURN) = sqrt(PRVM_G_FLOAT(OFS_PARM0));
1453 Returns a vector of length < 1 and > 0
1458 void VM_randomvec (void)
1463 VM_SAFEPARMCOUNT(0, VM_randomvec);
1468 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1469 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1470 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1472 while (DotProduct(temp, temp) >= 1);
1473 VectorCopy (temp, PRVM_G_VECTOR(OFS_RETURN));
1476 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1477 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1478 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1479 // length returned always > 0
1480 length = (rand()&32766 + 1) * (1.0 / 32767.0) / VectorLength(temp);
1481 VectorScale(temp,length, temp);*/
1482 //VectorCopy(temp, PRVM_G_VECTOR(OFS_RETURN));
1485 //=============================================================================
1491 float registercvar (string name, string value)
1494 void VM_registercvar (void)
1499 VM_SAFEPARMCOUNT(2,VM_registercvar);
1501 name = PRVM_G_STRING(OFS_PARM0);
1502 value = PRVM_G_STRING(OFS_PARM1);
1503 PRVM_G_FLOAT(OFS_RETURN) = 0;
1504 // first check to see if it has already been defined
1505 if (Cvar_FindVar (name))
1508 // check for overlap with a command
1509 if (Cmd_Exists (name))
1511 Con_Printf ("VM_registercvar: %s is a command\n", name);
1515 if (vm_currentqc_cvar >= MAX_QC_CVARS)
1516 PRVM_ERROR ("VM_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1518 // copy the name and value
1519 variable = &vm_qc_cvar[vm_currentqc_cvar++];
1520 variable->name = Z_Malloc (strlen(name)+1);
1521 strcpy (variable->name, name);
1522 variable->string = Z_Malloc (strlen(value)+1);
1523 strcpy (variable->string, value);
1524 variable->value = atof (value);
1526 Cvar_RegisterVariable(variable);
1527 PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1534 returns the minimum of two supplied floats
1536 float min(float a, float b, ...[float])
1541 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1542 if (prog->argc == 2)
1543 PRVM_G_FLOAT(OFS_RETURN) = min(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1544 else if (prog->argc >= 3)
1547 float f = PRVM_G_FLOAT(OFS_PARM0);
1548 for (i = 1;i < prog->argc;i++)
1549 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) < f)
1550 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1551 PRVM_G_FLOAT(OFS_RETURN) = f;
1554 PRVM_ERROR("VM_min: %s must supply at least 2 floats\n", PRVM_NAME);
1561 returns the maximum of two supplied floats
1563 float max(float a, float b, ...[float])
1568 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1569 if (prog->argc == 2)
1570 PRVM_G_FLOAT(OFS_RETURN) = max(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1571 else if (prog->argc >= 3)
1574 float f = PRVM_G_FLOAT(OFS_PARM0);
1575 for (i = 1;i < prog->argc;i++)
1576 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) > f)
1577 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1578 G_FLOAT(OFS_RETURN) = f;
1581 PRVM_ERROR("VM_max: %s must supply at least 2 floats\n", PRVM_NAME);
1588 returns number bounded by supplied range
1590 float bound(float min, float value, float max)
1593 void VM_bound (void)
1595 VM_SAFEPARMCOUNT(3,VM_bound);
1596 PRVM_G_FLOAT(OFS_RETURN) = bound(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2));
1603 returns a raised to power b
1605 float pow(float a, float b)
1610 VM_SAFEPARMCOUNT(2,VM_pow);
1611 PRVM_G_FLOAT(OFS_RETURN) = pow(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1618 copies data from one entity to another
1620 copyentity(entity src, entity dst)
1623 void VM_copyentity (void)
1625 prvm_edict_t *in, *out;
1626 VM_SAFEPARMCOUNT(2,VM_copyentity);
1627 in = PRVM_G_EDICT(OFS_PARM0);
1628 out = PRVM_G_EDICT(OFS_PARM1);
1629 memcpy(out->v, in->v, prog->progs->entityfields * 4);
1636 sets the color of a client and broadcasts the update to all connected clients
1638 setcolor(clientent, value)
1641 /*void PF_setcolor (void)
1647 entnum = G_EDICTNUM(OFS_PARM0);
1648 i = G_FLOAT(OFS_PARM1);
1650 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1652 Con_Printf ("tried to setcolor a non-client\n");
1656 client = svs.clients + entnum-1;
1657 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
1660 client->old_colors = i;
1661 client->edict->v->team = (i & 15) + 1;
1663 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1664 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
1665 MSG_WriteByte (&sv.reliable_datagram, i);
1668 void VM_Files_Init(void)
1670 memset(VM_FILES, 0, sizeof(qfile_t*[MAX_VMFILES]));
1673 void VM_Files_CloseAll(void)
1676 for (i = 0;i < MAX_VMFILES;i++)
1679 FS_Close(VM_FILES[i]);
1680 //VM_FILES[i] = NULL;
1682 memset(VM_FILES,0,sizeof(qfile_t*[MAX_VMFILES])); // this should be faster (is it ?)
1689 float fopen(string filename, float mode)
1692 // float(string filename, float mode) fopen = #110;
1693 // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE),
1694 // returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
1698 char *modestring, *filename;
1700 VM_SAFEPARMCOUNT(2,VM_fopen);
1702 for (filenum = 0;filenum < MAX_VMFILES;filenum++)
1703 if (VM_FILES[filenum] == NULL)
1705 if (filenum >= MAX_VMFILES)
1707 Con_Printf("VM_fopen: %s ran out of file handles (%i)\n", PRVM_NAME, MAX_VMFILES);
1708 PRVM_G_FLOAT(OFS_RETURN) = -2;
1711 mode = PRVM_G_FLOAT(OFS_PARM1);
1714 case 0: // FILE_READ
1717 case 1: // FILE_APPEND
1720 case 2: // FILE_WRITE
1724 Con_Printf ("VM_fopen: %s no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", PRVM_NAME, mode);
1725 PRVM_G_FLOAT(OFS_RETURN) = -3;
1728 filename = PRVM_G_STRING(OFS_PARM0);
1729 // .. is parent directory on many platforms
1730 // / is parent directory on Amiga
1731 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
1732 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
1733 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
1735 Con_Printf("VM_fopen: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
1736 PRVM_G_FLOAT(OFS_RETURN) = -4;
1739 VM_FILES[filenum] = FS_Open(va("data/%s", filename), modestring, false);
1740 if (VM_FILES[filenum] == NULL)
1741 PRVM_G_FLOAT(OFS_RETURN) = -1;
1743 PRVM_G_FLOAT(OFS_RETURN) = filenum;
1750 fclose(float fhandle)
1753 //void(float fhandle) fclose = #111; // closes a file
1754 void VM_fclose(void)
1758 VM_SAFEPARMCOUNT(1,VM_fclose);
1760 filenum = PRVM_G_FLOAT(OFS_PARM0);
1761 if (filenum < 0 || filenum >= MAX_VMFILES)
1763 Con_Printf("VM_fclose: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1766 if (VM_FILES[filenum] == NULL)
1768 Con_Printf("VM_fclose: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1771 FS_Close(VM_FILES[filenum]);
1772 VM_FILES[filenum] = NULL;
1779 string fgets(float fhandle)
1782 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
1786 static char string[VM_STRINGTEMP_LENGTH];
1789 VM_SAFEPARMCOUNT(1,VM_fgets);
1791 filenum = PRVM_G_FLOAT(OFS_PARM0);
1792 if (filenum < 0 || filenum >= MAX_VMFILES)
1794 Con_Printf("VM_fgets: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1797 if (VM_FILES[filenum] == NULL)
1799 Con_Printf("VM_fgets: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1805 c = FS_Getc(VM_FILES[filenum]);
1806 if (c == '\r' || c == '\n' || c < 0)
1808 if (end < VM_STRINGTEMP_LENGTH - 1)
1812 // remove \n following \r
1814 c = FS_Getc(VM_FILES[filenum]);
1815 if (developer.integer)
1816 Con_Printf("fgets: %s: %s\n", PRVM_NAME, string);
1818 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1820 PRVM_G_INT(OFS_RETURN) = 0;
1827 fputs(float fhandle, string s)
1830 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
1834 char string[VM_STRINGTEMP_LENGTH];
1837 VM_SAFEPARMCOUNT(2,VM_fputs);
1839 filenum = PRVM_G_FLOAT(OFS_PARM0);
1840 if (filenum < 0 || filenum >= MAX_VMFILES)
1842 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1845 if (VM_FILES[filenum] == NULL)
1847 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1850 VM_VarString(1, string, sizeof(string));
1851 if ((stringlength = strlen(string)))
1852 FS_Write(VM_FILES[filenum], string, stringlength);
1853 if (developer.integer)
1854 Con_Printf("fputs: %s: %s\n", PRVM_NAME, string);
1861 float strlen(string s)
1864 //float(string s) strlen = #114; // returns how many characters are in a string
1865 void VM_strlen(void)
1869 VM_SAFEPARMCOUNT(1,VM_strlen);
1871 s = PRVM_G_STRING(OFS_PARM0);
1873 PRVM_G_FLOAT(OFS_RETURN) = strlen(s);
1875 PRVM_G_FLOAT(OFS_RETURN) = 0;
1882 string strcat(string,string,...[string])
1885 //string(string s1, string s2) strcat = #115;
1886 // concatenates two strings (for example "abc", "def" would return "abcdef")
1887 // and returns as a tempstring
1888 void VM_strcat(void)
1893 PRVM_ERROR("VM_strcat wrong parameter count (min. 2 expected ) !\n");
1895 s = VM_GetTempString();
1896 VM_VarString(0, s, VM_STRINGTEMP_LENGTH);
1897 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
1904 string substring(string s, float start, float length)
1907 // string(string s, float start, float length) substring = #116;
1908 // returns a section of a string as a tempstring
1909 void VM_substring(void)
1911 int i, start, length;
1914 VM_SAFEPARMCOUNT(3,VM_substring);
1916 string = VM_GetTempString();
1917 s = PRVM_G_STRING(OFS_PARM0);
1918 start = PRVM_G_FLOAT(OFS_PARM1);
1919 length = PRVM_G_FLOAT(OFS_PARM2);
1922 for (i = 0;i < start && *s;i++, s++);
1923 for (i = 0;i < VM_STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
1926 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1933 vector stov(string s)
1936 //vector(string s) stov = #117; // returns vector value from a string
1939 char string[VM_STRINGTEMP_LENGTH];
1941 VM_SAFEPARMCOUNT(1,VM_stov);
1943 VM_VarString(0, string, sizeof(string));
1944 Math_atov(string, PRVM_G_VECTOR(OFS_RETURN));
1951 string strzone(string s)
1954 //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)
1955 void VM_strzone(void)
1959 VM_SAFEPARMCOUNT(1,VM_strzone);
1961 in = PRVM_G_STRING(OFS_PARM0);
1962 out = Mem_Alloc(VM_STRINGS_MEMPOOL, strlen(in) + 1);
1964 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(out);
1974 //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!!!)
1975 void VM_strunzone(void)
1977 VM_SAFEPARMCOUNT(1,VM_strunzone);
1979 Mem_Free(PRVM_G_STRING(OFS_PARM0));
1984 VM_command (used by client and menu)
1986 clientcommand(float client, string s) (for client and menu)
1989 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
1990 //this function originally written by KrimZon, made shorter by LordHavoc
1991 void VM_clcommand (void)
1993 client_t *temp_client;
1996 VM_SAFEPARMCOUNT(2,VM_clcommand);
1998 i = PRVM_G_FLOAT(OFS_PARM0);
1999 if (!sv.active || i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2001 Con_Printf("VM_clientcommand: %s: invalid client/server is not active !", PRVM_NAME);
2005 temp_client = host_client;
2006 host_client = svs.clients + i;
2007 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2008 host_client = temp_client;
2016 float tokenize(string s)
2019 //float(string s) tokenize = #441;
2020 // takes apart a string into individal words (access them with argv), returns how many
2021 // this function originally written by KrimZon, made shorter by LordHavoc
2022 static char **tokens = NULL;
2023 static int max_tokens, num_tokens = 0;
2024 void VM_tokenize (void)
2029 VM_SAFEPARMCOUNT(1,VM_tokenize);
2031 str = PRVM_G_STRING(OFS_PARM0);
2036 for (i=0;i<num_tokens;i++)
2042 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2043 max_tokens = strlen(str);
2045 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2047 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2048 strcpy(tokens[num_tokens], com_token);
2051 PRVM_G_FLOAT(OFS_RETURN) = num_tokens;
2058 string argv(float n)
2061 //string(float n) argv = #442;
2062 // returns a word from the tokenized string (returns nothing for an invalid index)
2063 // this function originally written by KrimZon, made shorter by LordHavoc
2068 VM_SAFEPARMCOUNT(1,VM_argv);
2070 token_num = PRVM_G_FLOAT(OFS_PARM0);
2071 if (token_num >= 0 && token_num < num_tokens)
2072 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tokens[token_num]);
2074 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
2078 //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)
2079 void PF_setattachment (void)
2081 edict_t *e = G_EDICT(OFS_PARM0);
2082 edict_t *tagentity = G_EDICT(OFS_PARM1);
2083 char *tagname = G_STRING(OFS_PARM2);
2088 if (tagentity == NULL)
2089 tagentity = sv.edicts;
2091 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
2093 v->edict = EDICT_TO_PROG(tagentity);
2095 v = GETEDICTFIELDVALUE(e, eval_tag_index);
2098 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
2100 modelindex = (int)tagentity->v->modelindex;
2101 if (modelindex >= 0 && modelindex < MAX_MODELS)
2103 model = sv.models[modelindex];
2104 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
2105 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
2106 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
2108 if (v->_float == 0 && model->alias.aliasnum_tags)
2109 for (i = 0;i < model->alias.aliasnum_tags;i++)
2110 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
2113 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);
2116 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));
2127 void VM_isserver(void)
2129 VM_SAFEPARMCOUNT(0,VM_serverstate);
2131 PRVM_G_FLOAT(OFS_RETURN) = sv.active;
2141 void VM_clientcount(void)
2143 VM_SAFEPARMCOUNT(0,VM_clientcount);
2145 PRVM_G_FLOAT(OFS_RETURN) = svs.maxclients;
2155 void VM_clientstate(void)
2157 VM_SAFEPARMCOUNT(0,VM_clientstate);
2159 PRVM_G_FLOAT(OFS_RETURN) = cls.state;
2166 float getostype(void)
2168 */ // not used at the moment -> not included in the common list
2169 void VM_getostype(void)
2171 VM_SAFEPARMCOUNT(0,VM_getostype);
2176 OS_MAC - not supported
2180 PRVM_G_FLOAT(OFS_RETURN) = 0;
2182 PRVM_G_FLOAT(OFS_RETURN) = 2;
2184 PRVM_G_FLOAT(OFS_RETURN) = 1;
2192 vector getmousepos()
2195 void VM_getmousepos(void)
2198 VM_SAFEPARMCOUNT(0,VM_getmousepos);
2200 PRVM_G_VECTOR(OFS_RETURN)[0] = in_mouse_x;
2201 PRVM_G_VECTOR(OFS_RETURN)[1] = in_mouse_y;
2202 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2212 void VM_gettime(void)
2214 VM_SAFEPARMCOUNT(0,VM_gettime);
2216 PRVM_G_FLOAT(OFS_RETURN) = (float) *prog->time;
2223 loadfromdata(string data)
2226 void VM_loadfromdata(void)
2228 VM_SAFEPARMCOUNT(1,VM_loadentsfromfile);
2230 PRVM_ED_LoadFromFile(PRVM_G_STRING(OFS_PARM0));
2237 loadfromfile(string file)
2240 void VM_loadfromfile(void)
2245 VM_SAFEPARMCOUNT(1,VM_loadfromfile);
2247 filename = PRVM_G_STRING(OFS_PARM0);
2248 // .. is parent directory on many platforms
2249 // / is parent directory on Amiga
2250 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2251 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2252 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2254 Con_Printf("VM_loadfromfile: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
2255 PRVM_G_FLOAT(OFS_RETURN) = -4;
2259 // not conform with VM_fopen
2260 data = FS_LoadFile(filename, false);
2262 PRVM_G_FLOAT(OFS_RETURN) = -1;
2264 PRVM_ED_LoadFromFile(data);
2275 float mod(float val, float m)
2278 void VM_modulo(void)
2281 VM_SAFEPARMCOUNT(2,VM_module);
2283 val = (int) PRVM_G_FLOAT(OFS_PARM0);
2284 m = (int) PRVM_G_FLOAT(OFS_PARM1);
2286 PRVM_G_FLOAT(OFS_RETURN) = (float) (val % m);
2289 void VM_Search_Init(void)
2291 memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
2294 void VM_Search_Reset(void)
2297 // reset the fssearch list
2298 for(i = 0; i < MAX_VMSEARCHES; i++)
2299 if(VM_SEARCHLIST[i])
2300 FS_FreeSearch(VM_SEARCHLIST[i]);
2301 memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
2308 float search_begin(string pattern, float caseinsensitive, float quiet)
2311 void VM_search_begin(void)
2315 int caseinsens, quiet;
2317 VM_SAFEPARMCOUNT(3, VM_search_begin);
2319 pattern = PRVM_G_STRING(OFS_PARM0);
2321 VM_CheckEmptyString(pattern);
2323 caseinsens = PRVM_G_FLOAT(OFS_PARM1);
2324 quiet = PRVM_G_FLOAT(OFS_PARM2);
2326 for(handle = 0; handle < MAX_VMSEARCHES; handle++)
2327 if(!VM_SEARCHLIST[handle])
2330 if(handle >= MAX_VMSEARCHES)
2332 Con_Printf("VM_search_begin: %s ran out of search handles (%i)\n", PRVM_NAME, MAX_VMSEARCHES);
2333 PRVM_G_FLOAT(OFS_RETURN) = -2;
2337 if(!(VM_SEARCHLIST[handle] = FS_Search(pattern,caseinsens, quiet)))
2338 PRVM_G_FLOAT(OFS_RETURN) = -1;
2340 PRVM_G_FLOAT(OFS_RETURN) = handle;
2347 void search_end(float handle)
2350 void VM_search_end(void)
2353 VM_SAFEPARMCOUNT(1, VM_search_end);
2355 handle = PRVM_G_FLOAT(OFS_PARM0);
2357 if(handle < 0 || handle >= MAX_VMSEARCHES)
2359 Con_Printf("VM_search_end: invalid handle %i used in %s\n", handle, PRVM_NAME);
2362 if(VM_SEARCHLIST[handle] == NULL)
2364 Con_Printf("VM_search_end: no such handle %i in %s\n", handle, PRVM_NAME);
2368 FS_FreeSearch(VM_SEARCHLIST[handle]);
2369 VM_SEARCHLIST[handle] = NULL;
2376 float search_getsize(float handle)
2379 void VM_search_getsize(void)
2382 VM_SAFEPARMCOUNT(1, VM_M_search_getsize);
2384 handle = PRVM_G_FLOAT(OFS_PARM0);
2386 if(handle < 0 || handle >= MAX_VMSEARCHES)
2388 Con_Printf("VM_search_getsize: invalid handle %i used in %s\n", handle, PRVM_NAME);
2391 if(VM_SEARCHLIST[handle] == NULL)
2393 Con_Printf("VM_search_getsize: no such handle %i in %s\n", handle, PRVM_NAME);
2397 PRVM_G_FLOAT(OFS_RETURN) = VM_SEARCHLIST[handle]->numfilenames;
2402 VM_search_getfilename
2404 string search_getfilename(float handle, float num)
2407 void VM_search_getfilename(void)
2409 int handle, filenum;
2411 VM_SAFEPARMCOUNT(2, VM_search_getfilename);
2413 handle = PRVM_G_FLOAT(OFS_PARM0);
2414 filenum = PRVM_G_FLOAT(OFS_PARM1);
2416 if(handle < 0 || handle >= MAX_VMSEARCHES)
2418 Con_Printf("VM_search_getfilename: invalid handle %i used in %s\n", handle, PRVM_NAME);
2421 if(VM_SEARCHLIST[handle] == NULL)
2423 Con_Printf("VM_search_getfilename: no such handle %i in %s\n", handle, PRVM_NAME);
2426 if(filenum < 0 || filenum >= VM_SEARCHLIST[handle]->numfilenames)
2428 Con_Printf("VM_search_getfilename: invalid filenum %i in %s\n", filenum, PRVM_NAME);
2432 tmp = VM_GetTempString();
2433 strcpy(tmp, VM_SEARCHLIST[handle]->filenames[filenum]);
2435 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
2442 string chr(float ascii)
2448 VM_SAFEPARMCOUNT(1, VM_chr);
2450 tmp = VM_GetTempString();
2451 tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0);
2454 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
2457 //=============================================================================
2458 // Draw builtins (client & menu)
2464 float iscachedpic(string pic)
2467 void VM_iscachedpic(void)
2469 VM_SAFEPARMCOUNT(1,VM_iscachedpic);
2471 // drawq hasnt such a function, thus always return true
2472 PRVM_G_FLOAT(OFS_RETURN) = TRUE;
2479 string precache_pic(string pic)
2482 void VM_precache_pic(void)
2486 VM_SAFEPARMCOUNT(1, VM_precache_pic);
2488 s = PRVM_G_STRING(OFS_PARM0);
2489 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
2492 PRVM_ERROR ("VM_precache_pic: %s: NULL\n", PRVM_NAME);
2494 VM_CheckEmptyString (s);
2496 if(!Draw_CachePic(s))
2497 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
2507 void VM_freepic(void)
2511 VM_SAFEPARMCOUNT(1,VM_freepic);
2513 s = PRVM_G_STRING(OFS_PARM0);
2516 PRVM_ERROR ("VM_freepic: %s: NULL\n");
2518 VM_CheckEmptyString (s);
2527 float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
2530 void VM_drawcharacter(void)
2532 float *pos,*scale,*rgb;
2535 VM_SAFEPARMCOUNT(6,VM_drawcharacter);
2537 character = (char) PRVM_G_FLOAT(OFS_PARM1);
2540 Con_Printf("VM_drawcharacter: %s passed null character !\n",PRVM_NAME);
2541 PRVM_G_FLOAT(OFS_RETURN) = -1;
2545 pos = PRVM_G_VECTOR(OFS_PARM0);
2546 scale = PRVM_G_VECTOR(OFS_PARM2);
2547 rgb = PRVM_G_VECTOR(OFS_PARM3);
2548 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2550 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2552 Con_Printf("VM_drawcharacter: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2553 PRVM_G_FLOAT(OFS_RETURN) = -2;
2557 if(pos[2] || scale[2])
2558 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")));
2560 if(!scale[0] || !scale[1])
2562 Con_Printf("VM_drawcharacter: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2563 PRVM_G_FLOAT(OFS_RETURN) = -3;
2567 DrawQ_String (pos[0], pos[1], &character, 1, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2568 PRVM_G_FLOAT(OFS_RETURN) = 1;
2575 float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
2578 void VM_drawstring(void)
2580 float *pos,*scale,*rgb;
2583 VM_SAFEPARMCOUNT(6,VM_drawstring);
2585 string = PRVM_G_STRING(OFS_PARM1);
2588 Con_Printf("VM_drawstring: %s passed null string !\n",PRVM_NAME);
2589 PRVM_G_FLOAT(OFS_RETURN) = -1;
2593 VM_CheckEmptyString(string);
2595 pos = PRVM_G_VECTOR(OFS_PARM0);
2596 scale = PRVM_G_VECTOR(OFS_PARM2);
2597 rgb = PRVM_G_VECTOR(OFS_PARM3);
2598 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2600 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2602 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2603 PRVM_G_FLOAT(OFS_RETURN) = -2;
2607 if(!scale[0] || !scale[1])
2609 Con_Printf("VM_drawstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2610 PRVM_G_FLOAT(OFS_RETURN) = -3;
2614 if(pos[2] || scale[2])
2615 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")));
2617 DrawQ_String (pos[0], pos[1], string, 0, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2618 PRVM_G_FLOAT(OFS_RETURN) = 1;
2624 float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
2627 void VM_drawpic(void)
2630 float *size, *pos, *rgb;
2633 VM_SAFEPARMCOUNT(6,VM_drawpic);
2635 pic = PRVM_G_STRING(OFS_PARM1);
2639 Con_Printf("VM_drawpic: %s passed null picture name !\n", PRVM_NAME);
2640 PRVM_G_FLOAT(OFS_RETURN) = -1;
2644 VM_CheckEmptyString (pic);
2646 // is pic cached ? no function yet for that
2649 Con_Printf("VM_drawpic: %s: %s not cached !\n", PRVM_NAME, pic);
2650 PRVM_G_FLOAT(OFS_RETURN) = -4;
2654 pos = PRVM_G_VECTOR(OFS_PARM0);
2655 size = PRVM_G_VECTOR(OFS_PARM2);
2656 rgb = PRVM_G_VECTOR(OFS_PARM3);
2657 flag = (int) PRVM_G_FLOAT(OFS_PARM5);
2659 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2661 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2662 PRVM_G_FLOAT(OFS_RETURN) = -2;
2666 if(pos[2] || size[2])
2667 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")));
2669 DrawQ_Pic(pos[0], pos[1], pic, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2670 PRVM_G_FLOAT(OFS_RETURN) = 1;
2677 float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
2680 void VM_drawfill(void)
2682 float *size, *pos, *rgb;
2685 VM_SAFEPARMCOUNT(5,VM_drawfill);
2688 pos = PRVM_G_VECTOR(OFS_PARM0);
2689 size = PRVM_G_VECTOR(OFS_PARM1);
2690 rgb = PRVM_G_VECTOR(OFS_PARM2);
2691 flag = (int) PRVM_G_FLOAT(OFS_PARM4);
2693 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2695 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2696 PRVM_G_FLOAT(OFS_RETURN) = -2;
2700 if(pos[2] || size[2])
2701 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")));
2703 DrawQ_Pic(pos[0], pos[1], 0, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM3), flag);
2704 PRVM_G_FLOAT(OFS_RETURN) = 1;
2711 drawsetcliparea(float x, float y, float width, float height)
2714 void VM_drawsetcliparea(void)
2717 VM_SAFEPARMCOUNT(4,VM_drawsetcliparea);
2719 x = bound(0,PRVM_G_FLOAT(OFS_PARM0),vid.conwidth);
2720 y = bound(0,PRVM_G_FLOAT(OFS_PARM1),vid.conheight);
2721 w = bound(0,PRVM_G_FLOAT(OFS_PARM2),(vid.conwidth - x));
2722 h = bound(0,PRVM_G_FLOAT(OFS_PARM3),(vid.conheight - y));
2724 DrawQ_SetClipArea(x,y,w,h);
2729 VM_drawresetcliparea
2734 void VM_drawresetcliparea(void)
2736 VM_SAFEPARMCOUNT(0,VM_drawresetcliparea);
2738 DrawQ_ResetClipArea();
2745 vector getimagesize(string pic)
2748 void VM_getimagesize(void)
2753 VM_SAFEPARMCOUNT(1,VM_getimagesize);
2755 p = PRVM_G_STRING(OFS_PARM0);
2758 PRVM_ERROR("VM_getimagepos: %s passed null picture name !\n", PRVM_NAME);
2760 VM_CheckEmptyString (p);
2762 pic = Draw_CachePic (p);
2764 PRVM_G_VECTOR(OFS_RETURN)[0] = pic->width;
2765 PRVM_G_VECTOR(OFS_RETURN)[1] = pic->height;
2766 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2769 void VM_Cmd_Init(void)
2771 // only init the stuff for the current prog
2772 VM_STRINGS_MEMPOOL = Mem_AllocPool(va("vm_stringsmempool[%s]",PRVM_NAME));
2777 void VM_Cmd_Reset(void)
2779 //Mem_EmptyPool(VM_STRINGS_MEMPOOL);
2780 Mem_FreePool(&VM_STRINGS_MEMPOOL);
2782 VM_Files_CloseAll();
2785 //============================================================================
2788 char *vm_sv_extensions =
2791 prvm_builtin_t vm_sv_builtins[] = {
2792 0 // to be consistent with the old vm
2795 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
2797 void VM_SV_Cmd_Init(void)
2801 void VM_SV_Cmd_Reset(void)
2805 //============================================================================
2808 char *vm_cl_extensions =
2811 prvm_builtin_t vm_cl_builtins[] = {
2812 0 // to be consistent with the old vm
2815 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
2817 void VM_CL_Cmd_Init(void)
2821 void VM_CL_Cmd_Reset(void)
2825 //============================================================================
2828 char *vm_m_extensions =
2835 setmousetarget(float target)
2838 void VM_M_setmousetarget(void)
2840 VM_SAFEPARMCOUNT(1, VM_M_setmousetarget);
2842 switch((int)PRVM_G_FLOAT(OFS_PARM0))
2845 in_client_mouse = false;
2848 in_client_mouse = true;
2851 PRVM_ERROR("VM_M_setmousetarget: wrong destination %i !\n",PRVM_G_FLOAT(OFS_PARM0));
2859 float getmousetarget
2862 void VM_M_getmousetarget(void)
2864 VM_SAFEPARMCOUNT(0,VM_M_getmousetarget);
2867 PRVM_G_FLOAT(OFS_RETURN) = 2;
2869 PRVM_G_FLOAT(OFS_RETURN) = 1;
2878 setkeydest(float dest)
2881 void VM_M_setkeydest(void)
2883 VM_SAFEPARMCOUNT(1,VM_M_setkeydest);
2885 switch((int)PRVM_G_FLOAT(OFS_PARM0))
2889 key_dest = key_game;
2893 key_dest = key_menu;
2897 // key_dest = key_message
2900 PRVM_ERROR("VM_M_setkeydest: wrong destination %i !\n",prog->globals[OFS_PARM0]);
2911 void VM_M_getkeydest(void)
2913 VM_SAFEPARMCOUNT(0,VM_M_getkeydest);
2915 // key_game = 0, key_message = 1, key_menu = 2, unknown = 3
2919 PRVM_G_FLOAT(OFS_RETURN) = 0;
2922 PRVM_G_FLOAT(OFS_RETURN) = 2;
2926 // PRVM_G_FLOAT(OFS_RETURN) = 1;
2929 PRVM_G_FLOAT(OFS_RETURN) = 3;
2937 callfunction(...,string function_name)
2940 mfunction_t *PRVM_ED_FindFunction (const char *name);
2941 void VM_M_callfunction(void)
2947 PRVM_ERROR("VM_M_callfunction: 1 parameter is required !\n");
2949 s = PRVM_G_STRING(OFS_PARM0 + (prog->argc - 1));
2952 PRVM_ERROR("VM_M_callfunction: null string !\n");
2954 VM_CheckEmptyString(s);
2956 func = PRVM_ED_FindFunction(s);
2959 PRVM_ERROR("VM_M_callfunciton: function %s not found !\n", s);
2960 else if (func->first_statement < 0)
2962 // negative statements are built in functions
2963 int builtinnumber = -func->first_statement;
2964 prog->xfunction->builtinsprofile++;
2965 if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber])
2966 prog->builtins[builtinnumber]();
2968 PRVM_ERROR("No such builtin #%i in %s", builtinnumber, PRVM_NAME);
2973 PRVM_ExecuteProgram(func - prog->functions,"");
2982 float isfunction(string function_name)
2985 mfunction_t *PRVM_ED_FindFunction (const char *name);
2986 void VM_M_isfunction(void)
2991 VM_SAFEPARMCOUNT(1, VM_M_isfunction);
2993 s = PRVM_G_STRING(OFS_PARM0);
2996 PRVM_ERROR("VM_M_isfunction: null string !\n");
2998 VM_CheckEmptyString(s);
3000 func = PRVM_ED_FindFunction(s);
3003 PRVM_G_FLOAT(OFS_RETURN) = false;
3005 PRVM_G_FLOAT(OFS_RETURN) = true;
3012 writetofile(float fhandle, entity ent)
3015 void VM_M_writetofile(void)
3020 VM_SAFEPARMCOUNT(2, VM_M_writetofile);
3022 filenum = PRVM_G_FLOAT(OFS_PARM0);
3023 if (filenum < 0 || filenum >= MAX_VMFILES)
3025 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
3028 if (VM_FILES[filenum] == NULL)
3030 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
3034 ent = PRVM_G_EDICT(OFS_PARM1);
3037 Con_Printf("VM_M_writetofile: %s: entity %i is free !\n", PRVM_NAME, PRVM_EDICT_NUM(OFS_PARM1));
3041 PRVM_ED_Write (VM_FILES[filenum], ent);
3048 vector getresolution(float number)
3051 extern unsigned short video_resolutions[][2];
3052 void VM_M_getresolution(void)
3055 VM_SAFEPARMCOUNT(1, VM_getresolution);
3057 nr = PRVM_G_FLOAT(OFS_PARM0);
3060 PRVM_G_VECTOR(OFS_RETURN)[0] = video_resolutions[nr][0];
3061 PRVM_G_VECTOR(OFS_RETURN)[1] = video_resolutions[nr][1];
3062 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
3069 string keynumtostring(float keynum)
3072 void VM_M_keynumtostring(void)
3076 VM_SAFEPARMCOUNT(1, VM_M_keynumtostring);
3078 keynum = PRVM_G_FLOAT(OFS_PARM0);
3080 tmp = VM_GetTempString();
3082 strcpy(tmp, Key_KeynumToString(keynum));
3084 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
3089 VM_M_findkeysforcommand
3091 string findkeysforcommand(string command)
3093 the returned string is an altstring
3096 #define NUMKEYS 5 // TODO: merge the constant in keys.c with this one somewhen
3098 void M_FindKeysForCommand(char *command, int *keys);
3099 void VM_M_findkeysforcommand(void)
3105 VM_SAFEPARMCOUNT(1, VM_M_findkeysforcommand);
3107 cmd = PRVM_G_STRING(OFS_PARM0);
3109 VM_CheckEmptyString(cmd);
3111 (ret = VM_GetTempString())[0] = 0;
3113 M_FindKeysForCommand(cmd, keys);
3115 for(i = 0; i < NUMKEYS; i++)
3116 ret = strcat(ret, va(" \'%i\'", keys[i]));
3118 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(ret);
3121 prvm_builtin_t vm_m_builtins[] = {
3122 0, // to be consistent with the old vm
3123 // common builtings (mostly)
3200 VM_search_getfilename, // 77
3216 VM_WriteEntity, // 408
3232 VM_drawresetcliparea,
3233 VM_getimagesize,// 460
3242 VM_M_setmousetarget,
3243 VM_M_getmousetarget,
3248 VM_M_keynumtostring,
3249 VM_M_findkeysforcommand// 610
3252 const int vm_m_numbuiltins = sizeof(vm_m_builtins) / sizeof(prvm_builtin_t);
3254 void VM_M_Cmd_Init(void)
3259 void VM_M_Cmd_Reset(void)