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)
127 #include "quakedef.h"
128 #include "progdefs.h"
129 #include "clprogdefs.h"
130 #include "mprogdefs.h"
132 //============================================================================
133 // nice helper macros
135 #ifndef VM_NOPARMCHECK
136 #define VM_SAFEPARMCOUNT(p,f) if(prog->argc != p) PRVM_ERROR(#f " wrong parameter count (" #p " expected ) !\n")
138 #define VM_SAFEPARMCOUNT(p,f)
141 #define VM_RETURN_EDICT(e) (((int *)prog->globals)[OFS_RETURN] = PRVM_EDICT_TO_PROG(e))
143 #define VM_STRINGS_MEMPOOL vm_strings_mempool[PRVM_GetProgNr()]
145 #define e10 0,0,0,0,0,0,0,0,0,0
146 #define e100 e10,e10,e10,e10,e10,e10,e10,e10,e10,e10
147 #define e1000 e100,e100,e100,e100,e100,e100,e100,e100,e100,e100
149 //============================================================================
152 // string zone mempool
153 mempool_t *vm_strings_mempool[PRVM_MAXPROGS];
155 // temp string handling
156 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
157 #define STRINGTEMP_BUFFERS 16
158 #define STRINGTEMP_LENGTH 4096
159 static char vm_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
160 static int vm_string_tempindex = 0;
163 #define MAX_QC_CVARS 128 * PRVM_MAXPROGS
164 cvar_t vm_qc_cvar[MAX_QC_CVARS];
165 int vm_currentqc_cvar;
168 #define MAX_VMFILES 256
169 #define MAX_PRVMFILES MAX_VMFILES * PRVM_MAXPROGS
170 #define VM_FILES ((qfile_t**)(vm_files + PRVM_GetProgNr() * MAX_VMFILES))
172 qfile_t *vm_files[MAX_PRVMFILES];
174 static char *VM_GetTempString(void)
177 s = vm_string_temp[vm_string_tempindex];
178 vm_string_tempindex = (vm_string_tempindex + 1) % STRINGTEMP_BUFFERS;
182 void VM_CheckEmptyString (char *s)
185 PRVM_ERROR ("%s: Bad string", PRVM_NAME);
188 //============================================================================
191 void VM_VarString(int first, char *out, int outlength)
197 outend = out + outlength - 1;
198 for (i = first;i < prog->argc && out < outend;i++)
200 s = PRVM_G_STRING((OFS_PARM0+i*3));
201 while (out < outend && *s)
211 returns true if the extension is supported by the server
213 checkextension(extensionname)
217 // kind of helper function
218 static qboolean checkextension(char *name)
224 for (e = prog->extensionstring;*e;e++)
231 while (*e && *e != ' ')
233 if (e - start == len)
234 if (!strncasecmp(start, name, len))
242 void VM_checkextension (void)
244 VM_SAFEPARMCOUNT(1,VM_checkextension);
246 PRVM_G_FLOAT(OFS_RETURN) = checkextension(PRVM_G_STRING(OFS_PARM0));
253 This is a TERMINAL error, which will kill off the entire prog.
262 char string[STRINGTEMP_LENGTH];
264 VM_VarString(0, string, sizeof(string));
265 Con_Printf ("======%S ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
268 ed = PRVM_G_EDICT(prog->self->ofs);
272 PRVM_ERROR ("%s: Program error", PRVM_NAME);
279 Dumps out self, then an error message. The program is aborted and self is
280 removed, but the level can continue.
285 void VM_objerror (void)
288 char string[STRINGTEMP_LENGTH];
290 VM_VarString(0, string, sizeof(string));
291 Con_Printf ("======%s OBJECT ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
294 ed = PRVM_G_EDICT (prog->self->ofs);
300 // objerror has to display the object fields -> else call
301 PRVM_ERROR ("VM_objecterror: self not defined !\n");
306 VM_print (actually used only by client and menu)
315 char string[STRINGTEMP_LENGTH];
317 VM_VarString(0, string, sizeof(string));
325 broadcast print to everyone on server
330 void VM_bprint (void)
332 char string[STRINGTEMP_LENGTH];
336 Con_Printf("VM_bprint: game is not server(%s) !", PRVM_NAME);
340 VM_VarString(0, string, sizeof(string));
341 SV_BroadcastPrintf("%s", string);
346 VM_sprint (menu & client but only if server.active == true)
348 single print to a specific client
350 sprint(float clientnum,...[string])
353 void VM_sprint (void)
357 char string[STRINGTEMP_LENGTH];
359 //find client for this entity
360 clientnum = PRVM_G_FLOAT(OFS_PARM0);
361 if (!sv.active || clientnum < 0 || clientnum >= svs.maxclients || !svs.clients[clientnum].active)
363 Con_Printf("VM_sprint: %s: invalid client or server is not active !", PRVM_NAME);
367 client = svs.clients + clientnum;
368 if (!client->netconnection)
370 VM_VarString(1, string, sizeof(string));
371 MSG_WriteChar(&client->message,svc_print);
372 MSG_WriteString(&client->message, string);
379 single print to the screen
381 centerprint(clientent, value)
384 void VM_centerprint (void)
386 char string[STRINGTEMP_LENGTH];
388 VM_VarString(0, string, sizeof(string));
389 SCR_CenterPrint(string);
396 vector normalize(vector)
399 void VM_normalize (void)
405 VM_SAFEPARMCOUNT(1,VM_normalize);
407 value1 = PRVM_G_VECTOR(OFS_PARM0);
409 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
413 newvalue[0] = newvalue[1] = newvalue[2] = 0;
417 newvalue[0] = value1[0] * new;
418 newvalue[1] = value1[1] * new;
419 newvalue[2] = value1[2] * new;
422 VectorCopy (newvalue, PRVM_G_VECTOR(OFS_RETURN));
437 VM_SAFEPARMCOUNT(1,VM_vlen);
439 value1 = PRVM_G_VECTOR(OFS_PARM0);
441 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
444 PRVM_G_FLOAT(OFS_RETURN) = new;
451 float vectoyaw(vector)
454 void VM_vectoyaw (void)
459 VM_SAFEPARMCOUNT(1,VM_vectoyaw);
461 value1 = PRVM_G_VECTOR(OFS_PARM0);
463 if (value1[1] == 0 && value1[0] == 0)
467 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
472 PRVM_G_FLOAT(OFS_RETURN) = yaw;
480 vector vectoangles(vector)
483 void VM_vectoangles (void)
489 VM_SAFEPARMCOUNT(1,VM_vectoangles);
491 value1 = PRVM_G_VECTOR(OFS_PARM0);
493 if (value1[1] == 0 && value1[0] == 0)
503 // LordHavoc: optimized a bit
506 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
510 else if (value1[1] > 0)
515 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
516 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
521 PRVM_G_FLOAT(OFS_RETURN+0) = pitch;
522 PRVM_G_FLOAT(OFS_RETURN+1) = yaw;
523 PRVM_G_FLOAT(OFS_RETURN+2) = 0;
530 Returns a number from 0<= num < 1
535 void VM_random (void)
539 VM_SAFEPARMCOUNT(0,VM_random);
541 num = (rand ()&0x7fff) / ((float)0x7fff);
543 PRVM_G_FLOAT(OFS_RETURN) = num;
550 Each entity can have eight independant sound sources, like voice,
553 Channel 0 is an auto-allocate channel, the others override anything
554 already running on that entity/channel pair.
556 An attenuation of 0 will play full volume everywhere in the level.
557 Larger attenuations will drop off.
570 entity = G_EDICT(OFS_PARM0);
571 channel = G_FLOAT(OFS_PARM1);
572 sample = G_STRING(OFS_PARM2);
573 volume = G_FLOAT(OFS_PARM3) * 255;
574 attenuation = G_FLOAT(OFS_PARM4);
576 if (volume < 0 || volume > 255)
577 Host_Error ("SV_StartSound: volume = %i", volume);
579 if (attenuation < 0 || attenuation > 4)
580 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
582 if (channel < 0 || channel > 7)
583 Host_Error ("SV_StartSound: channel = %i", channel);
585 SV_StartSound (entity, channel, sample, volume, attenuation);
593 localsound(string sample)
596 void VM_localsound(void)
600 VM_SAFEPARMCOUNT(1,VM_localsound);
602 s = PRVM_G_STRING(OFS_PARM0);
606 Con_Printf("VM_localsound: %s : %s not cached !\n", PRVM_NAME, s);
607 PRVM_G_FLOAT(OFS_RETURN) = -4;
612 PRVM_G_FLOAT(OFS_RETURN) = 1;
624 PRVM_ERROR ("%s: break statement", PRVM_NAME);
627 //============================================================================
633 Sends text over to the client's execution buffer
635 [localcmd (string) or]
639 void VM_localcmd (void)
641 VM_SAFEPARMCOUNT(1,VM_localcmd);
643 Cbuf_AddText(PRVM_G_STRING(OFS_PARM0));
655 VM_SAFEPARMCOUNT(1,VM_cvar);
657 PRVM_G_FLOAT(OFS_RETURN) = Cvar_VariableValue(PRVM_G_STRING(OFS_PARM0));
664 void cvar_set (string,string)
667 void VM_cvar_set (void)
669 VM_SAFEPARMCOUNT(2,VM_cvar_set);
671 Cvar_Set(PRVM_G_STRING(OFS_PARM0), PRVM_G_STRING(OFS_PARM1));
681 void VM_dprint (void)
683 char string[STRINGTEMP_LENGTH];
684 if (developer.integer)
686 VM_VarString(0, string, sizeof(string));
687 Con_Printf("%s: %s", PRVM_NAME, string);
704 VM_SAFEPARMCOUNT(1, VM_ftos);
706 v = PRVM_G_FLOAT(OFS_PARM0);
708 s = VM_GetTempString();
709 if ((float)((int)v) == v)
710 sprintf(s, "%i", (int)v);
713 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
728 VM_SAFEPARMCOUNT(1,VM_fabs);
730 v = PRVM_G_FLOAT(OFS_PARM0);
731 PRVM_G_FLOAT(OFS_RETURN) = fabs(v);
746 VM_SAFEPARMCOUNT(1,VM_vtos);
748 s = VM_GetTempString();
749 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]);
750 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
765 VM_SAFEPARMCOUNT(1, VM_etos);
767 s = VM_GetTempString();
768 sprintf (s, "entity %i", PRVM_G_EDICTNUM(OFS_PARM0));
769 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
776 float stof(...[string])
781 char string[STRINGTEMP_LENGTH];
782 VM_VarString(0, string, sizeof(string));
783 PRVM_G_FLOAT(OFS_RETURN) = atof(string);
797 prog->xfunction->builtinsprofile += 20;
798 ed = PRVM_ED_Alloc();
810 void VM_remove (void)
813 prog->xfunction->builtinsprofile += 20;
815 VM_SAFEPARMCOUNT(1, VM_remove);
817 ed = PRVM_G_EDICT(OFS_PARM0);
818 // if (ed == prog->edicts)
819 // PRVM_ERROR ("remove: tried to remove world\n");
820 // if (PRVM_NUM_FOR_EDICT(ed) <= sv.maxclients)
821 // Host_Error("remove: tried to remove a client\n");
829 entity find(entity start, .string field, string match)
840 VM_SAFEPARMCOUNT(3,VM_find);
842 e = PRVM_G_EDICTNUM(OFS_PARM0);
843 f = PRVM_G_INT(OFS_PARM1);
844 s = PRVM_G_STRING(OFS_PARM2);
848 // return reserved edict 0 (could be used for whatever the prog wants)
849 VM_RETURN_EDICT(prog->edicts);
853 for (e++ ; e < prog->num_edicts ; e++)
855 prog->xfunction->builtinsprofile++;
856 ed = PRVM_EDICT_NUM(e);
859 t = PRVM_E_STRING(ed,f);
869 VM_RETURN_EDICT(prog->edicts);
876 entity findfloat(entity start, .float field, float match)
877 entity findentity(entity start, .entity field, entity match)
880 // LordHavoc: added this for searching float, int, and entity reference fields
881 void VM_findfloat (void)
888 VM_SAFEPARMCOUNT(3,VM_findfloat);
890 e = PRVM_G_EDICTNUM(OFS_PARM0);
891 f = PRVM_G_INT(OFS_PARM1);
892 s = PRVM_G_FLOAT(OFS_PARM2);
894 for (e++ ; e < prog->num_edicts ; e++)
896 prog->xfunction->builtinsprofile++;
897 ed = PRVM_EDICT_NUM(e);
900 if (PRVM_E_FLOAT(ed,f) == s)
907 VM_RETURN_EDICT(prog->edicts);
914 entity findchain(.string field, string match)
917 int PRVM_ED_FindFieldOffset(const char *field);
918 // chained search for strings in entity fields
919 // entity(.string field, string match) findchain = #402;
920 void VM_findchain (void)
926 prvm_edict_t *ent, *chain;
928 VM_SAFEPARMCOUNT(2,VM_findchain);
930 // is the same like !(prog->flag & PRVM_FE_CHAIN) - even if the operator precedence is another
931 if(!prog->flag & PRVM_FE_CHAIN)
932 PRVM_ERROR("VM_findchain: %s doesnt have a chain field !\n", PRVM_NAME);
934 chain_of = PRVM_ED_FindFieldOffset ("chain");
936 chain = prog->edicts;
938 f = PRVM_G_INT(OFS_PARM0);
939 s = PRVM_G_STRING(OFS_PARM1);
942 VM_RETURN_EDICT(prog->edicts);
946 ent = PRVM_NEXT_EDICT(prog->edicts);
947 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
949 prog->xfunction->builtinsprofile++;
952 t = PRVM_E_STRING(ent,f);
958 PRVM_E_FLOAT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain);
962 VM_RETURN_EDICT(chain);
969 entity findchainfloat(.string field, float match)
970 entity findchainentity(.string field, entity match)
973 // LordHavoc: chained search for float, int, and entity reference fields
974 // entity(.string field, float match) findchainfloat = #403;
975 void VM_findchainfloat (void)
981 prvm_edict_t *ent, *chain;
983 VM_SAFEPARMCOUNT(2, VM_findchainfloat);
985 if(!prog->flag & PRVM_FE_CHAIN)
986 PRVM_ERROR("VM_findchainfloat: %s doesnt have a chain field !\n", PRVM_NAME);
988 chain_of = PRVM_ED_FindFieldOffset ("chain");
990 chain = (prvm_edict_t *)prog->edicts;
992 f = PRVM_G_INT(OFS_PARM0);
993 s = PRVM_G_FLOAT(OFS_PARM1);
995 ent = PRVM_NEXT_EDICT(prog->edicts);
996 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
998 prog->xfunction->builtinsprofile++;
1001 if (E_FLOAT(ent,f) != s)
1004 PRVM_E_FLOAT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain);
1008 VM_RETURN_EDICT(chain);
1015 string precache_file(string)
1018 void VM_precache_file (void)
1019 { // precache_file is only used to copy files with qcc, it does nothing
1020 VM_SAFEPARMCOUNT(1,VM_precache_file);
1022 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1029 used instead of the other VM_precache_* functions in the builtin list
1033 void VM_precache_error (void)
1035 PRVM_ERROR ("PF_Precache_*: Precache can only be done in spawn functions");
1042 string precache_sound (string sample)
1045 void VM_precache_sound (void)
1049 VM_SAFEPARMCOUNT(1, VM_precache_sound);
1051 s = PRVM_G_STRING(OFS_PARM0);
1052 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1053 VM_CheckEmptyString (s);
1057 Con_Printf("VM_precache_sound: %s already cached (%s)\n", s, PRVM_NAME);
1061 if(!S_PrecacheSound(s,true))
1062 Con_Printf("VM_prache_sound: Failed to load %s for %s\n", s, PRVM_NAME);
1072 void VM_coredump (void)
1074 VM_SAFEPARMCOUNT(0,VM_coredump);
1076 Cbuf_AddText("prvm_edicts ");
1077 Cbuf_AddText(PRVM_NAME);
1088 void VM_traceon (void)
1090 VM_SAFEPARMCOUNT(0,VM_traceon);
1102 void VM_traceoff (void)
1104 VM_SAFEPARMCOUNT(0,VM_traceoff);
1106 prog->trace = false;
1116 void VM_eprint (void)
1118 VM_SAFEPARMCOUNT(1,VM_eprint);
1120 PRVM_ED_PrintNum (PRVM_G_EDICTNUM(OFS_PARM0));
1134 VM_SAFEPARMCOUNT(1,VM_rint);
1136 f = PRVM_G_FLOAT(OFS_PARM0);
1138 PRVM_G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1140 PRVM_G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1150 void VM_floor (void)
1152 VM_SAFEPARMCOUNT(1,VM_floor);
1154 PRVM_G_FLOAT(OFS_RETURN) = floor(PRVM_G_FLOAT(OFS_PARM0));
1166 VM_SAFEPARMCOUNT(1,VM_ceil);
1168 PRVM_G_FLOAT(OFS_RETURN) = ceil(PRVM_G_FLOAT(OFS_PARM0));
1176 entity nextent(entity)
1179 void VM_nextent (void)
1184 i = PRVM_G_EDICTNUM(OFS_PARM0);
1187 prog->xfunction->builtinsprofile++;
1189 if (i == prog->num_edicts)
1191 VM_RETURN_EDICT(prog->edicts);
1194 ent = PRVM_EDICT_NUM(i);
1197 VM_RETURN_EDICT(ent);
1204 ===============================================================================
1207 used only for client and menu
1208 severs uses VM_SV_...
1210 Write*(* data, float type, float to)
1212 ===============================================================================
1215 #define MSG_BROADCAST 0 // unreliable to all
1216 #define MSG_ONE 1 // reliable to one (msg_entity)
1217 #define MSG_ALL 2 // reliable to all
1218 #define MSG_INIT 3 // write to the init string
1220 sizebuf_t *VM_WriteDest (void)
1226 PRVM_ERROR("VM_WriteDest: game is not server (%s)\n", PRVM_NAME);
1228 dest = G_FLOAT(OFS_PARM1);
1232 return &sv.datagram;
1235 destclient = (int) PRVM_G_FLOAT(OFS_PARM2);
1236 if (destclient < 0 || destclient >= svs.maxclients || !svs.clients[destclient].active)
1237 PRVM_ERROR("VM_clientcommand: %s: invalid client !\n", PRVM_NAME);
1239 return &svs.clients[destclient].message;
1242 return &sv.reliable_datagram;
1248 PRVM_ERROR ("WriteDest: bad destination");
1255 void VM_WriteByte (void)
1257 MSG_WriteByte (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1260 void VM_WriteChar (void)
1262 MSG_WriteChar (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1265 void VM_WriteShort (void)
1267 MSG_WriteShort (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1270 void VM_WriteLong (void)
1272 MSG_WriteLong (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1275 void VM_WriteAngle (void)
1277 MSG_WriteAngle (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1280 void VM_WriteCoord (void)
1282 MSG_WriteDPCoord (VM_WriteDest(), PRVM_G_FLOAT(OFS_PARM0));
1285 void VM_WriteString (void)
1287 MSG_WriteString (VM_WriteDest(), PRVM_G_STRING(OFS_PARM0));
1290 void VM_WriteEntity (void)
1292 MSG_WriteShort (VM_WriteDest(), PRVM_G_EDICTNUM(OFS_PARM0));
1295 //=============================================================================
1302 changelevel(string map)
1305 void VM_changelevel (void)
1309 VM_SAFEPARMCOUNT(1, VM_changelevel);
1313 Con_Printf("VM_changelevel: game is not server (%s)\n", PRVM_NAME);
1317 // make sure we don't issue two changelevels
1318 if (svs.changelevel_issued)
1320 svs.changelevel_issued = true;
1322 s = G_STRING(OFS_PARM0);
1323 Cbuf_AddText (va("changelevel %s\n",s));
1335 VM_SAFEPARMCOUNT(1,VM_sin);
1336 PRVM_G_FLOAT(OFS_RETURN) = sin(PRVM_G_FLOAT(OFS_PARM0));
1347 VM_SAFEPARMCOUNT(1,VM_cos);
1348 PRVM_G_FLOAT(OFS_RETURN) = cos(PRVM_G_FLOAT(OFS_PARM0));
1360 VM_SAFEPARMCOUNT(1,VM_sqrt);
1361 PRVM_G_FLOAT(OFS_RETURN) = sqrt(PRVM_G_FLOAT(OFS_PARM0));
1368 Returns a vector of length < 1 and > 0
1373 void VM_randomvec (void)
1378 VM_SAFEPARMCOUNT(0, VM_randomvec);
1383 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1384 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1385 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1387 while (DotProduct(temp, temp) >= 1);
1388 VectorCopy (temp, PRVM_G_VECTOR(OFS_RETURN));
1391 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1392 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1393 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1394 // length returned always > 0
1395 length = (rand()&32766 + 1) * (1.0 / 32767.0) / VectorLength(temp);
1396 VectorScale(temp,length, temp);*/
1397 //VectorCopy(temp, PRVM_G_VECTOR(OFS_RETURN));
1400 //=============================================================================
1406 float registercvar (string name, string value)
1409 void VM_registercvar (void)
1414 VM_SAFEPARMCOUNT(2,VM_registercvar);
1416 name = PRVM_G_STRING(OFS_PARM0);
1417 value = PRVM_G_STRING(OFS_PARM1);
1418 PRVM_G_FLOAT(OFS_RETURN) = 0;
1419 // first check to see if it has already been defined
1420 if (Cvar_FindVar (name))
1423 // check for overlap with a command
1424 if (Cmd_Exists (name))
1426 Con_Printf ("VM_registercvar: %s is a command\n", name);
1430 if (vm_currentqc_cvar >= MAX_QC_CVARS)
1431 PRVM_ERROR ("VM_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1433 // copy the name and value
1434 variable = &vm_qc_cvar[vm_currentqc_cvar++];
1435 variable->name = Z_Malloc (strlen(name)+1);
1436 strcpy (variable->name, name);
1437 variable->string = Z_Malloc (strlen(value)+1);
1438 strcpy (variable->string, value);
1439 variable->value = atof (value);
1441 Cvar_RegisterVariable(variable);
1442 PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1449 returns the minimum of two supplied floats
1451 float min(float a, float b, ...[float])
1456 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1457 if (prog->argc == 2)
1458 PRVM_G_FLOAT(OFS_RETURN) = min(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1459 else if (prog->argc >= 3)
1462 float f = PRVM_G_FLOAT(OFS_PARM0);
1463 for (i = 1;i < prog->argc;i++)
1464 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) < f)
1465 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1466 PRVM_G_FLOAT(OFS_RETURN) = f;
1469 PRVM_ERROR("VM_min: %s must supply at least 2 floats\n", PRVM_NAME);
1476 returns the maximum of two supplied floats
1478 float max(float a, float b, ...[float])
1483 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1484 if (prog->argc == 2)
1485 PRVM_G_FLOAT(OFS_RETURN) = max(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1486 else if (prog->argc >= 3)
1489 float f = PRVM_G_FLOAT(OFS_PARM0);
1490 for (i = 1;i < prog->argc;i++)
1491 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) > f)
1492 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1493 G_FLOAT(OFS_RETURN) = f;
1496 PRVM_ERROR("VM_max: %s must supply at least 2 floats\n", PRVM_NAME);
1503 returns number bounded by supplied range
1505 float bound(float min, float value, float max)
1508 void VM_bound (void)
1510 VM_SAFEPARMCOUNT(3,VM_bound);
1511 PRVM_G_FLOAT(OFS_RETURN) = bound(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2));
1518 returns a raised to power b
1520 float pow(float a, float b)
1525 VM_SAFEPARMCOUNT(2,VM_pow);
1526 PRVM_G_FLOAT(OFS_RETURN) = pow(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1533 copies data from one entity to another
1535 copyentity(entity src, entity dst)
1538 void VM_copyentity (void)
1540 prvm_edict_t *in, *out;
1541 VM_SAFEPARMCOUNT(2,VM_copyentity);
1542 in = PRVM_G_EDICT(OFS_PARM0);
1543 out = PRVM_G_EDICT(OFS_PARM1);
1544 memcpy(out->v, in->v, prog->progs->entityfields * 4);
1551 sets the color of a client and broadcasts the update to all connected clients
1553 setcolor(clientent, value)
1556 /*void PF_setcolor (void)
1562 entnum = G_EDICTNUM(OFS_PARM0);
1563 i = G_FLOAT(OFS_PARM1);
1565 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1567 Con_Printf ("tried to setcolor a non-client\n");
1571 client = svs.clients + entnum-1;
1572 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
1575 client->old_colors = i;
1576 client->edict->v->team = (i & 15) + 1;
1578 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1579 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
1580 MSG_WriteByte (&sv.reliable_datagram, i);
1583 void VM_Files_Init(void)
1585 memset(VM_FILES, 0, sizeof(qfile_t*[MAX_VMFILES]));
1588 void VM_Files_CloseAll(void)
1591 for (i = 0;i < MAX_VMFILES;i++)
1594 FS_Close(VM_FILES[i]);
1595 //VM_FILES[i] = NULL;
1597 memset(VM_FILES,0,sizeof(qfile_t*[MAX_VMFILES])); // this should be faster (is it ?)
1604 float fopen(string filename, float mode)
1607 // float(string filename, float mode) fopen = #110;
1608 // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE),
1609 // returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
1613 char *modestring, *filename;
1615 VM_SAFEPARMCOUNT(2,VM_fopen);
1617 for (filenum = 0;filenum < MAX_VMFILES;filenum++)
1618 if (VM_FILES[filenum] == NULL)
1620 if (filenum >= MAX_VMFILES)
1622 Con_Printf("VM_fopen: %s ran out of file handles (%i)\n", PRVM_NAME, MAX_VMFILES);
1623 PRVM_G_FLOAT(OFS_RETURN) = -2;
1626 mode = PRVM_G_FLOAT(OFS_PARM1);
1629 case 0: // FILE_READ
1632 case 1: // FILE_APPEND
1635 case 2: // FILE_WRITE
1639 Con_Printf ("VM_fopen: %s no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", PRVM_NAME, mode);
1640 PRVM_G_FLOAT(OFS_RETURN) = -3;
1643 filename = PRVM_G_STRING(OFS_PARM0);
1644 // .. is parent directory on many platforms
1645 // / is parent directory on Amiga
1646 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
1647 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
1648 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
1650 Con_Printf("VM_fopen: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
1651 PRVM_G_FLOAT(OFS_RETURN) = -4;
1654 VM_FILES[filenum] = FS_Open(va("data/%s", filename), modestring, false);
1655 if (VM_FILES[filenum] == NULL)
1656 PRVM_G_FLOAT(OFS_RETURN) = -1;
1658 PRVM_G_FLOAT(OFS_RETURN) = filenum;
1665 fclose(float fhandle)
1668 //void(float fhandle) fclose = #111; // closes a file
1669 void VM_fclose(void)
1673 VM_SAFEPARMCOUNT(1,VM_fclose);
1675 filenum = PRVM_G_FLOAT(OFS_PARM0);
1676 if (filenum < 0 || filenum >= MAX_VMFILES)
1678 Con_Printf("VM_fclose: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1681 if (VM_FILES[filenum] == NULL)
1683 Con_Printf("VM_fclose: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1686 FS_Close(VM_FILES[filenum]);
1687 VM_FILES[filenum] = NULL;
1694 string fgets(float fhandle)
1697 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
1701 static char string[STRINGTEMP_LENGTH];
1704 VM_SAFEPARMCOUNT(1,VM_fgets);
1706 filenum = PRVM_G_FLOAT(OFS_PARM0);
1707 if (filenum < 0 || filenum >= MAX_VMFILES)
1709 Con_Printf("VM_fgets: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1712 if (VM_FILES[filenum] == NULL)
1714 Con_Printf("VM_fgets: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1720 c = FS_Getc(VM_FILES[filenum]);
1721 if (c == '\r' || c == '\n' || c < 0)
1723 if (end < STRINGTEMP_LENGTH - 1)
1727 // remove \n following \r
1729 c = FS_Getc(VM_FILES[filenum]);
1730 if (developer.integer)
1731 Con_Printf("fgets: %s: %s\n", PRVM_NAME, string);
1733 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1735 PRVM_G_INT(OFS_RETURN) = 0;
1742 fputs(float fhandle, string s)
1745 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
1749 char string[STRINGTEMP_LENGTH];
1752 VM_SAFEPARMCOUNT(2,VM_fputs);
1754 filenum = PRVM_G_FLOAT(OFS_PARM0);
1755 if (filenum < 0 || filenum >= MAX_VMFILES)
1757 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1760 if (VM_FILES[filenum] == NULL)
1762 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1765 VM_VarString(1, string, sizeof(string));
1766 if ((stringlength = strlen(string)))
1767 FS_Write(VM_FILES[filenum], string, stringlength);
1768 if (developer.integer)
1769 Con_Printf("fputs: %s: %s\n", PRVM_NAME, string);
1776 float strlen(string s)
1779 //float(string s) strlen = #114; // returns how many characters are in a string
1780 void VM_strlen(void)
1784 VM_SAFEPARMCOUNT(1,VM_strlen);
1786 s = PRVM_G_STRING(OFS_PARM0);
1788 PRVM_G_FLOAT(OFS_RETURN) = strlen(s);
1790 PRVM_G_FLOAT(OFS_RETURN) = 0;
1797 string strcat(string,string,...[string])
1800 //string(string s1, string s2) strcat = #115;
1801 // concatenates two strings (for example "abc", "def" would return "abcdef")
1802 // and returns as a tempstring
1803 void VM_strcat(void)
1808 PRVM_ERROR("VM_strcat wrong parameter count (min. 2 expected ) !\n");
1810 s = VM_GetTempString();
1811 VM_VarString(0, s, STRINGTEMP_LENGTH);
1812 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
1819 string substring(string s, float start, float length)
1822 // string(string s, float start, float length) substring = #116;
1823 // returns a section of a string as a tempstring
1824 void VM_substring(void)
1826 int i, start, length;
1829 VM_SAFEPARMCOUNT(3,VM_substring);
1831 string = VM_GetTempString();
1832 s = PRVM_G_STRING(OFS_PARM0);
1833 start = PRVM_G_FLOAT(OFS_PARM1);
1834 length = PRVM_G_FLOAT(OFS_PARM2);
1837 for (i = 0;i < start && *s;i++, s++);
1838 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
1841 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1848 vector stov(string s)
1851 //vector(string s) stov = #117; // returns vector value from a string
1854 char string[STRINGTEMP_LENGTH];
1856 VM_SAFEPARMCOUNT(1,VM_stov);
1858 VM_VarString(0, string, sizeof(string));
1859 Math_atov(string, PRVM_G_VECTOR(OFS_RETURN));
1866 string strzone(string s)
1869 //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)
1870 void VM_strzone(void)
1874 VM_SAFEPARMCOUNT(1,VM_strzone);
1876 in = PRVM_G_STRING(OFS_PARM0);
1877 out = Mem_Alloc(VM_STRINGS_MEMPOOL, strlen(in) + 1);
1879 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(out);
1889 //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!!!)
1890 void VM_strunzone(void)
1892 VM_SAFEPARMCOUNT(1,VM_strunzone);
1894 Mem_Free(PRVM_G_STRING(OFS_PARM0));
1899 VM_command (used by client and menu)
1901 clientcommand(float client, string s) (for client and menu)
1904 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
1905 //this function originally written by KrimZon, made shorter by LordHavoc
1906 void VM_clcommand (void)
1908 client_t *temp_client;
1911 VM_SAFEPARMCOUNT(2,VM_clcommand);
1913 i = PRVM_G_FLOAT(OFS_PARM0);
1914 if (!sv.active || i < 0 || i >= svs.maxclients || !svs.clients[i].active)
1916 Con_Printf("VM_clientcommand: %s: invalid client/server is not active !", PRVM_NAME);
1920 temp_client = host_client;
1921 host_client = svs.clients + i;
1922 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
1923 host_client = temp_client;
1931 float tokenize(string s)
1934 //float(string s) tokenize = #441;
1935 // takes apart a string into individal words (access them with argv), returns how many
1936 // this function originally written by KrimZon, made shorter by LordHavoc
1937 static char **tokens = NULL;
1938 static int max_tokens, num_tokens = 0;
1939 void VM_tokenize (void)
1944 VM_SAFEPARMCOUNT(1,VM_tokenize);
1946 str = PRVM_G_STRING(OFS_PARM0);
1951 for (i=0;i<num_tokens;i++)
1957 tokens = Z_Malloc(strlen(str) * sizeof(char *));
1958 max_tokens = strlen(str);
1960 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
1962 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
1963 strcpy(tokens[num_tokens], com_token);
1966 PRVM_G_FLOAT(OFS_RETURN) = num_tokens;
1973 string argv(float n)
1976 //string(float n) argv = #442;
1977 // returns a word from the tokenized string (returns nothing for an invalid index)
1978 // this function originally written by KrimZon, made shorter by LordHavoc
1983 VM_SAFEPARMCOUNT(1,VM_argv);
1985 token_num = PRVM_G_FLOAT(OFS_PARM0);
1986 if (token_num >= 0 && token_num < num_tokens)
1987 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tokens[token_num]);
1989 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
1993 //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)
1994 void PF_setattachment (void)
1996 edict_t *e = G_EDICT(OFS_PARM0);
1997 edict_t *tagentity = G_EDICT(OFS_PARM1);
1998 char *tagname = G_STRING(OFS_PARM2);
2003 if (tagentity == NULL)
2004 tagentity = sv.edicts;
2006 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
2008 v->edict = EDICT_TO_PROG(tagentity);
2010 v = GETEDICTFIELDVALUE(e, eval_tag_index);
2013 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
2015 modelindex = (int)tagentity->v->modelindex;
2016 if (modelindex >= 0 && modelindex < MAX_MODELS)
2018 model = sv.models[modelindex];
2019 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
2020 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
2021 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
2023 if (v->_float == 0 && model->alias.aliasnum_tags)
2024 for (i = 0;i < model->alias.aliasnum_tags;i++)
2025 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
2028 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);
2031 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));
2042 void VM_isserver(void)
2044 VM_SAFEPARMCOUNT(0,VM_serverstate);
2046 PRVM_G_FLOAT(OFS_RETURN) = sv.active;
2056 void VM_clientcount(void)
2058 VM_SAFEPARMCOUNT(0,VM_clientcount);
2060 PRVM_G_FLOAT(OFS_RETURN) = svs.maxclients;
2070 void VM_clientstate(void)
2072 VM_SAFEPARMCOUNT(0,VM_clientstate);
2074 PRVM_G_FLOAT(OFS_RETURN) = cls.state;
2081 vector getmousepos()
2084 void VM_getmousepos(void)
2087 VM_SAFEPARMCOUNT(0,VM_getmousepos);
2089 PRVM_G_VECTOR(OFS_RETURN)[0] = in_mouse_x;
2090 PRVM_G_VECTOR(OFS_RETURN)[1] = in_mouse_y;
2091 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2101 void VM_gettime(void)
2103 VM_SAFEPARMCOUNT(0,VM_gettime);
2105 PRVM_G_FLOAT(OFS_RETURN) = (float) *prog->time;
2112 loadfromdata(string data)
2115 void VM_loadfromdata(void)
2117 VM_SAFEPARMCOUNT(1,VM_loadentsfromfile);
2119 PRVM_ED_LoadFromFile(PRVM_G_STRING(OFS_PARM0));
2126 loadfromfile(string file)
2129 void VM_loadfromfile(void)
2134 VM_SAFEPARMCOUNT(1,VM_loadfromfile);
2136 filename = PRVM_G_STRING(OFS_PARM0);
2137 // .. is parent directory on many platforms
2138 // / is parent directory on Amiga
2139 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
2140 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
2141 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
2143 Con_Printf("VM_loadfromfile: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
2144 PRVM_G_FLOAT(OFS_RETURN) = -4;
2148 // not conform with VM_fopen
2149 data = FS_LoadFile(filename, false);
2151 PRVM_G_FLOAT(OFS_RETURN) = -1;
2153 PRVM_ED_LoadFromFile(data);
2164 float mod(float val, float m)
2167 void VM_modulo(void)
2170 VM_SAFEPARMCOUNT(2,VM_module);
2172 val = (int) PRVM_G_FLOAT(OFS_PARM0);
2173 m = (int) PRVM_G_FLOAT(OFS_PARM1);
2175 PRVM_G_FLOAT(OFS_RETURN) = (float) (val % m);
2178 //=============================================================================
2179 // Draw builtins (client & menu)
2185 float iscachedpic(string pic)
2188 void VM_iscachedpic(void)
2190 VM_SAFEPARMCOUNT(1,VM_iscachedpic);
2192 // drawq hasnt such a function, thus always return true
2193 PRVM_G_FLOAT(OFS_RETURN) = TRUE;
2200 string precache_pic(string pic)
2203 void VM_precache_pic(void)
2207 VM_SAFEPARMCOUNT(1, VM_precache_pic);
2209 s = PRVM_G_STRING(OFS_PARM0);
2210 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
2213 PRVM_ERROR ("VM_precache_pic: %s: NULL\n", PRVM_NAME);
2215 VM_CheckEmptyString (s);
2217 if(!Draw_CachePic(s))
2218 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
2228 void VM_freepic(void)
2232 VM_SAFEPARMCOUNT(1,VM_freepic);
2234 s = PRVM_G_STRING(OFS_PARM0);
2237 PRVM_ERROR ("VM_freepic: %s: NULL\n");
2239 VM_CheckEmptyString (s);
2248 float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
2251 void VM_drawcharacter(void)
2253 float *pos,*scale,*rgb;
2256 VM_SAFEPARMCOUNT(6,VM_drawcharacter);
2258 character = (char) PRVM_G_FLOAT(OFS_PARM1);
2261 Con_Printf("VM_drawcharacter: %s passed null character !\n",PRVM_NAME);
2262 PRVM_G_FLOAT(OFS_RETURN) = -1;
2266 pos = PRVM_G_VECTOR(OFS_PARM0);
2267 scale = PRVM_G_VECTOR(OFS_PARM2);
2268 rgb = PRVM_G_VECTOR(OFS_PARM3);
2269 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2271 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2273 Con_Printf("VM_drawcharacter: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2274 PRVM_G_FLOAT(OFS_RETURN) = -2;
2278 if(pos[2] || scale[2])
2279 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")));
2281 if(!scale[0] || !scale[1])
2283 Con_Printf("VM_drawcharacter: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2284 PRVM_G_FLOAT(OFS_RETURN) = -3;
2288 DrawQ_String (pos[0], pos[1], &character, 1, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2289 PRVM_G_FLOAT(OFS_RETURN) = 1;
2296 float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
2299 void VM_drawstring(void)
2301 float *pos,*scale,*rgb;
2304 VM_SAFEPARMCOUNT(6,VM_drawstring);
2306 string = PRVM_G_STRING(OFS_PARM1);
2309 Con_Printf("VM_drawstring: %s passed null string !\n",PRVM_NAME);
2310 PRVM_G_FLOAT(OFS_RETURN) = -1;
2314 VM_CheckEmptyString(string);
2316 pos = PRVM_G_VECTOR(OFS_PARM0);
2317 scale = PRVM_G_VECTOR(OFS_PARM2);
2318 rgb = PRVM_G_VECTOR(OFS_PARM3);
2319 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
2321 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2323 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2324 PRVM_G_FLOAT(OFS_RETURN) = -2;
2328 if(!scale[0] || !scale[1])
2330 Con_Printf("VM_drawstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
2331 PRVM_G_FLOAT(OFS_RETURN) = -3;
2335 if(pos[2] || scale[2])
2336 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")));
2338 DrawQ_String (pos[0], pos[1], string, 0, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2339 PRVM_G_FLOAT(OFS_RETURN) = 1;
2345 float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
2348 void VM_drawpic(void)
2351 float *size, *pos, *rgb;
2354 VM_SAFEPARMCOUNT(6,VM_drawpic);
2356 pic = PRVM_G_STRING(OFS_PARM1);
2360 Con_Printf("VM_drawpic: %s passed null picture name !\n", PRVM_NAME);
2361 PRVM_G_FLOAT(OFS_RETURN) = -1;
2365 VM_CheckEmptyString (pic);
2367 // is pic cached ? no function yet for that
2370 Con_Printf("VM_drawpic: %s: %s not cached !\n", PRVM_NAME, pic);
2371 PRVM_G_FLOAT(OFS_RETURN) = -4;
2375 pos = PRVM_G_VECTOR(OFS_PARM0);
2376 size = PRVM_G_VECTOR(OFS_PARM2);
2377 rgb = PRVM_G_VECTOR(OFS_PARM3);
2378 flag = (int) PRVM_G_FLOAT(OFS_PARM5);
2380 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2382 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2383 PRVM_G_FLOAT(OFS_RETURN) = -2;
2387 if(pos[2] || size[2])
2388 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")));
2390 DrawQ_Pic(pos[0], pos[1], pic, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
2391 PRVM_G_FLOAT(OFS_RETURN) = 1;
2398 float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
2401 void VM_drawfill(void)
2403 float *size, *pos, *rgb;
2406 VM_SAFEPARMCOUNT(5,VM_drawfill);
2409 pos = PRVM_G_VECTOR(OFS_PARM0);
2410 size = PRVM_G_VECTOR(OFS_PARM1);
2411 rgb = PRVM_G_VECTOR(OFS_PARM2);
2412 flag = (int) PRVM_G_FLOAT(OFS_PARM4);
2414 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
2416 Con_Printf("VM_drawstring: %s: wrong DRAWFLAG %i !\n",PRVM_NAME,flag);
2417 PRVM_G_FLOAT(OFS_RETURN) = -2;
2421 if(pos[2] || size[2])
2422 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")));
2424 DrawQ_Pic(pos[0], pos[1], 0, size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM3), flag);
2425 PRVM_G_FLOAT(OFS_RETURN) = 1;
2432 drawsetcliparea(float x, float y, float width, float height)
2435 void VM_drawsetcliparea(void)
2438 VM_SAFEPARMCOUNT(4,VM_drawsetcliparea);
2440 x = bound(0,PRVM_G_FLOAT(OFS_PARM0),vid.conwidth);
2441 y = bound(0,PRVM_G_FLOAT(OFS_PARM1),vid.conheight);
2442 w = bound(0,PRVM_G_FLOAT(OFS_PARM2),x);
2443 h = bound(0,PRVM_G_FLOAT(OFS_PARM3),y);
2445 DrawQ_SetClipArea(x,y,w,h);
2450 VM_drawresetcliparea
2455 void VM_drawresetcliparea(void)
2457 VM_SAFEPARMCOUNT(0,VM_drawresetcliparea);
2459 DrawQ_ResetClipArea();
2466 vector getimagesize(string pic)
2469 void VM_getimagesize(void)
2474 VM_SAFEPARMCOUNT(1,VM_getimagesize);
2476 p = PRVM_G_STRING(OFS_PARM0);
2479 PRVM_ERROR("VM_getimagepos: %s passed null picture name !\n", PRVM_NAME);
2481 VM_CheckEmptyString (p);
2483 pic = Draw_CachePic (p);
2485 PRVM_G_VECTOR(OFS_RETURN)[0] = pic->width;
2486 PRVM_G_VECTOR(OFS_RETURN)[1] = pic->height;
2487 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
2490 void VM_Cmd_Init(void)
2492 // only init the stuff for the current prog
2493 VM_STRINGS_MEMPOOL = Mem_AllocPool(va("vm_stringsmempool[%s]",PRVM_NAME));
2497 void VM_Cmd_Reset(void)
2499 Mem_EmptyPool(VM_STRINGS_MEMPOOL);
2500 VM_Files_CloseAll();
2503 //============================================================================
2506 char *vm_sv_extensions =
2509 prvm_builtin_t vm_sv_builtins[] = {
2510 0 // to be consistent with the old vm
2513 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
2515 void VM_SV_Cmd_Init(void)
2519 void VM_SV_Cmd_Reset(void)
2523 //============================================================================
2526 char *vm_cl_extensions =
2529 prvm_builtin_t vm_cl_builtins[] = {
2530 0 // to be consistent with the old vm
2533 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
2535 void VM_CL_Cmd_Init(void)
2539 void VM_CL_Cmd_Reset(void)
2543 //============================================================================
2546 char *vm_m_extensions =
2553 setmousetarget(float target)
2556 void VM_M_setmousetarget(void)
2558 VM_SAFEPARMCOUNT(1, VM_M_setmousetarget);
2560 switch((int)PRVM_G_FLOAT(OFS_PARM0))
2563 in_client_mouse = false;
2566 in_client_mouse = true;
2569 PRVM_ERROR("VM_M_setmousetarget: wrong destination %i !\n",PRVM_G_FLOAT(OFS_PARM0));
2577 float getmousetarget
2580 void VM_M_getmousetarget(void)
2582 VM_SAFEPARMCOUNT(0,VM_M_getmousetarget);
2585 PRVM_G_FLOAT(OFS_RETURN) = 2;
2587 PRVM_G_FLOAT(OFS_RETURN) = 1;
2596 setkeydest(float dest)
2599 void VM_M_setkeydest(void)
2601 VM_SAFEPARMCOUNT(1,VM_M_setkeydest);
2603 switch((int)PRVM_G_FLOAT(OFS_PARM0))
2607 key_dest = key_game;
2611 key_dest = key_menu;
2615 // key_dest = key_message
2618 PRVM_ERROR("VM_M_setkeydest: wrong destination %i !\n",prog->globals[OFS_PARM0]);
2629 void VM_M_getkeydest(void)
2631 VM_SAFEPARMCOUNT(0,VM_M_getkeydest);
2633 // key_game = 0, key_message = 1, key_menu = 2, unknown = 3
2637 PRVM_G_FLOAT(OFS_RETURN) = 0;
2640 PRVM_G_FLOAT(OFS_RETURN) = 2;
2644 // PRVM_G_FLOAT(OFS_RETURN) = 1;
2647 PRVM_G_FLOAT(OFS_RETURN) = 3;
2651 prvm_builtin_t vm_m_builtins[] = {
2652 0, // to be consistent with the old vm
2653 // common builtings (mostly)
2738 VM_WriteEntity, // 408
2754 VM_drawresetcliparea,
2755 VM_getimagesize,// 460
2764 VM_M_setmousetarget,
2768 const int vm_m_numbuiltins = sizeof(vm_m_builtins) / sizeof(prvm_builtin_t);
2770 void VM_M_Cmd_Init(void)
2775 void VM_M_Cmd_Reset(void)