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)
144 #include "quakedef.h"
145 #include "progdefs.h"
146 #include "clprogdefs.h"
147 #include "mprogdefs.h"
149 //============================================================================
150 // nice helper macros
152 #ifndef VM_NOPARMCHECK
153 #define VM_SAFEPARMCOUNT(p,f) if(prog->argc != p) PRVM_ERROR(#f " wrong parameter count (" #p " expected ) !\n")
155 #define VM_SAFEPARMCOUNT(p,f)
158 #define VM_RETURN_EDICT(e) (((int *)prog->globals)[OFS_RETURN] = PRVM_EDICT_TO_PROG(e))
160 #define VM_STRINGS_MEMPOOL vm_strings_mempool[PRVM_GetProgNr()]
162 #define e10 0,0,0,0,0,0,0,0,0,0
163 #define e100 e10,e10,e10,e10,e10,e10,e10,e10,e10,e10
164 #define e1000 e100,e100,e100,e100,e100,e100,e100,e100,e100,e100
166 //============================================================================
169 // string zone mempool
170 mempool_t *vm_strings_mempool[PRVM_MAXPROGS];
172 // temp string handling
173 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
174 #define VM_STRINGTEMP_BUFFERS 16
175 #define VM_STRINGTEMP_LENGTH 4096
176 static char vm_string_temp[VM_STRINGTEMP_BUFFERS][VM_STRINGTEMP_LENGTH];
177 static int vm_string_tempindex = 0;
180 #define MAX_QC_CVARS 128 * PRVM_MAXPROGS
181 cvar_t vm_qc_cvar[MAX_QC_CVARS];
182 int vm_currentqc_cvar;
185 #define MAX_VMFILES 256
186 #define MAX_PRVMFILES MAX_VMFILES * PRVM_MAXPROGS
187 #define VM_FILES ((qfile_t**)(vm_files + PRVM_GetProgNr() * MAX_VMFILES))
189 qfile_t *vm_files[MAX_PRVMFILES];
191 // qc fs search handling
192 #define MAX_VMSEARCHES 128
193 #define TOTAL_VMSEARCHES MAX_VMSEARCHES * PRVM_MAXPROGS
194 #define VM_SEARCHLIST ((fssearch_t**)(vm_fssearchlist + PRVM_GetProgNr() * MAX_VMSEARCHES))
196 fssearch_t *vm_fssearchlist[TOTAL_VMSEARCHES];
198 static char *VM_GetTempString(void)
201 s = vm_string_temp[vm_string_tempindex];
202 vm_string_tempindex = (vm_string_tempindex + 1) % VM_STRINGTEMP_BUFFERS;
206 void VM_CheckEmptyString (char *s)
209 PRVM_ERROR ("%s: Bad string", PRVM_NAME);
212 //============================================================================
215 void VM_VarString(int first, char *out, int outlength)
221 outend = out + outlength - 1;
222 for (i = first;i < prog->argc && out < outend;i++)
224 s = PRVM_G_STRING((OFS_PARM0+i*3));
225 while (out < outend && *s)
235 returns true if the extension is supported by the server
237 checkextension(extensionname)
241 // kind of helper function
242 static qboolean checkextension(char *name)
248 for (e = prog->extensionstring;*e;e++)
255 while (*e && *e != ' ')
257 if (e - start == len)
258 if (!strncasecmp(start, name, len))
266 void VM_checkextension (void)
268 VM_SAFEPARMCOUNT(1,VM_checkextension);
270 PRVM_G_FLOAT(OFS_RETURN) = checkextension(PRVM_G_STRING(OFS_PARM0));
277 This is a TERMINAL error, which will kill off the entire prog.
286 char string[VM_STRINGTEMP_LENGTH];
288 VM_VarString(0, string, sizeof(string));
289 Con_Printf ("======%S ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
292 ed = PRVM_G_EDICT(prog->self->ofs);
296 PRVM_ERROR ("%s: Program error", PRVM_NAME);
303 Dumps out self, then an error message. The program is aborted and self is
304 removed, but the level can continue.
309 void VM_objerror (void)
312 char string[VM_STRINGTEMP_LENGTH];
314 VM_VarString(0, string, sizeof(string));
315 Con_Printf ("======%s OBJECT ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
318 ed = PRVM_G_EDICT (prog->self->ofs);
324 // objerror has to display the object fields -> else call
325 PRVM_ERROR ("VM_objecterror: self not defined !\n");
330 VM_print (actually used only by client and menu)
339 char string[VM_STRINGTEMP_LENGTH];
341 VM_VarString(0, string, sizeof(string));
349 broadcast print to everyone on server
354 void VM_bprint (void)
356 char string[VM_STRINGTEMP_LENGTH];
360 Con_Printf("VM_bprint: game is not server(%s) !", PRVM_NAME);
364 VM_VarString(0, string, sizeof(string));
365 SV_BroadcastPrintf("%s", string);
370 VM_sprint (menu & client but only if server.active == true)
372 single print to a specific client
374 sprint(float clientnum,...[string])
377 void VM_sprint (void)
381 char string[VM_STRINGTEMP_LENGTH];
383 //find client for this entity
384 clientnum = PRVM_G_FLOAT(OFS_PARM0);
385 if (!sv.active || clientnum < 0 || clientnum >= svs.maxclients || !svs.clients[clientnum].active)
387 Con_Printf("VM_sprint: %s: invalid client or server is not active !", PRVM_NAME);
391 client = svs.clients + clientnum;
392 if (!client->netconnection)
394 VM_VarString(1, string, sizeof(string));
395 MSG_WriteChar(&client->message,svc_print);
396 MSG_WriteString(&client->message, string);
403 single print to the screen
405 centerprint(clientent, value)
408 void VM_centerprint (void)
410 char string[VM_STRINGTEMP_LENGTH];
412 VM_VarString(0, string, sizeof(string));
413 SCR_CenterPrint(string);
420 vector normalize(vector)
423 void VM_normalize (void)
429 VM_SAFEPARMCOUNT(1,VM_normalize);
431 value1 = PRVM_G_VECTOR(OFS_PARM0);
433 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
437 newvalue[0] = newvalue[1] = newvalue[2] = 0;
441 newvalue[0] = value1[0] * new;
442 newvalue[1] = value1[1] * new;
443 newvalue[2] = value1[2] * new;
446 VectorCopy (newvalue, PRVM_G_VECTOR(OFS_RETURN));
461 VM_SAFEPARMCOUNT(1,VM_vlen);
463 value1 = PRVM_G_VECTOR(OFS_PARM0);
465 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
468 PRVM_G_FLOAT(OFS_RETURN) = new;
475 float vectoyaw(vector)
478 void VM_vectoyaw (void)
483 VM_SAFEPARMCOUNT(1,VM_vectoyaw);
485 value1 = PRVM_G_VECTOR(OFS_PARM0);
487 if (value1[1] == 0 && value1[0] == 0)
491 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
496 PRVM_G_FLOAT(OFS_RETURN) = yaw;
504 vector vectoangles(vector)
507 void VM_vectoangles (void)
513 VM_SAFEPARMCOUNT(1,VM_vectoangles);
515 value1 = PRVM_G_VECTOR(OFS_PARM0);
517 if (value1[1] == 0 && value1[0] == 0)
527 // LordHavoc: optimized a bit
530 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
534 else if (value1[1] > 0)
539 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
540 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
545 PRVM_G_FLOAT(OFS_RETURN+0) = pitch;
546 PRVM_G_FLOAT(OFS_RETURN+1) = yaw;
547 PRVM_G_FLOAT(OFS_RETURN+2) = 0;
554 Returns a number from 0<= num < 1
559 void VM_random (void)
563 VM_SAFEPARMCOUNT(0,VM_random);
565 num = (rand ()&0x7fff) / ((float)0x7fff);
567 PRVM_G_FLOAT(OFS_RETURN) = num;
574 Each entity can have eight independant sound sources, like voice,
577 Channel 0 is an auto-allocate channel, the others override anything
578 already running on that entity/channel pair.
580 An attenuation of 0 will play full volume everywhere in the level.
581 Larger attenuations will drop off.
594 entity = G_EDICT(OFS_PARM0);
595 channel = G_FLOAT(OFS_PARM1);
596 sample = G_STRING(OFS_PARM2);
597 volume = G_FLOAT(OFS_PARM3) * 255;
598 attenuation = G_FLOAT(OFS_PARM4);
600 if (volume < 0 || volume > 255)
601 Host_Error ("SV_StartSound: volume = %i", volume);
603 if (attenuation < 0 || attenuation > 4)
604 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
606 if (channel < 0 || channel > 7)
607 Host_Error ("SV_StartSound: channel = %i", channel);
609 SV_StartSound (entity, channel, sample, volume, attenuation);
617 localsound(string sample)
620 void VM_localsound(void)
624 VM_SAFEPARMCOUNT(1,VM_localsound);
626 s = PRVM_G_STRING(OFS_PARM0);
630 Con_Printf("VM_localsound: %s : %s not cached !\n", PRVM_NAME, s);
631 PRVM_G_FLOAT(OFS_RETURN) = -4;
636 PRVM_G_FLOAT(OFS_RETURN) = 1;
648 PRVM_ERROR ("%s: break statement", PRVM_NAME);
651 //============================================================================
657 Sends text over to the client's execution buffer
659 [localcmd (string) or]
663 void VM_localcmd (void)
665 VM_SAFEPARMCOUNT(1,VM_localcmd);
667 Cbuf_AddText(PRVM_G_STRING(OFS_PARM0));
679 VM_SAFEPARMCOUNT(1,VM_cvar);
681 PRVM_G_FLOAT(OFS_RETURN) = Cvar_VariableValue(PRVM_G_STRING(OFS_PARM0));
688 const string str_cvar (string)
691 void VM_str_cvar(void)
694 const char *cvar_string;
695 VM_SAFEPARMCOUNT(1,VM_str_cvar);
697 name = PRVM_G_STRING(OFS_PARM0);
700 PRVM_ERROR("VM_str_cvar: %s: null string\n", PRVM_NAME);
702 VM_CheckEmptyString(name);
704 out = VM_GetTempString();
706 cvar_string = Cvar_VariableString(name);
708 strcpy(out, cvar_string);
710 PRVM_G_INT(OFS_PARM0) = PRVM_SetString(out);
717 void cvar_set (string,string)
720 void VM_cvar_set (void)
722 VM_SAFEPARMCOUNT(2,VM_cvar_set);
724 Cvar_Set(PRVM_G_STRING(OFS_PARM0), PRVM_G_STRING(OFS_PARM1));
734 void VM_dprint (void)
736 char string[VM_STRINGTEMP_LENGTH];
737 if (developer.integer)
739 VM_VarString(0, string, sizeof(string));
740 Con_Printf("%s: %s", PRVM_NAME, string);
757 VM_SAFEPARMCOUNT(1, VM_ftos);
759 v = PRVM_G_FLOAT(OFS_PARM0);
761 s = VM_GetTempString();
762 if ((float)((int)v) == v)
763 sprintf(s, "%i", (int)v);
766 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
781 VM_SAFEPARMCOUNT(1,VM_fabs);
783 v = PRVM_G_FLOAT(OFS_PARM0);
784 PRVM_G_FLOAT(OFS_RETURN) = fabs(v);
799 VM_SAFEPARMCOUNT(1,VM_vtos);
801 s = VM_GetTempString();
802 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]);
803 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
818 VM_SAFEPARMCOUNT(1, VM_etos);
820 s = VM_GetTempString();
821 sprintf (s, "entity %i", PRVM_G_EDICTNUM(OFS_PARM0));
822 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
829 float stof(...[string])
834 char string[VM_STRINGTEMP_LENGTH];
835 VM_VarString(0, string, sizeof(string));
836 PRVM_G_FLOAT(OFS_RETURN) = atof(string);
850 prog->xfunction->builtinsprofile += 20;
851 ed = PRVM_ED_Alloc();
863 void VM_remove (void)
866 prog->xfunction->builtinsprofile += 20;
868 VM_SAFEPARMCOUNT(1, VM_remove);
870 ed = PRVM_G_EDICT(OFS_PARM0);
871 // if (ed == prog->edicts)
872 // PRVM_ERROR ("remove: tried to remove world\n");
873 // if (PRVM_NUM_FOR_EDICT(ed) <= sv.maxclients)
874 // Host_Error("remove: tried to remove a client\n");
882 entity find(entity start, .string field, string match)
893 VM_SAFEPARMCOUNT(3,VM_find);
895 e = PRVM_G_EDICTNUM(OFS_PARM0);
896 f = PRVM_G_INT(OFS_PARM1);
897 s = PRVM_G_STRING(OFS_PARM2);
901 // return reserved edict 0 (could be used for whatever the prog wants)
902 VM_RETURN_EDICT(prog->edicts);
906 for (e++ ; e < prog->num_edicts ; e++)
908 prog->xfunction->builtinsprofile++;
909 ed = PRVM_EDICT_NUM(e);
912 t = PRVM_E_STRING(ed,f);
922 VM_RETURN_EDICT(prog->edicts);
929 entity findfloat(entity start, .float field, float match)
930 entity findentity(entity start, .entity field, entity match)
933 // LordHavoc: added this for searching float, int, and entity reference fields
934 void VM_findfloat (void)
941 VM_SAFEPARMCOUNT(3,VM_findfloat);
943 e = PRVM_G_EDICTNUM(OFS_PARM0);
944 f = PRVM_G_INT(OFS_PARM1);
945 s = PRVM_G_FLOAT(OFS_PARM2);
947 for (e++ ; e < prog->num_edicts ; e++)
949 prog->xfunction->builtinsprofile++;
950 ed = PRVM_EDICT_NUM(e);
953 if (PRVM_E_FLOAT(ed,f) == s)
960 VM_RETURN_EDICT(prog->edicts);
967 entity findchain(.string field, string match)
970 int PRVM_ED_FindFieldOffset(const char *field);
971 // chained search for strings in entity fields
972 // entity(.string field, string match) findchain = #402;
973 void VM_findchain (void)
979 prvm_edict_t *ent, *chain;
981 VM_SAFEPARMCOUNT(2,VM_findchain);
983 // is the same like !(prog->flag & PRVM_FE_CHAIN) - even if the operator precedence is another
984 if(!prog->flag & PRVM_FE_CHAIN)
985 PRVM_ERROR("VM_findchain: %s doesnt have a chain field !\n", PRVM_NAME);
987 chain_of = PRVM_ED_FindFieldOffset ("chain");
989 chain = prog->edicts;
991 f = PRVM_G_INT(OFS_PARM0);
992 s = PRVM_G_STRING(OFS_PARM1);
995 VM_RETURN_EDICT(prog->edicts);
999 ent = PRVM_NEXT_EDICT(prog->edicts);
1000 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
1002 prog->xfunction->builtinsprofile++;
1005 t = PRVM_E_STRING(ent,f);
1011 PRVM_E_FLOAT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain);
1015 VM_RETURN_EDICT(chain);
1022 entity findchainfloat(.string field, float match)
1023 entity findchainentity(.string field, entity match)
1026 // LordHavoc: chained search for float, int, and entity reference fields
1027 // entity(.string field, float match) findchainfloat = #403;
1028 void VM_findchainfloat (void)
1034 prvm_edict_t *ent, *chain;
1036 VM_SAFEPARMCOUNT(2, VM_findchainfloat);
1038 if(!prog->flag & PRVM_FE_CHAIN)
1039 PRVM_ERROR("VM_findchainfloat: %s doesnt have a chain field !\n", PRVM_NAME);
1041 chain_of = PRVM_ED_FindFieldOffset ("chain");
1043 chain = (prvm_edict_t *)prog->edicts;
1045 f = PRVM_G_INT(OFS_PARM0);
1046 s = PRVM_G_FLOAT(OFS_PARM1);
1048 ent = PRVM_NEXT_EDICT(prog->edicts);
1049 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
1051 prog->xfunction->builtinsprofile++;
1054 if (E_FLOAT(ent,f) != s)
1057 PRVM_E_FLOAT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain);
1061 VM_RETURN_EDICT(chain);
1068 string precache_file(string)
1071 void VM_precache_file (void)
1072 { // precache_file is only used to copy files with qcc, it does nothing
1073 VM_SAFEPARMCOUNT(1,VM_precache_file);
1075 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1082 used instead of the other VM_precache_* functions in the builtin list
1086 void VM_precache_error (void)
1088 PRVM_ERROR ("PF_Precache_*: Precache can only be done in spawn functions");
1095 string precache_sound (string sample)
1098 void VM_precache_sound (void)
1102 VM_SAFEPARMCOUNT(1, VM_precache_sound);
1104 s = PRVM_G_STRING(OFS_PARM0);
1105 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1106 VM_CheckEmptyString (s);
1110 Con_Printf("VM_precache_sound: %s already cached (%s)\n", s, PRVM_NAME);
1114 if(!S_PrecacheSound(s,true))
1115 Con_Printf("VM_prache_sound: Failed to load %s for %s\n", s, PRVM_NAME);
1125 void VM_coredump (void)
1127 VM_SAFEPARMCOUNT(0,VM_coredump);
1129 Cbuf_AddText("prvm_edicts ");
1130 Cbuf_AddText(PRVM_NAME);
1141 void PRVM_StackTrace(void);
1142 void VM_stackdump (void)
1144 VM_SAFEPARMCOUNT(0, VM_stackdump);
1159 VM_SAFEPARMCOUNT(0, VM_crash);
1161 PRVM_ERROR("Crash called by %s\n",PRVM_NAME);
1171 void VM_traceon (void)
1173 VM_SAFEPARMCOUNT(0,VM_traceon);
1185 void VM_traceoff (void)
1187 VM_SAFEPARMCOUNT(0,VM_traceoff);
1189 prog->trace = false;
1199 void VM_eprint (void)
1201 VM_SAFEPARMCOUNT(1,VM_eprint);
1203 PRVM_ED_PrintNum (PRVM_G_EDICTNUM(OFS_PARM0));
1217 VM_SAFEPARMCOUNT(1,VM_rint);
1219 f = PRVM_G_FLOAT(OFS_PARM0);
1221 PRVM_G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1223 PRVM_G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1233 void VM_floor (void)
1235 VM_SAFEPARMCOUNT(1,VM_floor);
1237 PRVM_G_FLOAT(OFS_RETURN) = floor(PRVM_G_FLOAT(OFS_PARM0));
1249 VM_SAFEPARMCOUNT(1,VM_ceil);
1251 PRVM_G_FLOAT(OFS_RETURN) = ceil(PRVM_G_FLOAT(OFS_PARM0));
1259 entity nextent(entity)
1262 void VM_nextent (void)
1267 i = PRVM_G_EDICTNUM(OFS_PARM0);
1270 prog->xfunction->builtinsprofile++;
1272 if (i == prog->num_edicts)
1274 VM_RETURN_EDICT(prog->edicts);
1277 ent = PRVM_EDICT_NUM(i);
1280 VM_RETURN_EDICT(ent);
1287 ===============================================================================
1290 used only for client and menu
1291 severs uses VM_SV_...
1293 Write*(* data, float type, float to)
1295 ===============================================================================
1298 #define MSG_BROADCAST 0 // unreliable to all
1299 #define MSG_ONE 1 // reliable to one (msg_entity)
1300 #define MSG_ALL 2 // reliable to all
1301 #define MSG_INIT 3 // write to the init string
1303 sizebuf_t *VM_WriteDest (void)
1309 PRVM_ERROR("VM_WriteDest: game is not server (%s)\n", PRVM_NAME);
1311 dest = G_FLOAT(OFS_PARM1);
1315 return &sv.datagram;
1318 destclient = (int) PRVM_G_FLOAT(OFS_PARM2);
1319 if (destclient < 0 || destclient >= svs.maxclients || !svs.clients[destclient].active)
1320 PRVM_ERROR("VM_clientcommand: %s: invalid client !\n", PRVM_NAME);
1322 return &svs.clients[destclient].message;
1325 return &sv.reliable_datagram;
1331 PRVM_ERROR ("WriteDest: bad destination");
1338 void VM_WriteByte (void)
1340 MSG_WriteByte (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1343 void VM_WriteChar (void)
1345 MSG_WriteChar (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1348 void VM_WriteShort (void)
1350 MSG_WriteShort (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1353 void VM_WriteLong (void)
1355 MSG_WriteLong (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1358 void VM_WriteAngle (void)
1360 MSG_WriteAngle (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1363 void VM_WriteCoord (void)
1365 MSG_WriteDPCoord (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1368 void VM_WriteString (void)
1370 MSG_WriteString (VM_WriteDest(), PRVM_G_STRING(OFS_PARM0));
1373 void VM_WriteEntity (void)
1375 MSG_WriteShort (VM_WriteDest(), PRVM_G_EDICTNUM(OFS_PARM0));
1378 //=============================================================================
1385 changelevel(string map)
1388 void VM_changelevel (void)
1392 VM_SAFEPARMCOUNT(1, VM_changelevel);
1396 Con_Printf("VM_changelevel: game is not server (%s)\n", PRVM_NAME);
1400 // make sure we don't issue two changelevels
1401 if (svs.changelevel_issued)
1403 svs.changelevel_issued = true;
1405 s = G_STRING(OFS_PARM0);
1406 Cbuf_AddText (va("changelevel %s\n",s));
1418 VM_SAFEPARMCOUNT(1,VM_sin);
1419 PRVM_G_FLOAT(OFS_RETURN) = sin(PRVM_G_FLOAT(OFS_PARM0));
1430 VM_SAFEPARMCOUNT(1,VM_cos);
1431 PRVM_G_FLOAT(OFS_RETURN) = cos(PRVM_G_FLOAT(OFS_PARM0));
1443 VM_SAFEPARMCOUNT(1,VM_sqrt);
1444 PRVM_G_FLOAT(OFS_RETURN) = sqrt(PRVM_G_FLOAT(OFS_PARM0));
1451 Returns a vector of length < 1 and > 0
1456 void VM_randomvec (void)
1461 VM_SAFEPARMCOUNT(0, VM_randomvec);
1466 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1467 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1468 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1470 while (DotProduct(temp, temp) >= 1);
1471 VectorCopy (temp, PRVM_G_VECTOR(OFS_RETURN));
1474 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1475 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1476 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1477 // length returned always > 0
1478 length = (rand()&32766 + 1) * (1.0 / 32767.0) / VectorLength(temp);
1479 VectorScale(temp,length, temp);*/
1480 //VectorCopy(temp, PRVM_G_VECTOR(OFS_RETURN));
1483 //=============================================================================
1489 float registercvar (string name, string value)
1492 void VM_registercvar (void)
1497 VM_SAFEPARMCOUNT(2,VM_registercvar);
1499 name = PRVM_G_STRING(OFS_PARM0);
1500 value = PRVM_G_STRING(OFS_PARM1);
1501 PRVM_G_FLOAT(OFS_RETURN) = 0;
1502 // first check to see if it has already been defined
1503 if (Cvar_FindVar (name))
1506 // check for overlap with a command
1507 if (Cmd_Exists (name))
1509 Con_Printf ("VM_registercvar: %s is a command\n", name);
1513 if (vm_currentqc_cvar >= MAX_QC_CVARS)
1514 PRVM_ERROR ("VM_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1516 // copy the name and value
1517 variable = &vm_qc_cvar[vm_currentqc_cvar++];
1518 variable->name = Z_Malloc (strlen(name)+1);
1519 strcpy (variable->name, name);
1520 variable->string = Z_Malloc (strlen(value)+1);
1521 strcpy (variable->string, value);
1522 variable->value = atof (value);
1524 Cvar_RegisterVariable(variable);
1525 PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1532 returns the minimum of two supplied floats
1534 float min(float a, float b, ...[float])
1539 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1540 if (prog->argc == 2)
1541 PRVM_G_FLOAT(OFS_RETURN) = min(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1542 else if (prog->argc >= 3)
1545 float f = PRVM_G_FLOAT(OFS_PARM0);
1546 for (i = 1;i < prog->argc;i++)
1547 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) < f)
1548 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1549 PRVM_G_FLOAT(OFS_RETURN) = f;
1552 PRVM_ERROR("VM_min: %s must supply at least 2 floats\n", PRVM_NAME);
1559 returns the maximum of two supplied floats
1561 float max(float a, float b, ...[float])
1566 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1567 if (prog->argc == 2)
1568 PRVM_G_FLOAT(OFS_RETURN) = max(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1569 else if (prog->argc >= 3)
1572 float f = PRVM_G_FLOAT(OFS_PARM0);
1573 for (i = 1;i < prog->argc;i++)
1574 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) > f)
1575 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1576 G_FLOAT(OFS_RETURN) = f;
1579 PRVM_ERROR("VM_max: %s must supply at least 2 floats\n", PRVM_NAME);
1586 returns number bounded by supplied range
1588 float bound(float min, float value, float max)
1591 void VM_bound (void)
1593 VM_SAFEPARMCOUNT(3,VM_bound);
1594 PRVM_G_FLOAT(OFS_RETURN) = bound(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2));
1601 returns a raised to power b
1603 float pow(float a, float b)
1608 VM_SAFEPARMCOUNT(2,VM_pow);
1609 PRVM_G_FLOAT(OFS_RETURN) = pow(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1616 copies data from one entity to another
1618 copyentity(entity src, entity dst)
1621 void VM_copyentity (void)
1623 prvm_edict_t *in, *out;
1624 VM_SAFEPARMCOUNT(2,VM_copyentity);
1625 in = PRVM_G_EDICT(OFS_PARM0);
1626 out = PRVM_G_EDICT(OFS_PARM1);
1627 memcpy(out->v, in->v, prog->progs->entityfields * 4);
1634 sets the color of a client and broadcasts the update to all connected clients
1636 setcolor(clientent, value)
1639 /*void PF_setcolor (void)
1645 entnum = G_EDICTNUM(OFS_PARM0);
1646 i = G_FLOAT(OFS_PARM1);
1648 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1650 Con_Printf ("tried to setcolor a non-client\n");
1654 client = svs.clients + entnum-1;
1655 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
1658 client->old_colors = i;
1659 client->edict->v->team = (i & 15) + 1;
1661 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1662 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
1663 MSG_WriteByte (&sv.reliable_datagram, i);
1666 void VM_Files_Init(void)
1668 memset(VM_FILES, 0, sizeof(qfile_t*[MAX_VMFILES]));
1671 void VM_Files_CloseAll(void)
1674 for (i = 0;i < MAX_VMFILES;i++)
1677 FS_Close(VM_FILES[i]);
1678 //VM_FILES[i] = NULL;
1680 memset(VM_FILES,0,sizeof(qfile_t*[MAX_VMFILES])); // this should be faster (is it ?)
1687 float fopen(string filename, float mode)
1690 // float(string filename, float mode) fopen = #110;
1691 // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE),
1692 // returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
1696 char *modestring, *filename;
1698 VM_SAFEPARMCOUNT(2,VM_fopen);
1700 for (filenum = 0;filenum < MAX_VMFILES;filenum++)
1701 if (VM_FILES[filenum] == NULL)
1703 if (filenum >= MAX_VMFILES)
1705 Con_Printf("VM_fopen: %s ran out of file handles (%i)\n", PRVM_NAME, MAX_VMFILES);
1706 PRVM_G_FLOAT(OFS_RETURN) = -2;
1709 mode = PRVM_G_FLOAT(OFS_PARM1);
1712 case 0: // FILE_READ
1715 case 1: // FILE_APPEND
1718 case 2: // FILE_WRITE
1722 Con_Printf ("VM_fopen: %s no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", PRVM_NAME, mode);
1723 PRVM_G_FLOAT(OFS_RETURN) = -3;
1726 filename = PRVM_G_STRING(OFS_PARM0);
1727 // .. is parent directory on many platforms
1728 // / is parent directory on Amiga
1729 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
1730 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
1731 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
1733 Con_Printf("VM_fopen: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
1734 PRVM_G_FLOAT(OFS_RETURN) = -4;
1737 VM_FILES[filenum] = FS_Open(va("data/%s", filename), modestring, false);
1738 if (VM_FILES[filenum] == NULL)
1739 PRVM_G_FLOAT(OFS_RETURN) = -1;
1741 PRVM_G_FLOAT(OFS_RETURN) = filenum;
1748 fclose(float fhandle)
1751 //void(float fhandle) fclose = #111; // closes a file
1752 void VM_fclose(void)
1756 VM_SAFEPARMCOUNT(1,VM_fclose);
1758 filenum = PRVM_G_FLOAT(OFS_PARM0);
1759 if (filenum < 0 || filenum >= MAX_VMFILES)
1761 Con_Printf("VM_fclose: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1764 if (VM_FILES[filenum] == NULL)
1766 Con_Printf("VM_fclose: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1769 FS_Close(VM_FILES[filenum]);
1770 VM_FILES[filenum] = NULL;
1777 string fgets(float fhandle)
1780 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
1784 static char string[VM_STRINGTEMP_LENGTH];
1787 VM_SAFEPARMCOUNT(1,VM_fgets);
1789 filenum = PRVM_G_FLOAT(OFS_PARM0);
1790 if (filenum < 0 || filenum >= MAX_VMFILES)
1792 Con_Printf("VM_fgets: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1795 if (VM_FILES[filenum] == NULL)
1797 Con_Printf("VM_fgets: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1803 c = FS_Getc(VM_FILES[filenum]);
1804 if (c == '\r' || c == '\n' || c < 0)
1806 if (end < VM_STRINGTEMP_LENGTH - 1)
1810 // remove \n following \r
1812 c = FS_Getc(VM_FILES[filenum]);
1813 if (developer.integer)
1814 Con_Printf("fgets: %s: %s\n", PRVM_NAME, string);
1816 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1818 PRVM_G_INT(OFS_RETURN) = 0;
1825 fputs(float fhandle, string s)
1828 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
1832 char string[VM_STRINGTEMP_LENGTH];
1835 VM_SAFEPARMCOUNT(2,VM_fputs);
1837 filenum = PRVM_G_FLOAT(OFS_PARM0);
1838 if (filenum < 0 || filenum >= MAX_VMFILES)
1840 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1843 if (VM_FILES[filenum] == NULL)
1845 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1848 VM_VarString(1, string, sizeof(string));
1849 if ((stringlength = strlen(string)))
1850 FS_Write(VM_FILES[filenum], string, stringlength);
1851 if (developer.integer)
1852 Con_Printf("fputs: %s: %s\n", PRVM_NAME, string);
1859 float strlen(string s)
1862 //float(string s) strlen = #114; // returns how many characters are in a string
1863 void VM_strlen(void)
1867 VM_SAFEPARMCOUNT(1,VM_strlen);
1869 s = PRVM_G_STRING(OFS_PARM0);
1871 PRVM_G_FLOAT(OFS_RETURN) = strlen(s);
1873 PRVM_G_FLOAT(OFS_RETURN) = 0;
1880 string strcat(string,string,...[string])
1883 //string(string s1, string s2) strcat = #115;
1884 // concatenates two strings (for example "abc", "def" would return "abcdef")
1885 // and returns as a tempstring
1886 void VM_strcat(void)
1891 PRVM_ERROR("VM_strcat wrong parameter count (min. 2 expected ) !\n");
1893 s = VM_GetTempString();
1894 VM_VarString(0, s, VM_STRINGTEMP_LENGTH);
1895 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
1902 string substring(string s, float start, float length)
1905 // string(string s, float start, float length) substring = #116;
1906 // returns a section of a string as a tempstring
1907 void VM_substring(void)
1909 int i, start, length;
1912 VM_SAFEPARMCOUNT(3,VM_substring);
1914 string = VM_GetTempString();
1915 s = PRVM_G_STRING(OFS_PARM0);
1916 start = PRVM_G_FLOAT(OFS_PARM1);
1917 length = PRVM_G_FLOAT(OFS_PARM2);
1920 for (i = 0;i < start && *s;i++, s++);
1921 for (i = 0;i < VM_STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
1924 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1931 vector stov(string s)
1934 //vector(string s) stov = #117; // returns vector value from a string
1937 char string[VM_STRINGTEMP_LENGTH];
1939 VM_SAFEPARMCOUNT(1,VM_stov);
1941 VM_VarString(0, string, sizeof(string));
1942 Math_atov(string, PRVM_G_VECTOR(OFS_RETURN));
1949 string strzone(string s)
1952 //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)
1953 void VM_strzone(void)
1957 VM_SAFEPARMCOUNT(1,VM_strzone);
1959 in = PRVM_G_STRING(OFS_PARM0);
1960 out = Mem_Alloc(VM_STRINGS_MEMPOOL, strlen(in) + 1);
1962 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(out);
1972 //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!!!)
1973 void VM_strunzone(void)
1975 VM_SAFEPARMCOUNT(1,VM_strunzone);
1977 Mem_Free(PRVM_G_STRING(OFS_PARM0));
1982 VM_command (used by client and menu)
1984 clientcommand(float client, string s) (for client and menu)
1987 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
1988 //this function originally written by KrimZon, made shorter by LordHavoc
1989 void VM_clcommand (void)
1991 client_t *temp_client;
1994 VM_SAFEPARMCOUNT(2,VM_clcommand);
1996 i = PRVM_G_FLOAT(OFS_PARM0);
1997 if (!sv.active || i < 0 || i >= svs.maxclients || !svs.clients[i].active)
1999 Con_Printf("VM_clientcommand: %s: invalid client/server is not active !", PRVM_NAME);
2003 temp_client = host_client;
2004 host_client = svs.clients + i;
2005 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2006 host_client = temp_client;
2014 float tokenize(string s)
2017 //float(string s) tokenize = #441;
2018 // takes apart a string into individal words (access them with argv), returns how many
2019 // this function originally written by KrimZon, made shorter by LordHavoc
2020 static char **tokens = NULL;
2021 static int max_tokens, num_tokens = 0;
2022 void VM_tokenize (void)
2027 VM_SAFEPARMCOUNT(1,VM_tokenize);
2029 str = PRVM_G_STRING(OFS_PARM0);
2034 for (i=0;i<num_tokens;i++)
2040 tokens = Z_Malloc(strlen(str) * sizeof(char *));
2041 max_tokens = strlen(str);
2043 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
2045 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
2046 strcpy(tokens[num_tokens], com_token);
2049 PRVM_G_FLOAT(OFS_RETURN) = num_tokens;
2056 string argv(float n)
2059 //string(float n) argv = #442;
2060 // returns a word from the tokenized string (returns nothing for an invalid index)
2061 // this function originally written by KrimZon, made shorter by LordHavoc
2066 VM_SAFEPARMCOUNT(1,VM_argv);
2068 token_num = PRVM_G_FLOAT(OFS_PARM0);
2069 if (token_num >= 0 && token_num < num_tokens)
2070 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tokens[token_num]);
2072 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
2076 //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)
2077 void PF_setattachment (void)
2079 edict_t *e = G_EDICT(OFS_PARM0);
2080 edict_t *tagentity = G_EDICT(OFS_PARM1);
2081 char *tagname = G_STRING(OFS_PARM2);
2086 if (tagentity == NULL)
2087 tagentity = sv.edicts;
2089 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
2091 v->edict = EDICT_TO_PROG(tagentity);
2093 v = GETEDICTFIELDVALUE(e, eval_tag_index);
2096 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
2098 modelindex = (int)tagentity->v->modelindex;
2099 if (modelindex >= 0 && modelindex < MAX_MODELS)
2101 model = sv.models[modelindex];
2102 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
2103 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
2104 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
2106 if (v->_float == 0 && model->alias.aliasnum_tags)
2107 for (i = 0;i < model->alias.aliasnum_tags;i++)
2108 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
2111 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);
2114 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));
2125 void VM_isserver(void)
2127 VM_SAFEPARMCOUNT(0,VM_serverstate);
2129 PRVM_G_FLOAT(OFS_RETURN) = sv.active;
2139 void VM_clientcount(void)
2141 VM_SAFEPARMCOUNT(0,VM_clientcount);
2143 PRVM_G_FLOAT(OFS_RETURN) = svs.maxclients;
2153 void VM_clientstate(void)
2155 VM_SAFEPARMCOUNT(0,VM_clientstate);
2157 PRVM_G_FLOAT(OFS_RETURN) = cls.state;
2164 float getostype(void)
2166 */ // not used at the moment -> not included in the common list
2167 void VM_getostype(void)
2169 VM_SAFEPARMCOUNT(0,VM_getostype);
2174 OS_MAC - not supported
2178 PRVM_G_FLOAT(OFS_RETURN) = 0;
2180 PRVM_G_FLOAT(OFS_RETURN) = 2;
2182 PRVM_G_FLOAT(OFS_RETURN) = 1;
2190 vector getmousepos()
2193 void VM_getmousepos(void)
2196 VM_SAFEPARMCOUNT(0,VM_getmousepos);
2198 PRVM_G_VECTOR(OFS_RETURN)[0] = in_mouse_x;
2199 PRVM_G_VECTOR(OFS_RETURN)[1] = in_mouse_y;
2200 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2210 void VM_gettime(void)
2212 VM_SAFEPARMCOUNT(0,VM_gettime);
2214 PRVM_G_FLOAT(OFS_RETURN) = (float) *prog->time;
2221 loadfromdata(string data)
2224 void VM_loadfromdata(void)
2226 VM_SAFEPARMCOUNT(1,VM_loadentsfromfile);
2228 PRVM_ED_LoadFromFile(PRVM_G_STRING(OFS_PARM0));
2235 loadfromfile(string file)
2238 void VM_loadfromfile(void)
2243 VM_SAFEPARMCOUNT(1,VM_loadfromfile);
2245 filename = PRVM_G_STRING(OFS_PARM0);
2246 // .. is parent directory on many platforms
2247 // / is parent directory on Amiga
2248 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2249 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2250 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2252 Con_Printf("VM_loadfromfile: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
2253 PRVM_G_FLOAT(OFS_RETURN) = -4;
2257 // not conform with VM_fopen
2258 data = FS_LoadFile(filename, false);
2260 PRVM_G_FLOAT(OFS_RETURN) = -1;
2262 PRVM_ED_LoadFromFile(data);
2273 float mod(float val, float m)
2276 void VM_modulo(void)
2279 VM_SAFEPARMCOUNT(2,VM_module);
2281 val = (int) PRVM_G_FLOAT(OFS_PARM0);
2282 m = (int) PRVM_G_FLOAT(OFS_PARM1);
2284 PRVM_G_FLOAT(OFS_RETURN) = (float) (val % m);
2287 void VM_Search_Init(void)
2289 memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
2292 void VM_Search_Reset(void)
2295 // reset the fssearch list
2296 for(i = 0; i < MAX_VMSEARCHES; i++)
2297 if(VM_SEARCHLIST[i])
2298 FS_FreeSearch(VM_SEARCHLIST[i]);
2299 memset(VM_SEARCHLIST,0,sizeof(fssearch_t*[MAX_VMSEARCHES]));
2306 float search_begin(string pattern, float caseinsensitive, float quiet)
2309 void VM_search_begin(void)
2313 int caseinsens, quiet;
2315 VM_SAFEPARMCOUNT(3, VM_search_begin);
2317 pattern = PRVM_G_STRING(OFS_PARM0);
2319 VM_CheckEmptyString(pattern);
2321 caseinsens = PRVM_G_FLOAT(OFS_PARM1);
2322 quiet = PRVM_G_FLOAT(OFS_PARM2);
2324 for(handle = 0; handle < MAX_VMSEARCHES; handle++)
2325 if(!VM_SEARCHLIST[handle])
2328 if(handle >= MAX_VMSEARCHES)
2330 Con_Printf("VM_search_begin: %s ran out of search handles (%i)\n", PRVM_NAME, MAX_VMSEARCHES);
2331 PRVM_G_FLOAT(OFS_RETURN) = -2;
2335 if(!(VM_SEARCHLIST[handle] = FS_Search(pattern,caseinsens, quiet)))
2336 PRVM_G_FLOAT(OFS_RETURN) = -1;
2338 PRVM_G_FLOAT(OFS_RETURN) = handle;
2345 void search_end(float handle)
2348 void VM_search_end(void)
2351 VM_SAFEPARMCOUNT(1, VM_search_end);
2353 handle = PRVM_G_FLOAT(OFS_PARM0);
2355 if(handle < 0 || handle >= MAX_VMSEARCHES)
2357 Con_Printf("VM_search_end: invalid handle %i used in %s\n", handle, PRVM_NAME);
2360 if(VM_SEARCHLIST[handle] == NULL)
2362 Con_Printf("VM_search_end: no such handle %i in %s\n", handle, PRVM_NAME);
2366 FS_FreeSearch(VM_SEARCHLIST[handle]);
2367 VM_SEARCHLIST[handle] = NULL;
2374 float search_getsize(float handle)
2377 void VM_search_getsize(void)
2380 VM_SAFEPARMCOUNT(1, VM_M_search_getsize);
2382 handle = PRVM_G_FLOAT(OFS_PARM0);
2384 if(handle < 0 || handle >= MAX_VMSEARCHES)
2386 Con_Printf("VM_search_getsize: invalid handle %i used in %s\n", handle, PRVM_NAME);
2389 if(VM_SEARCHLIST[handle] == NULL)
2391 Con_Printf("VM_search_getsize: no such handle %i in %s\n", handle, PRVM_NAME);
2395 PRVM_G_FLOAT(OFS_RETURN) = VM_SEARCHLIST[handle]->numfilenames;
2400 VM_search_getfilename
2402 string search_getfilename(float handle, float num)
2405 void VM_search_getfilename(void)
2407 int handle, filenum;
2409 VM_SAFEPARMCOUNT(2, VM_search_getfilename);
2411 handle = PRVM_G_FLOAT(OFS_PARM0);
2412 filenum = PRVM_G_FLOAT(OFS_PARM1);
2414 if(handle < 0 || handle >= MAX_VMSEARCHES)
2416 Con_Printf("VM_search_getfilename: invalid handle %i used in %s\n", handle, PRVM_NAME);
2419 if(VM_SEARCHLIST[handle] == NULL)
2421 Con_Printf("VM_search_getfilename: no such handle %i in %s\n", handle, PRVM_NAME);
2424 if(filenum < 0 || filenum >= VM_SEARCHLIST[handle]->numfilenames)
2426 Con_Printf("VM_search_getfilename: invalid filenum %i in %s\n", filenum, PRVM_NAME);
2430 tmp = VM_GetTempString();
2431 strcpy(tmp, VM_SEARCHLIST[handle]->filenames[filenum]);
2433 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
2440 string chr(float ascii)
2446 VM_SAFEPARMCOUNT(1, VM_chr);
2448 tmp = VM_GetTempString();
2449 tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0);
2452 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
2455 //=============================================================================
2456 // Draw builtins (client & menu)
2462 float iscachedpic(string pic)
2465 void VM_iscachedpic(void)
2467 VM_SAFEPARMCOUNT(1,VM_iscachedpic);
2469 // drawq hasnt such a function, thus always return true
2470 PRVM_G_FLOAT(OFS_RETURN) = TRUE;
2477 string precache_pic(string pic)
2480 void VM_precache_pic(void)
2484 VM_SAFEPARMCOUNT(1, VM_precache_pic);
2486 s = PRVM_G_STRING(OFS_PARM0);
2487 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
2490 PRVM_ERROR ("VM_precache_pic: %s: NULL\n", PRVM_NAME);
2492 VM_CheckEmptyString (s);
2494 if(!Draw_CachePic(s))
2495 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
2505 void VM_freepic(void)
2509 VM_SAFEPARMCOUNT(1,VM_freepic);
2511 s = PRVM_G_STRING(OFS_PARM0);
2514 PRVM_ERROR ("VM_freepic: %s: NULL\n");
2516 VM_CheckEmptyString (s);
2525 float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
2528 void VM_drawcharacter(void)
2530 float *pos,*scale,*rgb;
2533 VM_SAFEPARMCOUNT(6,VM_drawcharacter);
2535 character = (char) PRVM_G_FLOAT(OFS_PARM1);
2538 Con_Printf("VM_drawcharacter: %s passed null character !\n",PRVM_NAME);
2539 PRVM_G_FLOAT(OFS_RETURN) = -1;
2543 pos = PRVM_G_VECTOR(OFS_PARM0);
2544 scale = PRVM_G_VECTOR(OFS_PARM2);
2545 rgb = PRVM_G_VECTOR(OFS_PARM3);
2546 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2548 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2550 Con_Printf("VM_drawcharacter: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2551 PRVM_G_FLOAT(OFS_RETURN) = -2;
2555 if(pos[2] || scale[2])
2556 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")));
2558 if(!scale[0] || !scale[1])
2560 Con_Printf("VM_drawcharacter: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2561 PRVM_G_FLOAT(OFS_RETURN) = -3;
2565 DrawQ_String (pos[0], pos[1], &character, 1, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2566 PRVM_G_FLOAT(OFS_RETURN) = 1;
2573 float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
2576 void VM_drawstring(void)
2578 float *pos,*scale,*rgb;
2581 VM_SAFEPARMCOUNT(6,VM_drawstring);
2583 string = PRVM_G_STRING(OFS_PARM1);
2586 Con_Printf("VM_drawstring: %s passed null string !\n",PRVM_NAME);
2587 PRVM_G_FLOAT(OFS_RETURN) = -1;
2591 VM_CheckEmptyString(string);
2593 pos = PRVM_G_VECTOR(OFS_PARM0);
2594 scale = PRVM_G_VECTOR(OFS_PARM2);
2595 rgb = PRVM_G_VECTOR(OFS_PARM3);
2596 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2598 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2600 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2601 PRVM_G_FLOAT(OFS_RETURN) = -2;
2605 if(!scale[0] || !scale[1])
2607 Con_Printf("VM_drawstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2608 PRVM_G_FLOAT(OFS_RETURN) = -3;
2612 if(pos[2] || scale[2])
2613 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")));
2615 DrawQ_String (pos[0], pos[1], string, 0, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2616 PRVM_G_FLOAT(OFS_RETURN) = 1;
2622 float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
2625 void VM_drawpic(void)
2628 float *size, *pos, *rgb;
2631 VM_SAFEPARMCOUNT(6,VM_drawpic);
2633 pic = PRVM_G_STRING(OFS_PARM1);
2637 Con_Printf("VM_drawpic: %s passed null picture name !\n", PRVM_NAME);
2638 PRVM_G_FLOAT(OFS_RETURN) = -1;
2642 VM_CheckEmptyString (pic);
2644 // is pic cached ? no function yet for that
2647 Con_Printf("VM_drawpic: %s: %s not cached !\n", PRVM_NAME, pic);
2648 PRVM_G_FLOAT(OFS_RETURN) = -4;
2652 pos = PRVM_G_VECTOR(OFS_PARM0);
2653 size = PRVM_G_VECTOR(OFS_PARM2);
2654 rgb = PRVM_G_VECTOR(OFS_PARM3);
2655 flag = (int) PRVM_G_FLOAT(OFS_PARM5);
2657 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2659 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2660 PRVM_G_FLOAT(OFS_RETURN) = -2;
2664 if(pos[2] || size[2])
2665 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")));
2667 DrawQ_Pic(pos[0], pos[1], pic, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2668 PRVM_G_FLOAT(OFS_RETURN) = 1;
2675 float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
2678 void VM_drawfill(void)
2680 float *size, *pos, *rgb;
2683 VM_SAFEPARMCOUNT(5,VM_drawfill);
2686 pos = PRVM_G_VECTOR(OFS_PARM0);
2687 size = PRVM_G_VECTOR(OFS_PARM1);
2688 rgb = PRVM_G_VECTOR(OFS_PARM2);
2689 flag = (int) PRVM_G_FLOAT(OFS_PARM4);
2691 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2693 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2694 PRVM_G_FLOAT(OFS_RETURN) = -2;
2698 if(pos[2] || size[2])
2699 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")));
2701 DrawQ_Pic(pos[0], pos[1], 0, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM3), flag);
2702 PRVM_G_FLOAT(OFS_RETURN) = 1;
2709 drawsetcliparea(float x, float y, float width, float height)
2712 void VM_drawsetcliparea(void)
2715 VM_SAFEPARMCOUNT(4,VM_drawsetcliparea);
2717 x = bound(0,PRVM_G_FLOAT(OFS_PARM0),vid.conwidth);
2718 y = bound(0,PRVM_G_FLOAT(OFS_PARM1),vid.conheight);
2719 w = bound(0,PRVM_G_FLOAT(OFS_PARM2),(vid.conwidth - x));
2720 h = bound(0,PRVM_G_FLOAT(OFS_PARM3),(vid.conheight - y));
2722 DrawQ_SetClipArea(x,y,w,h);
2727 VM_drawresetcliparea
2732 void VM_drawresetcliparea(void)
2734 VM_SAFEPARMCOUNT(0,VM_drawresetcliparea);
2736 DrawQ_ResetClipArea();
2743 vector getimagesize(string pic)
2746 void VM_getimagesize(void)
2751 VM_SAFEPARMCOUNT(1,VM_getimagesize);
2753 p = PRVM_G_STRING(OFS_PARM0);
2756 PRVM_ERROR("VM_getimagepos: %s passed null picture name !\n", PRVM_NAME);
2758 VM_CheckEmptyString (p);
2760 pic = Draw_CachePic (p);
2762 PRVM_G_VECTOR(OFS_RETURN)[0] = pic->width;
2763 PRVM_G_VECTOR(OFS_RETURN)[1] = pic->height;
2764 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2767 void VM_Cmd_Init(void)
2769 // only init the stuff for the current prog
2770 VM_STRINGS_MEMPOOL = Mem_AllocPool(va("vm_stringsmempool[%s]",PRVM_NAME));
2775 void VM_Cmd_Reset(void)
2777 //Mem_EmptyPool(VM_STRINGS_MEMPOOL);
2778 Mem_FreePool(&VM_STRINGS_MEMPOOL);
2780 VM_Files_CloseAll();
2783 //============================================================================
2786 char *vm_sv_extensions =
2789 prvm_builtin_t vm_sv_builtins[] = {
2790 0 // to be consistent with the old vm
2793 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
2795 void VM_SV_Cmd_Init(void)
2799 void VM_SV_Cmd_Reset(void)
2803 //============================================================================
2806 char *vm_cl_extensions =
2809 prvm_builtin_t vm_cl_builtins[] = {
2810 0 // to be consistent with the old vm
2813 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
2815 void VM_CL_Cmd_Init(void)
2819 void VM_CL_Cmd_Reset(void)
2823 //============================================================================
2826 char *vm_m_extensions =
2833 setmousetarget(float target)
2836 void VM_M_setmousetarget(void)
2838 VM_SAFEPARMCOUNT(1, VM_M_setmousetarget);
2840 switch((int)PRVM_G_FLOAT(OFS_PARM0))
2843 in_client_mouse = false;
2846 in_client_mouse = true;
2849 PRVM_ERROR("VM_M_setmousetarget: wrong destination %i !\n",PRVM_G_FLOAT(OFS_PARM0));
2857 float getmousetarget
2860 void VM_M_getmousetarget(void)
2862 VM_SAFEPARMCOUNT(0,VM_M_getmousetarget);
2865 PRVM_G_FLOAT(OFS_RETURN) = 2;
2867 PRVM_G_FLOAT(OFS_RETURN) = 1;
2876 setkeydest(float dest)
2879 void VM_M_setkeydest(void)
2881 VM_SAFEPARMCOUNT(1,VM_M_setkeydest);
2883 switch((int)PRVM_G_FLOAT(OFS_PARM0))
2887 key_dest = key_game;
2891 key_dest = key_menu;
2895 // key_dest = key_message
2898 PRVM_ERROR("VM_M_setkeydest: wrong destination %i !\n",prog->globals[OFS_PARM0]);
2909 void VM_M_getkeydest(void)
2911 VM_SAFEPARMCOUNT(0,VM_M_getkeydest);
2913 // key_game = 0, key_message = 1, key_menu = 2, unknown = 3
2917 PRVM_G_FLOAT(OFS_RETURN) = 0;
2920 PRVM_G_FLOAT(OFS_RETURN) = 2;
2924 // PRVM_G_FLOAT(OFS_RETURN) = 1;
2927 PRVM_G_FLOAT(OFS_RETURN) = 3;
2935 callfunction(...,string function_name)
2938 mfunction_t *PRVM_ED_FindFunction (const char *name);
2939 void VM_M_callfunction(void)
2945 PRVM_ERROR("VM_M_callfunction: 1 parameter is required !\n");
2947 s = PRVM_G_STRING(OFS_PARM0 + (prog->argc - 1));
2950 PRVM_ERROR("VM_M_callfunction: null string !\n");
2952 VM_CheckEmptyString(s);
2954 func = PRVM_ED_FindFunction(s);
2957 PRVM_ERROR("VM_M_callfunciton: function %s not found !\n", s);
2958 else if (func->first_statement < 0)
2960 // negative statements are built in functions
2961 int builtinnumber = -func->first_statement;
2962 prog->xfunction->builtinsprofile++;
2963 if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber])
2964 prog->builtins[builtinnumber]();
2966 PRVM_ERROR("No such builtin #%i in %s", builtinnumber, PRVM_NAME);
2971 PRVM_ExecuteProgram(func - prog->functions,"");
2980 float isfunction(string function_name)
2983 mfunction_t *PRVM_ED_FindFunction (const char *name);
2984 void VM_M_isfunction(void)
2989 VM_SAFEPARMCOUNT(1, VM_M_isfunction);
2991 s = PRVM_G_STRING(OFS_PARM0);
2994 PRVM_ERROR("VM_M_isfunction: null string !\n");
2996 VM_CheckEmptyString(s);
2998 func = PRVM_ED_FindFunction(s);
3001 PRVM_G_FLOAT(OFS_RETURN) = false;
3003 PRVM_G_FLOAT(OFS_RETURN) = true;
3010 writetofile(float fhandle, entity ent)
3013 void VM_M_writetofile(void)
3018 VM_SAFEPARMCOUNT(2, VM_M_writetofile);
3020 filenum = PRVM_G_FLOAT(OFS_PARM0);
3021 if (filenum < 0 || filenum >= MAX_VMFILES)
3023 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
3026 if (VM_FILES[filenum] == NULL)
3028 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
3032 ent = PRVM_G_EDICT(OFS_PARM1);
3035 Con_Printf("VM_M_writetofile: %s: entity %i is free !\n", PRVM_NAME, PRVM_EDICT_NUM(OFS_PARM1));
3039 PRVM_ED_Write (VM_FILES[filenum], ent);
3046 vector getresolution(float number)
3049 extern unsigned short video_resolutions[][2];
3050 void VM_M_getresolution(void)
3053 VM_SAFEPARMCOUNT(1, VM_getresolution);
3055 nr = PRVM_G_FLOAT(OFS_PARM0);
3058 PRVM_G_VECTOR(OFS_RETURN)[0] = video_resolutions[nr][0];
3059 PRVM_G_VECTOR(OFS_RETURN)[1] = video_resolutions[nr][1];
3060 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
3067 string keynumtostring(float keynum)
3070 void VM_M_keynumtostring(void)
3074 VM_SAFEPARMCOUNT(1, VM_M_keynumtostring);
3076 keynum = PRVM_G_FLOAT(OFS_PARM0);
3078 tmp = VM_GetTempString();
3080 strcpy(tmp, Key_KeynumToString(keynum));
3082 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tmp);
3085 prvm_builtin_t vm_m_builtins[] = {
3086 0, // to be consistent with the old vm
3087 // common builtings (mostly)
3164 VM_search_getfilename, // 77
3180 VM_WriteEntity, // 408
3196 VM_drawresetcliparea,
3197 VM_getimagesize,// 460
3206 VM_M_setmousetarget,
3207 VM_M_getmousetarget,
3212 VM_M_keynumtostring // 609
3215 const int vm_m_numbuiltins = sizeof(vm_m_builtins) / sizeof(prvm_builtin_t);
3217 void VM_M_Cmd_Init(void)
3222 void VM_M_Cmd_Reset(void)