2 // Basically every vm builtin cmd should be in here.
3 // All 3 builtin list and extension lists can be found here
4 // cause large (I think they will) are from pr_cmds the same copyright like in pr_cms
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)
90 perhaps only : Menu : WriteMsg
91 ===============================
93 WriteByte(float data, float dest, float desto)
94 WriteChar(float data, float dest, float desto)
95 WriteShort(float data, float dest, float desto)
96 WriteLong(float data, float dest, float desto)
97 WriteAngle(float data, float dest, float desto)
98 WriteCoord(float data, float dest, float desto)
99 WriteString(string data, float dest, float desto)
100 WriteEntity(entity data, float dest, float desto)
102 Client & Menu : draw functions
103 ===============================
105 float iscachedpic(string pic)
106 string precache_pic(string pic)
108 float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
109 float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
110 float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
111 float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
112 drawsetcliparea(float x, float y, float width, float height)
114 vector getimagesize(string pic)
117 ==============================================================================
121 setkeydest(float dest)
123 setmousetarget(float target)
124 float getmousetarget(void)
126 callfunction(...,string function_name)
127 writetofile(float fhandle, entity ent)
130 #include "quakedef.h"
131 #include "progdefs.h"
132 #include "clprogdefs.h"
133 #include "mprogdefs.h"
135 //============================================================================
136 // nice helper macros
138 #ifndef VM_NOPARMCHECK
139 #define VM_SAFEPARMCOUNT(p,f) if(prog->argc != p) PRVM_ERROR(#f " wrong parameter count (" #p " expected ) !\n")
141 #define VM_SAFEPARMCOUNT(p,f)
144 #define VM_RETURN_EDICT(e) (((int *)prog->globals)[OFS_RETURN] = PRVM_EDICT_TO_PROG(e))
146 #define VM_STRINGS_MEMPOOL vm_strings_mempool[PRVM_GetProgNr()]
148 #define e10 0,0,0,0,0,0,0,0,0,0
149 #define e100 e10,e10,e10,e10,e10,e10,e10,e10,e10,e10
150 #define e1000 e100,e100,e100,e100,e100,e100,e100,e100,e100,e100
152 //============================================================================
155 // string zone mempool
156 mempool_t *vm_strings_mempool[PRVM_MAXPROGS];
158 // temp string handling
159 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
160 #define VM_STRINGTEMP_BUFFERS 16
161 #define VM_STRINGTEMP_LENGTH 4096
162 static char vm_string_temp[VM_STRINGTEMP_BUFFERS][VM_STRINGTEMP_LENGTH];
163 static int vm_string_tempindex = 0;
166 #define MAX_QC_CVARS 128 * PRVM_MAXPROGS
167 cvar_t vm_qc_cvar[MAX_QC_CVARS];
168 int vm_currentqc_cvar;
171 #define MAX_VMFILES 256
172 #define MAX_PRVMFILES MAX_VMFILES * PRVM_MAXPROGS
173 #define VM_FILES ((qfile_t**)(vm_files + PRVM_GetProgNr() * MAX_VMFILES))
175 qfile_t *vm_files[MAX_PRVMFILES];
177 static char *VM_GetTempString(void)
180 s = vm_string_temp[vm_string_tempindex];
181 vm_string_tempindex = (vm_string_tempindex + 1) % VM_STRINGTEMP_BUFFERS;
185 void VM_CheckEmptyString (char *s)
188 PRVM_ERROR ("%s: Bad string", PRVM_NAME);
191 //============================================================================
194 void VM_VarString(int first, char *out, int outlength)
200 outend = out + outlength - 1;
201 for (i = first;i < prog->argc && out < outend;i++)
203 s = PRVM_G_STRING((OFS_PARM0+i*3));
204 while (out < outend && *s)
214 returns true if the extension is supported by the server
216 checkextension(extensionname)
220 // kind of helper function
221 static qboolean checkextension(char *name)
227 for (e = prog->extensionstring;*e;e++)
234 while (*e && *e != ' ')
236 if (e - start == len)
237 if (!strncasecmp(start, name, len))
245 void VM_checkextension (void)
247 VM_SAFEPARMCOUNT(1,VM_checkextension);
249 PRVM_G_FLOAT(OFS_RETURN) = checkextension(PRVM_G_STRING(OFS_PARM0));
256 This is a TERMINAL error, which will kill off the entire prog.
265 char string[VM_STRINGTEMP_LENGTH];
267 VM_VarString(0, string, sizeof(string));
268 Con_Printf ("======%S ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
271 ed = PRVM_G_EDICT(prog->self->ofs);
275 PRVM_ERROR ("%s: Program error", PRVM_NAME);
282 Dumps out self, then an error message. The program is aborted and self is
283 removed, but the level can continue.
288 void VM_objerror (void)
291 char string[VM_STRINGTEMP_LENGTH];
293 VM_VarString(0, string, sizeof(string));
294 Con_Printf ("======%s OBJECT ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
297 ed = PRVM_G_EDICT (prog->self->ofs);
303 // objerror has to display the object fields -> else call
304 PRVM_ERROR ("VM_objecterror: self not defined !\n");
309 VM_print (actually used only by client and menu)
318 char string[VM_STRINGTEMP_LENGTH];
320 VM_VarString(0, string, sizeof(string));
328 broadcast print to everyone on server
333 void VM_bprint (void)
335 char string[VM_STRINGTEMP_LENGTH];
339 Con_Printf("VM_bprint: game is not server(%s) !", PRVM_NAME);
343 VM_VarString(0, string, sizeof(string));
344 SV_BroadcastPrintf("%s", string);
349 VM_sprint (menu & client but only if server.active == true)
351 single print to a specific client
353 sprint(float clientnum,...[string])
356 void VM_sprint (void)
360 char string[VM_STRINGTEMP_LENGTH];
362 //find client for this entity
363 clientnum = PRVM_G_FLOAT(OFS_PARM0);
364 if (!sv.active || clientnum < 0 || clientnum >= svs.maxclients || !svs.clients[clientnum].active)
366 Con_Printf("VM_sprint: %s: invalid client or server is not active !", PRVM_NAME);
370 client = svs.clients + clientnum;
371 if (!client->netconnection)
373 VM_VarString(1, string, sizeof(string));
374 MSG_WriteChar(&client->message,svc_print);
375 MSG_WriteString(&client->message, string);
382 single print to the screen
384 centerprint(clientent, value)
387 void VM_centerprint (void)
389 char string[VM_STRINGTEMP_LENGTH];
391 VM_VarString(0, string, sizeof(string));
392 SCR_CenterPrint(string);
399 vector normalize(vector)
402 void VM_normalize (void)
408 VM_SAFEPARMCOUNT(1,VM_normalize);
410 value1 = PRVM_G_VECTOR(OFS_PARM0);
412 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
416 newvalue[0] = newvalue[1] = newvalue[2] = 0;
420 newvalue[0] = value1[0] * new;
421 newvalue[1] = value1[1] * new;
422 newvalue[2] = value1[2] * new;
425 VectorCopy (newvalue, PRVM_G_VECTOR(OFS_RETURN));
440 VM_SAFEPARMCOUNT(1,VM_vlen);
442 value1 = PRVM_G_VECTOR(OFS_PARM0);
444 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
447 PRVM_G_FLOAT(OFS_RETURN) = new;
454 float vectoyaw(vector)
457 void VM_vectoyaw (void)
462 VM_SAFEPARMCOUNT(1,VM_vectoyaw);
464 value1 = PRVM_G_VECTOR(OFS_PARM0);
466 if (value1[1] == 0 && value1[0] == 0)
470 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
475 PRVM_G_FLOAT(OFS_RETURN) = yaw;
483 vector vectoangles(vector)
486 void VM_vectoangles (void)
492 VM_SAFEPARMCOUNT(1,VM_vectoangles);
494 value1 = PRVM_G_VECTOR(OFS_PARM0);
496 if (value1[1] == 0 && value1[0] == 0)
506 // LordHavoc: optimized a bit
509 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
513 else if (value1[1] > 0)
518 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
519 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
524 PRVM_G_FLOAT(OFS_RETURN+0) = pitch;
525 PRVM_G_FLOAT(OFS_RETURN+1) = yaw;
526 PRVM_G_FLOAT(OFS_RETURN+2) = 0;
533 Returns a number from 0<= num < 1
538 void VM_random (void)
542 VM_SAFEPARMCOUNT(0,VM_random);
544 num = (rand ()&0x7fff) / ((float)0x7fff);
546 PRVM_G_FLOAT(OFS_RETURN) = num;
553 Each entity can have eight independant sound sources, like voice,
556 Channel 0 is an auto-allocate channel, the others override anything
557 already running on that entity/channel pair.
559 An attenuation of 0 will play full volume everywhere in the level.
560 Larger attenuations will drop off.
573 entity = G_EDICT(OFS_PARM0);
574 channel = G_FLOAT(OFS_PARM1);
575 sample = G_STRING(OFS_PARM2);
576 volume = G_FLOAT(OFS_PARM3) * 255;
577 attenuation = G_FLOAT(OFS_PARM4);
579 if (volume < 0 || volume > 255)
580 Host_Error ("SV_StartSound: volume = %i", volume);
582 if (attenuation < 0 || attenuation > 4)
583 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
585 if (channel < 0 || channel > 7)
586 Host_Error ("SV_StartSound: channel = %i", channel);
588 SV_StartSound (entity, channel, sample, volume, attenuation);
596 localsound(string sample)
599 void VM_localsound(void)
603 VM_SAFEPARMCOUNT(1,VM_localsound);
605 s = PRVM_G_STRING(OFS_PARM0);
609 Con_Printf("VM_localsound: %s : %s not cached !\n", PRVM_NAME, s);
610 PRVM_G_FLOAT(OFS_RETURN) = -4;
615 PRVM_G_FLOAT(OFS_RETURN) = 1;
627 PRVM_ERROR ("%s: break statement", PRVM_NAME);
630 //============================================================================
636 Sends text over to the client's execution buffer
638 [localcmd (string) or]
642 void VM_localcmd (void)
644 VM_SAFEPARMCOUNT(1,VM_localcmd);
646 Cbuf_AddText(PRVM_G_STRING(OFS_PARM0));
658 VM_SAFEPARMCOUNT(1,VM_cvar);
660 PRVM_G_FLOAT(OFS_RETURN) = Cvar_VariableValue(PRVM_G_STRING(OFS_PARM0));
667 void cvar_set (string,string)
670 void VM_cvar_set (void)
672 VM_SAFEPARMCOUNT(2,VM_cvar_set);
674 Cvar_Set(PRVM_G_STRING(OFS_PARM0), PRVM_G_STRING(OFS_PARM1));
684 void VM_dprint (void)
686 char string[VM_STRINGTEMP_LENGTH];
687 if (developer.integer)
689 VM_VarString(0, string, sizeof(string));
690 Con_Printf("%s: %s", PRVM_NAME, string);
707 VM_SAFEPARMCOUNT(1, VM_ftos);
709 v = PRVM_G_FLOAT(OFS_PARM0);
711 s = VM_GetTempString();
712 if ((float)((int)v) == v)
713 sprintf(s, "%i", (int)v);
716 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
731 VM_SAFEPARMCOUNT(1,VM_fabs);
733 v = PRVM_G_FLOAT(OFS_PARM0);
734 PRVM_G_FLOAT(OFS_RETURN) = fabs(v);
749 VM_SAFEPARMCOUNT(1,VM_vtos);
751 s = VM_GetTempString();
752 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]);
753 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
768 VM_SAFEPARMCOUNT(1, VM_etos);
770 s = VM_GetTempString();
771 sprintf (s, "entity %i", PRVM_G_EDICTNUM(OFS_PARM0));
772 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
779 float stof(...[string])
784 char string[VM_STRINGTEMP_LENGTH];
785 VM_VarString(0, string, sizeof(string));
786 PRVM_G_FLOAT(OFS_RETURN) = atof(string);
800 prog->xfunction->builtinsprofile += 20;
801 ed = PRVM_ED_Alloc();
813 void VM_remove (void)
816 prog->xfunction->builtinsprofile += 20;
818 VM_SAFEPARMCOUNT(1, VM_remove);
820 ed = PRVM_G_EDICT(OFS_PARM0);
821 // if (ed == prog->edicts)
822 // PRVM_ERROR ("remove: tried to remove world\n");
823 // if (PRVM_NUM_FOR_EDICT(ed) <= sv.maxclients)
824 // Host_Error("remove: tried to remove a client\n");
832 entity find(entity start, .string field, string match)
843 VM_SAFEPARMCOUNT(3,VM_find);
845 e = PRVM_G_EDICTNUM(OFS_PARM0);
846 f = PRVM_G_INT(OFS_PARM1);
847 s = PRVM_G_STRING(OFS_PARM2);
851 // return reserved edict 0 (could be used for whatever the prog wants)
852 VM_RETURN_EDICT(prog->edicts);
856 for (e++ ; e < prog->num_edicts ; e++)
858 prog->xfunction->builtinsprofile++;
859 ed = PRVM_EDICT_NUM(e);
862 t = PRVM_E_STRING(ed,f);
872 VM_RETURN_EDICT(prog->edicts);
879 entity findfloat(entity start, .float field, float match)
880 entity findentity(entity start, .entity field, entity match)
883 // LordHavoc: added this for searching float, int, and entity reference fields
884 void VM_findfloat (void)
891 VM_SAFEPARMCOUNT(3,VM_findfloat);
893 e = PRVM_G_EDICTNUM(OFS_PARM0);
894 f = PRVM_G_INT(OFS_PARM1);
895 s = PRVM_G_FLOAT(OFS_PARM2);
897 for (e++ ; e < prog->num_edicts ; e++)
899 prog->xfunction->builtinsprofile++;
900 ed = PRVM_EDICT_NUM(e);
903 if (PRVM_E_FLOAT(ed,f) == s)
910 VM_RETURN_EDICT(prog->edicts);
917 entity findchain(.string field, string match)
920 int PRVM_ED_FindFieldOffset(const char *field);
921 // chained search for strings in entity fields
922 // entity(.string field, string match) findchain = #402;
923 void VM_findchain (void)
929 prvm_edict_t *ent, *chain;
931 VM_SAFEPARMCOUNT(2,VM_findchain);
933 // is the same like !(prog->flag & PRVM_FE_CHAIN) - even if the operator precedence is another
934 if(!prog->flag & PRVM_FE_CHAIN)
935 PRVM_ERROR("VM_findchain: %s doesnt have a chain field !\n", PRVM_NAME);
937 chain_of = PRVM_ED_FindFieldOffset ("chain");
939 chain = prog->edicts;
941 f = PRVM_G_INT(OFS_PARM0);
942 s = PRVM_G_STRING(OFS_PARM1);
945 VM_RETURN_EDICT(prog->edicts);
949 ent = PRVM_NEXT_EDICT(prog->edicts);
950 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
952 prog->xfunction->builtinsprofile++;
955 t = PRVM_E_STRING(ent,f);
961 PRVM_E_FLOAT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain);
965 VM_RETURN_EDICT(chain);
972 entity findchainfloat(.string field, float match)
973 entity findchainentity(.string field, entity match)
976 // LordHavoc: chained search for float, int, and entity reference fields
977 // entity(.string field, float match) findchainfloat = #403;
978 void VM_findchainfloat (void)
984 prvm_edict_t *ent, *chain;
986 VM_SAFEPARMCOUNT(2, VM_findchainfloat);
988 if(!prog->flag & PRVM_FE_CHAIN)
989 PRVM_ERROR("VM_findchainfloat: %s doesnt have a chain field !\n", PRVM_NAME);
991 chain_of = PRVM_ED_FindFieldOffset ("chain");
993 chain = (prvm_edict_t *)prog->edicts;
995 f = PRVM_G_INT(OFS_PARM0);
996 s = PRVM_G_FLOAT(OFS_PARM1);
998 ent = PRVM_NEXT_EDICT(prog->edicts);
999 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
1001 prog->xfunction->builtinsprofile++;
1004 if (E_FLOAT(ent,f) != s)
1007 PRVM_E_FLOAT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain);
1011 VM_RETURN_EDICT(chain);
1018 string precache_file(string)
1021 void VM_precache_file (void)
1022 { // precache_file is only used to copy files with qcc, it does nothing
1023 VM_SAFEPARMCOUNT(1,VM_precache_file);
1025 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1032 used instead of the other VM_precache_* functions in the builtin list
1036 void VM_precache_error (void)
1038 PRVM_ERROR ("PF_Precache_*: Precache can only be done in spawn functions");
1045 string precache_sound (string sample)
1048 void VM_precache_sound (void)
1052 VM_SAFEPARMCOUNT(1, VM_precache_sound);
1054 s = PRVM_G_STRING(OFS_PARM0);
1055 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1056 VM_CheckEmptyString (s);
1060 Con_Printf("VM_precache_sound: %s already cached (%s)\n", s, PRVM_NAME);
1064 if(!S_PrecacheSound(s,true))
1065 Con_Printf("VM_prache_sound: Failed to load %s for %s\n", s, PRVM_NAME);
1075 void VM_coredump (void)
1077 VM_SAFEPARMCOUNT(0,VM_coredump);
1079 Cbuf_AddText("prvm_edicts ");
1080 Cbuf_AddText(PRVM_NAME);
1091 void VM_traceon (void)
1093 VM_SAFEPARMCOUNT(0,VM_traceon);
1105 void VM_traceoff (void)
1107 VM_SAFEPARMCOUNT(0,VM_traceoff);
1109 prog->trace = false;
1119 void VM_eprint (void)
1121 VM_SAFEPARMCOUNT(1,VM_eprint);
1123 PRVM_ED_PrintNum (PRVM_G_EDICTNUM(OFS_PARM0));
1137 VM_SAFEPARMCOUNT(1,VM_rint);
1139 f = PRVM_G_FLOAT(OFS_PARM0);
1141 PRVM_G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1143 PRVM_G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1153 void VM_floor (void)
1155 VM_SAFEPARMCOUNT(1,VM_floor);
1157 PRVM_G_FLOAT(OFS_RETURN) = floor(PRVM_G_FLOAT(OFS_PARM0));
1169 VM_SAFEPARMCOUNT(1,VM_ceil);
1171 PRVM_G_FLOAT(OFS_RETURN) = ceil(PRVM_G_FLOAT(OFS_PARM0));
1179 entity nextent(entity)
1182 void VM_nextent (void)
1187 i = PRVM_G_EDICTNUM(OFS_PARM0);
1190 prog->xfunction->builtinsprofile++;
1192 if (i == prog->num_edicts)
1194 VM_RETURN_EDICT(prog->edicts);
1197 ent = PRVM_EDICT_NUM(i);
1200 VM_RETURN_EDICT(ent);
1207 ===============================================================================
1210 used only for client and menu
1211 severs uses VM_SV_...
1213 Write*(* data, float type, float to)
1215 ===============================================================================
1218 #define MSG_BROADCAST 0 // unreliable to all
1219 #define MSG_ONE 1 // reliable to one (msg_entity)
1220 #define MSG_ALL 2 // reliable to all
1221 #define MSG_INIT 3 // write to the init string
1223 sizebuf_t *VM_WriteDest (void)
1229 PRVM_ERROR("VM_WriteDest: game is not server (%s)\n", PRVM_NAME);
1231 dest = G_FLOAT(OFS_PARM1);
1235 return &sv.datagram;
1238 destclient = (int) PRVM_G_FLOAT(OFS_PARM2);
1239 if (destclient < 0 || destclient >= svs.maxclients || !svs.clients[destclient].active)
1240 PRVM_ERROR("VM_clientcommand: %s: invalid client !\n", PRVM_NAME);
1242 return &svs.clients[destclient].message;
1245 return &sv.reliable_datagram;
1251 PRVM_ERROR ("WriteDest: bad destination");
1258 void VM_WriteByte (void)
1260 MSG_WriteByte (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1263 void VM_WriteChar (void)
1265 MSG_WriteChar (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1268 void VM_WriteShort (void)
1270 MSG_WriteShort (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1273 void VM_WriteLong (void)
1275 MSG_WriteLong (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1278 void VM_WriteAngle (void)
1280 MSG_WriteAngle (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1283 void VM_WriteCoord (void)
1285 MSG_WriteDPCoord (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1288 void VM_WriteString (void)
1290 MSG_WriteString (VM_WriteDest(), PRVM_G_STRING(OFS_PARM0));
1293 void VM_WriteEntity (void)
1295 MSG_WriteShort (VM_WriteDest(), PRVM_G_EDICTNUM(OFS_PARM0));
1298 //=============================================================================
1305 changelevel(string map)
1308 void VM_changelevel (void)
1312 VM_SAFEPARMCOUNT(1, VM_changelevel);
1316 Con_Printf("VM_changelevel: game is not server (%s)\n", PRVM_NAME);
1320 // make sure we don't issue two changelevels
1321 if (svs.changelevel_issued)
1323 svs.changelevel_issued = true;
1325 s = G_STRING(OFS_PARM0);
1326 Cbuf_AddText (va("changelevel %s\n",s));
1338 VM_SAFEPARMCOUNT(1,VM_sin);
1339 PRVM_G_FLOAT(OFS_RETURN) = sin(PRVM_G_FLOAT(OFS_PARM0));
1350 VM_SAFEPARMCOUNT(1,VM_cos);
1351 PRVM_G_FLOAT(OFS_RETURN) = cos(PRVM_G_FLOAT(OFS_PARM0));
1363 VM_SAFEPARMCOUNT(1,VM_sqrt);
1364 PRVM_G_FLOAT(OFS_RETURN) = sqrt(PRVM_G_FLOAT(OFS_PARM0));
1371 Returns a vector of length < 1 and > 0
1376 void VM_randomvec (void)
1381 VM_SAFEPARMCOUNT(0, VM_randomvec);
1386 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1387 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1388 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1390 while (DotProduct(temp, temp) >= 1);
1391 VectorCopy (temp, PRVM_G_VECTOR(OFS_RETURN));
1394 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1395 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1396 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1397 // length returned always > 0
1398 length = (rand()&32766 + 1) * (1.0 / 32767.0) / VectorLength(temp);
1399 VectorScale(temp,length, temp);*/
1400 //VectorCopy(temp, PRVM_G_VECTOR(OFS_RETURN));
1403 //=============================================================================
1409 float registercvar (string name, string value)
1412 void VM_registercvar (void)
1417 VM_SAFEPARMCOUNT(2,VM_registercvar);
1419 name = PRVM_G_STRING(OFS_PARM0);
1420 value = PRVM_G_STRING(OFS_PARM1);
1421 PRVM_G_FLOAT(OFS_RETURN) = 0;
1422 // first check to see if it has already been defined
1423 if (Cvar_FindVar (name))
1426 // check for overlap with a command
1427 if (Cmd_Exists (name))
1429 Con_Printf ("VM_registercvar: %s is a command\n", name);
1433 if (vm_currentqc_cvar >= MAX_QC_CVARS)
1434 PRVM_ERROR ("VM_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1436 // copy the name and value
1437 variable = &vm_qc_cvar[vm_currentqc_cvar++];
1438 variable->name = Z_Malloc (strlen(name)+1);
1439 strcpy (variable->name, name);
1440 variable->string = Z_Malloc (strlen(value)+1);
1441 strcpy (variable->string, value);
1442 variable->value = atof (value);
1444 Cvar_RegisterVariable(variable);
1445 PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1452 returns the minimum of two supplied floats
1454 float min(float a, float b, ...[float])
1459 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1460 if (prog->argc == 2)
1461 PRVM_G_FLOAT(OFS_RETURN) = min(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1462 else if (prog->argc >= 3)
1465 float f = PRVM_G_FLOAT(OFS_PARM0);
1466 for (i = 1;i < prog->argc;i++)
1467 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) < f)
1468 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1469 PRVM_G_FLOAT(OFS_RETURN) = f;
1472 PRVM_ERROR("VM_min: %s must supply at least 2 floats\n", PRVM_NAME);
1479 returns the maximum of two supplied floats
1481 float max(float a, float b, ...[float])
1486 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1487 if (prog->argc == 2)
1488 PRVM_G_FLOAT(OFS_RETURN) = max(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1489 else if (prog->argc >= 3)
1492 float f = PRVM_G_FLOAT(OFS_PARM0);
1493 for (i = 1;i < prog->argc;i++)
1494 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) > f)
1495 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1496 G_FLOAT(OFS_RETURN) = f;
1499 PRVM_ERROR("VM_max: %s must supply at least 2 floats\n", PRVM_NAME);
1506 returns number bounded by supplied range
1508 float bound(float min, float value, float max)
1511 void VM_bound (void)
1513 VM_SAFEPARMCOUNT(3,VM_bound);
1514 PRVM_G_FLOAT(OFS_RETURN) = bound(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2));
1521 returns a raised to power b
1523 float pow(float a, float b)
1528 VM_SAFEPARMCOUNT(2,VM_pow);
1529 PRVM_G_FLOAT(OFS_RETURN) = pow(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1536 copies data from one entity to another
1538 copyentity(entity src, entity dst)
1541 void VM_copyentity (void)
1543 prvm_edict_t *in, *out;
1544 VM_SAFEPARMCOUNT(2,VM_copyentity);
1545 in = PRVM_G_EDICT(OFS_PARM0);
1546 out = PRVM_G_EDICT(OFS_PARM1);
1547 memcpy(out->v, in->v, prog->progs->entityfields * 4);
1554 sets the color of a client and broadcasts the update to all connected clients
1556 setcolor(clientent, value)
1559 /*void PF_setcolor (void)
1565 entnum = G_EDICTNUM(OFS_PARM0);
1566 i = G_FLOAT(OFS_PARM1);
1568 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1570 Con_Printf ("tried to setcolor a non-client\n");
1574 client = svs.clients + entnum-1;
1575 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
1578 client->old_colors = i;
1579 client->edict->v->team = (i & 15) + 1;
1581 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1582 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
1583 MSG_WriteByte (&sv.reliable_datagram, i);
1586 void VM_Files_Init(void)
1588 memset(VM_FILES, 0, sizeof(qfile_t*[MAX_VMFILES]));
1591 void VM_Files_CloseAll(void)
1594 for (i = 0;i < MAX_VMFILES;i++)
1597 FS_Close(VM_FILES[i]);
1598 //VM_FILES[i] = NULL;
1600 memset(VM_FILES,0,sizeof(qfile_t*[MAX_VMFILES])); // this should be faster (is it ?)
1607 float fopen(string filename, float mode)
1610 // float(string filename, float mode) fopen = #110;
1611 // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE),
1612 // returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
1616 char *modestring, *filename;
1618 VM_SAFEPARMCOUNT(2,VM_fopen);
1620 for (filenum = 0;filenum < MAX_VMFILES;filenum++)
1621 if (VM_FILES[filenum] == NULL)
1623 if (filenum >= MAX_VMFILES)
1625 Con_Printf("VM_fopen: %s ran out of file handles (%i)\n", PRVM_NAME, MAX_VMFILES);
1626 PRVM_G_FLOAT(OFS_RETURN) = -2;
1629 mode = PRVM_G_FLOAT(OFS_PARM1);
1632 case 0: // FILE_READ
1635 case 1: // FILE_APPEND
1638 case 2: // FILE_WRITE
1642 Con_Printf ("VM_fopen: %s no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", PRVM_NAME, mode);
1643 PRVM_G_FLOAT(OFS_RETURN) = -3;
1646 filename = PRVM_G_STRING(OFS_PARM0);
1647 // .. is parent directory on many platforms
1648 // / is parent directory on Amiga
1649 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
1650 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
1651 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
1653 Con_Printf("VM_fopen: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
1654 PRVM_G_FLOAT(OFS_RETURN) = -4;
1657 VM_FILES[filenum] = FS_Open(va("data/%s", filename), modestring, false);
1658 if (VM_FILES[filenum] == NULL)
1659 PRVM_G_FLOAT(OFS_RETURN) = -1;
1661 PRVM_G_FLOAT(OFS_RETURN) = filenum;
1668 fclose(float fhandle)
1671 //void(float fhandle) fclose = #111; // closes a file
1672 void VM_fclose(void)
1676 VM_SAFEPARMCOUNT(1,VM_fclose);
1678 filenum = PRVM_G_FLOAT(OFS_PARM0);
1679 if (filenum < 0 || filenum >= MAX_VMFILES)
1681 Con_Printf("VM_fclose: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1684 if (VM_FILES[filenum] == NULL)
1686 Con_Printf("VM_fclose: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1689 FS_Close(VM_FILES[filenum]);
1690 VM_FILES[filenum] = NULL;
1697 string fgets(float fhandle)
1700 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
1704 static char string[VM_STRINGTEMP_LENGTH];
1707 VM_SAFEPARMCOUNT(1,VM_fgets);
1709 filenum = PRVM_G_FLOAT(OFS_PARM0);
1710 if (filenum < 0 || filenum >= MAX_VMFILES)
1712 Con_Printf("VM_fgets: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1715 if (VM_FILES[filenum] == NULL)
1717 Con_Printf("VM_fgets: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1723 c = FS_Getc(VM_FILES[filenum]);
1724 if (c == '\r' || c == '\n' || c < 0)
1726 if (end < VM_STRINGTEMP_LENGTH - 1)
1730 // remove \n following \r
1732 c = FS_Getc(VM_FILES[filenum]);
1733 if (developer.integer)
1734 Con_Printf("fgets: %s: %s\n", PRVM_NAME, string);
1736 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1738 PRVM_G_INT(OFS_RETURN) = 0;
1745 fputs(float fhandle, string s)
1748 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
1752 char string[VM_STRINGTEMP_LENGTH];
1755 VM_SAFEPARMCOUNT(2,VM_fputs);
1757 filenum = PRVM_G_FLOAT(OFS_PARM0);
1758 if (filenum < 0 || filenum >= MAX_VMFILES)
1760 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1763 if (VM_FILES[filenum] == NULL)
1765 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1768 VM_VarString(1, string, sizeof(string));
1769 if ((stringlength = strlen(string)))
1770 FS_Write(VM_FILES[filenum], string, stringlength);
1771 if (developer.integer)
1772 Con_Printf("fputs: %s: %s\n", PRVM_NAME, string);
1779 float strlen(string s)
1782 //float(string s) strlen = #114; // returns how many characters are in a string
1783 void VM_strlen(void)
1787 VM_SAFEPARMCOUNT(1,VM_strlen);
1789 s = PRVM_G_STRING(OFS_PARM0);
1791 PRVM_G_FLOAT(OFS_RETURN) = strlen(s);
1793 PRVM_G_FLOAT(OFS_RETURN) = 0;
1800 string strcat(string,string,...[string])
1803 //string(string s1, string s2) strcat = #115;
1804 // concatenates two strings (for example "abc", "def" would return "abcdef")
1805 // and returns as a tempstring
1806 void VM_strcat(void)
1811 PRVM_ERROR("VM_strcat wrong parameter count (min. 2 expected ) !\n");
1813 s = VM_GetTempString();
1814 VM_VarString(0, s, VM_STRINGTEMP_LENGTH);
1815 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
1822 string substring(string s, float start, float length)
1825 // string(string s, float start, float length) substring = #116;
1826 // returns a section of a string as a tempstring
1827 void VM_substring(void)
1829 int i, start, length;
1832 VM_SAFEPARMCOUNT(3,VM_substring);
1834 string = VM_GetTempString();
1835 s = PRVM_G_STRING(OFS_PARM0);
1836 start = PRVM_G_FLOAT(OFS_PARM1);
1837 length = PRVM_G_FLOAT(OFS_PARM2);
1840 for (i = 0;i < start && *s;i++, s++);
1841 for (i = 0;i < VM_STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
1844 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1851 vector stov(string s)
1854 //vector(string s) stov = #117; // returns vector value from a string
1857 char string[VM_STRINGTEMP_LENGTH];
1859 VM_SAFEPARMCOUNT(1,VM_stov);
1861 VM_VarString(0, string, sizeof(string));
1862 Math_atov(string, PRVM_G_VECTOR(OFS_RETURN));
1869 string strzone(string s)
1872 //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)
1873 void VM_strzone(void)
1877 VM_SAFEPARMCOUNT(1,VM_strzone);
1879 in = PRVM_G_STRING(OFS_PARM0);
1880 out = Mem_Alloc(VM_STRINGS_MEMPOOL, strlen(in) + 1);
1882 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(out);
1892 //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!!!)
1893 void VM_strunzone(void)
1895 VM_SAFEPARMCOUNT(1,VM_strunzone);
1897 Mem_Free(PRVM_G_STRING(OFS_PARM0));
1902 VM_command (used by client and menu)
1904 clientcommand(float client, string s) (for client and menu)
1907 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
1908 //this function originally written by KrimZon, made shorter by LordHavoc
1909 void VM_clcommand (void)
1911 client_t *temp_client;
1914 VM_SAFEPARMCOUNT(2,VM_clcommand);
1916 i = PRVM_G_FLOAT(OFS_PARM0);
1917 if (!sv.active || i < 0 || i >= svs.maxclients || !svs.clients[i].active)
1919 Con_Printf("VM_clientcommand: %s: invalid client/server is not active !", PRVM_NAME);
1923 temp_client = host_client;
1924 host_client = svs.clients + i;
1925 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
1926 host_client = temp_client;
1934 float tokenize(string s)
1937 //float(string s) tokenize = #441;
1938 // takes apart a string into individal words (access them with argv), returns how many
1939 // this function originally written by KrimZon, made shorter by LordHavoc
1940 static char **tokens = NULL;
1941 static int max_tokens, num_tokens = 0;
1942 void VM_tokenize (void)
1947 VM_SAFEPARMCOUNT(1,VM_tokenize);
1949 str = PRVM_G_STRING(OFS_PARM0);
1954 for (i=0;i<num_tokens;i++)
1960 tokens = Z_Malloc(strlen(str) * sizeof(char *));
1961 max_tokens = strlen(str);
1963 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
1965 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
1966 strcpy(tokens[num_tokens], com_token);
1969 PRVM_G_FLOAT(OFS_RETURN) = num_tokens;
1976 string argv(float n)
1979 //string(float n) argv = #442;
1980 // returns a word from the tokenized string (returns nothing for an invalid index)
1981 // this function originally written by KrimZon, made shorter by LordHavoc
1986 VM_SAFEPARMCOUNT(1,VM_argv);
1988 token_num = PRVM_G_FLOAT(OFS_PARM0);
1989 if (token_num >= 0 && token_num < num_tokens)
1990 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tokens[token_num]);
1992 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
1996 //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)
1997 void PF_setattachment (void)
1999 edict_t *e = G_EDICT(OFS_PARM0);
2000 edict_t *tagentity = G_EDICT(OFS_PARM1);
2001 char *tagname = G_STRING(OFS_PARM2);
2006 if (tagentity == NULL)
2007 tagentity = sv.edicts;
2009 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
2011 v->edict = EDICT_TO_PROG(tagentity);
2013 v = GETEDICTFIELDVALUE(e, eval_tag_index);
2016 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
2018 modelindex = (int)tagentity->v->modelindex;
2019 if (modelindex >= 0 && modelindex < MAX_MODELS)
2021 model = sv.models[modelindex];
2022 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
2023 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
2024 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
2026 if (v->_float == 0 && model->alias.aliasnum_tags)
2027 for (i = 0;i < model->alias.aliasnum_tags;i++)
2028 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
2031 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);
2034 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));
2045 void VM_isserver(void)
2047 VM_SAFEPARMCOUNT(0,VM_serverstate);
2049 PRVM_G_FLOAT(OFS_RETURN) = sv.active;
2059 void VM_clientcount(void)
2061 VM_SAFEPARMCOUNT(0,VM_clientcount);
2063 PRVM_G_FLOAT(OFS_RETURN) = svs.maxclients;
2073 void VM_clientstate(void)
2075 VM_SAFEPARMCOUNT(0,VM_clientstate);
2077 PRVM_G_FLOAT(OFS_RETURN) = cls.state;
2084 vector getmousepos()
2087 void VM_getmousepos(void)
2090 VM_SAFEPARMCOUNT(0,VM_getmousepos);
2092 PRVM_G_VECTOR(OFS_RETURN)[0] = in_mouse_x;
2093 PRVM_G_VECTOR(OFS_RETURN)[1] = in_mouse_y;
2094 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2104 void VM_gettime(void)
2106 VM_SAFEPARMCOUNT(0,VM_gettime);
2108 PRVM_G_FLOAT(OFS_RETURN) = (float) *prog->time;
2115 loadfromdata(string data)
2118 void VM_loadfromdata(void)
2120 VM_SAFEPARMCOUNT(1,VM_loadentsfromfile);
2122 PRVM_ED_LoadFromFile(PRVM_G_STRING(OFS_PARM0));
2129 loadfromfile(string file)
2132 void VM_loadfromfile(void)
2137 VM_SAFEPARMCOUNT(1,VM_loadfromfile);
2139 filename = PRVM_G_STRING(OFS_PARM0);
2140 // .. is parent directory on many platforms
2141 // / is parent directory on Amiga
2142 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2143 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2144 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2146 Con_Printf("VM_loadfromfile: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
2147 PRVM_G_FLOAT(OFS_RETURN) = -4;
2151 // not conform with VM_fopen
2152 data = FS_LoadFile(filename, false);
2154 PRVM_G_FLOAT(OFS_RETURN) = -1;
2156 PRVM_ED_LoadFromFile(data);
2167 float mod(float val, float m)
2170 void VM_modulo(void)
2173 VM_SAFEPARMCOUNT(2,VM_module);
2175 val = (int) PRVM_G_FLOAT(OFS_PARM0);
2176 m = (int) PRVM_G_FLOAT(OFS_PARM1);
2178 PRVM_G_FLOAT(OFS_RETURN) = (float) (val % m);
2181 //=============================================================================
2182 // Draw builtins (client & menu)
2188 float iscachedpic(string pic)
2191 void VM_iscachedpic(void)
2193 VM_SAFEPARMCOUNT(1,VM_iscachedpic);
2195 // drawq hasnt such a function, thus always return true
2196 PRVM_G_FLOAT(OFS_RETURN) = TRUE;
2203 string precache_pic(string pic)
2206 void VM_precache_pic(void)
2210 VM_SAFEPARMCOUNT(1, VM_precache_pic);
2212 s = PRVM_G_STRING(OFS_PARM0);
2213 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
2216 PRVM_ERROR ("VM_precache_pic: %s: NULL\n", PRVM_NAME);
2218 VM_CheckEmptyString (s);
2220 if(!Draw_CachePic(s))
2221 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
2231 void VM_freepic(void)
2235 VM_SAFEPARMCOUNT(1,VM_freepic);
2237 s = PRVM_G_STRING(OFS_PARM0);
2240 PRVM_ERROR ("VM_freepic: %s: NULL\n");
2242 VM_CheckEmptyString (s);
2251 float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
2254 void VM_drawcharacter(void)
2256 float *pos,*scale,*rgb;
2259 VM_SAFEPARMCOUNT(6,VM_drawcharacter);
2261 character = (char) PRVM_G_FLOAT(OFS_PARM1);
2264 Con_Printf("VM_drawcharacter: %s passed null character !\n",PRVM_NAME);
2265 PRVM_G_FLOAT(OFS_RETURN) = -1;
2269 pos = PRVM_G_VECTOR(OFS_PARM0);
2270 scale = PRVM_G_VECTOR(OFS_PARM2);
2271 rgb = PRVM_G_VECTOR(OFS_PARM3);
2272 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2274 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2276 Con_Printf("VM_drawcharacter: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2277 PRVM_G_FLOAT(OFS_RETURN) = -2;
2281 if(pos[2] || scale[2])
2282 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")));
2284 if(!scale[0] || !scale[1])
2286 Con_Printf("VM_drawcharacter: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2287 PRVM_G_FLOAT(OFS_RETURN) = -3;
2291 DrawQ_String (pos[0], pos[1], &character, 1, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2292 PRVM_G_FLOAT(OFS_RETURN) = 1;
2299 float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
2302 void VM_drawstring(void)
2304 float *pos,*scale,*rgb;
2307 VM_SAFEPARMCOUNT(6,VM_drawstring);
2309 string = PRVM_G_STRING(OFS_PARM1);
2312 Con_Printf("VM_drawstring: %s passed null string !\n",PRVM_NAME);
2313 PRVM_G_FLOAT(OFS_RETURN) = -1;
2317 VM_CheckEmptyString(string);
2319 pos = PRVM_G_VECTOR(OFS_PARM0);
2320 scale = PRVM_G_VECTOR(OFS_PARM2);
2321 rgb = PRVM_G_VECTOR(OFS_PARM3);
2322 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2324 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2326 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2327 PRVM_G_FLOAT(OFS_RETURN) = -2;
2331 if(!scale[0] || !scale[1])
2333 Con_Printf("VM_drawstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2334 PRVM_G_FLOAT(OFS_RETURN) = -3;
2338 if(pos[2] || scale[2])
2339 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")));
2341 DrawQ_String (pos[0], pos[1], string, 0, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2342 PRVM_G_FLOAT(OFS_RETURN) = 1;
2348 float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
2351 void VM_drawpic(void)
2354 float *size, *pos, *rgb;
2357 VM_SAFEPARMCOUNT(6,VM_drawpic);
2359 pic = PRVM_G_STRING(OFS_PARM1);
2363 Con_Printf("VM_drawpic: %s passed null picture name !\n", PRVM_NAME);
2364 PRVM_G_FLOAT(OFS_RETURN) = -1;
2368 VM_CheckEmptyString (pic);
2370 // is pic cached ? no function yet for that
2373 Con_Printf("VM_drawpic: %s: %s not cached !\n", PRVM_NAME, pic);
2374 PRVM_G_FLOAT(OFS_RETURN) = -4;
2378 pos = PRVM_G_VECTOR(OFS_PARM0);
2379 size = PRVM_G_VECTOR(OFS_PARM2);
2380 rgb = PRVM_G_VECTOR(OFS_PARM3);
2381 flag = (int) PRVM_G_FLOAT(OFS_PARM5);
2383 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2385 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2386 PRVM_G_FLOAT(OFS_RETURN) = -2;
2390 if(pos[2] || size[2])
2391 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")));
2393 DrawQ_Pic(pos[0], pos[1], pic, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2394 PRVM_G_FLOAT(OFS_RETURN) = 1;
2401 float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
2404 void VM_drawfill(void)
2406 float *size, *pos, *rgb;
2409 VM_SAFEPARMCOUNT(5,VM_drawfill);
2412 pos = PRVM_G_VECTOR(OFS_PARM0);
2413 size = PRVM_G_VECTOR(OFS_PARM1);
2414 rgb = PRVM_G_VECTOR(OFS_PARM2);
2415 flag = (int) PRVM_G_FLOAT(OFS_PARM4);
2417 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2419 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2420 PRVM_G_FLOAT(OFS_RETURN) = -2;
2424 if(pos[2] || size[2])
2425 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")));
2427 DrawQ_Pic(pos[0], pos[1], 0, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM3), flag);
2428 PRVM_G_FLOAT(OFS_RETURN) = 1;
2435 drawsetcliparea(float x, float y, float width, float height)
2438 void VM_drawsetcliparea(void)
2441 VM_SAFEPARMCOUNT(4,VM_drawsetcliparea);
2443 x = bound(0,PRVM_G_FLOAT(OFS_PARM0),vid.conwidth);
2444 y = bound(0,PRVM_G_FLOAT(OFS_PARM1),vid.conheight);
2445 w = bound(0,PRVM_G_FLOAT(OFS_PARM2),(vid.conwidth - x));
2446 h = bound(0,PRVM_G_FLOAT(OFS_PARM3),(vid.conheight - y));
2448 DrawQ_SetClipArea(x,y,w,h);
2453 VM_drawresetcliparea
2458 void VM_drawresetcliparea(void)
2460 VM_SAFEPARMCOUNT(0,VM_drawresetcliparea);
2462 DrawQ_ResetClipArea();
2469 vector getimagesize(string pic)
2472 void VM_getimagesize(void)
2477 VM_SAFEPARMCOUNT(1,VM_getimagesize);
2479 p = PRVM_G_STRING(OFS_PARM0);
2482 PRVM_ERROR("VM_getimagepos: %s passed null picture name !\n", PRVM_NAME);
2484 VM_CheckEmptyString (p);
2486 pic = Draw_CachePic (p);
2488 PRVM_G_VECTOR(OFS_RETURN)[0] = pic->width;
2489 PRVM_G_VECTOR(OFS_RETURN)[1] = pic->height;
2490 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2493 void VM_Cmd_Init(void)
2495 // only init the stuff for the current prog
2496 VM_STRINGS_MEMPOOL = Mem_AllocPool(va("vm_stringsmempool[%s]",PRVM_NAME));
2500 void VM_Cmd_Reset(void)
2502 Mem_EmptyPool(VM_STRINGS_MEMPOOL);
2503 VM_Files_CloseAll();
2506 //============================================================================
2509 char *vm_sv_extensions =
2512 prvm_builtin_t vm_sv_builtins[] = {
2513 0 // to be consistent with the old vm
2516 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
2518 void VM_SV_Cmd_Init(void)
2522 void VM_SV_Cmd_Reset(void)
2526 //============================================================================
2529 char *vm_cl_extensions =
2532 prvm_builtin_t vm_cl_builtins[] = {
2533 0 // to be consistent with the old vm
2536 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
2538 void VM_CL_Cmd_Init(void)
2542 void VM_CL_Cmd_Reset(void)
2546 //============================================================================
2549 char *vm_m_extensions =
2556 setmousetarget(float target)
2559 void VM_M_setmousetarget(void)
2561 VM_SAFEPARMCOUNT(1, VM_M_setmousetarget);
2563 switch((int)PRVM_G_FLOAT(OFS_PARM0))
2566 in_client_mouse = false;
2569 in_client_mouse = true;
2572 PRVM_ERROR("VM_M_setmousetarget: wrong destination %i !\n",PRVM_G_FLOAT(OFS_PARM0));
2580 float getmousetarget
2583 void VM_M_getmousetarget(void)
2585 VM_SAFEPARMCOUNT(0,VM_M_getmousetarget);
2588 PRVM_G_FLOAT(OFS_RETURN) = 2;
2590 PRVM_G_FLOAT(OFS_RETURN) = 1;
2599 setkeydest(float dest)
2602 void VM_M_setkeydest(void)
2604 VM_SAFEPARMCOUNT(1,VM_M_setkeydest);
2606 switch((int)PRVM_G_FLOAT(OFS_PARM0))
2610 key_dest = key_game;
2614 key_dest = key_menu;
2618 // key_dest = key_message
2621 PRVM_ERROR("VM_M_setkeydest: wrong destination %i !\n",prog->globals[OFS_PARM0]);
2632 void VM_M_getkeydest(void)
2634 VM_SAFEPARMCOUNT(0,VM_M_getkeydest);
2636 // key_game = 0, key_message = 1, key_menu = 2, unknown = 3
2640 PRVM_G_FLOAT(OFS_RETURN) = 0;
2643 PRVM_G_FLOAT(OFS_RETURN) = 2;
2647 // PRVM_G_FLOAT(OFS_RETURN) = 1;
2650 PRVM_G_FLOAT(OFS_RETURN) = 3;
2658 callfunction(...,string function_name)
2661 mfunction_t *PRVM_ED_FindFunction (const char *name);
2662 int PRVM_EnterFunction (mfunction_t *f);
2663 void VM_M_callfunction(void)
2668 s = PRVM_G_STRING(OFS_PARM0 + (prog->argc - 1));
2671 PRVM_ERROR("VM_M_getfunction: null string !\n");
2673 VM_CheckEmptyString(s);
2675 func = PRVM_ED_FindFunction(s);
2678 PRVM_EnterFunction(func);
2685 writetofile(float fhandle, entity ent)
2688 void VM_M_writetofile(void)
2693 VM_SAFEPARMCOUNT(2, VM_M_writetofile);
2695 filenum = PRVM_G_FLOAT(OFS_PARM0);
2696 if (filenum < 0 || filenum >= MAX_VMFILES)
2698 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
2701 if (VM_FILES[filenum] == NULL)
2703 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
2707 ent = PRVM_G_EDICT(OFS_PARM1);
2710 Con_Printf("VM_M_writetofile: %s: entity %i is free !\n", PRVM_NAME, PRVM_EDICT_NUM(OFS_PARM1));
2714 PRVM_ED_Write (VM_FILES[filenum], ent);
2717 prvm_builtin_t vm_m_builtins[] = {
2718 0, // to be consistent with the old vm
2719 // common builtings (mostly)
2804 VM_WriteEntity, // 408
2820 VM_drawresetcliparea,
2821 VM_getimagesize,// 460
2830 VM_M_setmousetarget,
2831 VM_M_getmousetarget,
2833 VM_M_writetofile // 606
2836 const int vm_m_numbuiltins = sizeof(vm_m_builtins) / sizeof(prvm_builtin_t);
2838 void VM_M_Cmd_Init(void)
2843 void VM_M_Cmd_Reset(void)