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
8 /*============================================================================
12 checkextension(string)
16 centerprint(...[string])
17 vector normalize(vector)
19 float vectoyaw(vector)
20 vector vectoangles(vector)
24 cvar_set (string,string)
30 float stof(...[string])
33 entity find(entity start, .string field, string match)
35 entity findfloat(entity start, .float field, string match)
36 entity findentity(entity start, .entity field, string match)
38 entity findchain(.string field, string match)
40 entity findchainfloat(.string field, float match)
41 entity findchainentity(.string field, entity match)
50 entity nextent(entity)
55 float registercvar (string name, string value)
56 float min(float a, float b, ...[float])
57 float max(float a, float b, ...[float])
58 float bound(float min, float value, float max)
59 float pow(float a, float b)
60 copyentity(entity src, entity dst)
61 float fopen(string filename, float mode)
63 string fgets(float fhandle)
64 fputs(float fhandle, string s)
65 float strlen(string s)
66 string strcat(string s1, string s2)
67 string substring(string s, float start, float length)
69 string strzone(string s)
74 clientcommand(float client, string s) (for client and menu)
75 float tokenize(string s)
81 #include "clprogdefs.h"
82 #include "mprogdefs.h"
84 //============================================================================
87 #ifndef VM_NOPARMCHECK
88 #define VM_SAFEPARMCOUNT(p,f) if(prog->argc != p) PRVM_ERROR(#f "wrong parameter count (" #p "expected ) !\n")
90 #define VM_SAFEPARMCOUNT(p,f)
93 #define VM_RETURN_EDICT(e) (((int *)prog->globals)[OFS_RETURN] = PRVM_EDICT_TO_PROG(e))
95 #define VM_STRINGS_MEMPOOL vm_strings_mempool[PRVM_GetProgNr()]
97 #define e10 0,0,0,0,0,0,0,0,0,0
98 #define e100 e10,e10,e10,e10,e10,e10,e10,e10,e10,e10
99 #define e1000 e100,e100,e100,e100,e100,e100,e100,e100,e100,e100
101 //============================================================================
103 cvar_t vm_zone_min_strings = {0, "prvm_zone_min_strings", "64"};
105 mempool_t *vm_strings_mempool[PRVM_MAXPROGS];
108 typedef struct vm_string_s
111 // here follows everything else
116 // LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
117 #define STRINGTEMP_BUFFERS 16
118 #define STRINGTEMP_LENGTH 4096
119 static char vm_string_temp[STRINGTEMP_BUFFERS][STRINGTEMP_LENGTH];
120 static int vm_string_tempindex = 0;
122 static char *VM_GetTempString(void)
125 s = vm_string_temp[vm_string_tempindex];
126 vm_string_tempindex = (vm_string_tempindex + 1) % STRINGTEMP_BUFFERS;
131 void VM_CheckEmptyString (char *s)
134 PRVM_ERROR ("%s: Bad string", PRVM_NAME);
137 //============================================================================
140 void VM_VarString(int first, char *out, int outlength)
146 outend = out + outlength - 1;
147 for (i = first;i < pr_argc && out < outend;i++)
149 s = PRVM_G_STRING((OFS_PARM0+i*3));
150 while (out < outend && *s)
160 returns true if the extension is supported by the server
162 checkextension(extensionname)
166 // kind of helper function
167 static qboolean checkextension(char *name)
173 for (e = prog->extensionstring;*e;e++)
180 while (*e && *e != ' ')
182 if (e - start == len)
183 if (!strncasecmp(start, name, len))
191 void VM_checkextension (void)
193 VM_SAFEPARMCOUNT(1,VM_checkextension);
195 PRVM_G_FLOAT(OFS_RETURN) = checkextension(PRVM_G_STRING(OFS_PARM0));
202 This is a TERMINAL error, which will kill off the entire prog.
211 char string[STRINGTEMP_LENGTH];
213 VM_VarString(0, string, sizeof(string));
214 Con_Printf ("======%S ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
217 ed = PRVM_G_EDICT(prog->self->ofs);
221 PRVM_ERROR ("%s: Program error", PRVM_NAME);
228 Dumps out self, then an error message. The program is aborted and self is
229 removed, but the level can continue.
234 void VM_objerror (void)
237 char string[STRINGTEMP_LENGTH];
239 VM_VarString(0, string, sizeof(string));
240 Con_Printf ("======%s OBJECT ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string);
243 ed = PRVM_G_EDICT (prog->self->ofs);
248 // objerror has to display the object fields -> else call
249 PRVM_ERROR ("VM_objecterror: self not defined !\n");
254 VM_print (actually used only by client and menu)
263 char string[STRINGTEMP_LENGTH];
265 VM_VarString(0, string, sizeof(string));
273 single print to the screen
275 centerprint(clientent, value)
278 void VM_centerprint (void)
280 char string[STRINGTEMP_LENGTH];
282 VM_VarString(0, string, sizeof(string));
283 SCR_CenterPrint(string);
290 vector normalize(vector)
293 void VM_normalize (void)
299 VM_SAFEPARMCOUNT(1,VM_normalize);
301 value1 = PRVM_G_VECTOR(OFS_PARM0);
303 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
307 newvalue[0] = newvalue[1] = newvalue[2] = 0;
311 newvalue[0] = value1[0] * new;
312 newvalue[1] = value1[1] * new;
313 newvalue[2] = value1[2] * new;
316 VectorCopy (newvalue, PRVM_G_VECTOR(OFS_RETURN));
331 VM_SAFEPARMCOUNT(1,VM_vlen);
333 value1 = PRVM_G_VECTOR(OFS_PARM0);
335 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
338 PRVM_G_FLOAT(OFS_RETURN) = new;
345 float vectoyaw(vector)
348 void VM_vectoyaw (void)
353 VM_SAFEPARMCOUNT(1,VM_vectoyaw);
355 value1 = PRVM_G_VECTOR(OFS_PARM0);
357 if (value1[1] == 0 && value1[0] == 0)
361 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
366 PRVM_G_FLOAT(OFS_RETURN) = yaw;
374 vector vectoangles(vector)
377 void VM_vectoangles (void)
383 VM_SAFEPARMCOUNT(1,VM_vectoangles);
385 value1 = PRVM_G_VECTOR(OFS_PARM0);
387 if (value1[1] == 0 && value1[0] == 0)
397 // LordHavoc: optimized a bit
400 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
404 else if (value1[1] > 0)
409 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
410 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
415 PRVM_G_FLOAT(OFS_RETURN+0) = pitch;
416 PRVM_G_FLOAT(OFS_RETURN+1) = yaw;
417 PRVM_G_FLOAT(OFS_RETURN+2) = 0;
424 Returns a number from 0<= num < 1
429 void VM_random (void)
433 VM_SAFEPARMCOUNT(0,VM_random);
435 num = (rand ()&0x7fff) / ((float)0x7fff);
437 PRVM_G_FLOAT(OFS_RETURN) = num;
444 Each entity can have eight independant sound sources, like voice,
447 Channel 0 is an auto-allocate channel, the others override anything
448 already running on that entity/channel pair.
450 An attenuation of 0 will play full volume everywhere in the level.
451 Larger attenuations will drop off.
464 entity = G_EDICT(OFS_PARM0);
465 channel = G_FLOAT(OFS_PARM1);
466 sample = G_STRING(OFS_PARM2);
467 volume = G_FLOAT(OFS_PARM3) * 255;
468 attenuation = G_FLOAT(OFS_PARM4);
470 if (volume < 0 || volume > 255)
471 Host_Error ("SV_StartSound: volume = %i", volume);
473 if (attenuation < 0 || attenuation > 4)
474 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
476 if (channel < 0 || channel > 7)
477 Host_Error ("SV_StartSound: channel = %i", channel);
479 SV_StartSound (entity, channel, sample, volume, attenuation);
492 PRVM_ERROR ("%s: break statement", PRVM_NAME);
495 //============================================================================
498 qbyte checkpvs[MAX_MAP_LEAFS/8];
500 //============================================================================
506 Sends text over to the client's execution buffer
508 [localcmd (string) or]
512 void VM_localcmd (void)
514 VM_SAFEPARMCOUNT(1,VM_localcmd);
516 Cbuf_AddText(PRVM_G_STRING(OFS_PARM0));
528 VM_SAFEPARMCOUNT(1,VM_cvar);
530 PRVM_G_FLOAT(OFS_RETURN) = Cvar_VariableValue(PRVM_G_STRING(OFS_PARM0));
537 void cvar_set (string,string)
540 void VM_cvar_set (void)
542 VM_SAFEPARMCOUNT(2,VM_cvar_set);
544 Cvar_Set(PRVM_G_STRING(OFS_PARM0), PRVM_G_STRING(OFS_PARM1));
554 void VM_dprint (void)
556 char string[STRINGTEMP_LENGTH];
557 if (developer.integer)
559 VM_VarString(0, string, sizeof(string));
560 Con_Printf("%s: %s", PRVM_NAME, string);
577 VM_SAFEPARMCOUNT(1, VM_ftos);
579 v = PRVM_G_FLOAT(OFS_PARM0);
581 s = VM_GetTempString();
582 if ((float)((int)v) == v)
583 sprintf(s, "%i", (int)v);
586 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
601 VM_SAFEPARMCOUNT(1,VM_fabs);
603 v = PRVM_G_FLOAT(OFS_PARM0);
604 PRVM_G_FLOAT(OFS_RETURN) = fabs(v);
619 VM_SAFEPARMCOUNT(1,VM_vtos);
621 s = VM_GetTempString();
622 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]);
623 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
638 VM_SAFEPARMCOUNT(1, VM_etos);
640 s = VM_GetTempString();
641 sprintf (s, "entity %i", PRVM_G_EDICTNUM(OFS_PARM0));
642 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
649 float stof(...[string])
654 char string[STRINGTEMP_LENGTH];
655 VM_VarString(0, string, sizeof(string));
656 PRVM_G_FLOAT(OFS_RETURN) = atof(string);
670 prog->xfunction->builtinsprofile += 20;
671 ed = PRVM_ED_Alloc();
683 void VM_remove (void)
686 prog->xfunction->builtinsprofile += 20;
688 VM_SAFEPARMCOUNT(1, VM_remove);
690 ed = PRVM_G_EDICT(OFS_PARM0);
691 // if (ed == prog->edicts)
692 // PRVM_ERROR ("remove: tried to remove world\n");
693 // if (PRVM_NUM_FOR_EDICT(ed) <= sv.maxclients)
694 // Host_Error("remove: tried to remove a client\n");
702 entity find(entity start, .string field, string match)
713 VM_SAFEPARMCOUNT(3,VM_find);
715 e = PRVM_G_EDICTNUM(OFS_PARM0);
716 f = PRVM_G_INT(OFS_PARM1);
717 s = PRVM_G_STRING(OFS_PARM2);
721 // return reserved edict 0 (could be used for whatever the prog wants)
722 VM_RETURN_EDICT(prog->edicts);
726 for (e++ ; e < prog->num_edicts ; e++)
728 prog->xfunction->builtinsprofile++;
729 ed = PRVM_EDICT_NUM(e);
732 t = PRVM_E_STRING(ed,f);
742 VM_RETURN_EDICT(sv.edicts);
749 entity findfloat(entity start, .float field, string match)
750 entity findentity(entity start, .entity field, string match)
753 // LordHavoc: added this for searching float, int, and entity reference fields
754 void VM_findfloat (void)
761 VM_SAFEPARMCOUNT(3,VM_findfloat);
763 e = PRVM_G_EDICTNUM(OFS_PARM0);
764 f = PRVM_G_INT(OFS_PARM1);
765 s = PRVM_G_FLOAT(OFS_PARM2);
767 for (e++ ; e < prog->num_edicts ; e++)
769 prog->xfunction->builtinsprofile++;
770 ed = PRVM_EDICT_NUM(e);
773 if (PRVM_E_FLOAT(ed,f) == s)
780 VM_RETURN_EDICT(prog->edicts);
787 entity findchain(.string field, string match)
790 int PRVM_ED_FindFieldOffset(const char *field);
791 // chained search for strings in entity fields
792 // entity(.string field, string match) findchain = #402;
793 void VM_findchain (void)
799 prvm_edict_t *ent, *chain;
801 VM_SAFEPARMCOUNT(2,VM_findchain);
803 // is the same like !(prog->flag & PRVM_FE_CHAIN) - even if the operator precedence is another
804 if(!prog->flag & PRVM_FE_CHAIN)
805 PRVM_ERROR("VM_findchain: %s doesnt have a chain field !\n", PRVM_NAME);
807 chain_of = PRVM_ED_FindFieldOffset ("chain");
809 chain = prog->edicts;
811 f = PRVM_G_INT(OFS_PARM0);
812 s = PRVM_G_STRING(OFS_PARM1);
815 VM_RETURN_EDICT(prog->edicts);
819 ent = PRVM_NEXT_EDICT(prog->edicts);
820 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
822 prog->xfunction->builtinsprofile++;
825 t = PRVM_E_STRING(ent,f);
831 PRVM_E_FLOAT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain);
835 VM_RETURN_EDICT(chain);
842 entity findchainfloat(.string field, float match)
843 entity findchainentity(.string field, entity match)
846 // LordHavoc: chained search for float, int, and entity reference fields
847 // entity(.string field, float match) findchainfloat = #403;
848 void VM_findchainfloat (void)
854 prvm_edict_t *ent, *chain;
856 VM_SAFEPARMCOUNT(2, VM_findchainfloat);
858 if(!prog->flag & PRVM_FE_CHAIN)
859 PRVM_ERROR("VM_findchainfloat: %s doesnt have a chain field !\n", PRVM_NAME);
861 chain_of = PRVM_ED_FindFieldOffset ("chain");
863 chain = (prvm_edict_t *)prog->edicts;
865 f = PRVM_G_INT(OFS_PARM0);
866 s = PRVM_G_FLOAT(OFS_PARM1);
868 ent = PRVM_NEXT_EDICT(prog->edicts);
869 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
871 prog->xfunction->builtinsprofile++;
874 if (E_FLOAT(ent,f) != s)
877 PRVM_E_FLOAT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain);
881 VM_RETURN_EDICT(chain);
891 void VM_precache_file (void)
892 { // precache_file is only used to copy files with qcc, it does nothing
893 VM_SAFEPARMCOUNT(1,VM_precache_file);
895 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
902 used instead of the other VM_precache_* functions in the builtin list
906 void VM_precache_error (void)
908 PRVM_ERROR ("PF_Precache_*: Precache can only be done in spawn functions");
918 void VM_precache_sound (void)
923 VM_SAFEPARMCOUNT(1, VM_precache_sound);
925 s = PRVM_G_STRING(OFS_PARM0);
926 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
927 VM_CheckEmptyString (s);
929 for (i=0 ; i < MAX_SOUNDS ; i++)
931 if (!sv.sound_precache[i])
933 sv.sound_precache[i] = s;
936 if (!strcmp(sv.sound_precache[i], s))
939 Host_Error ("PF_precache_sound: overflow");
949 void VM_coredump (void)
951 VM_SAFEPARMCOUNT(0,VM_coredump);
953 PRVM_ED_PrintEdicts_f ();
963 void VM_traceon (void)
965 VM_SAFEPARMCOUNT(0,VM_traceon);
977 void VM_traceoff (void)
979 VM_SAFEPARMCOUNT(0,VM_traceoff);
991 void VM_eprint (void)
993 VM_SAFEPARMCOUNT(1,VM_eprint);
995 PRVM_ED_PrintNum (PRVM_G_EDICTNUM(OFS_PARM0));
1009 VM_SAFEPARMCOUNT(1,VM_rint);
1011 f = PRVM_G_FLOAT(OFS_PARM0);
1013 PRVM_G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1015 PRVM_G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1025 void VM_floor (void)
1027 VM_SAFEPARMCOUNT(1,VM_floor);
1029 PRVM_G_FLOAT(OFS_RETURN) = floor(PRVM_G_FLOAT(OFS_PARM0));
1041 VM_SAFEPARMCOUNT(1,VM_ceil);
1043 PRVM_G_FLOAT(OFS_RETURN) = ceil(PRVM_G_FLOAT(OFS_PARM0));
1051 entity nextent(entity)
1054 void VM_nextent (void)
1059 i = PRVM_G_EDICTNUM(OFS_PARM0);
1062 prog->xfunction->builtinsprofile++;
1064 if (i == prog->num_edicts)
1066 VM_RETURN_EDICT(prog->edicts);
1069 ent = PRVM_EDICT_NUM(i);
1072 VM_RETURN_EDICT(ent);
1078 //=============================================================================
1085 /*void PF_changelevel (void)
1089 // make sure we don't issue two changelevels
1090 if (svs.changelevel_issued)
1092 svs.changelevel_issued = true;
1094 s = G_STRING(OFS_PARM0);
1095 Cbuf_AddText (va("changelevel %s\n",s));
1107 VM_SAFEPARMCOUNT(1,VM_sin);
1108 PRVM_G_FLOAT(OFS_RETURN) = sin(PRVM_G_FLOAT(OFS_PARM0));
1119 VM_SAFEPARMCOUNT(1,VM_cos);
1120 PRVM_G_FLOAT(OFS_RETURN) = cos(PRVM_G_FLOAT(OFS_PARM0));
1132 VM_SAFEPARMCOUNT(1,VM_sqrt);
1133 PRVM_G_FLOAT(OFS_RETURN) = sqrt(PRVM_G_FLOAT(OFS_PARM0));
1140 Returns a vector of length < 1 and > 0
1145 void VM_randomvec (void)
1150 VM_SAFEPARMCOUNT(0, VM_randomvec);
1155 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1156 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1157 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1159 while (DotProduct(temp, temp) >= 1);
1160 VectorCopy (temp, PRVM_G_VECTOR(OFS_RETURN));
1163 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1164 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1165 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1166 // length returned always > 0
1167 length = (rand()&32766 + 1) * (1.0 / 32767.0) / VectorLength(temp);
1168 VectorScale(temp,length, temp);*/
1169 VectorCopy(temp, PRVM_G_VECTOR(OFS_RETURN));
1172 //=============================================================================
1173 #define MAX_QC_CVARS 128 * PRVM_MAXPROGS
1174 cvar_t vm_qc_cvar[MAX_QC_CVARS];
1175 int vm_currentqc_cvar;
1181 float registercvar (string name, string value)
1184 void VM_registercvar (void)
1189 VM_SAFEPARMCOUNT(2,VM_registercvar);
1191 name = PRVM_G_STRING(OFS_PARM0);
1192 value = PRVM_G_STRING(OFS_PARM1);
1193 PRVM_G_FLOAT(OFS_RETURN) = 0;
1194 // first check to see if it has already been defined
1195 if (Cvar_FindVar (name))
1198 // check for overlap with a command
1199 if (Cmd_Exists (name))
1201 Con_Printf ("VM_registercvar: %s is a command\n", name);
1205 if (vm_currentqc_cvar >= MAX_QC_CVARS)
1206 PRVM_ERROR ("VM_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1208 // copy the name and value
1209 variable = &vm_qc_cvar[vm_currentqc_cvar++];
1210 variable->name = Z_Malloc (strlen(name)+1);
1211 strcpy (variable->name, name);
1212 variable->string = Z_Malloc (strlen(value)+1);
1213 strcpy (variable->string, value);
1214 variable->value = atof (value);
1216 Cvar_RegisterVariable(variable);
1217 PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1224 returns the minimum of two supplied floats
1226 float min(float a, float b, ...[float])
1231 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1232 if (prog->argc == 2)
1233 PRVM_G_FLOAT(OFS_RETURN) = min(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1234 else if (prog->argc >= 3)
1237 float f = PRVM_G_FLOAT(OFS_PARM0);
1238 for (i = 1;i < prog->argc;i++)
1239 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) < f)
1240 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1241 PRVM_G_FLOAT(OFS_RETURN) = f;
1244 PRVM_ERROR("VM_min: %s must supply at least 2 floats\n", PRVM_NAME);
1251 returns the maximum of two supplied floats
1253 float max(float a, float b, ...[float])
1258 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1260 PRVM_G_FLOAT(OFS_RETURN) = max(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1261 else if (pr_argc >= 3)
1264 float f = PRVM_G_FLOAT(OFS_PARM0);
1265 for (i = 1;i < pr_argc;i++)
1266 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) > f)
1267 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1268 G_FLOAT(OFS_RETURN) = f;
1271 PRVM_ERROR("VM_max: %s must supply at least 2 floats\n", PRVM_NAME);
1278 returns number bounded by supplied range
1280 float bound(float min, float value, float max)
1283 void VM_bound (void)
1285 VM_SAFEPARMCOUNT(3,VM_bound);
1286 PRVM_G_FLOAT(OFS_RETURN) = bound(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2));
1293 returns a raised to power b
1295 float pow(float a, float b)
1300 VM_SAFEPARMCOUNT(2,VM_pow);
1301 PRVM_G_FLOAT(OFS_RETURN) = pow(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1308 copies data from one entity to another
1310 copyentity(entity src, entity dst)
1313 void VM_copyentity (void)
1315 prvm_edict_t *in, *out;
1316 VM_SAFEPARMCOUNT(2,VM_copyentity);
1317 in = PRVM_G_EDICT(OFS_PARM0);
1318 out = PRVM_G_EDICT(OFS_PARM1);
1319 memcpy(out->v, in->v, prog->progs->entityfields * 4);
1326 sets the color of a client and broadcasts the update to all connected clients
1328 setcolor(clientent, value)
1331 /*void PF_setcolor (void)
1337 entnum = G_EDICTNUM(OFS_PARM0);
1338 i = G_FLOAT(OFS_PARM1);
1340 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1342 Con_Printf ("tried to setcolor a non-client\n");
1346 client = svs.clients + entnum-1;
1347 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
1350 client->old_colors = i;
1351 client->edict->v->team = (i & 15) + 1;
1353 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1354 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
1355 MSG_WriteByte (&sv.reliable_datagram, i);
1358 #define MAX_VMFILES 256
1359 #define MAX_PRVMFILES MAX_VMFILES * PRVM_MAXPROGS
1360 // old #define VM_FILES(index) vm_files[PRVM_GetProgNr()+(index)]
1361 #define VM_FILES ((qfile_t**)(vm_files + PRVM_GetProgNr() * MAX_VMFILES))
1363 qfile_t *vm_files[MAX_PRVMFILES];
1365 void VM_Files_Init(void)
1367 memset(vm_files, 0, sizeof(qfile_t*[MAX_VMFILES]));
1370 void VM_Files_CloseAll(void)
1373 for (i = 0;i < MAX_VMFILES;i++)
1376 FS_Close(VM_FILES[i]);
1377 //VM_FILES[i] = NULL;
1379 memset(VM_FILES,0,sizeof(qfile_t*[MAX_VMFILES])); // this should be faster (is it ?)
1386 float fopen(string filename, float mode)
1389 // float(string filename, float mode) fopen = #110;
1390 // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE),
1391 // returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
1395 char *modestring, *filename;
1397 VM_SAFEPARMCOUNT(2,VM_fopen);
1399 for (filenum = 0;filenum < MAX_VMFILES;filenum++)
1400 if (VM_FILES[filenum] == NULL)
1402 if (filenum >= MAX_VMFILES)
1404 Con_Printf("VM_fopen: %s ran out of file handles (%i)\n", PRVM_NAME, MAX_VMFILES);
1405 PRVM_G_FLOAT(OFS_RETURN) = -2;
1408 mode = PRVM_G_FLOAT(OFS_PARM1);
1411 case 0: // FILE_READ
1414 case 1: // FILE_APPEND
1417 case 2: // FILE_WRITE
1421 Con_Printf ("VM_fopen: %s no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", PRVM_NAME, mode);
1422 PRVM_G_FLOAT(OFS_RETURN) = -3;
1425 filename = PRVM_G_STRING(OFS_PARM0);
1426 // .. is parent directory on many platforms
1427 // / is parent directory on Amiga
1428 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
1429 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
1430 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
1432 Con_Printf("VM_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
1433 PRVM_G_FLOAT(OFS_RETURN) = -4;
1436 VM_FILES[filenum] = FS_Open(va("data/%s", filename), modestring, false);
1437 if (VM_FILES[filenum] == NULL)
1438 PRVM_G_FLOAT(OFS_RETURN) = -1;
1440 PRVM_G_FLOAT(OFS_RETURN) = filenum;
1447 fclose(float fhandle)
1450 //void(float fhandle) fclose = #111; // closes a file
1451 void VM_fclose(void)
1455 VM_SAFEPARMCOUNT(1,VM_fclose);
1457 filenum = PRVM_G_FLOAT(OFS_PARM0);
1458 if (filenum < 0 || filenum >= MAX_VMFILES)
1460 Con_Printf("VM_fclose: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1463 if (VM_FILES[filenum] == NULL)
1465 Con_Printf("VM_fclose: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1468 FS_Close(VM_FILES[filenum]);
1469 VM_FILES[filenum] = NULL;
1476 string fgets(float fhandle)
1479 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
1483 static char string[STRINGTEMP_LENGTH];
1486 VM_SAFEPARMCOUNT(1,VM_fgets);
1488 filenum = PRVM_G_FLOAT(OFS_PARM0);
1489 if (filenum < 0 || filenum >= MAX_VMFILES)
1491 Con_Printf("VM_fgets: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1494 if (VM_FILES[filenum] == NULL)
1496 Con_Printf("VM_fgets: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1502 c = FS_Getc(VM_FILES[filenum]);
1503 if (c == '\r' || c == '\n' || c < 0)
1505 if (end < STRINGTEMP_LENGTH - 1)
1509 // remove \n following \r
1511 c = FS_Getc(VM_FILES[filenum]);
1512 if (developer.integer)
1513 Con_Printf("fgets: %s: %s\n", PRVM_NAME, string);
1515 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1517 PRVM_G_INT(OFS_RETURN) = 0;
1524 fputs(float fhandle, string s)
1527 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
1531 char string[STRINGTEMP_LENGTH];
1534 VM_SAFEPARMCOUNT(2,VM_fputs);
1536 filenum = PRVM_G_FLOAT(OFS_PARM0);
1537 if (filenum < 0 || filenum >= MAX_VMFILES)
1539 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1542 if (VM_FILES[filenum] == NULL)
1544 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1547 VM_VarString(1, string, sizeof(string));
1548 if ((stringlength = strlen(string)))
1549 FS_Write(VM_FILES[filenum], string, stringlength);
1550 if (developer.integer)
1551 Con_Printf("fputs: %s: %s\n", PRVM_NAME, string);
1558 float strlen(string s)
1561 //float(string s) strlen = #114; // returns how many characters are in a string
1562 void VM_strlen(void)
1566 VM_SAFEPARMCOUNT(1,VM_strlen);
1568 s = PRVM_G_STRING(OFS_PARM0);
1570 PRVM_G_FLOAT(OFS_RETURN) = strlen(s);
1572 PRVM_G_FLOAT(OFS_RETURN) = 0;
1579 string strcat(string s1, string s2)
1582 //string(string s1, string s2) strcat = #115;
1583 // concatenates two strings (for example "abc", "def" would return "abcdef")
1584 // and returns as a tempstring
1585 void VM_strcat(void)
1589 VM_SAFEPARMCOUNT(2,VM_strcat);
1591 s = VM_GetTempString();
1592 VM_VarString(0, s, STRINGTEMP_LENGTH);
1593 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
1600 string substring(string s, float start, float length)
1603 // string(string s, float start, float length) substring = #116;
1604 // returns a section of a string as a tempstring
1605 void VM_substring(void)
1607 int i, start, length;
1610 VM_SAFEPARMCOUNT(3,VM_substring);
1612 string = VM_GetTempString();
1613 s = PRVM_G_STRING(OFS_PARM0);
1614 start = PRVM_G_FLOAT(OFS_PARM1);
1615 length = PRVM_G_FLOAT(OFS_PARM2);
1618 for (i = 0;i < start && *s;i++, s++);
1619 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
1622 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1629 vector stov(string s)
1632 //vector(string s) stov = #117; // returns vector value from a string
1635 char string[STRINGTEMP_LENGTH];
1637 VM_SAFEPARMCOUNT(1,VM_stov);
1639 VM_VarString(0, string, sizeof(string));
1640 Math_atov(string, PRVM_G_VECTOR(OFS_RETURN));
1647 string strzone(string s)
1650 //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)
1651 void VM_strzone(void)
1655 VM_SAFEPARMCOUNT(1,VM_strzone);
1657 in = PRVM_G_STRING(OFS_PARM0);
1658 out = Mem_Alloc(VM_STRINGS_MEMPOOL, strlen(in) + 1);
1660 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(out);
1670 //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!!!)
1671 void VM_strunzone(void)
1673 VM_SAFEPARMCOUNT(1,VM_strunzone);
1675 Mem_Free(PRVM_G_STRING(OFS_PARM0));
1680 VM_command (used by client and menu)
1682 clientcommand(float client, string s) (for client and menu)
1685 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
1686 //this function originally written by KrimZon, made shorter by LordHavoc
1687 void VM_clcommand (void)
1689 client_t *temp_client;
1692 VM_SAFEPARMCOUNT(2,VM_clcommand);
1694 //find client for this entity
1695 i = PRVM_G_FLOAT(OFS_PARM0);
1696 if (!sv.active || i < 0 || i >= svs.maxclients || !svs.clients[i].active)
1698 Con_Printf("VM_clientcommand: %s: invalid client/server is not active !", PRVM_NAME);
1702 temp_client = host_client;
1703 host_client = svs.clients + i;
1704 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
1705 host_client = temp_client;
1713 float tokenize(string s)
1716 //float(string s) tokenize = #441;
1717 // takes apart a string into individal words (access them with argv), returns how many
1718 // this function originally written by KrimZon, made shorter by LordHavoc
1719 static char **tokens = NULL;
1720 static int max_tokens, num_tokens = 0;
1721 void VM_tokenize (void)
1726 VM_SAFEPARMCOUNT(1,VM_tokenize);
1728 str = PRVM_G_STRING(OFS_PARM0);
1733 for (i=0;i<num_tokens;i++)
1739 tokens = Z_Malloc(strlen(str) * sizeof(char *));
1740 max_tokens = strlen(str);
1742 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
1744 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
1745 strcpy(tokens[num_tokens], com_token);
1748 PRVM_G_FLOAT(OFS_RETURN) = num_tokens;
1755 string argv(float n)
1758 //string(float n) argv = #442;
1759 // returns a word from the tokenized string (returns nothing for an invalid index)
1760 // this function originally written by KrimZon, made shorter by LordHavoc
1765 VM_SAFEPARMCOUNT(1,VM_argv);
1767 token_num = PRVM_G_FLOAT(OFS_PARM0);
1768 if (token_num >= 0 && token_num < num_tokens)
1769 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tokens[token_num]);
1771 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
1775 //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)
1776 void PF_setattachment (void)
1778 edict_t *e = G_EDICT(OFS_PARM0);
1779 edict_t *tagentity = G_EDICT(OFS_PARM1);
1780 char *tagname = G_STRING(OFS_PARM2);
1785 if (tagentity == NULL)
1786 tagentity = sv.edicts;
1788 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
1790 v->edict = EDICT_TO_PROG(tagentity);
1792 v = GETEDICTFIELDVALUE(e, eval_tag_index);
1795 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
1797 modelindex = (int)tagentity->v->modelindex;
1798 if (modelindex >= 0 && modelindex < MAX_MODELS)
1800 model = sv.models[modelindex];
1801 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
1802 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
1803 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
1805 if (v->_float == 0 && model->alias.aliasnum_tags)
1806 for (i = 0;i < model->alias.aliasnum_tags;i++)
1807 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
1810 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);
1813 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));
1824 void VM_isserver(void)
1826 VM_SAFEPARMCOUNT(0,VM_serverstate);
1828 PRVM_G_FLOAT(OFS_RETURN) = sv.active;
1838 void VM_clientcount(void)
1840 VM_SAFEPARMCOUNT(0,VM_clientcount);
1842 PRVM_G_FLOAT(OFS_RETURN) = svs.maxclients;
1852 void VM_clientstate(void)
1854 VM_SAFEPARMCOUNT(0,VM_clientstate);
1856 PRVM_G_FLOAT(OFS_RETURN) = cls.state;
1859 void VM_Cmd_Init(void)
1863 void VM_Cmd_Reset(void)
1867 //============================================================================
1870 char *vm_sv_extensions =
1873 prvm_builtin_t vm_sv_builtins[] = {
1874 0 // to be consistent with the old vm
1877 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
1879 void VM_SV_Cmd_Init(void)
1883 void VM_SV_Cmd_Reset(void)
1887 //============================================================================
1890 char *vm_cl_extensions =
1893 prvm_builtin_t vm_cl_builtins[] = {
1894 0 // to be consistent with the old vm
1897 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
1899 void VM_CL_Cmd_Init(void)
1903 void VM_CL_Cmd_Reset(void)
1907 //============================================================================
1910 char *vm_m_extensions =
1913 // void setkeydest(float dest)
1914 void VM_M_SetKeyDest(void)
1916 VM_SAFEPARMCOUNT(1,VM_M_SetKeyDest);
1918 switch((int)PRVM_G_FLOAT(OFS_PARM0))
1922 key_dest = key_game;
1926 key_dest = key_menu;
1930 // key_dest = key_message
1933 PRVM_ERROR("VM_M_SetKeyDest: wrong destination %i !\n",prog->globals[OFS_PARM0]);
1939 // float getkeydest(void)
1940 void VM_M_GetKeyDest(void)
1942 VM_SAFEPARMCOUNT(0,VM_M_GetKeyDest);
1944 // key_game = 0, key_message = 1, key_menu = 2, unknown = 3
1948 PRVM_G_FLOAT(OFS_RETURN) = 0;
1951 PRVM_G_FLOAT(OFS_RETURN) = 2;
1955 // PRVM_G_FLOAT(OFS_RETURN) = 1;
1958 PRVM_G_FLOAT(OFS_RETURN) = 3;
1962 prvm_builtin_t vm_m_builtins[] = {
1963 0, // to be consistent with the old vm
1969 const int vm_m_numbuiltins = sizeof(vm_m_builtins) / sizeof(prvm_builtin_t);
1971 void VM_M_Cmd_Init(void)
1975 void VM_M_Cmd_Reset(void)