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);
247 // objerror has to display the object fields -> else call
248 PRVM_ERROR ("VM_objecterror: self not defined !\n");
255 VM_print (actually used only by client and menu)
264 char string[STRINGTEMP_LENGTH];
266 VM_VarString(0, string, sizeof(string));
274 single print to the screen
276 centerprint(clientent, value)
279 void VM_centerprint (void)
281 char string[STRINGTEMP_LENGTH];
283 VM_VarString(0, string, sizeof(string));
284 SCR_CenterPrint(string);
291 vector normalize(vector)
294 void VM_normalize (void)
300 VM_SAFEPARMCOUNT(1,VM_normalize);
302 value1 = PRVM_G_VECTOR(OFS_PARM0);
304 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
308 newvalue[0] = newvalue[1] = newvalue[2] = 0;
312 newvalue[0] = value1[0] * new;
313 newvalue[1] = value1[1] * new;
314 newvalue[2] = value1[2] * new;
317 VectorCopy (newvalue, PRVM_G_VECTOR(OFS_RETURN));
332 VM_SAFEPARMCOUNT(1,VM_vlen);
334 value1 = PRVM_G_VECTOR(OFS_PARM0);
336 new = value1[0] * value1[0] + value1[1] * value1[1] + value1[2]*value1[2];
339 PRVM_G_FLOAT(OFS_RETURN) = new;
346 float vectoyaw(vector)
349 void VM_vectoyaw (void)
354 VM_SAFEPARMCOUNT(1,VM_vectoyaw);
356 value1 = PRVM_G_VECTOR(OFS_PARM0);
358 if (value1[1] == 0 && value1[0] == 0)
362 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
367 PRVM_G_FLOAT(OFS_RETURN) = yaw;
375 vector vectoangles(vector)
378 void VM_vectoangles (void)
384 VM_SAFEPARMCOUNT(1,VM_vectoangles);
386 value1 = PRVM_G_VECTOR(OFS_PARM0);
388 if (value1[1] == 0 && value1[0] == 0)
398 // LordHavoc: optimized a bit
401 yaw = (atan2(value1[1], value1[0]) * 180 / M_PI);
405 else if (value1[1] > 0)
410 forward = sqrt(value1[0]*value1[0] + value1[1]*value1[1]);
411 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
416 PRVM_G_FLOAT(OFS_RETURN+0) = pitch;
417 PRVM_G_FLOAT(OFS_RETURN+1) = yaw;
418 PRVM_G_FLOAT(OFS_RETURN+2) = 0;
425 Returns a number from 0<= num < 1
430 void VM_random (void)
434 VM_SAFEPARMCOUNT(0,VM_random);
436 num = (rand ()&0x7fff) / ((float)0x7fff);
438 PRVM_G_FLOAT(OFS_RETURN) = num;
445 Each entity can have eight independant sound sources, like voice,
448 Channel 0 is an auto-allocate channel, the others override anything
449 already running on that entity/channel pair.
451 An attenuation of 0 will play full volume everywhere in the level.
452 Larger attenuations will drop off.
465 entity = G_EDICT(OFS_PARM0);
466 channel = G_FLOAT(OFS_PARM1);
467 sample = G_STRING(OFS_PARM2);
468 volume = G_FLOAT(OFS_PARM3) * 255;
469 attenuation = G_FLOAT(OFS_PARM4);
471 if (volume < 0 || volume > 255)
472 Host_Error ("SV_StartSound: volume = %i", volume);
474 if (attenuation < 0 || attenuation > 4)
475 Host_Error ("SV_StartSound: attenuation = %f", attenuation);
477 if (channel < 0 || channel > 7)
478 Host_Error ("SV_StartSound: channel = %i", channel);
480 SV_StartSound (entity, channel, sample, volume, attenuation);
493 PRVM_ERROR ("%s: break statement", PRVM_NAME);
496 //============================================================================
500 qbyte checkpvs[MAX_MAP_LEAFS/8];
502 //============================================================================
508 Sends text over to the client's execution buffer
510 [localcmd (string) or]
514 void VM_localcmd (void)
516 VM_SAFEPARMCOUNT(1,VM_localcmd);
518 Cbuf_AddText(PRVM_G_STRING(OFS_PARM0));
530 VM_SAFEPARMCOUNT(1,VM_cvar);
532 PRVM_G_FLOAT(OFS_RETURN) = Cvar_VariableValue(PRVM_G_STRING(OFS_PARM0));
539 void cvar_set (string,string)
542 void VM_cvar_set (void)
544 VM_SAFEPARMCOUNT(2,VM_cvar_set);
546 Cvar_Set(PRVM_G_STRING(OFS_PARM0), PRVM_G_STRING(OFS_PARM1));
556 void VM_dprint (void)
558 char string[STRINGTEMP_LENGTH];
559 if (developer.integer)
561 VM_VarString(0, string, sizeof(string));
562 Con_Printf("%s: %s", PRVM_NAME, string);
579 VM_SAFEPARMCOUNT(1, VM_ftos);
581 v = PRVM_G_FLOAT(OFS_PARM0);
583 s = VM_GetTempString();
584 if ((float)((int)v) == v)
585 sprintf(s, "%i", (int)v);
588 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
603 VM_SAFEPARMCOUNT(1,VM_fabs);
605 v = PRVM_G_FLOAT(OFS_PARM0);
606 PRVM_G_FLOAT(OFS_RETURN) = fabs(v);
621 VM_SAFEPARMCOUNT(1,VM_vtos);
623 s = VM_GetTempString();
624 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]);
625 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
640 VM_SAFEPARMCOUNT(1, VM_etos);
642 s = VM_GetTempString();
643 sprintf (s, "entity %i", PRVM_G_EDICTNUM(OFS_PARM0));
644 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
651 float stof(...[string])
656 char string[STRINGTEMP_LENGTH];
657 VM_VarString(0, string, sizeof(string));
658 PRVM_G_FLOAT(OFS_RETURN) = atof(string);
672 prog->xfunction->builtinsprofile += 20;
673 ed = PRVM_ED_Alloc();
685 void VM_remove (void)
688 prog->xfunction->builtinsprofile += 20;
690 VM_SAFEPARMCOUNT(1, VM_remove);
692 ed = PRVM_G_EDICT(OFS_PARM0);
693 // if (ed == prog->edicts)
694 // PRVM_ERROR ("remove: tried to remove world\n");
695 // if (PRVM_NUM_FOR_EDICT(ed) <= sv.maxclients)
696 // Host_Error("remove: tried to remove a client\n");
704 entity find(entity start, .string field, string match)
715 VM_SAFEPARMCOUNT(3,VM_find);
717 e = PRVM_G_EDICTNUM(OFS_PARM0);
718 f = PRVM_G_INT(OFS_PARM1);
719 s = PRVM_G_STRING(OFS_PARM2);
723 // return reserved edict 0 (could be used for whatever the prog wants)
724 VM_RETURN_EDICT(prog->edicts);
728 for (e++ ; e < prog->num_edicts ; e++)
730 prog->xfunction->builtinsprofile++;
731 ed = PRVM_EDICT_NUM(e);
734 t = PRVM_E_STRING(ed,f);
744 VM_RETURN_EDICT(sv.edicts);
751 entity findfloat(entity start, .float field, string match)
752 entity findentity(entity start, .entity field, string match)
755 // LordHavoc: added this for searching float, int, and entity reference fields
756 void VM_findfloat (void)
763 VM_SAFEPARMCOUNT(3,VM_findfloat);
765 e = PRVM_G_EDICTNUM(OFS_PARM0);
766 f = PRVM_G_INT(OFS_PARM1);
767 s = PRVM_G_FLOAT(OFS_PARM2);
769 for (e++ ; e < prog->num_edicts ; e++)
771 prog->xfunction->builtinsprofile++;
772 ed = PRVM_EDICT_NUM(e);
775 if (PRVM_E_FLOAT(ed,f) == s)
782 VM_RETURN_EDICT(prog->edicts);
789 entity findchain(.string field, string match)
792 int PRVM_ED_FindFieldOffset(const char *field);
793 // chained search for strings in entity fields
794 // entity(.string field, string match) findchain = #402;
795 void VM_findchain (void)
801 prvm_edict_t *ent, *chain;
803 VM_SAFEPARMCOUNT(2,VM_findchain);
805 // is the same like !(prog->flag & PRVM_FE_CHAIN) - even if the operator precedence is another
806 if(!prog->flag & PRVM_FE_CHAIN)
807 PRVM_ERROR("VM_findchain: %s doesnt have a chain field !\n", PRVM_NAME);
809 chain_of = PRVM_ED_FindFieldOffset ("chain");
811 chain = prog->edicts;
813 f = PRVM_G_INT(OFS_PARM0);
814 s = PRVM_G_STRING(OFS_PARM1);
817 VM_RETURN_EDICT(prog->edicts);
821 ent = PRVM_NEXT_EDICT(prog->edicts);
822 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
824 prog->xfunction->builtinsprofile++;
827 t = PRVM_E_STRING(ent,f);
833 PRVM_E_FLOAT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain);
837 VM_RETURN_EDICT(chain);
844 entity findchainfloat(.string field, float match)
845 entity findchainentity(.string field, entity match)
848 // LordHavoc: chained search for float, int, and entity reference fields
849 // entity(.string field, float match) findchainfloat = #403;
850 void VM_findchainfloat (void)
856 prvm_edict_t *ent, *chain;
858 VM_SAFEPARMCOUNT(2, VM_findchainfloat);
860 if(!prog->flag & PRVM_FE_CHAIN)
861 PRVM_ERROR("VM_findchainfloat: %s doesnt have a chain field !\n", PRVM_NAME);
863 chain_of = PRVM_ED_FindFieldOffset ("chain");
865 chain = (prvm_edict_t *)prog->edicts;
867 f = PRVM_G_INT(OFS_PARM0);
868 s = PRVM_G_FLOAT(OFS_PARM1);
870 ent = PRVM_NEXT_EDICT(prog->edicts);
871 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
873 prog->xfunction->builtinsprofile++;
876 if (E_FLOAT(ent,f) != s)
879 PRVM_E_FLOAT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain);
883 VM_RETURN_EDICT(chain);
893 void VM_precache_file (void)
894 { // precache_file is only used to copy files with qcc, it does nothing
895 VM_SAFEPARMCOUNT(1,VM_precache_file);
897 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
904 used instead of the other VM_precache_* functions in the builtin list
908 void VM_precache_error (void)
910 PRVM_ERROR ("PF_Precache_*: Precache can only be done in spawn functions");
920 void VM_precache_sound (void)
925 VM_SAFEPARMCOUNT(1, VM_precache_sound);
927 s = PRVM_G_STRING(OFS_PARM0);
928 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
929 VM_CheckEmptyString (s);
931 for (i=0 ; i < MAX_SOUNDS ; i++)
933 if (!sv.sound_precache[i])
935 sv.sound_precache[i] = s;
938 if (!strcmp(sv.sound_precache[i], s))
941 Host_Error ("PF_precache_sound: overflow");
951 void VM_coredump (void)
953 VM_SAFEPARMCOUNT(0,VM_coredump);
955 PRVM_ED_PrintEdicts_f ();
965 void VM_traceon (void)
967 VM_SAFEPARMCOUNT(0,VM_traceon);
979 void VM_traceoff (void)
981 VM_SAFEPARMCOUNT(0,VM_traceoff);
993 void VM_eprint (void)
995 VM_SAFEPARMCOUNT(1,VM_eprint);
997 PRVM_ED_PrintNum (PRVM_G_EDICTNUM(OFS_PARM0));
1011 VM_SAFEPARMCOUNT(1,VM_rint);
1013 f = PRVM_G_FLOAT(OFS_PARM0);
1015 PRVM_G_FLOAT(OFS_RETURN) = (int)(f + 0.5);
1017 PRVM_G_FLOAT(OFS_RETURN) = (int)(f - 0.5);
1027 void VM_floor (void)
1029 VM_SAFEPARMCOUNT(1,VM_floor);
1031 PRVM_G_FLOAT(OFS_RETURN) = floor(PRVM_G_FLOAT(OFS_PARM0));
1043 VM_SAFEPARMCOUNT(1,VM_ceil);
1045 PRVM_G_FLOAT(OFS_RETURN) = ceil(PRVM_G_FLOAT(OFS_PARM0));
1053 entity nextent(entity)
1056 void VM_nextent (void)
1061 i = PRVM_G_EDICTNUM(OFS_PARM0);
1064 prog->xfunction->builtinsprofile++;
1066 if (i == prog->num_edicts)
1068 VM_RETURN_EDICT(prog->edicts);
1071 ent = PRVM_EDICT_NUM(i);
1074 VM_RETURN_EDICT(ent);
1080 //=============================================================================
1087 /*void PF_changelevel (void)
1091 // make sure we don't issue two changelevels
1092 if (svs.changelevel_issued)
1094 svs.changelevel_issued = true;
1096 s = G_STRING(OFS_PARM0);
1097 Cbuf_AddText (va("changelevel %s\n",s));
1109 VM_SAFEPARMCOUNT(1,VM_sin);
1110 PRVM_G_FLOAT(OFS_RETURN) = sin(PRVM_G_FLOAT(OFS_PARM0));
1121 VM_SAFEPARMCOUNT(1,VM_cos);
1122 PRVM_G_FLOAT(OFS_RETURN) = cos(PRVM_G_FLOAT(OFS_PARM0));
1134 VM_SAFEPARMCOUNT(1,VM_sqrt);
1135 PRVM_G_FLOAT(OFS_RETURN) = sqrt(PRVM_G_FLOAT(OFS_PARM0));
1142 Returns a vector of length < 1 and > 0
1147 void VM_randomvec (void)
1152 VM_SAFEPARMCOUNT(0, VM_randomvec);
1157 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1158 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1159 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1161 while (DotProduct(temp, temp) >= 1);
1162 VectorCopy (temp, PRVM_G_VECTOR(OFS_RETURN));
1165 temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1166 temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1167 temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0;
1168 // length returned always > 0
1169 length = (rand()&32766 + 1) * (1.0 / 32767.0) / VectorLength(temp);
1170 VectorScale(temp,length, temp);*/
1171 VectorCopy(temp, PRVM_G_VECTOR(OFS_RETURN));
1174 //=============================================================================
1175 #define MAX_QC_CVARS 128 * PRVM_MAXPROGS
1176 cvar_t vm_qc_cvar[MAX_QC_CVARS];
1177 int vm_currentqc_cvar;
1183 float registercvar (string name, string value)
1186 void VM_registercvar (void)
1191 VM_SAFEPARMCOUNT(2,VM_registercvar);
1193 name = PRVM_G_STRING(OFS_PARM0);
1194 value = PRVM_G_STRING(OFS_PARM1);
1195 PRVM_G_FLOAT(OFS_RETURN) = 0;
1196 // first check to see if it has already been defined
1197 if (Cvar_FindVar (name))
1200 // check for overlap with a command
1201 if (Cmd_Exists (name))
1203 Con_Printf ("VM_registercvar: %s is a command\n", name);
1207 if (vm_currentqc_cvar >= MAX_QC_CVARS)
1208 PRVM_ERROR ("VM_registercvar: ran out of cvar slots (%i)\n", MAX_QC_CVARS);
1210 // copy the name and value
1211 variable = &vm_qc_cvar[vm_currentqc_cvar++];
1212 variable->name = Z_Malloc (strlen(name)+1);
1213 strcpy (variable->name, name);
1214 variable->string = Z_Malloc (strlen(value)+1);
1215 strcpy (variable->string, value);
1216 variable->value = atof (value);
1218 Cvar_RegisterVariable(variable);
1219 PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1226 returns the minimum of two supplied floats
1228 float min(float a, float b, ...[float])
1233 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1234 if (prog->argc == 2)
1235 PRVM_G_FLOAT(OFS_RETURN) = min(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1236 else if (prog->argc >= 3)
1239 float f = PRVM_G_FLOAT(OFS_PARM0);
1240 for (i = 1;i < prog->argc;i++)
1241 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) < f)
1242 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1243 PRVM_G_FLOAT(OFS_RETURN) = f;
1246 PRVM_ERROR("VM_min: %s must supply at least 2 floats\n", PRVM_NAME);
1253 returns the maximum of two supplied floats
1255 float max(float a, float b, ...[float])
1260 // LordHavoc: 3+ argument enhancement suggested by FrikaC
1262 PRVM_G_FLOAT(OFS_RETURN) = max(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1263 else if (pr_argc >= 3)
1266 float f = PRVM_G_FLOAT(OFS_PARM0);
1267 for (i = 1;i < pr_argc;i++)
1268 if (PRVM_G_FLOAT((OFS_PARM0+i*3)) > f)
1269 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1270 G_FLOAT(OFS_RETURN) = f;
1273 PRVM_ERROR("VM_max: %s must supply at least 2 floats\n", PRVM_NAME);
1280 returns number bounded by supplied range
1282 float bound(float min, float value, float max)
1285 void VM_bound (void)
1287 VM_SAFEPARMCOUNT(3,VM_bound);
1288 PRVM_G_FLOAT(OFS_RETURN) = bound(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2));
1295 returns a raised to power b
1297 float pow(float a, float b)
1302 VM_SAFEPARMCOUNT(2,VM_pow);
1303 PRVM_G_FLOAT(OFS_RETURN) = pow(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
1310 copies data from one entity to another
1312 copyentity(entity src, entity dst)
1315 void VM_copyentity (void)
1317 prvm_edict_t *in, *out;
1318 VM_SAFEPARMCOUNT(2,VM_copyentity);
1319 in = PRVM_G_EDICT(OFS_PARM0);
1320 out = PRVM_G_EDICT(OFS_PARM1);
1321 memcpy(out->v, in->v, prog->progs->entityfields * 4);
1328 sets the color of a client and broadcasts the update to all connected clients
1330 setcolor(clientent, value)
1333 /*void PF_setcolor (void)
1339 entnum = G_EDICTNUM(OFS_PARM0);
1340 i = G_FLOAT(OFS_PARM1);
1342 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1344 Con_Printf ("tried to setcolor a non-client\n");
1348 client = svs.clients + entnum-1;
1349 if ((val = GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
1352 client->old_colors = i;
1353 client->edict->v->team = (i & 15) + 1;
1355 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1356 MSG_WriteByte (&sv.reliable_datagram, entnum - 1);
1357 MSG_WriteByte (&sv.reliable_datagram, i);
1360 #define MAX_VMFILES 256
1361 #define MAX_PRVMFILES MAX_VMFILES * PRVM_MAXPROGS
1362 // old #define VM_FILES(index) vm_files[PRVM_GetProgNr()+(index)]
1363 #define VM_FILES ((qfile_t**)(vm_files + PRVM_GetProgNr() * MAX_VMFILES))
1365 qfile_t *vm_files[MAX_PRVMFILES];
1367 void VM_Files_Init(void)
1369 memset(vm_files, 0, sizeof(qfile_t*[MAX_VMFILES]));
1372 void VM_Files_CloseAll(void)
1375 for (i = 0;i < MAX_VMFILES;i++)
1378 FS_Close(VM_FILES[i]);
1379 //VM_FILES[i] = NULL;
1381 memset(VM_FILES,0,sizeof(qfile_t*[MAX_VMFILES])); // this should be faster (is it ?)
1388 float fopen(string filename, float mode)
1391 // float(string filename, float mode) fopen = #110;
1392 // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE),
1393 // returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
1397 char *modestring, *filename;
1399 VM_SAFEPARMCOUNT(2,VM_fopen);
1401 for (filenum = 0;filenum < MAX_VMFILES;filenum++)
1402 if (VM_FILES[filenum] == NULL)
1404 if (filenum >= MAX_VMFILES)
1406 Con_Printf("VM_fopen: %s ran out of file handles (%i)\n", PRVM_NAME, MAX_VMFILES);
1407 PRVM_G_FLOAT(OFS_RETURN) = -2;
1410 mode = PRVM_G_FLOAT(OFS_PARM1);
1413 case 0: // FILE_READ
1416 case 1: // FILE_APPEND
1419 case 2: // FILE_WRITE
1423 Con_Printf ("VM_fopen: %s no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", PRVM_NAME, mode);
1424 PRVM_G_FLOAT(OFS_RETURN) = -3;
1427 filename = PRVM_G_STRING(OFS_PARM0);
1428 // .. is parent directory on many platforms
1429 // / is parent directory on Amiga
1430 // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
1431 // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
1432 if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
1434 Con_Printf("VM_fopen: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
1435 PRVM_G_FLOAT(OFS_RETURN) = -4;
1438 VM_FILES[filenum] = FS_Open(va("data/%s", filename), modestring, false);
1439 if (VM_FILES[filenum] == NULL)
1440 PRVM_G_FLOAT(OFS_RETURN) = -1;
1442 PRVM_G_FLOAT(OFS_RETURN) = filenum;
1449 fclose(float fhandle)
1452 //void(float fhandle) fclose = #111; // closes a file
1453 void VM_fclose(void)
1457 VM_SAFEPARMCOUNT(1,VM_fclose);
1459 filenum = PRVM_G_FLOAT(OFS_PARM0);
1460 if (filenum < 0 || filenum >= MAX_VMFILES)
1462 Con_Printf("VM_fclose: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1465 if (VM_FILES[filenum] == NULL)
1467 Con_Printf("VM_fclose: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1470 FS_Close(VM_FILES[filenum]);
1471 VM_FILES[filenum] = NULL;
1478 string fgets(float fhandle)
1481 //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
1485 static char string[STRINGTEMP_LENGTH];
1488 VM_SAFEPARMCOUNT(1,VM_fgets);
1490 filenum = PRVM_G_FLOAT(OFS_PARM0);
1491 if (filenum < 0 || filenum >= MAX_VMFILES)
1493 Con_Printf("VM_fgets: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1496 if (VM_FILES[filenum] == NULL)
1498 Con_Printf("VM_fgets: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1504 c = FS_Getc(VM_FILES[filenum]);
1505 if (c == '\r' || c == '\n' || c < 0)
1507 if (end < STRINGTEMP_LENGTH - 1)
1511 // remove \n following \r
1513 c = FS_Getc(VM_FILES[filenum]);
1514 if (developer.integer)
1515 Con_Printf("fgets: %s: %s\n", PRVM_NAME, string);
1517 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1519 PRVM_G_INT(OFS_RETURN) = 0;
1526 fputs(float fhandle, string s)
1529 //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
1533 char string[STRINGTEMP_LENGTH];
1536 VM_SAFEPARMCOUNT(2,VM_fputs);
1538 filenum = PRVM_G_FLOAT(OFS_PARM0);
1539 if (filenum < 0 || filenum >= MAX_VMFILES)
1541 Con_Printf("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME);
1544 if (VM_FILES[filenum] == NULL)
1546 Con_Printf("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME);
1549 VM_VarString(1, string, sizeof(string));
1550 if ((stringlength = strlen(string)))
1551 FS_Write(VM_FILES[filenum], string, stringlength);
1552 if (developer.integer)
1553 Con_Printf("fputs: %s: %s\n", PRVM_NAME, string);
1560 float strlen(string s)
1563 //float(string s) strlen = #114; // returns how many characters are in a string
1564 void VM_strlen(void)
1568 VM_SAFEPARMCOUNT(1,VM_strlen);
1570 s = PRVM_G_STRING(OFS_PARM0);
1572 PRVM_G_FLOAT(OFS_RETURN) = strlen(s);
1574 PRVM_G_FLOAT(OFS_RETURN) = 0;
1581 string strcat(string s1, string s2)
1584 //string(string s1, string s2) strcat = #115;
1585 // concatenates two strings (for example "abc", "def" would return "abcdef")
1586 // and returns as a tempstring
1587 void VM_strcat(void)
1591 VM_SAFEPARMCOUNT(2,VM_strcat);
1593 s = VM_GetTempString();
1594 VM_VarString(0, s, STRINGTEMP_LENGTH);
1595 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(s);
1602 string substring(string s, float start, float length)
1605 // string(string s, float start, float length) substring = #116;
1606 // returns a section of a string as a tempstring
1607 void VM_substring(void)
1609 int i, start, length;
1612 VM_SAFEPARMCOUNT(3,VM_substring);
1614 string = VM_GetTempString();
1615 s = PRVM_G_STRING(OFS_PARM0);
1616 start = PRVM_G_FLOAT(OFS_PARM1);
1617 length = PRVM_G_FLOAT(OFS_PARM2);
1620 for (i = 0;i < start && *s;i++, s++);
1621 for (i = 0;i < STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
1624 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(string);
1631 vector stov(string s)
1634 //vector(string s) stov = #117; // returns vector value from a string
1637 char string[STRINGTEMP_LENGTH];
1639 VM_SAFEPARMCOUNT(1,VM_stov);
1641 VM_VarString(0, string, sizeof(string));
1642 Math_atov(string, PRVM_G_VECTOR(OFS_RETURN));
1649 string strzone(string s)
1652 //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)
1653 void VM_strzone(void)
1657 VM_SAFEPARMCOUNT(1,VM_strzone);
1659 in = PRVM_G_STRING(OFS_PARM0);
1660 out = Mem_Alloc(VM_STRINGS_MEMPOOL, strlen(in) + 1);
1662 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(out);
1672 //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!!!)
1673 void VM_strunzone(void)
1675 VM_SAFEPARMCOUNT(1,VM_strunzone);
1677 Mem_Free(PRVM_G_STRING(OFS_PARM0));
1682 VM_command (used by client and menu)
1684 clientcommand(float client, string s) (for client and menu)
1687 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
1688 //this function originally written by KrimZon, made shorter by LordHavoc
1689 void VM_clcommand (void)
1691 client_t *temp_client;
1694 VM_SAFEPARMCOUNT(2,VM_clcommand);
1696 //find client for this entity
1697 i = PRVM_G_FLOAT(OFS_PARM0);
1698 if (!sv.active || i < 0 || i >= svs.maxclients || !svs.clients[i].active)
1700 Con_Printf("VM_clientcommand: %s: invalid client/server is not active !", PRVM_NAME);
1704 temp_client = host_client;
1705 host_client = svs.clients + i;
1706 Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
1707 host_client = temp_client;
1715 float tokenize(string s)
1718 //float(string s) tokenize = #441;
1719 // takes apart a string into individal words (access them with argv), returns how many
1720 // this function originally written by KrimZon, made shorter by LordHavoc
1721 static char **tokens = NULL;
1722 static int max_tokens, num_tokens = 0;
1723 void VM_tokenize (void)
1728 VM_SAFEPARMCOUNT(1,VM_tokenize);
1730 str = PRVM_G_STRING(OFS_PARM0);
1735 for (i=0;i<num_tokens;i++)
1741 tokens = Z_Malloc(strlen(str) * sizeof(char *));
1742 max_tokens = strlen(str);
1744 for (p = str;COM_ParseToken(&p, false) && num_tokens < max_tokens;num_tokens++)
1746 tokens[num_tokens] = Z_Malloc(strlen(com_token) + 1);
1747 strcpy(tokens[num_tokens], com_token);
1750 PRVM_G_FLOAT(OFS_RETURN) = num_tokens;
1757 string argv(float n)
1760 //string(float n) argv = #442;
1761 // returns a word from the tokenized string (returns nothing for an invalid index)
1762 // this function originally written by KrimZon, made shorter by LordHavoc
1767 VM_SAFEPARMCOUNT(1,VM_argv);
1769 token_num = PRVM_G_FLOAT(OFS_PARM0);
1770 if (token_num >= 0 && token_num < num_tokens)
1771 PRVM_G_INT(OFS_RETURN) = PRVM_SetString(tokens[token_num]);
1773 PRVM_G_INT(OFS_RETURN) = PRVM_SetString("");
1777 //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)
1778 void PF_setattachment (void)
1780 edict_t *e = G_EDICT(OFS_PARM0);
1781 edict_t *tagentity = G_EDICT(OFS_PARM1);
1782 char *tagname = G_STRING(OFS_PARM2);
1787 if (tagentity == NULL)
1788 tagentity = sv.edicts;
1790 v = GETEDICTFIELDVALUE(e, eval_tag_entity);
1792 v->edict = EDICT_TO_PROG(tagentity);
1794 v = GETEDICTFIELDVALUE(e, eval_tag_index);
1797 if (tagentity != NULL && tagentity != sv.edicts && tagname && tagname[0])
1799 modelindex = (int)tagentity->v->modelindex;
1800 if (modelindex >= 0 && modelindex < MAX_MODELS)
1802 model = sv.models[modelindex];
1803 if (model->data_overridetagnamesforskin && (unsigned int)tagentity->v->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames)
1804 for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].num_overridetagnames;i++)
1805 if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->v->skin].data_overridetagnames[i].name))
1807 if (v->_float == 0 && model->alias.aliasnum_tags)
1808 for (i = 0;i < model->alias.aliasnum_tags;i++)
1809 if (!strcmp(tagname, model->alias.aliasdata_tags[i].name))
1812 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);
1815 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));
1826 void VM_isserver(void)
1828 VM_SAFEPARMCOUNT(0,VM_serverstate);
1830 PRVM_G_FLOAT(OFS_RETURN) = sv.active;
1840 void VM_clientcount(void)
1842 VM_SAFEPARMCOUNT(0,VM_clientcount);
1844 PRVM_G_FLOAT(OFS_RETURN) = svs.maxclients;
1854 void VM_clientstate(void)
1856 VM_SAFEPARMCOUNT(0,VM_clientstate);
1858 PRVM_G_FLOAT(OFS_RETURN) = cls.state;
1861 void VM_Cmd_Init(void)
1865 void VM_Cmd_Reset(void)
1869 //============================================================================
1872 char *vm_sv_extensions =
1875 prvm_builtin_t vm_sv_builtins[] = {
1876 0 // to be consistent with the old vm
1879 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
1881 void VM_SV_Cmd_Init(void)
1885 void VM_SV_Cmd_Reset(void)
1889 //============================================================================
1892 char *vm_cl_extensions =
1895 prvm_builtin_t vm_cl_builtins[] = {
1896 0 // to be consistent with the old vm
1899 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
1901 void VM_CL_Cmd_Init(void)
1905 void VM_CL_Cmd_Reset(void)
1909 //============================================================================
1912 char *vm_m_extensions =
1915 // void setkeydest(float dest)
1916 void VM_M_SetKeyDest(void)
1918 VM_SAFEPARMCOUNT(1,VM_M_SetKeyDest);
1920 switch((int)PRVM_G_FLOAT(OFS_PARM0))
1924 key_dest = key_game;
1928 key_dest = key_menu;
1932 // key_dest = key_message
1935 PRVM_ERROR("VM_M_SetKeyDest: wrong destination %i !\n",prog->globals[OFS_PARM0]);
1941 // float getkeydest(void)
1942 void VM_M_GetKeyDest(void)
1944 VM_SAFEPARMCOUNT(0,VM_M_GetKeyDest);
1946 // key_game = 0, key_message = 1, key_menu = 2, unknown = 3
1950 PRVM_G_FLOAT(OFS_RETURN) = 0;
1953 PRVM_G_FLOAT(OFS_RETURN) = 2;
1957 // PRVM_G_FLOAT(OFS_RETURN) = 1;
1960 PRVM_G_FLOAT(OFS_RETURN) = 3;
1964 prvm_builtin_t vm_m_builtins[] = {
1965 0, // to be consistent with the old vm
1971 const int vm_m_numbuiltins = sizeof(vm_m_builtins) / sizeof(prvm_builtin_t);
1973 void VM_M_Cmd_Init(void)
1977 void VM_M_Cmd_Reset(void)