DarkPlaces
Game engine based on the Quake 1 engine by id Software, developed by LadyHavoc
 
prvm_cmds.c
Go to the documentation of this file.
1// AK
2// Basically every vm builtin cmd should be in here.
3// All 3 builtin and extension lists can be found here
4// cause large (I think they will) parts are from pr_cmds the same copyright like in pr_cmds
5// also applies here
6
7#include "quakedef.h"
8
9#include "prvm_cmds.h"
10#include "libcurl.h"
11#include <time.h>
12
13#include "cl_collision.h"
14#include "clvm_cmds.h"
15#include "csprogs.h"
16#include "ft2.h"
17#include "mdfour.h"
18
20#ifdef USEODE
21extern dllhandle_t ode_dll;
22#endif
23
24// LadyHavoc: changed this to NOT use a return statement, so that it can be used in functions that must return a value
25void VM_Warning(prvm_prog_t *prog, const char *fmt, ...)
26{
27 va_list argptr;
28 char msg[MAX_INPUTLINE];
29 static double recursive = -1;
30 int outfd = sys.outfd;
31
32 // set output to stderr
33 sys.outfd = fileno(stderr);
34
35 va_start(argptr,fmt);
36 dpvsnprintf(msg,sizeof(msg),fmt,argptr);
37 va_end(argptr);
38
39 Con_Printf(CON_WARN "%s VM warning: %s", prog->name, msg);
40
41 // TODO: either add a cvar/cmd to control the state dumping or replace some of the calls with Con_Printf [9/13/2006 Black]
42 if(prvm_backtraceforwarnings.integer && recursive != host.realtime) // NOTE: this compares to the time, just in case if PRVM_PrintState causes a Host_Error and keeps recursive set
43 {
44 recursive = host.realtime;
45 PRVM_PrintState(prog, 0);
46 recursive = -1;
47 }
48
49 // restore configured outfd
50 sys.outfd = outfd;
51}
52
53
54//============================================================================
55// Common
56
57// TODO DONE: move vm_files and vm_fssearchlist to prvm_prog_t struct
58// TODO: move vm_files and vm_fssearchlist back [9/13/2006 Black]
59// TODO: (move vm_files and vm_fssearchlist to prvm_prog_t struct again) [2007-01-23 LadyHavoc]
60// TODO: will this war ever end? [2007-01-23 LadyHavoc]
61
62void VM_CheckEmptyString(prvm_prog_t *prog, const char *s)
63{
64 if (ISWHITESPACE(s[0]))
65 prog->error_cmd("%s: Bad string", prog->name);
66}
67
68qbool PRVM_ConsoleCommand(prvm_prog_t *prog, const char *text, size_t textlen, int *func, qbool preserve_self, int curself, double ptime, const char *error_message)
69{
70 int restorevm_tempstringsbuf_cursize;
71 int save_self = 0; // hush compiler warning
72 qbool r = false;
73
74 if(!prog->loaded)
75 return false;
76
77 if(func)
78 {
79 if(preserve_self)
80 save_self = PRVM_gameglobaledict(self);
81 if(ptime)
83 PRVM_gameglobaledict(self) = curself;
84 restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
85 PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(prog, text, textlen);
86 prog->ExecuteProgram(prog, *func, error_message);
87 prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
88 if(preserve_self)
89 PRVM_gameglobaledict(self) = save_self;
90 r = (int) PRVM_G_FLOAT(OFS_RETURN) != 0;
91 }
92
93 return r;
94}
95
97{
98 // self.frame is the interpolation target (new frame)
99 // self.frame1time is the animation base time for the interpolation target
100 // self.frame2 is the interpolation start (previous frame)
101 // self.frame2time is the animation base time for the interpolation start
102 // self.lerpfrac is the interpolation strength for self.frame2
103 // self.lerpfrac3 is the interpolation strength for self.frame3
104 // self.lerpfrac4 is the interpolation strength for self.frame4
105 // pitch angle on a player model where the animator set up 5 sets of
106 // animations and the csqc simply lerps between sets)
107 framegroupblend[0].frame = (int) PRVM_gameedictfloat(ed, frame );
108 framegroupblend[1].frame = (int) PRVM_gameedictfloat(ed, frame2 );
109 framegroupblend[2].frame = (int) PRVM_gameedictfloat(ed, frame3 );
110 framegroupblend[3].frame = (int) PRVM_gameedictfloat(ed, frame4 );
111 framegroupblend[0].start = PRVM_gameedictfloat(ed, frame1time);
112 framegroupblend[1].start = PRVM_gameedictfloat(ed, frame2time);
113 framegroupblend[2].start = PRVM_gameedictfloat(ed, frame3time);
114 framegroupblend[3].start = PRVM_gameedictfloat(ed, frame4time);
115 framegroupblend[1].lerp = PRVM_gameedictfloat(ed, lerpfrac );
116 framegroupblend[2].lerp = PRVM_gameedictfloat(ed, lerpfrac3 );
117 framegroupblend[3].lerp = PRVM_gameedictfloat(ed, lerpfrac4 );
118 // assume that the (missing) lerpfrac1 is whatever remains after lerpfrac2+lerpfrac3+lerpfrac4 are summed
119 framegroupblend[0].lerp = 1 - framegroupblend[1].lerp - framegroupblend[2].lerp - framegroupblend[3].lerp;
120}
121
122// LadyHavoc: quite tempting to break apart this function to reuse the
123// duplicated code, but I suspect it is better for performance
124// this way
125void VM_FrameBlendFromFrameGroupBlend(frameblend_t *frameblend, const framegroupblend_t *framegroupblend, const model_t *model, double curtime)
126{
127 int sub2, numframes, f, i, k;
128 int isfirstframegroup = true;
129 int nolerp;
130 double sublerp, lerp, d;
131 const animscene_t *scene;
132 const framegroupblend_t *g;
133 frameblend_t *blend = frameblend;
134
135 memset(blend, 0, MAX_FRAMEBLENDS * sizeof(*blend));
136
137 // rpolzer: Not testing isanimated here - a model might have
138 // "animations" that move no vertices (but only bones), thus rendering
139 // may assume it's not animated while processing can't.
140 if (!model)
141 {
142 blend[0].lerp = 1;
143 return;
144 }
145
146 nolerp = ((model->type == mod_sprite) ? !r_lerpsprites.integer : !r_lerpmodels.integer) || (model->nolerp == true);
147 numframes = model->numframes;
148 for (k = 0, g = framegroupblend;k < MAX_FRAMEGROUPBLENDS;k++, g++)
149 {
150 f = g->frame;
151 if ((unsigned int)f >= (unsigned int)numframes)
152 {
154 Con_DPrintf("VM_FrameBlendFromFrameGroupBlend: no such frame %d in model %s\n", f, model->name);
155 f = 0;
156 }
157 d = lerp = g->lerp;
158 if (lerp <= 0)
159 continue;
160 if (nolerp)
161 {
162 if (isfirstframegroup)
163 {
164 d = lerp = 1;
165 isfirstframegroup = false;
166 }
167 else
168 continue;
169 }
170 if (model->animscenes)
171 {
172 scene = model->animscenes + f;
173 f = scene->firstframe;
174 if (scene->framecount > 1)
175 {
176 // this code path is only used on .zym models and torches
177 sublerp = scene->framerate * (curtime - g->start);
178 f = (int) floor(sublerp);
179 sublerp -= f;
180 sub2 = f + 1;
181 if (sublerp < (1.0 / 65536.0f))
182 sublerp = 0;
183 if (sublerp > (65535.0f / 65536.0f))
184 sublerp = 1;
185 if (nolerp)
186 sublerp = 0;
187 if (scene->loop)
188 {
189 f = (f % scene->framecount);
190 sub2 = (sub2 % scene->framecount);
191 }
192 f = bound(0, f, (scene->framecount - 1)) + scene->firstframe;
193 sub2 = bound(0, sub2, (scene->framecount - 1)) + scene->firstframe;
194 d = sublerp * lerp;
195 // two framelerps produced from one animation
196 if (d > 0)
197 {
198 for (i = 0;i < MAX_FRAMEBLENDS;i++)
199 {
200 if (blend[i].lerp <= 0 || blend[i].subframe == sub2)
201 {
202 blend[i].subframe = sub2;
203 blend[i].lerp += d;
204 break;
205 }
206 }
207 }
208 d = (1 - sublerp) * lerp;
209 }
210 }
211 if (d > 0)
212 {
213 for (i = 0;i < MAX_FRAMEBLENDS;i++)
214 {
215 if (blend[i].lerp <= 0 || blend[i].subframe == f)
216 {
217 blend[i].subframe = f;
218 blend[i].lerp += d;
219 break;
220 }
221 }
222 }
223 }
224}
225
226void VM_UpdateEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed, const model_t *edmodel, const frameblend_t *frameblend)
227{
228 if (ed->priv.server->skeleton.model != edmodel)
229 {
230 VM_RemoveEdictSkeleton(prog, ed);
231 ed->priv.server->skeleton.model = edmodel;
232 }
233 if (!ed->priv.server->skeleton.model || !ed->priv.server->skeleton.model->num_bones)
234 {
235 if(ed->priv.server->skeleton.relativetransforms)
236 Mem_Free(ed->priv.server->skeleton.relativetransforms);
237 ed->priv.server->skeleton.relativetransforms = NULL;
238 return;
239 }
240
241 {
242 int skeletonindex = -1;
243 skeleton_t *skeleton;
245 if (skeletonindex >= 0 && skeletonindex < MAX_EDICTS && (skeleton = prog->skeletons[skeletonindex]) && skeleton->model->num_bones == ed->priv.server->skeleton.model->num_bones)
246 {
247 // custom skeleton controlled by the game (FTE_CSQC_SKELETONOBJECTS)
248 if (!ed->priv.server->skeleton.relativetransforms)
249 ed->priv.server->skeleton.relativetransforms = (matrix4x4_t *)Mem_Alloc(prog->progs_mempool, ed->priv.server->skeleton.model->num_bones * sizeof(matrix4x4_t));
250 memcpy(ed->priv.server->skeleton.relativetransforms, skeleton->relativetransforms, ed->priv.server->skeleton.model->num_bones * sizeof(matrix4x4_t));
251 }
252 else
253 {
254 if(ed->priv.server->skeleton.relativetransforms)
255 Mem_Free(ed->priv.server->skeleton.relativetransforms);
256 ed->priv.server->skeleton.relativetransforms = NULL;
257 }
258 }
259}
260
262{
263 if (ed->priv.server->skeleton.relativetransforms)
264 Mem_Free(ed->priv.server->skeleton.relativetransforms);
265 memset(&ed->priv.server->skeleton, 0, sizeof(ed->priv.server->skeleton));
266}
267
268
269
270
271//============================================================================
272//BUILT-IN FUNCTIONS
273
274#ifdef WIN32
275 // memccpy() is standard in POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD, C23.
276 // Microsoft supports it, but apparently complains if we use it.
277 #undef memccpy
278 #define memccpy _memccpy
279#endif
280size_t VM_VarString(prvm_prog_t *prog, int first, char *out, size_t outsize)
281{
282 int i;
283 const char *s;
284 char *p;
285 char *outend = out + outsize - 1;
286
287 // bones_was_here: && out < outend improves perf significantly in some tests that don't trigger the warning,
288 // which seems odd, surely it would only help when the warning is printed?
289 for (i = first;i < prog->argc && out < outend;i++)
290 {
291 s = PRVM_G_STRING((OFS_PARM0+i*3));
292 if (*s)
293 {
294 // like dp_stpecpy but with a VM_Warning for use with `prvm_backtraceforwarnings 1`
295 p = (char *)memccpy(out, s, '\0', (outend + 1) - out);
296 if (p)
297 out = p - 1;
298 else
299 {
300 VM_Warning(prog, "%lu of %lu bytes available, will truncate %lu byte string \"%s\"\n", (unsigned long)(outend - out), (unsigned long)outsize - 1, (unsigned long)strlen(s), s);
301 out = outend;
302 *out = '\0';
303 }
304 }
305 else
306 *out = '\0';
307 }
308
309 return outsize - ((outend + 1) - out);
310}
311
312/*
313=================
314VM_checkextension
315
316returns true if the extension is supported by the server
317
318checkextension(extensionname)
319=================
320*/
321
322// kind of helper function
323static qbool checkextension(prvm_prog_t *prog, const char *name)
324{
325 const char **e;
326
327 for (e = prog->extensionstring;*e;e++)
328 {
329 if(!strcasecmp(*e, name))
330 {
331#ifdef USEODE
332 // special sheck for ODE
333 if (!strncasecmp("DP_PHYSICS_ODE", name, 14))
334 {
335#ifndef LINK_TO_LIBODE
336 return ode_dll ? true : false;
337#else
338#ifdef LINK_TO_LIBODE
339 return true;
340#else
341 return false;
342#endif
343#endif
344 }
345#endif
346
347 // special sheck for d0_blind_id
348 if (!strcasecmp("DP_CRYPTO", name))
349 return Crypto_Available();
350 if (!strcasecmp("DP_QC_DIGEST_SHA256", name))
351 return Crypto_Available();
352
353 // special shreck for libcurl
354 if (!strcasecmp("DP_QC_URI_GET", name) || !strcasecmp("DP_QC_URI_POST", name))
355 return Curl_Available();
356
357 return true;
358 }
359 }
360 return false;
361}
362
369
370/*
371=================
372VM_error
373
374This is a TERMINAL error, which will kill off the entire prog.
375Dumps self.
376
377error(value)
378=================
379*/
381{
382 prvm_edict_t *ed;
383 char string[VM_TEMPSTRING_MAXSIZE];
384
385 VM_VarString(prog, 0, string, sizeof(string));
386 Con_Printf(CON_ERROR "======%s ERROR in %s:\n%s\n", prog->name, PRVM_GetString(prog, prog->xfunction->s_name), string);
388 PRVM_ED_Print(prog, ed, NULL);
389
390 prog->error_cmd("%s: Program error in function %s:\n%s\nTip: read above for entity information\n", prog->name, PRVM_GetString(prog, prog->xfunction->s_name), string);
391}
392
393/*
394=================
395VM_objerror
396
397Dumps out self, then an error message. The program is aborted and self is
398removed, but the level can continue.
399
400objerror(value)
401=================
402*/
404{
405 prvm_edict_t *ed;
406 char string[VM_TEMPSTRING_MAXSIZE];
407
408 VM_VarString(prog, 0, string, sizeof(string));
409 Con_Printf(CON_ERROR "======OBJECT ERROR======\n"); // , prog->name, PRVM_GetString(prog->xfunction->s_name), string); // or include them? FIXME
411 PRVM_ED_Print(prog, ed, NULL);
412 PRVM_ED_Free (prog, ed);
413 Con_Printf(CON_ERROR "%s OBJECT ERROR in %s:\n%s\nTip: read above for entity information\n", prog->name, PRVM_GetString(prog, prog->xfunction->s_name), string);
414}
415
416/*
417=================
418VM_print
419
420print to console
421
422print(...[string])
423=================
424*/
426{
427 char string[VM_TEMPSTRING_MAXSIZE];
428
429 VM_VarString(prog, 0, string, sizeof(string));
430 Con_Print(string);
431}
432
433/*
434=================
435VM_bprint
436
437broadcast print to everyone on server
438
439bprint(...[string])
440=================
441*/
443{
444 char string[VM_TEMPSTRING_MAXSIZE];
445
446 if(!sv.active)
447 {
448 VM_Warning(prog, "VM_bprint: server is not active!\n");
449 return;
450 }
451
452 VM_VarString(prog, 0, string, sizeof(string));
453 SV_BroadcastPrint(string);
454}
455
456/*
457=================
458VM_sprint (menu & client but only if server.active == true)
459
460single print to a specific client
461
462sprint(float clientnum,...[string])
463=================
464*/
466{
467 client_t *client;
468 int clientnum;
469 char string[VM_TEMPSTRING_MAXSIZE];
470
472
473 //find client for this entity
474 clientnum = (int)PRVM_G_FLOAT(OFS_PARM0);
475 if (!sv.active || clientnum < 0 || clientnum >= svs.maxclients || !svs.clients[clientnum].active)
476 {
477 VM_Warning(prog, "VM_sprint: invalid client or server is not active!\n");
478 return;
479 }
480
481 client = svs.clients + clientnum;
482 if (!client->netconnection)
483 return;
484
485 VM_VarString(prog, 1, string, sizeof(string));
487 MSG_WriteString(&client->netconnection->message, string);
488}
489
490/*
491=================
492VM_centerprint
493
494single print to the screen
495
496centerprint(value)
497=================
498*/
500{
501 char string[VM_TEMPSTRING_MAXSIZE];
502
504 VM_VarString(prog, 0, string, sizeof(string));
505 SCR_CenterPrint(string);
506}
507
508/*
509=================
510VM_normalize
511
512vector normalize(vector)
513=================
514*/
516{
517 prvm_vec_t *value1;
518 vec3_t newvalue;
519 double f;
520
522
523 value1 = PRVM_G_VECTOR(OFS_PARM0);
524
525 f = VectorLength2(value1);
526 if (f)
527 {
528 f = 1.0 / sqrt(f);
529 VectorScale(value1, f, newvalue);
530 }
531 else
532 VectorClear(newvalue);
533
535}
536
537/*
538=================
539VM_vlen
540
541scalar vlen(vector)
542=================
543*/
549
550/*
551=================
552VM_vectoyaw
553
554float vectoyaw(vector)
555=================
556*/
558{
559 prvm_vec_t *value1;
560 prvm_vec_t yaw;
561
563
564 value1 = PRVM_G_VECTOR(OFS_PARM0);
565
566 if (value1[1] == 0 && value1[0] == 0)
567 yaw = 0;
568 else
569 {
570 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
571 if (yaw < 0)
572 yaw += 360;
573 }
574
576}
577
578
579/*
580=================
581VM_vectoangles
582
583vector vectoangles(vector[, vector])
584=================
585*/
587{
588 vec3_t result, forward, up;
590
592 if (prog->argc >= 2)
593 {
595 AnglesFromVectors(result, forward, up, true);
596 }
597 else
598 AnglesFromVectors(result, forward, NULL, true);
600}
601
602/*
603=================
604VM_random
605
606Returns a random number > 0 and < 1
607
608float random()
609=================
610*/
612{
614
616}
617
618/*
619=========
620VM_localsound
621
622localsound(string sample, float chan, float vol)
623=========
624*/
626{
627 const char *s;
628 float chan, vol;
629
631
633 if(prog->argc == 3)
634 {
635 chan = PRVM_G_FLOAT(OFS_PARM1);
636 vol = PRVM_G_FLOAT(OFS_PARM2) == 0 ? 1 : PRVM_G_FLOAT(OFS_PARM2);
637 if(!S_LocalSoundEx(s, chan, vol))
638 {
640 VM_Warning(prog, "VM_localsound: Failed to play %s !\n", s);
641 return;
642 }
643 }
644 else if(!S_LocalSound (s))
645 {
647 VM_Warning(prog, "VM_localsound: Failed to play %s !\n", s);
648 return;
649 }
650
652}
653
654/*
655=================
656VM_break
657
658break()
659=================
660*/
662{
663 prog->error_cmd("%s: break statement", prog->name);
664}
665
666//============================================================================
667
668/*
669=================
670VM_localcmd
671
672Appends text to the command buffer
673
674[localcmd (string, ...) or]
675cmd (string, ...)
676=================
677*/
679{
680 char string[VM_TEMPSTRING_MAXSIZE];
682 VM_VarString(prog, 0, string, sizeof(string));
683 Cbuf_AddText(cmd_local, string);
684}
685
686static qbool PRVM_Cvar_ReadOk(prvm_prog_t *prog, const char *string)
687{
688 cvar_t *cvar;
689 cvar = Cvar_FindVar(prog->console_cmd->cvars, string, prog->console_cmd->cvars_flagsmask);
690 return ((cvar) && ((cvar->flags & CF_PRIVATE) == 0));
691}
692
693/*
694=================
695VM_cvar
696
697float cvar (string)
698=================
699*/
701{
702 char string[VM_TEMPSTRING_MAXSIZE];
704 VM_VarString(prog, 0, string, sizeof(string));
705 VM_CheckEmptyString(prog, string);
706 PRVM_G_FLOAT(OFS_RETURN) = PRVM_Cvar_ReadOk(prog, string) ? Cvar_VariableValue(prog->console_cmd->cvars, string, prog->console_cmd->cvars_flagsmask) : 0;
707}
708
709/*
710=================
711VM_cvar
712
713float cvar_type (string)
714float CVAR_TYPEFLAG_EXISTS = 1;
715float CVAR_TYPEFLAG_SAVED = 2;
716float CVAR_TYPEFLAG_PRIVATE = 4;
717float CVAR_TYPEFLAG_ENGINE = 8;
718float CVAR_TYPEFLAG_HASDESCRIPTION = 16;
719float CVAR_TYPEFLAG_READONLY = 32;
720=================
721*/
723{
724 char string[VM_TEMPSTRING_MAXSIZE];
725 cvar_t *cvar;
726 int ret;
727
729 VM_VarString(prog, 0, string, sizeof(string));
730 VM_CheckEmptyString(prog, string);
731 cvar = Cvar_FindVar(prog->console_cmd->cvars, string, prog->console_cmd->cvars_flagsmask);
732
733
734 if(!cvar)
735 {
737 return; // CVAR_TYPE_NONE
738 }
739
740 ret = 1; // CVAR_EXISTS
741 if(cvar->flags & CF_ARCHIVE)
742 ret |= 2; // CVAR_TYPE_SAVED
743 if(cvar->flags & CF_PRIVATE)
744 ret |= 4; // CVAR_TYPE_PRIVATE
745 if(!(cvar->flags & CF_ALLOCATED))
746 ret |= 8; // CVAR_TYPE_ENGINE
747 if(cvar->description != cvar_dummy_description)
748 ret |= 16; // CVAR_TYPE_HASDESCRIPTION
749 if(cvar->flags & CF_READONLY)
750 ret |= 32; // CVAR_TYPE_READONLY
751
753}
754
755/*
756=================
757VM_cvar_string
758
759const string VM_cvar_string (string, ...)
760=================
761*/
763{
764 char cvar_name[VM_TEMPSTRING_MAXSIZE];
765
767 VM_VarString(prog, 0, cvar_name, sizeof(cvar_name));
768 VM_CheckEmptyString(prog, cvar_name);
769 if (PRVM_Cvar_ReadOk(prog, cvar_name))
770 {
771 const char *cvar_string = Cvar_VariableString(prog->console_cmd->cvars, cvar_name, prog->console_cmd->cvars_flagsmask);
773 }
774 else
776}
777
778
779/*
780========================
781VM_cvar_defstring
782
783const string VM_cvar_defstring (string, ...)
784========================
785*/
787{
788 char cvar_name[VM_TEMPSTRING_MAXSIZE];
789 const char *cvar_defstring;
790
792 VM_VarString(prog, 0, cvar_name, sizeof(cvar_name));
793 VM_CheckEmptyString(prog, cvar_name);
794 cvar_defstring = Cvar_VariableDefString(prog->console_cmd->cvars, cvar_name, prog->console_cmd->cvars_flagsmask);
796}
797
798/*
799========================
800VM_cvar_defstring
801
802const string VM_cvar_description (string, ...)
803========================
804*/
806{
807 char cvar_name[VM_TEMPSTRING_MAXSIZE];
808 const char *cvar_desc;
809
811 VM_VarString(prog, 0, cvar_name, sizeof(cvar_name));
812 VM_CheckEmptyString(prog, cvar_name);
813 cvar_desc = Cvar_VariableDescription(prog->console_cmd->cvars, cvar_name, prog->console_cmd->cvars_flagsmask);
814 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, cvar_desc, strlen(cvar_desc));
815}
816/*
817=================
818VM_cvar_set
819
820void cvar_set (string,string, ...)
821=================
822*/
824{
825 const char *name;
827 cvar_t *cvar;
828
832 cvar = Cvar_FindVar(prog->console_cmd->cvars, name, prog->console_cmd->cvars_flagsmask);
833 if (!cvar)
834 {
835 VM_Warning(prog, "VM_cvar_set: variable %s not found\n", name);
836 return;
837 }
838 if (cvar->flags & CF_READONLY)
839 {
840 VM_Warning(prog, "VM_cvar_set: variable %s is read-only\n", cvar->name);
841 return;
842 }
843 VM_VarString(prog, 1, value, sizeof(value));
845}
846
847/*
848=========
849VM_dprint
850
851dprint(...[string])
852=========
853*/
855{
856 char string[VM_TEMPSTRING_MAXSIZE];
858 VM_VarString(prog, 0, string, sizeof(string));
859#if 1
860 Con_DPrintf("%s", string);
861#else
862 Con_DPrintf("%s: %s", prog->name, string);
863#endif
864}
865
866/*
867=========
868VM_ftos
869
870string ftos(float)
871=========
872*/
873
875{
877 char s[128];
878 size_t slen;
879
881
883
884 if ((prvm_vec_t)((prvm_int_t)v) == v)
885 slen = dpsnprintf(s, sizeof(s), "%.0f", v);
886 else
887 slen = dpsnprintf(s, sizeof(s), "%f", v);
888 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s, slen);
889}
890
891/*
892=========
893VM_fabs
894
895float fabs(float)
896=========
897*/
898
900{
902
904
907}
908
909/*
910=========
911VM_vtos
912
913string vtos(vector)
914=========
915*/
916
918{
919 char s[512];
920 size_t slen;
921
923
924 slen = dpsnprintf(s, sizeof(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]);
925 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s, slen);
926}
927
928/*
929=========
930VM_etos
931
932string etos(entity)
933=========
934*/
935
937{
938 char s[128];
939 size_t slen;
940
942
943 slen = dpsnprintf(s, sizeof(s), "entity %i", PRVM_G_EDICTNUM(OFS_PARM0));
944 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s, slen);
945}
946
947/*
948=========
949VM_stof
950
951float stof(...[string])
952=========
953*/
955{
956 char string[VM_TEMPSTRING_MAXSIZE];
958 VM_VarString(prog, 0, string, sizeof(string));
959 PRVM_G_FLOAT(OFS_RETURN) = atof(string);
960}
961
962/*
963========================
964VM_itof
965
966float itof(int ent)
967========================
968*/
974
975/*
976========================
977VM_ftoe
978
979entity ftoe(float num)
980========================
981*/
983{
984 prvm_int_t ent;
986
988 if (ent < 0 || ent >= prog->max_edicts || PRVM_PROG_TO_EDICT(ent)->free)
989 ent = 0; // return world instead of a free or invalid entity
990
991 PRVM_G_INT(OFS_RETURN) = ent;
992}
993
994/*
995========================
996VM_etof
997
998float etof(entity ent)
999========================
1000*/
1006
1007/*
1008=========
1009VM_strftime
1010
1011string strftime(float uselocaltime, string[, string ...])
1012=========
1013*/
1015{
1016 time_t t;
1017#if _MSC_VER >= 1400
1018 struct tm tm;
1019 int tmresult;
1020#else
1021 struct tm *tm;
1022#endif
1023 char fmt[VM_TEMPSTRING_MAXSIZE];
1024 char result[VM_TEMPSTRING_MAXSIZE];
1025 size_t result_len;
1026
1028 VM_VarString(prog, 1, fmt, sizeof(fmt));
1029 t = time(NULL);
1030#if _MSC_VER >= 1400
1032 tmresult = localtime_s(&tm, &t);
1033 else
1034 tmresult = gmtime_s(&tm, &t);
1035 if (!tmresult)
1036#else
1038 tm = localtime(&t);
1039 else
1040 tm = gmtime(&t);
1041 if (!tm)
1042#endif
1043 {
1045 return;
1046 }
1047#if _MSC_VER >= 1400
1048 result_len = strftime(result, sizeof(result), fmt, &tm);
1049#else
1050 result_len = strftime(result, sizeof(result), fmt, tm);
1051#endif
1052 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, result, result_len);
1053}
1054
1055/*
1056=========
1057VM_spawn
1058
1059entity spawn()
1060=========
1061*/
1062
1064{
1065 prvm_edict_t *ed;
1067 prog->xfunction->builtinsprofile += 20;
1068 ed = PRVM_ED_Alloc(prog);
1069 VM_RETURN_EDICT(ed);
1070}
1071
1072/*
1073=========
1074VM_remove
1075
1076remove(entity e)
1077=========
1078*/
1079
1081{
1082 prvm_edict_t *ed;
1083 prog->xfunction->builtinsprofile += 20;
1084
1086
1087 ed = PRVM_G_EDICT(OFS_PARM0);
1088 if( PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
1089 {
1090 if (developer.integer > 0)
1091 VM_Warning(prog, "VM_remove: tried to remove the null entity or a reserved entity!\n" );
1092 }
1093 else if( ed->free )
1094 {
1095 if (developer.integer > 0)
1096 VM_Warning(prog, "VM_remove: tried to remove an already freed entity!\n" );
1097 }
1098 else
1099 PRVM_ED_Free (prog, ed);
1100}
1101
1102/*
1103=========
1104VM_find
1105
1106entity find(entity start, .string field, string match)
1107=========
1108*/
1109
1111{
1112 int e;
1113 int f;
1114 const char *s, *t;
1115 prvm_edict_t *ed;
1116
1118
1122
1123 // LadyHavoc: apparently BloodMage does a find(world, weaponmodel, "") and
1124 // expects it to find all the monsters, so we must be careful to support
1125 // searching for ""
1126
1127 for (e++ ; e < prog->num_edicts ; e++)
1128 {
1129 prog->xfunction->builtinsprofile++;
1130 ed = PRVM_EDICT_NUM(e);
1131 if (ed->free)
1132 continue;
1133 t = PRVM_E_STRING(ed,f);
1134 if (!t)
1135 t = "";
1136 if (!strcmp(t,s))
1137 {
1138 VM_RETURN_EDICT(ed);
1139 return;
1140 }
1141 }
1142
1143 VM_RETURN_EDICT(prog->edicts);
1144}
1145
1146/*
1147=========
1148VM_findfloat
1149
1150 entity findfloat(entity start, .float field, float match)
1151 entity findentity(entity start, .entity field, entity match)
1152=========
1153*/
1154// LadyHavoc: added this for searching float, int, and entity reference fields
1156{
1157 int e;
1158 int f;
1159 prvm_vec_t s;
1160 prvm_edict_t *ed;
1161
1163
1167
1168 for (e++ ; e < prog->num_edicts ; e++)
1169 {
1170 prog->xfunction->builtinsprofile++;
1171 ed = PRVM_EDICT_NUM(e);
1172 if (ed->free)
1173 continue;
1174 if (PRVM_E_FLOAT(ed,f) == s)
1175 {
1176 VM_RETURN_EDICT(ed);
1177 return;
1178 }
1179 }
1180
1181 VM_RETURN_EDICT(prog->edicts);
1182}
1183
1184/*
1185=========
1186VM_findchain
1187
1188entity findchain(.string field, string match)
1189=========
1190*/
1191// chained search for strings in entity fields
1192// entity(.string field, string match) findchain = #402;
1194{
1195 int i;
1196 int f;
1197 const char *s, *t;
1198 prvm_edict_t *ent, *chain;
1199 int chainfield;
1200
1202
1203 if(prog->argc == 3)
1204 chainfield = PRVM_G_INT(OFS_PARM2);
1205 else
1206 chainfield = prog->fieldoffsets.chain;
1207 if (chainfield < 0)
1208 prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
1209
1210 chain = prog->edicts;
1211
1214
1215 // LadyHavoc: apparently BloodMage does a find(world, weaponmodel, "") and
1216 // expects it to find all the monsters, so we must be careful to support
1217 // searching for ""
1218
1219 ent = PRVM_NEXT_EDICT(prog->edicts);
1220 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
1221 {
1222 prog->xfunction->builtinsprofile++;
1223 if (ent->free)
1224 continue;
1225 t = PRVM_E_STRING(ent,f);
1226 if (!t)
1227 t = "";
1228 if (strcmp(t,s))
1229 continue;
1230
1232 chain = ent;
1233 }
1234
1236}
1237
1238/*
1239=========
1240VM_findchainfloat
1241
1242entity findchainfloat(.string field, float match)
1243entity findchainentity(.string field, entity match)
1244=========
1245*/
1246// LadyHavoc: chained search for float, int, and entity reference fields
1247// entity(.string field, float match) findchainfloat = #403;
1249{
1250 int i;
1251 int f;
1252 prvm_vec_t s;
1253 prvm_edict_t *ent, *chain;
1254 int chainfield;
1255
1257
1258 if(prog->argc == 3)
1259 chainfield = PRVM_G_INT(OFS_PARM2);
1260 else
1261 chainfield = prog->fieldoffsets.chain;
1262 if (chainfield < 0)
1263 prog->error_cmd("VM_findchainfloat: %s doesnt have the specified chain field !", prog->name);
1264
1265 chain = (prvm_edict_t *)prog->edicts;
1266
1269
1270 ent = PRVM_NEXT_EDICT(prog->edicts);
1271 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
1272 {
1273 prog->xfunction->builtinsprofile++;
1274 if (ent->free)
1275 continue;
1276 if (PRVM_E_FLOAT(ent,f) != s)
1277 continue;
1278
1280 chain = ent;
1281 }
1282
1284}
1285
1286/*
1287========================
1288VM_findflags
1289
1290entity findflags(entity start, .float field, float match)
1291========================
1292*/
1293// LadyHavoc: search for flags in float fields
1295{
1296 prvm_int_t e;
1297 prvm_int_t f;
1298 prvm_int_t s;
1299 prvm_edict_t *ed;
1300
1302
1303
1307
1308 for (e++ ; e < prog->num_edicts ; e++)
1309 {
1310 prog->xfunction->builtinsprofile++;
1311 ed = PRVM_EDICT_NUM(e);
1312 if (ed->free)
1313 continue;
1314 if (!PRVM_E_FLOAT(ed,f))
1315 continue;
1316 if ((prvm_int_t)PRVM_E_FLOAT(ed,f) & s)
1317 {
1318 VM_RETURN_EDICT(ed);
1319 return;
1320 }
1321 }
1322
1323 VM_RETURN_EDICT(prog->edicts);
1324}
1325
1326/*
1327========================
1328VM_findchainflags
1329
1330entity findchainflags(.float field, float match)
1331========================
1332*/
1333// LadyHavoc: chained search for flags in float fields
1335{
1336 prvm_int_t i;
1337 prvm_int_t f;
1338 prvm_int_t s;
1339 prvm_edict_t *ent, *chain;
1340 int chainfield;
1341
1343
1344 if(prog->argc == 3)
1345 chainfield = PRVM_G_INT(OFS_PARM2);
1346 else
1347 chainfield = prog->fieldoffsets.chain;
1348 if (chainfield < 0)
1349 prog->error_cmd("VM_findchainflags: %s doesnt have the specified chain field !", prog->name);
1350
1351 chain = (prvm_edict_t *)prog->edicts;
1352
1355
1356 ent = PRVM_NEXT_EDICT(prog->edicts);
1357 for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
1358 {
1359 prog->xfunction->builtinsprofile++;
1360 if (ent->free)
1361 continue;
1362 if (!PRVM_E_FLOAT(ent,f))
1363 continue;
1364 if (!((prvm_int_t)PRVM_E_FLOAT(ent,f) & s))
1365 continue;
1366
1368 chain = ent;
1369 }
1370
1372}
1373
1374/*
1375=========
1376VM_precache_sound
1377
1378string precache_sound (string sample)
1379=========
1380*/
1382{
1383 const char *s;
1384
1386
1389 //VM_CheckEmptyString(prog, s);
1390
1391 if(snd_initialized.integer && !S_PrecacheSound(s, true, true))
1392 {
1393 VM_Warning(prog, "VM_precache_sound: Failed to load %s !\n", s);
1394 return;
1395 }
1396}
1397
1398/*
1399=================
1400VM_precache_file
1401
1402returns the same string as output
1403
1404does nothing, only used by qcc to build .pak archives
1405=================
1406*/
1408{
1410 // precache_file is only used to copy files with qcc, it does nothing
1412}
1413
1414/*
1415=========
1416VM_coredump
1417
1418coredump()
1419=========
1420*/
1422{
1424
1425 Cbuf_AddText(cmd_local, "prvm_edicts ");
1426 Cbuf_AddText(cmd_local, prog->name);
1427 Cbuf_AddText(cmd_local, "\n");
1428}
1429
1430/*
1431=========
1432VM_stackdump
1433
1434stackdump()
1435=========
1436*/
1438{
1440
1441 PRVM_StackTrace(prog);
1442}
1443
1444/*
1445=========
1446VM_crash
1447
1448crash()
1449=========
1450*/
1451
1453{
1455
1456 prog->error_cmd("Crash called by %s",prog->name);
1457}
1458
1459/*
1460=========
1461VM_traceon
1462
1463traceon()
1464=========
1465*/
1467{
1469
1470 prog->trace = true;
1471}
1472
1473/*
1474=========
1475VM_traceoff
1476
1477traceoff()
1478=========
1479*/
1481{
1483
1484 prog->trace = false;
1485}
1486
1487/*
1488=========
1489VM_eprint
1490
1491eprint(entity e)
1492=========
1493*/
1500
1501/*
1502=========
1503VM_rint
1504
1505float rint(float)
1506=========
1507*/
1509{
1510 prvm_vec_t f;
1512
1514 if (f > 0)
1515 PRVM_G_FLOAT(OFS_RETURN) = floor(f + 0.5);
1516 else
1517 PRVM_G_FLOAT(OFS_RETURN) = ceil(f - 0.5);
1518}
1519
1520/*
1521=========
1522VM_floor
1523
1524float floor(float)
1525=========
1526*/
1533
1534/*
1535=========
1536VM_ceil
1537
1538float ceil(float)
1539=========
1540*/
1547
1548
1549/*
1550=============
1551VM_nextent
1552
1553entity nextent(entity)
1554=============
1555*/
1557{
1558 int i;
1559 prvm_edict_t *ent;
1560
1562
1564 while (1)
1565 {
1566 prog->xfunction->builtinsprofile++;
1567 i++;
1568 if (i == prog->num_edicts)
1569 {
1570 VM_RETURN_EDICT(prog->edicts);
1571 return;
1572 }
1573 ent = PRVM_EDICT_NUM(i);
1574 if (!ent->free)
1575 {
1576 VM_RETURN_EDICT(ent);
1577 return;
1578 }
1579 }
1580}
1581
1582//=============================================================================
1583
1584/*
1585==============
1586VM_changelevel
1587server and menu
1588
1589changelevel(string map)
1590==============
1591*/
1593{
1594 char vabuf[1024];
1596
1597 if(!sv.active)
1598 {
1599 VM_Warning(prog, "VM_changelevel: server is not active!\n");
1600 return;
1601 }
1602
1603// make sure we don't issue two changelevels
1605 return;
1606 svs.changelevel_issued = true;
1607
1608 Cbuf_AddText(cmd_local, va(vabuf, sizeof(vabuf), "changelevel %s\n", PRVM_G_STRING(OFS_PARM0)));
1609}
1610
1611/*
1612=========
1613VM_sin
1614
1615float sin(float)
1616=========
1617*/
1623
1624/*
1625=========
1626VM_cos
1627float cos(float)
1628=========
1629*/
1635
1636/*
1637=========
1638VM_sqrt
1639
1640float sqrt(float)
1641=========
1642*/
1648
1649/*
1650=========
1651VM_asin
1652
1653float asin(float)
1654=========
1655*/
1661
1662/*
1663=========
1664VM_acos
1665float acos(float)
1666=========
1667*/
1673
1674/*
1675=========
1676VM_atan
1677float atan(float)
1678=========
1679*/
1685
1686/*
1687=========
1688VM_atan2
1689float atan2(float,float)
1690=========
1691*/
1697
1698/*
1699=========
1700VM_tan
1701float tan(float)
1702=========
1703*/
1709
1710/*
1711=================
1712VM_randomvec
1713
1714Returns a vector of length < 1 and > 0
1715
1716vector randomvec()
1717=================
1718*/
1720{
1721 vec3_t temp;
1723 VectorRandom(temp);
1725}
1726
1727//=============================================================================
1728
1729/*
1730=========
1731VM_registercvar
1732
1733float registercvar (string name, string value[, float flags])
1734=========
1735*/
1737{
1738 const char *name, *value;
1739 unsigned flags;
1740
1742
1745 flags = prog->argc >= 3 ? (int)PRVM_G_FLOAT(OFS_PARM2) : 0;
1747
1748 if(flags > CF_MAXFLAGSVAL)
1749 return;
1750
1751// first check to see if it has already been defined
1752 if (Cvar_FindVar (prog->console_cmd->cvars, name, prog->console_cmd->cvars_flagsmask))
1753 return;
1754
1755// check for overlap with a command
1757 {
1758 VM_Warning(prog, "VM_registercvar: %s is a command\n", name);
1759 return;
1760 }
1761
1762 Cvar_Get(prog->console_cmd->cvars, name, value, prog->console_cmd->cvars_flagsmask | flags, NULL);
1763
1764 PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1765}
1766
1767
1768/*
1769=================
1770VM_min
1771
1772returns the minimum of two supplied floats
1773
1774float min(float a, float b, ...[float])
1775=================
1776*/
1778{
1780 // LadyHavoc: 3+ argument enhancement suggested by FrikaC
1781 if (prog->argc >= 3)
1782 {
1783 int i;
1784 float f = PRVM_G_FLOAT(OFS_PARM0);
1785 for (i = 1;i < prog->argc;i++)
1786 if (f > PRVM_G_FLOAT((OFS_PARM0+i*3)))
1787 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1789 }
1790 else
1792}
1793
1794/*
1795=================
1796VM_max
1797
1798returns the maximum of two supplied floats
1799
1800float max(float a, float b, ...[float])
1801=================
1802*/
1804{
1806 // LadyHavoc: 3+ argument enhancement suggested by FrikaC
1807 if (prog->argc >= 3)
1808 {
1809 int i;
1810 float f = PRVM_G_FLOAT(OFS_PARM0);
1811 for (i = 1;i < prog->argc;i++)
1812 if (f < PRVM_G_FLOAT((OFS_PARM0+i*3)))
1813 f = PRVM_G_FLOAT((OFS_PARM0+i*3));
1815 }
1816 else
1818}
1819
1820/*
1821=================
1822VM_bound
1823
1824returns number bounded by supplied range
1825
1826float bound(float min, float value, float max)
1827=================
1828*/
1834
1835/*
1836=================
1837VM_pow
1838
1839returns a raised to power b
1840
1841float pow(float a, float b)
1842=================
1843*/
1849
1855
1857{
1858 int i;
1859 for (i = 0;i < PRVM_MAX_OPENFILES;i++)
1860 prog->openfiles[i] = NULL;
1861}
1862
1864{
1865 int i;
1866 for (i = 0;i < PRVM_MAX_OPENFILES;i++)
1867 {
1868 if (prog->openfiles[i])
1869 FS_Close(prog->openfiles[i]);
1870 prog->openfiles[i] = NULL;
1871 }
1872}
1873
1874static qfile_t *VM_GetFileHandle(prvm_prog_t *prog, int index)
1875{
1877 {
1878 Con_Printf("VM_GetFileHandle: invalid file handle %i used in %s\n", index, prog->name);
1879 return NULL;
1880 }
1881 if (prog->openfiles[index] == NULL)
1882 {
1883 Con_Printf("VM_GetFileHandle: no such file handle %i (or file has been closed) in %s\n", index, prog->name);
1884 return NULL;
1885 }
1886 return prog->openfiles[index];
1887}
1888
1889/*
1890=========
1891VM_fopen
1892
1893float fopen(string filename, float mode)
1894=========
1895*/
1896// float(string filename, float mode) fopen = #110;
1897// opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE),
1898// returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
1900{
1901 int filenum, mode;
1902 const char *modestring, *filename;
1903 char vabuf[1024];
1904
1906
1907 for (filenum = 0;filenum < PRVM_MAX_OPENFILES;filenum++)
1908 if (prog->openfiles[filenum] == NULL)
1909 break;
1910 if (filenum >= PRVM_MAX_OPENFILES)
1911 {
1913 VM_Warning(prog, "VM_fopen: ran out of file handles (max %i)\n", PRVM_MAX_OPENFILES);
1914 return;
1915 }
1916 filename = PRVM_G_STRING(OFS_PARM0);
1918 switch(mode)
1919 {
1920 case 0: // FILE_READ
1921 modestring = "rb";
1922 prog->openfiles[filenum] = FS_OpenVirtualFile(va(vabuf, sizeof(vabuf), "data/%s", filename), false);
1923 if (prog->openfiles[filenum] == NULL)
1924 prog->openfiles[filenum] = FS_OpenVirtualFile(va(vabuf, sizeof(vabuf), "%s", filename), false);
1925 break;
1926 case 1: // FILE_APPEND
1927 modestring = "a";
1928 prog->openfiles[filenum] = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "data/%s", filename), modestring, false);
1929 break;
1930 case 2: // FILE_WRITE
1931 modestring = "w";
1932 prog->openfiles[filenum] = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "data/%s", filename), modestring, false);
1933 break;
1934 default:
1936 VM_Warning(prog, "VM_fopen: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", mode);
1937 return;
1938 }
1939
1940 if (prog->openfiles[filenum] == NULL)
1941 {
1944 VM_Warning(prog, "VM_fopen: %s mode %s failed\n", filename, modestring);
1945 }
1946 else
1947 {
1948 PRVM_G_FLOAT(OFS_RETURN) = filenum;
1950 Con_DPrintf("VM_fopen: %s: %s mode %s opened as #%i\n", prog->name, filename, modestring, filenum);
1951 prog->openfiles_origin[filenum] = PRVM_AllocationOrigin(prog);
1952 }
1953}
1954
1955/*
1956=========
1957VM_fclose
1958
1959fclose(float fhandle)
1960=========
1961*/
1962//void(float fhandle) fclose = #111; // closes a file
1964{
1965 int filenum;
1966
1968
1969 filenum = (int)PRVM_G_FLOAT(OFS_PARM0);
1970 if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES)
1971 {
1972 VM_Warning(prog, "VM_fclose: invalid file handle %i\n", filenum);
1973 return;
1974 }
1975 if (prog->openfiles[filenum] == NULL)
1976 {
1977 VM_Warning(prog, "VM_fclose: no such file handle %i (or file has been closed)\n", filenum);
1978 return;
1979 }
1980 FS_Close(prog->openfiles[filenum]);
1981 prog->openfiles[filenum] = NULL;
1982 if(prog->openfiles_origin[filenum])
1983 PRVM_Free((char *)prog->openfiles_origin[filenum]);
1985 Con_DPrintf("VM_fclose: %s: #%i closed\n", prog->name, filenum);
1986}
1987
1988/*
1989=========
1990VM_fgets
1991
1992string fgets(float fhandle)
1993=========
1994*/
1995//string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
1997{
1998 int c, end;
1999 char string[VM_TEMPSTRING_MAXSIZE];
2000 int filenum;
2001
2003
2004 // set the return value regardless of any possible errors
2006
2007 filenum = (int)PRVM_G_FLOAT(OFS_PARM0);
2008 if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES)
2009 {
2010 VM_Warning(prog, "VM_fgets: invalid file handle %i\n", filenum);
2011 return;
2012 }
2013 if (prog->openfiles[filenum] == NULL)
2014 {
2015 VM_Warning(prog, "VM_fgets: no such file handle %i (or file has been closed)\n", filenum);
2016 return;
2017 }
2018 end = 0;
2019 for (;;)
2020 {
2021 c = FS_Getc(prog->openfiles[filenum]);
2022 if (c == '\r' || c == '\n' || c < 0)
2023 break;
2024 if (end < VM_TEMPSTRING_MAXSIZE - 1)
2025 string[end++] = c;
2026 }
2027 string[end] = '\0';
2028 // remove \n following \r
2029 if (c == '\r')
2030 {
2031 c = FS_Getc(prog->openfiles[filenum]);
2032 if (c != '\n')
2033 FS_UnGetc(prog->openfiles[filenum], (unsigned char)c);
2034 }
2036 Con_DPrintf("fgets: %s: %s\n", prog->name, string);
2037 if (c >= 0 || end)
2038 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string, end);
2039}
2040
2041/*
2042=========
2043VM_fputs
2044
2045fputs(float fhandle, string s)
2046=========
2047*/
2048//void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
2050{
2051 size_t stringlength;
2052 char string[VM_TEMPSTRING_MAXSIZE];
2053 int filenum;
2054
2056
2057 filenum = (int)PRVM_G_FLOAT(OFS_PARM0);
2058 if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES)
2059 {
2060 VM_Warning(prog, "VM_fputs: invalid file handle %i\n", filenum);
2061 return;
2062 }
2063 if (prog->openfiles[filenum] == NULL)
2064 {
2065 VM_Warning(prog, "VM_fputs: no such file handle %i (or file has been closed)\n", filenum);
2066 return;
2067 }
2068 stringlength = VM_VarString(prog, 1, string, sizeof(string));
2069 if (stringlength)
2070 FS_Write(prog->openfiles[filenum], string, stringlength);
2072 Con_DPrintf("fputs: %s: %s\n", prog->name, string);
2073}
2074
2075/*
2076=========
2077VM_writetofile
2078
2079 writetofile(float fhandle, entity ent)
2080=========
2081*/
2083{
2084 prvm_edict_t * ent;
2085 qfile_t *file;
2086
2088
2089 file = VM_GetFileHandle(prog, (int)PRVM_G_FLOAT(OFS_PARM0));
2090 if( !file )
2091 {
2092 VM_Warning(prog, "VM_writetofile: invalid or closed file handle\n");
2093 return;
2094 }
2095
2096 ent = PRVM_G_EDICT(OFS_PARM1);
2097 if(ent->free)
2098 {
2099 VM_Warning(prog, "VM_writetofile: entity %i is free!\n", PRVM_NUM_FOR_EDICT(ent));
2100 return;
2101 }
2102
2103 PRVM_ED_Write (prog, file, ent);
2104}
2105
2106// KrimZon - DP_QC_ENTITYDATA
2107/*
2108=========
2109VM_numentityfields
2110
2111float() numentityfields
2112Return the number of entity fields - NOT offsets
2113=========
2114*/
2119
2120// KrimZon - DP_QC_ENTITYDATA
2121/*
2122=========
2123VM_entityfieldname
2124
2125string(float fieldnum) entityfieldname
2126Return name of the specified field as a string, or empty if the field is invalid (warning)
2127=========
2128*/
2130{
2131 mdef_t *d;
2132 int i = (int)PRVM_G_FLOAT(OFS_PARM0);
2133
2134 if (i < 0 || i >= prog->numfielddefs)
2135 {
2136 VM_Warning(prog, "VM_entityfieldname: field index out of bounds!\n");
2138 return;
2139 }
2140
2141 d = &prog->fielddefs[i];
2142 PRVM_G_INT(OFS_RETURN) = d->s_name; // presuming that s_name points to a string already
2143}
2144
2145// KrimZon - DP_QC_ENTITYDATA
2146/*
2147=========
2148VM_entityfieldtype
2149
2150float(float fieldnum) entityfieldtype
2151=========
2152*/
2154{
2155 mdef_t *d;
2156 int i = (int)PRVM_G_FLOAT(OFS_PARM0);
2157
2158 if (i < 0 || i >= prog->numfielddefs)
2159 {
2160 VM_Warning(prog, "VM_entityfieldtype: field index out of bounds!\n");
2161 PRVM_G_FLOAT(OFS_RETURN) = -1.0;
2162 return;
2163 }
2164
2165 d = &prog->fielddefs[i];
2167}
2168
2169// KrimZon - DP_QC_ENTITYDATA
2170/*
2171=========
2172VM_getentityfieldstring
2173
2174string(float fieldnum, entity ent) getentityfieldstring
2175=========
2176*/
2178{
2179 // put the data into a string
2180 mdef_t *d;
2181 int type, j;
2182 prvm_eval_t *val;
2183 prvm_edict_t * ent;
2184 int i = (int)PRVM_G_FLOAT(OFS_PARM0);
2185 char valuebuf[MAX_INPUTLINE];
2186
2187 if (i < 0 || i >= prog->numfielddefs)
2188 {
2189 VM_Warning(prog, "VM_entityfielddata: field index out of bounds!\n");
2191 return;
2192 }
2193
2194 d = &prog->fielddefs[i];
2195
2196 // get the entity
2197 ent = PRVM_G_EDICT(OFS_PARM1);
2198 if(ent->free)
2199 {
2201 VM_Warning(prog, "VM_entityfielddata: entity %i is free!\n", PRVM_NUM_FOR_EDICT(ent));
2202 return;
2203 }
2204 val = (prvm_eval_t *)(ent->fields.fp + d->ofs);
2205
2206 // if it's 0 or blank, return an empty string
2207 type = d->type & ~DEF_SAVEGLOBAL;
2208 for (j=0 ; j<prvm_type_size[type] ; j++)
2209 if (val->ivector[j])
2210 break;
2211 if (j == prvm_type_size[type])
2212 {
2214 return;
2215 }
2216
2217 PRVM_UglyValueString(prog, (etype_t)d->type, val, valuebuf, sizeof(valuebuf));
2218 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, valuebuf, strlen(valuebuf));
2219}
2220
2221// KrimZon - DP_QC_ENTITYDATA
2222/*
2223=========
2224VM_putentityfieldstring
2225
2226float(float fieldnum, entity ent, string s) putentityfieldstring
2227=========
2228*/
2230{
2231 mdef_t *d;
2232 prvm_edict_t * ent;
2233 int i = (int)PRVM_G_FLOAT(OFS_PARM0);
2234
2235 if (i < 0 || i >= prog->numfielddefs)
2236 {
2237 VM_Warning(prog, "VM_entityfielddata: field index out of bounds!\n");
2238 PRVM_G_FLOAT(OFS_RETURN) = 0.0f;
2239 return;
2240 }
2241
2242 d = &prog->fielddefs[i];
2243
2244 // get the entity
2245 ent = PRVM_G_EDICT(OFS_PARM1);
2246 if(ent->free)
2247 {
2248 VM_Warning(prog, "VM_entityfielddata: entity %i is free!\n", PRVM_NUM_FOR_EDICT(ent));
2249 PRVM_G_FLOAT(OFS_RETURN) = 0.0f;
2250 return;
2251 }
2252
2253 // parse the string into the value
2254 PRVM_G_FLOAT(OFS_RETURN) = ( PRVM_ED_ParseEpair(prog, ent, d, PRVM_G_STRING(OFS_PARM2), false) ) ? 1.0f : 0.0f;
2255}
2256
2257/*
2258=========
2259VM_strlen
2260
2261float strlen(string s)
2262=========
2263*/
2264//float(string s) strlen = #114; // returns how many characters are in a string
2266{
2268
2269 //PRVM_G_FLOAT(OFS_RETURN) = strlen(PRVM_G_STRING(OFS_PARM0));
2271}
2272
2273// DRESK - Decolorized String
2274/*
2275=========
2276VM_strdecolorize
2277
2278string strdecolorize(string s)
2279=========
2280*/
2281// string (string s) strdecolorize = #472; // returns the passed in string with color codes stripped
2283{
2284 char szNewString[VM_TEMPSTRING_MAXSIZE];
2285 size_t szNewString_len;
2286 const char *szString;
2287
2288 // Prepare Strings
2290 szString = PRVM_G_STRING(OFS_PARM0);
2291 szNewString_len = COM_StringDecolorize(szString, 0, szNewString, sizeof(szNewString), true);
2292 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString, szNewString_len);
2293}
2294
2295// DRESK - String Length (not counting color codes)
2296/*
2297=========
2298VM_strlennocol
2299
2300float strlennocol(string s)
2301=========
2302*/
2303// float(string s) strlennocol = #471; // returns how many characters are in a string not including color codes
2304// For example, ^2Dresk returns a length of 5
2306{
2307 const char *szString;
2308 int nCnt;
2309
2311
2312 szString = PRVM_G_STRING(OFS_PARM0);
2313
2314 //nCnt = (int)COM_StringLengthNoColors(szString, 0, NULL);
2315 nCnt = (int)u8_COM_StringLengthNoColors(szString, 0, NULL);
2316
2317 PRVM_G_FLOAT(OFS_RETURN) = nCnt;
2318}
2319
2320// DRESK - String to Uppercase and Lowercase
2321/*
2322=========
2323VM_strtolower
2324
2325string strtolower(string s)
2326=========
2327*/
2328// string (string s) strtolower = #480; // returns passed in string in lowercase form
2330{
2331 char szNewString[VM_TEMPSTRING_MAXSIZE];
2332 size_t szNewString_len;
2333 const char *szString;
2334
2335 // Prepare Strings
2337 szString = PRVM_G_STRING(OFS_PARM0);
2338
2339 szNewString_len = COM_ToLowerString(szString, szNewString, sizeof(szNewString) );
2340
2341 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString, szNewString_len);
2342}
2343
2344/*
2345=========
2346VM_strtoupper
2347
2348string strtoupper(string s)
2349=========
2350*/
2351// string (string s) strtoupper = #481; // returns passed in string in uppercase form
2353{
2354 char szNewString[VM_TEMPSTRING_MAXSIZE];
2355 size_t szNewString_len;
2356 const char *szString;
2357
2358 // Prepare Strings
2360 szString = PRVM_G_STRING(OFS_PARM0);
2361
2362 szNewString_len = COM_ToUpperString(szString, szNewString, sizeof(szNewString) );
2363
2364 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString, szNewString_len);
2365}
2366
2367/*
2368=========
2369VM_strcat
2370
2371string strcat(string s, string...)
2372=========
2373*/
2374//string(string s, string...) strcat = #115;
2375// concatenates strings (for example "abc", "def" would return "abcdef")
2376// and returns as a tempstring
2378{
2379 char s[VM_TEMPSTRING_MAXSIZE];
2380 size_t slen;
2381
2383
2384 slen = VM_VarString(prog, 0, s, sizeof(s));
2385 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s, slen);
2386}
2387
2388/*
2389=========
2390VM_substring
2391
2392string substring(string s, float start, float length)
2393=========
2394*/
2395// string(string s, float start, float length) substring = #116;
2396// returns a section of a string as a tempstring
2398{
2399 int start, length;
2400 int u_slength = 0, u_start;
2401 size_t u_length;
2402 const char *s;
2403 char string[VM_TEMPSTRING_MAXSIZE];
2404
2406
2407 /*
2408 s = PRVM_G_STRING(OFS_PARM0);
2409 start = (int)PRVM_G_FLOAT(OFS_PARM1);
2410 length = (int)PRVM_G_FLOAT(OFS_PARM2);
2411 slength = strlen(s);
2412
2413 if (start < 0) // FTE_STRINGS feature
2414 start += slength;
2415 start = bound(0, start, slength);
2416
2417 if (length < 0) // FTE_STRINGS feature
2418 length += slength - start + 1;
2419 maxlen = min((int)sizeof(string) - 1, slength - start);
2420 length = bound(0, length, maxlen);
2421
2422 memcpy(string, s + start, length);
2423 string[length] = 0;
2424 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
2425 */
2426
2428 start = (int)PRVM_G_FLOAT(OFS_PARM1);
2430
2431 if (start < 0) // FTE_STRINGS feature
2432 {
2433 u_slength = (int)u8_strlen(s);
2434 start += u_slength;
2435 start = bound(0, start, u_slength);
2436 }
2437
2438 if (length < 0) // FTE_STRINGS feature
2439 {
2440 if (!u_slength) // it's not calculated when it's not needed above
2441 u_slength = (int)u8_strlen(s);
2442 length += u_slength - start + 1;
2443 }
2444
2445 // positive start, positive length
2446 u_start = u8_byteofs(s, start, NULL);
2447 if (u_start < 0)
2448 {
2450 return;
2451 }
2452 u_length = u8_bytelen(s + u_start, length);
2453 if (u_length >= sizeof(string)-1)
2454 u_length = sizeof(string)-1;
2455
2456 memcpy(string, s + u_start, u_length);
2457 string[u_length] = '\0';
2458 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string, u_length);
2459}
2460
2461/*
2462=========
2463VM_strreplace
2464
2465string(string search, string replace, string subject) strreplace = #484;
2466=========
2467*/
2468// replaces all occurrences of search with replace in the string subject, and returns the result
2470{
2471 int i, j, si;
2472 const char *search, *replace, *subject;
2473 char string[VM_TEMPSTRING_MAXSIZE];
2474 int search_len, replace_len, subject_len;
2475
2477
2478 search = PRVM_G_STRING(OFS_PARM0);
2479 replace = PRVM_G_STRING(OFS_PARM1);
2480 subject = PRVM_G_STRING(OFS_PARM2);
2481
2482 search_len = (int)strlen(search);
2483 replace_len = (int)strlen(replace);
2484 subject_len = (int)strlen(subject);
2485
2486 si = 0;
2487 for (i = 0; i <= subject_len - search_len; i++)
2488 {
2489 for (j = 0; j < search_len; j++) // thus, i+j < subject_len
2490 if (subject[i+j] != search[j])
2491 break;
2492 if (j == search_len)
2493 {
2494 // NOTE: if search_len == 0, we always hit THIS case, and never the other
2495 // found it at offset 'i'
2496 for (j = 0; j < replace_len && si < (int)sizeof(string) - 1; j++)
2497 string[si++] = replace[j];
2498 if(search_len > 0)
2499 {
2500 i += search_len - 1;
2501 }
2502 else
2503 {
2504 // the above would subtract 1 from i... so we
2505 // don't do that, but instead output the next
2506 // char
2507 if (si < (int)sizeof(string) - 1)
2508 string[si++] = subject[i];
2509 }
2510 }
2511 else
2512 {
2513 // in THIS case, we know search_len > 0, thus i < subject_len
2514 // not found
2515 if (si < (int)sizeof(string) - 1)
2516 string[si++] = subject[i];
2517 }
2518 }
2519 // remaining chars (these cannot match)
2520 for (; i < subject_len; i++)
2521 if (si < (int)sizeof(string) - 1)
2522 string[si++] = subject[i];
2523 string[si] = '\0';
2524
2525 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string, si);
2526}
2527
2528/*
2529=========
2530VM_strireplace
2531
2532string(string search, string replace, string subject) strireplace = #485;
2533=========
2534*/
2535// case-insensitive version of strreplace
2537{
2538 int i, j, si;
2539 const char *search, *replace, *subject;
2540 char string[VM_TEMPSTRING_MAXSIZE];
2541 int search_len, replace_len, subject_len;
2542
2544
2545 search = PRVM_G_STRING(OFS_PARM0);
2546 replace = PRVM_G_STRING(OFS_PARM1);
2547 subject = PRVM_G_STRING(OFS_PARM2);
2548
2549 search_len = (int)strlen(search);
2550 replace_len = (int)strlen(replace);
2551 subject_len = (int)strlen(subject);
2552
2553 si = 0;
2554 for (i = 0; i <= subject_len - search_len; i++)
2555 {
2556 for (j = 0; j < search_len; j++) // thus, i+j < subject_len
2557 if (tolower(subject[i+j]) != tolower(search[j]))
2558 break;
2559 if (j == search_len)
2560 {
2561 // NOTE: if search_len == 0, we always hit THIS case, and never the other
2562 // found it at offset 'i'
2563 for (j = 0; j < replace_len && si < (int)sizeof(string) - 1; j++)
2564 string[si++] = replace[j];
2565 if(search_len > 0)
2566 {
2567 i += search_len - 1;
2568 }
2569 else
2570 {
2571 // the above would subtract 1 from i... so we
2572 // don't do that, but instead output the next
2573 // char
2574 if (si < (int)sizeof(string) - 1)
2575 string[si++] = subject[i];
2576 }
2577 }
2578 else
2579 {
2580 // in THIS case, we know search_len > 0, thus i < subject_len
2581 // not found
2582 if (si < (int)sizeof(string) - 1)
2583 string[si++] = subject[i];
2584 }
2585 }
2586 // remaining chars (these cannot match)
2587 for (; i < subject_len; i++)
2588 if (si < (int)sizeof(string) - 1)
2589 string[si++] = subject[i];
2590 string[si] = '\0';
2591
2592 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string, si);
2593}
2594
2595/*
2596=========
2597VM_stov
2598
2599vector stov(string s)
2600=========
2601*/
2602//vector(string s) stov = #117; // returns vector value from a string
2604{
2605 char string[VM_TEMPSTRING_MAXSIZE];
2606
2608
2609 VM_VarString(prog, 0, string, sizeof(string));
2611}
2612
2613/*
2614=========
2615VM_strzone
2616
2617string strzone(string s)
2618=========
2619*/
2620//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)
2622{
2623 char *out;
2624 char string[VM_TEMPSTRING_MAXSIZE];
2625 size_t alloclen;
2626
2628
2629 alloclen = VM_VarString(prog, 0, string, sizeof(string)) + 1;
2630 PRVM_G_INT(OFS_RETURN) = PRVM_AllocString(prog, alloclen, &out);
2631 memcpy(out, string, alloclen);
2632}
2633
2634/*
2635=========
2636VM_strunzone
2637
2638strunzone(string s)
2639=========
2640*/
2641//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!!!)
2647
2648/*
2649=========
2650VM_tokenize
2651
2652float tokenize(string s)
2653=========
2654*/
2655//float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many
2656//this function originally written by KrimZon, made shorter by LadyHavoc
2657//20040203: rewritten by LadyHavoc (no longer uses allocations)
2658static int num_tokens = 0;
2664{
2665 const char *p;
2666
2668
2670 p = tokenize_string;
2671
2672 num_tokens = 0;
2673 for(;;)
2674 {
2675 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
2676 break;
2677
2678 // skip whitespace here to find token start pos
2679 while(*p && ISWHITESPACE(*p))
2680 ++p;
2681
2683 if(!COM_ParseToken_VM_Tokenize(&p, false))
2684 break;
2687 ++num_tokens;
2688 }
2689
2691}
2692
2693//float(string s) tokenize = #514; // takes apart a string into individal words (access them with argv), returns how many
2695{
2696 const char *p;
2697
2699
2701 p = tokenize_string;
2702
2703 num_tokens = 0;
2704 for(;;)
2705 {
2706 if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
2707 break;
2708
2709 // skip whitespace here to find token start pos
2710 while(*p && ISWHITESPACE(*p))
2711 ++p;
2712
2714 if(!COM_ParseToken_Console(&p))
2715 break;
2718 ++num_tokens;
2719 }
2720
2722}
2723
2724/*
2725=========
2726VM_tokenizebyseparator
2727
2728float tokenizebyseparator(string s, string separator1, ...)
2729=========
2730*/
2731//float(string s, string separator1, ...) tokenizebyseparator = #479; // takes apart a string into individal words (access them with argv), returns how many
2732//this function returns the token preceding each instance of a separator (of
2733//which there can be multiple), and the text following the last separator
2734//useful for parsing certain kinds of data like IP addresses
2735//example:
2736//numnumbers = tokenizebyseparator("10.1.2.3", ".");
2737//returns 4 and the tokens "10" "1" "2" "3".
2739{
2740 int j, k;
2741 int numseparators;
2742 int separatorlen[7];
2743 const char *separators[7];
2744 const char *p, *p0;
2745 const char *token;
2746 char tokentext[MAX_INPUTLINE];
2747
2749
2751 p = tokenize_string;
2752
2753 numseparators = 0;
2754 for (j = 1;j < prog->argc;j++)
2755 {
2756 // skip any blank separator strings
2757 const char *s = PRVM_G_STRING(OFS_PARM0+j*3);
2758 if (!s[0])
2759 continue;
2760 separators[numseparators] = s;
2761 separatorlen[numseparators] = (int)strlen(s);
2762 numseparators++;
2763 }
2764
2765 num_tokens = 0;
2766 j = 0;
2767
2768 while (num_tokens < (int)(sizeof(tokens)/sizeof(tokens[0])))
2769 {
2770 token = tokentext + j;
2772 p0 = p;
2773 while (*p)
2774 {
2775 for (k = 0;k < numseparators;k++)
2776 {
2777 if (!strncmp(p, separators[k], separatorlen[k]))
2778 {
2779 p += separatorlen[k];
2780 break;
2781 }
2782 }
2783 if (k < numseparators)
2784 break;
2785 if (j < (int)sizeof(tokentext)-1)
2786 tokentext[j++] = *p;
2787 p++;
2788 p0 = p;
2789 }
2791 if (j >= (int)sizeof(tokentext))
2792 break;
2793 tokentext[j] = '\0';
2794 tokens[num_tokens++] = PRVM_SetTempString(prog, token, j++ - (token - tokentext));
2795 if (!*p)
2796 break;
2797 }
2798
2800}
2801
2802//string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index)
2803//this function originally written by KrimZon, made shorter by LadyHavoc
2805{
2806 int token_num;
2807
2809
2810 token_num = (int)PRVM_G_FLOAT(OFS_PARM0);
2811
2812 if(token_num < 0)
2813 token_num += num_tokens;
2814
2815 if (token_num >= 0 && token_num < num_tokens)
2816 PRVM_G_INT(OFS_RETURN) = tokens[token_num];
2817 else
2819}
2820
2821//float(float n) argv_start_index = #515; // returns the start index of a token
2823{
2824 int token_num;
2825
2827
2828 token_num = (int)PRVM_G_FLOAT(OFS_PARM0);
2829
2830 if(token_num < 0)
2831 token_num += num_tokens;
2832
2833 if (token_num >= 0 && token_num < num_tokens)
2835 else
2837}
2838
2839//float(float n) argv_end_index = #516; // returns the end index of a token
2841{
2842 int token_num;
2843
2845
2846 token_num = (int)PRVM_G_FLOAT(OFS_PARM0);
2847
2848 if(token_num < 0)
2849 token_num += num_tokens;
2850
2851 if (token_num >= 0 && token_num < num_tokens)
2853 else
2855}
2856
2857/*
2858=========
2859VM_isserver
2860
2861float isserver()
2862=========
2863*/
2865{
2867
2869}
2870
2871/*
2872=========
2873VM_clientcount
2874
2875float clientcount()
2876=========
2877*/
2884
2885/*
2886=========
2887VM_clientstate
2888
2889float clientstate()
2890=========
2891*/
2893{
2895
2896
2897 switch( cls.state ) {
2898 case ca_uninitialized:
2899 case ca_dedicated:
2901 break;
2902 case ca_disconnected:
2904 break;
2905 case ca_connected:
2907 break;
2908 default:
2909 // should never be reached!
2910 break;
2911 }
2912}
2913
2914/*
2915=========
2916VM_getostype
2917
2918float getostype(prvm_prog_t *prog)
2919=========
2920*/ // not used at the moment -> not included in the common list
2922{
2924
2925 /*
2926 OS_WINDOWS
2927 OS_LINUX
2928 OS_MAC - not supported
2929 */
2930
2931#ifdef WIN32
2933#elif defined(MACOSX)
2935#else
2937#endif
2938}
2939
2940/*
2941=========
2942VM_gettime
2943
2944float gettime(prvm_prog_t *prog)
2945=========
2946*/
2947float CDAudio_GetPosition(void);
2949{
2950 int timer_index;
2951
2953
2954 if(prog->argc == 0)
2955 {
2957 }
2958 else
2959 {
2960 timer_index = (int) PRVM_G_FLOAT(OFS_PARM0);
2961 switch(timer_index)
2962 {
2963 case 0: // GETTIME_FRAMESTART
2965 break;
2966 case 1: // GETTIME_REALTIME
2968 break;
2969 case 2: // GETTIME_HIRES
2971 break;
2972 case 3: // GETTIME_UPTIME
2974 break;
2975 case 4: // GETTIME_CDTRACK
2977 break;
2978 default:
2979 VM_Warning(prog, "VM_gettime: unsupported timer specified, returning realtime\n");
2981 break;
2982 }
2983 }
2984}
2985
2986/*
2987=========
2988VM_getsoundtime
2989
2990float getsoundtime(prvm_prog_t *prog)
2991=========
2992*/
2993
2995{
2996 int entnum, entchannel;
2998
2999 if (prog == SVVM_prog)
3001 else if (prog == CLVM_prog)
3003 else
3004 {
3005 VM_Warning(prog, "VM_getsoundtime: not supported on this progs\n");
3007 return;
3008 }
3009 entchannel = (int)PRVM_G_FLOAT(OFS_PARM1);
3010 entchannel = CHAN_USER2ENGINE(entchannel);
3011 if (!IS_CHAN(entchannel))
3012 VM_Warning(prog, "VM_getsoundtime: bad channel %i\n", entchannel);
3014}
3015
3016/*
3017=========
3018VM_GetSoundLen
3019
3020string soundlength (string sample)
3021=========
3022*/
3024{
3025 const char *s;
3026
3028
3031}
3032
3033/*
3034=========
3035VM_loadfromdata
3036
3037loadfromdata(string data)
3038=========
3039*/
3046
3047/*
3048========================
3049VM_parseentitydata
3050
3051parseentitydata(entity ent, string data)
3052========================
3053*/
3055{
3056 prvm_edict_t *ent;
3057 const char *data;
3058
3060
3061 // get edict and test it
3062 ent = PRVM_G_EDICT(OFS_PARM0);
3063 if (ent->free)
3064 prog->error_cmd("VM_parseentitydata: %s: Can only set already spawned entities (entity %i is free)!", prog->name, PRVM_NUM_FOR_EDICT(ent));
3065
3067
3068 // parse the opening brace
3069 if (!COM_ParseToken_Simple(&data, false, false, true) || com_token[0] != '{' )
3070 prog->error_cmd("VM_parseentitydata: %s: Couldn't parse entity data:\n%s", prog->name, data );
3071
3072 PRVM_ED_ParseEdict(prog, data, ent, true);
3073}
3074
3075/*
3076=========
3077VM_loadfromfile
3078
3079loadfromfile(string file)
3080=========
3081*/
3083{
3084 const char *filename;
3085 char *data;
3086
3088
3089 filename = PRVM_G_STRING(OFS_PARM0);
3090 if (FS_CheckNastyPath(filename, false))
3091 {
3093 VM_Warning(prog, "VM_loadfromfile: dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", filename);
3094 return;
3095 }
3096
3097 // not conform with VM_fopen
3098 data = (char *)FS_LoadFile(filename, tempmempool, false, NULL);
3099 if (data == NULL)
3101
3103
3104 if(data)
3105 Mem_Free(data);
3106}
3107
3108
3109/*
3110=========
3111VM_modulo
3112
3113float mod(float val, float m)
3114=========
3115*/
3117{
3118 vec_t val, m;
3119
3121
3122 val = PRVM_G_FLOAT(OFS_PARM0);
3124
3125 // matches how gmqcc implements % when mod() builtin isn't defined, and FTEQW mod()
3126 if (m)
3127 PRVM_G_FLOAT(OFS_RETURN) = val - m * (prvm_int_t)(val / m);
3128 else
3129 {
3130 VM_Warning(prog, "Attempted modulo of %f by zero\n", val);
3132 }
3133}
3134
3135static void VM_Search_Init(prvm_prog_t *prog)
3136{
3137 int i;
3138 for (i = 0;i < PRVM_MAX_OPENSEARCHES;i++)
3139 prog->opensearches[i] = NULL;
3140}
3141
3143{
3144 int i;
3145 // reset the fssearch list
3146 for(i = 0; i < PRVM_MAX_OPENSEARCHES; i++)
3147 {
3148 if(prog->opensearches[i])
3150 prog->opensearches[i] = NULL;
3151 }
3152}
3153
3154/*
3155=========
3156VM_search_begin
3157
3158float search_begin(string pattern, float caseinsensitive, float quiet[, string packfile])
3159=========
3160*/
3162{
3163 int handle;
3164 const char *packfile = NULL, *pattern;
3165 int caseinsens, quiet;
3166
3168
3169 pattern = PRVM_G_STRING(OFS_PARM0);
3170
3171 VM_CheckEmptyString(prog, pattern);
3172
3173 caseinsens = (int)PRVM_G_FLOAT(OFS_PARM1);
3174 quiet = (int)PRVM_G_FLOAT(OFS_PARM2);
3175
3176 // optional packfile parameter (DP_QC_FS_SEARCH_PACKFILE)
3177 if(prog->argc >= 4)
3178 packfile = PRVM_G_STRING(OFS_PARM3);
3179
3180 for(handle = 0; handle < PRVM_MAX_OPENSEARCHES; handle++)
3181 if(!prog->opensearches[handle])
3182 break;
3183
3184 if(handle >= PRVM_MAX_OPENSEARCHES)
3185 {
3187 VM_Warning(prog, "VM_search_begin: ran out of search handles (max %i)\n", PRVM_MAX_OPENSEARCHES);
3188 return;
3189 }
3190
3191 if(!(prog->opensearches[handle] = FS_Search(pattern,caseinsens, quiet, packfile)))
3193 else
3194 {
3195 prog->opensearches_origin[handle] = PRVM_AllocationOrigin(prog);
3196 PRVM_G_FLOAT(OFS_RETURN) = handle;
3197 }
3198}
3199
3200/*
3201=========
3202VM_search_end
3203
3204void search_end(float handle)
3205=========
3206*/
3208{
3209 int handle;
3211
3212 handle = (int)PRVM_G_FLOAT(OFS_PARM0);
3213
3214 if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES)
3215 {
3216 VM_Warning(prog, "VM_search_end: invalid handle %i\n", handle);
3217 return;
3218 }
3219 if(prog->opensearches[handle] == NULL)
3220 {
3221 VM_Warning(prog, "VM_search_end: no such handle %i\n", handle);
3222 return;
3223 }
3224
3225 FS_FreeSearch(prog->opensearches[handle]);
3226 prog->opensearches[handle] = NULL;
3227 if(prog->opensearches_origin[handle])
3228 PRVM_Free((char *)prog->opensearches_origin[handle]);
3229}
3230
3231/*
3232=========
3233VM_search_getsize
3234
3235float search_getsize(float handle)
3236=========
3237*/
3239{
3240 int handle;
3242
3243 handle = (int)PRVM_G_FLOAT(OFS_PARM0);
3244
3245 if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES)
3246 {
3247 VM_Warning(prog, "VM_search_getsize: invalid handle %i\n", handle);
3248 return;
3249 }
3250 if(prog->opensearches[handle] == NULL)
3251 {
3252 VM_Warning(prog, "VM_search_getsize: no such handle %i\n", handle);
3253 return;
3254 }
3255
3256 PRVM_G_FLOAT(OFS_RETURN) = prog->opensearches[handle]->numfilenames;
3257}
3258
3259/*
3260=========
3261VM_search_getfilename
3262
3263string search_getfilename(float handle, float num)
3264=========
3265*/
3267{
3268 int handle, filenum;
3269
3271
3272 handle = (int)PRVM_G_FLOAT(OFS_PARM0);
3273 filenum = (int)PRVM_G_FLOAT(OFS_PARM1);
3274
3275 if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES)
3276 {
3277 VM_Warning(prog, "VM_search_getfilename: invalid handle %i\n", handle);
3278 return;
3279 }
3280 if(prog->opensearches[handle] == NULL)
3281 {
3282 VM_Warning(prog, "VM_search_getfilename: no such handle %i\n", handle);
3283 return;
3284 }
3285 if(filenum < 0 || filenum >= prog->opensearches[handle]->numfilenames)
3286 {
3287 VM_Warning(prog, "VM_search_getfilename: invalid filenum %i\n", filenum);
3288 return;
3289 }
3290
3292 prog->opensearches[handle]->filenames[filenum],
3293 strlen(prog->opensearches[handle]->filenames[filenum]));
3294}
3295
3296/*
3297=========
3298VM_chr
3299
3300string chr(float ascii)
3301=========
3302*/
3304{
3305 /*
3306 char tmp[2];
3307 VM_SAFEPARMCOUNT(1, VM_chr);
3308
3309 tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0);
3310 tmp[1] = 0;
3311
3312 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, tmp);
3313 */
3314
3315 char tmp[8];
3316 int len;
3317
3319 len = u8_fromchar((Uchar)PRVM_G_FLOAT(OFS_PARM0), tmp, sizeof(tmp));
3320 tmp[len] = '\0';
3321 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, tmp, len);
3322}
3323
3324/*
3325=========
3326VM_keynumtostring
3327
3328string keynumtostring(float keynum)
3329=========
3330*/
3332{
3333 char tinystr[TINYSTR_LEN];
3334 const char *str; // Key_KeynumToString doesn't always return tinystr
3335
3337 str = Key_KeynumToString((int)PRVM_G_FLOAT(OFS_PARM0), tinystr, sizeof(tinystr));
3338 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, str, strlen(str));
3339}
3340
3341/*
3342=========
3343VM_findkeysforcommand
3344
3345string findkeysforcommand(string command, float bindmap)
3346
3347the returned string is an altstring
3348=========
3349*/
3350#define FKFC_NUMKEYS 5
3351void M_FindKeysForCommand(const char *command, int *keys);
3353{
3354 const char *cmd;
3356 size_t ret_len;
3357 int keys[FKFC_NUMKEYS];
3358 int i;
3359 int bindmap;
3360 char vabuf[1024];
3361
3363
3365 if(prog->argc == 2)
3366 bindmap = bound(-1, PRVM_G_FLOAT(OFS_PARM1), MAX_BINDMAPS-1);
3367 else
3368 bindmap = 0; // consistent to "bind"
3369
3370 VM_CheckEmptyString(prog, cmd);
3371
3372 Key_FindKeysForCommand(cmd, keys, FKFC_NUMKEYS, bindmap);
3373
3374 ret[0] = 0;
3375 for(i = 0; i < FKFC_NUMKEYS; i++)
3376 ret_len = dp_strlcat(ret, va(vabuf, sizeof(vabuf), " \'%i\'", keys[i]), sizeof(ret));
3377
3378 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, ret, ret_len);
3379}
3380
3381/*
3382=========
3383VM_stringtokeynum
3384
3385float stringtokeynum(string key)
3386=========
3387*/
3394
3395/*
3396=========
3397VM_getkeybind
3398
3399string getkeybind(float key, float bindmap)
3400=========
3401*/
3403{
3404 int bindmap;
3405 const char *bind;
3406
3408 if(prog->argc == 2)
3409 bindmap = bound(-1, PRVM_G_FLOAT(OFS_PARM1), MAX_BINDMAPS-1);
3410 else
3411 bindmap = 0; // consistent to "bind"
3412 bind = Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0), bindmap);
3413 PRVM_G_INT(OFS_RETURN) = bind ? PRVM_SetTempString(prog, bind, strlen(bind)) : 0;
3414}
3415
3416/*
3417=========
3418VM_setkeybind
3419
3420float setkeybind(float key, string cmd, float bindmap)
3421=========
3422*/
3424{
3425 int bindmap;
3427 if(prog->argc == 3)
3428 bindmap = bound(-1, PRVM_G_FLOAT(OFS_PARM2), MAX_BINDMAPS-1);
3429 else
3430 bindmap = 0; // consistent to "bind"
3431
3435}
3436
3437/*
3438=========
3439VM_getbindmap
3440
3441vector getbindmaps()
3442=========
3443*/
3445{
3446 int fg, bg;
3448 Key_GetBindMap(&fg, &bg);
3449 PRVM_G_VECTOR(OFS_RETURN)[0] = fg;
3450 PRVM_G_VECTOR(OFS_RETURN)[1] = bg;
3451 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
3452}
3453
3454/*
3455=========
3456VM_setbindmap
3457
3458float setbindmaps(vector bindmap)
3459=========
3460*/
3469
3470/*
3471========================
3472VM_gecko_create
3473
3474float[bool] gecko_create( string name )
3475========================
3476*/
3478 // REMOVED
3479 PRVM_G_FLOAT( OFS_RETURN ) = 0;
3480}
3481
3482/*
3483========================
3484VM_gecko_destroy
3485
3486void gecko_destroy( string name )
3487========================
3488*/
3490 // REMOVED
3491}
3492
3493/*
3494========================
3495VM_gecko_navigate
3496
3497void gecko_navigate( string name, string URI )
3498========================
3499*/
3501 // REMOVED
3502}
3503
3504/*
3505========================
3506VM_gecko_keyevent
3507
3508float[bool] gecko_keyevent( string name, float key, float eventtype )
3509========================
3510*/
3512 // REMOVED
3513 PRVM_G_FLOAT( OFS_RETURN ) = 0;
3514}
3515
3516/*
3517========================
3518VM_gecko_movemouse
3519
3520void gecko_mousemove( string name, float x, float y )
3521========================
3522*/
3524 // REMOVED
3525}
3526
3527
3528/*
3529========================
3530VM_gecko_resize
3531
3532void gecko_resize( string name, float w, float h )
3533========================
3534*/
3536 // REMOVED
3537}
3538
3539
3540/*
3541========================
3542VM_gecko_get_texture_extent
3543
3544vector gecko_get_texture_extent( string name )
3545========================
3546*/
3548 // REMOVED
3549 PRVM_G_VECTOR(OFS_RETURN)[0] = 0;
3550 PRVM_G_VECTOR(OFS_RETURN)[1] = 0;
3551}
3552
3553
3554
3555/*
3556==============
3557VM_makevectors
3558
3559Writes new values for v_forward, v_up, and v_right based on angles
3560void makevectors(vector angle)
3561==============
3562*/
3573
3574/*
3575==============
3576VM_vectorvectors
3577
3578Writes new values for v_forward, v_up, and v_right based on the given forward vector
3579vectorvectors(vector)
3580==============
3581*/
3592
3593// float(float number, float quantity) bitshift (EXT_BITSHIFT)
3595{
3596 prvm_int_t n1, n2;
3598
3601 if(!n1)
3603 else
3604 if(n2 < 0)
3605 PRVM_G_FLOAT(OFS_RETURN) = (n1 >> -n2);
3606 else
3607 PRVM_G_FLOAT(OFS_RETURN) = (n1 << n2);
3608}
3609
3611// AltString functions
3613
3614/*
3615========================
3616VM_altstr_count
3617
3618float altstr_count(string)
3619========================
3620*/
3622{
3623 const char *altstr, *pos;
3624 int count;
3625
3627
3628 altstr = PRVM_G_STRING( OFS_PARM0 );
3629 //VM_CheckEmptyString(prog, altstr );
3630
3631 for( count = 0, pos = altstr ; *pos ; pos++ ) {
3632 if( *pos == '\\' ) {
3633 if( !*++pos ) {
3634 break;
3635 }
3636 } else if( *pos == '\'' ) {
3637 count++;
3638 }
3639 }
3640
3642}
3643
3644/*
3645========================
3646VM_altstr_prepare
3647
3648string altstr_prepare(string)
3649========================
3650*/
3652{
3653 const char *instr, *in;
3654 char outstr[VM_TEMPSTRING_MAXSIZE];
3655 size_t outpos;
3656
3658
3659 instr = PRVM_G_STRING( OFS_PARM0 );
3660
3661 for (in = instr, outpos = 0; *in && outpos < sizeof(outstr) - 1; ++in)
3662 {
3663 if (*in == '\'' && outpos < sizeof(outstr) - 2)
3664 {
3665 outstr[outpos++] = '\\';
3666 outstr[outpos++] = '\'';
3667 }
3668 else
3669 outstr[outpos++] = *in;
3670 }
3671
3672 outstr[outpos] = '\0';
3673 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outstr, outpos);
3674}
3675
3676/*
3677========================
3678VM_altstr_get
3679
3680string altstr_get(string, float)
3681========================
3682*/
3684{
3685 const char *altstr, *pos;
3686 char *out;
3687 int count, size;
3688 char outstr[VM_TEMPSTRING_MAXSIZE];
3689
3691
3692 altstr = PRVM_G_STRING( OFS_PARM0 );
3693
3695 count = count * 2 + 1;
3696
3697 for( pos = altstr ; *pos && count ; pos++ )
3698 if( *pos == '\\' ) {
3699 if( !*++pos )
3700 break;
3701 } else if( *pos == '\'' )
3702 count--;
3703
3704 if( !*pos ) {
3705 PRVM_G_INT( OFS_RETURN ) = 0;
3706 return;
3707 }
3708
3709 for( out = outstr, size = sizeof(outstr) - 1 ; size && *pos ; size--, pos++, out++ )
3710 if( *pos == '\\' ) {
3711 if( !*++pos )
3712 break;
3713 *out = *pos;
3714 size--;
3715 } else if( *pos == '\'' )
3716 break;
3717 else
3718 *out = *pos;
3719
3720 *out = '\0';
3721 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outstr, out - outstr);
3722}
3723
3724/*
3725========================
3726VM_altstr_set
3727
3728string altstr_set(string altstr, float num, string set)
3729========================
3730*/
3732{
3733 int num;
3734 const char *altstr, *str;
3735 const char *in;
3736 char *out;
3737 char outstr[VM_TEMPSTRING_MAXSIZE];
3738
3740
3741 altstr = PRVM_G_STRING( OFS_PARM0 );
3742
3743 num = (int)PRVM_G_FLOAT( OFS_PARM1 );
3744
3745 str = PRVM_G_STRING( OFS_PARM2 );
3746
3747 out = outstr;
3748 for( num = num * 2 + 1, in = altstr; *in && num; *out++ = *in++ )
3749 if( *in == '\\' ) {
3750 if( !*++in ) {
3751 break;
3752 }
3753 } else if( *in == '\'' ) {
3754 num--;
3755 }
3756
3757 // copy set in
3758 for( ; *str; *out++ = *str++ );
3759 // now jump over the old content
3760 for( ; *in ; in++ )
3761 if( *in == '\'' || (*in == '\\' && !*++in) )
3762 break;
3763
3764 out += dp_strlcpy(out, in, outstr + sizeof(outstr) - out);
3765 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outstr, out - outstr);
3766}
3767
3768/*
3769========================
3770VM_altstr_ins
3771insert after num
3772string altstr_ins(string altstr, float num, string set)
3773========================
3774*/
3776{
3777 int num;
3778 const char *set;
3779 const char *in;
3780 char *out;
3781 char outstr[VM_TEMPSTRING_MAXSIZE];
3782
3784
3785 in = PRVM_G_STRING( OFS_PARM0 );
3786 num = (int)PRVM_G_FLOAT( OFS_PARM1 );
3787 set = PRVM_G_STRING( OFS_PARM2 );
3788
3789 out = outstr;
3790 for( num = num * 2 + 2 ; *in && num > 0 ; *out++ = *in++ )
3791 if( *in == '\\' ) {
3792 if( !*++in ) {
3793 break;
3794 }
3795 } else if( *in == '\'' ) {
3796 num--;
3797 }
3798
3799 *out++ = '\'';
3800 for( ; *set ; *out++ = *set++ );
3801 *out++ = '\'';
3802
3803 out += dp_strlcpy(out, in, outstr + sizeof(outstr) - out);
3804 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outstr, out - outstr);
3805}
3806
3807
3809// BufString functions
3811//[515]: string buffers support
3812
3814
3815static void BufStr_Expand(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer, int strindex)
3816{
3817 if (stringbuffer->max_strings <= strindex)
3818 {
3819 char **oldstrings = stringbuffer->strings;
3820 stringbuffer->max_strings = max(stringbuffer->max_strings * 2, 128);
3821 while (stringbuffer->max_strings <= strindex)
3822 stringbuffer->max_strings *= 2;
3823 stringbuffer->strings = (char **) Mem_Alloc(prog->progs_mempool, stringbuffer->max_strings * sizeof(stringbuffer->strings[0]));
3824 if (stringbuffer->num_strings > 0)
3825 memcpy(stringbuffer->strings, oldstrings, stringbuffer->num_strings * sizeof(stringbuffer->strings[0]));
3826 if (oldstrings)
3827 Mem_Free(oldstrings);
3828 }
3829}
3830
3831static void BufStr_Shrink(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer)
3832{
3833 // reduce num_strings if there are empty string slots at the end
3834 while (stringbuffer->num_strings > 0 && stringbuffer->strings[stringbuffer->num_strings - 1] == NULL)
3835 stringbuffer->num_strings--;
3836
3837 // if empty, free the string pointer array
3838 if (stringbuffer->num_strings == 0)
3839 {
3840 stringbuffer->max_strings = 0;
3841 if (stringbuffer->strings)
3842 Mem_Free(stringbuffer->strings);
3843 stringbuffer->strings = NULL;
3844 }
3845}
3846
3847static int BufStr_SortStringsUP (const void *in1, const void *in2)
3848{
3849 const char *a, *b;
3850 a = *((const char **) in1);
3851 b = *((const char **) in2);
3852 if(!a || !a[0]) return 1;
3853 if(!b || !b[0]) return -1;
3854 return strncmp(a, b, stringbuffers_sortlength);
3855}
3856
3857static int BufStr_SortStringsDOWN (const void *in1, const void *in2)
3858{
3859 const char *a, *b;
3860 a = *((const char **) in1);
3861 b = *((const char **) in2);
3862 if(!a || !a[0]) return 1;
3863 if(!b || !b[0]) return -1;
3864 return strncmp(b, a, stringbuffers_sortlength);
3865}
3866
3867prvm_stringbuffer_t *BufStr_FindCreateReplace (prvm_prog_t *prog, int bufindex, unsigned flags, const char *format)
3868{
3869 prvm_stringbuffer_t *stringbuffer;
3870 int i;
3871
3872 if (bufindex < 0)
3873 return NULL;
3874
3875 // find buffer with wanted index
3876 if (bufindex < (int)Mem_ExpandableArray_IndexRange(&prog->stringbuffersarray))
3877 {
3878 if ( (stringbuffer = (prvm_stringbuffer_t*) Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, bufindex)) )
3879 {
3880 if (stringbuffer->flags & STRINGBUFFER_TEMP)
3881 stringbuffer->flags = flags; // created but has not been used yet
3882 return stringbuffer;
3883 }
3884 return NULL;
3885 }
3886
3887 // allocate new buffer with wanted index
3888 while(1)
3889 {
3891 stringbuffer->flags = STRINGBUFFER_TEMP;
3892 for (i = 0;stringbuffer != Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);i++);
3893 if (i == bufindex)
3894 {
3895 stringbuffer->flags = flags; // mark as used
3896 break;
3897 }
3898 }
3899 return stringbuffer;
3900}
3901
3902void BufStr_Set(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer, int strindex, const char *str)
3903{
3904 size_t alloclen;
3905
3906 if (!stringbuffer || strindex < 0)
3907 return;
3908
3909 BufStr_Expand(prog, stringbuffer, strindex);
3910 stringbuffer->num_strings = max(stringbuffer->num_strings, strindex + 1);
3911 if (stringbuffer->strings[strindex])
3912 Mem_Free(stringbuffer->strings[strindex]);
3913 stringbuffer->strings[strindex] = NULL;
3914
3915 if (str)
3916 {
3917 // not the NULL string!
3918 alloclen = strlen(str) + 1;
3919 stringbuffer->strings[strindex] = (char *)Mem_Alloc(prog->progs_mempool, alloclen);
3920 memcpy(stringbuffer->strings[strindex], str, alloclen);
3921 }
3922
3923 BufStr_Shrink(prog, stringbuffer);
3924}
3925
3927{
3928 int i;
3929
3930 if (!stringbuffer)
3931 return;
3932
3933 for (i = 0;i < stringbuffer->num_strings;i++)
3934 if (stringbuffer->strings[i])
3935 Mem_Free(stringbuffer->strings[i]);
3936 if (stringbuffer->strings)
3937 Mem_Free(stringbuffer->strings);
3938 if(stringbuffer->origin)
3939 PRVM_Free((char *)stringbuffer->origin);
3941}
3942
3944{
3945 prvm_stringbuffer_t *stringbuffer;
3946 int i, numbuffers;
3947
3949 for (i = 0; i < numbuffers; i++)
3951 BufStr_Del(prog, stringbuffer);
3953}
3954
3955/*
3956========================
3957VM_buf_create
3958creates new buffer, and returns it's index, returns -1 if failed
3959float buf_create(prvm_prog_t *prog) = #460;
3960float newbuf(string format, float flags) = #460;
3961========================
3962*/
3963
3965{
3966 prvm_stringbuffer_t *stringbuffer;
3967 int i;
3968
3970
3971 // VorteX: optional parm1 (buffer format) is unfinished, to keep intact with future databuffers extension must be set to "string"
3972 if(prog->argc >= 1 && strcmp(PRVM_G_STRING(OFS_PARM0), "string"))
3973 {
3975 return;
3976 }
3978 for (i = 0;stringbuffer != Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, i);i++);
3979 stringbuffer->origin = PRVM_AllocationOrigin(prog);
3980 // optional flags parm
3981 if (prog->argc >= 2)
3984}
3985
3986
3987
3988/*
3989========================
3990VM_buf_del
3991deletes buffer and all strings in it
3992void buf_del(float bufhandle) = #461;
3993========================
3994*/
3996{
3997 prvm_stringbuffer_t *stringbuffer;
4000 if (stringbuffer)
4001 BufStr_Del(prog, stringbuffer);
4002 else
4003 {
4004 VM_Warning(prog, "VM_buf_del: invalid buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM0));
4005 return;
4006 }
4007}
4008
4009/*
4010========================
4011VM_buf_getsize
4012how many strings are stored in buffer
4013float buf_getsize(float bufhandle) = #462;
4014========================
4015*/
4017{
4018 prvm_stringbuffer_t *stringbuffer;
4020
4022 if(!stringbuffer)
4023 {
4025 VM_Warning(prog, "VM_buf_getsize: invalid buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM0));
4026 return;
4027 }
4028 else
4029 PRVM_G_FLOAT(OFS_RETURN) = stringbuffer->num_strings;
4030}
4031
4032/*
4033========================
4034VM_buf_copy
4035copy all content from one buffer to another, make sure it exists
4036void buf_copy(float bufhandle_from, float bufhandle_to) = #463;
4037========================
4038*/
4040{
4041 prvm_stringbuffer_t *srcstringbuffer, *dststringbuffer;
4042 int i;
4044
4046 if(!srcstringbuffer)
4047 {
4048 VM_Warning(prog, "VM_buf_copy: invalid source buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM0));
4049 return;
4050 }
4052 if(i == (int)PRVM_G_FLOAT(OFS_PARM0))
4053 {
4054 VM_Warning(prog, "VM_buf_copy: source == destination (%i)\n", i);
4055 return;
4056 }
4058 if(!dststringbuffer)
4059 {
4060 VM_Warning(prog, "VM_buf_copy: invalid destination buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM1));
4061 return;
4062 }
4063
4064 for (i = 0;i < dststringbuffer->num_strings;i++)
4065 if (dststringbuffer->strings[i])
4066 Mem_Free(dststringbuffer->strings[i]);
4067 if (dststringbuffer->strings)
4068 Mem_Free(dststringbuffer->strings);
4069 *dststringbuffer = *srcstringbuffer;
4070 if (dststringbuffer->max_strings)
4071 dststringbuffer->strings = (char **)Mem_Alloc(prog->progs_mempool, sizeof(dststringbuffer->strings[0]) * dststringbuffer->max_strings);
4072
4073 for (i = 0;i < dststringbuffer->num_strings;i++)
4074 {
4075 if (srcstringbuffer->strings[i])
4076 {
4077 size_t stringlen;
4078 stringlen = strlen(srcstringbuffer->strings[i]) + 1;
4079 dststringbuffer->strings[i] = (char *)Mem_Alloc(prog->progs_mempool, stringlen);
4080 memcpy(dststringbuffer->strings[i], srcstringbuffer->strings[i], stringlen);
4081 }
4082 }
4083}
4084
4085/*
4086========================
4087VM_buf_sort
4088sort buffer by beginnings of strings (cmplength defaults it's length)
4089"backward == true" means that sorting goes upside-down
4090void buf_sort(float bufhandle, float cmplength, float backward) = #464;
4091========================
4092*/
4094{
4095 prvm_stringbuffer_t *stringbuffer;
4097
4099 if(!stringbuffer)
4100 {
4101 VM_Warning(prog, "VM_buf_sort: invalid buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM0));
4102 return;
4103 }
4104 if(stringbuffer->num_strings <= 0)
4105 {
4106 VM_Warning(prog, "VM_buf_sort: tried to sort empty buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM0));
4107 return;
4108 }
4111 stringbuffers_sortlength = 0x7FFFFFFF;
4112
4114 qsort(stringbuffer->strings, stringbuffer->num_strings, sizeof(char*), BufStr_SortStringsUP);
4115 else
4116 qsort(stringbuffer->strings, stringbuffer->num_strings, sizeof(char*), BufStr_SortStringsDOWN);
4117
4118 BufStr_Shrink(prog, stringbuffer);
4119}
4120
4121/*
4122========================
4123VM_buf_implode
4124concantenates all buffer string into one with "glue" separator and returns it as tempstring
4125string buf_implode(float bufhandle, string glue) = #465;
4126========================
4127*/
4129{
4130 prvm_stringbuffer_t *stringbuffer;
4131 char k[VM_TEMPSTRING_MAXSIZE];
4132 size_t k_len;
4133 const char *sep;
4134 int i;
4135 size_t l;
4136
4138
4141 if(!stringbuffer)
4142 {
4143 VM_Warning(prog, "VM_buf_implode: invalid buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM0));
4144 return;
4145 }
4146 if(!stringbuffer->num_strings)
4147 return;
4148 sep = PRVM_G_STRING(OFS_PARM1);
4149 k[0] = '\0';
4150 k_len = 0;
4151 for(l = i = 0;i < stringbuffer->num_strings;i++)
4152 {
4153 if(stringbuffer->strings[i])
4154 {
4155 l += (i > 0 ? strlen(sep) : 0) + strlen(stringbuffer->strings[i]);
4156 if (l >= sizeof(k) - 1)
4157 break;
4158 dp_strlcat(k, sep, sizeof(k));
4159 k_len = dp_strlcat(k, stringbuffer->strings[i], sizeof(k));
4160 }
4161 }
4162 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, k, k_len);
4163}
4164
4165/*
4166========================
4167VM_bufstr_get
4168get a string from buffer, returns tempstring, dont str_unzone it!
4169string bufstr_get(float bufhandle, float string_index) = #465;
4170========================
4171*/
4173{
4174 prvm_stringbuffer_t *stringbuffer;
4175 int strindex;
4177
4180 if(!stringbuffer)
4181 {
4182 VM_Warning(prog, "VM_bufstr_get: invalid buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM0));
4183 return;
4184 }
4185 strindex = (int)PRVM_G_FLOAT(OFS_PARM1);
4186 if (strindex < 0)
4187 {
4188 // VM_Warning(prog, "VM_bufstr_get: invalid string index %i\n", strindex);
4189 return;
4190 }
4191 if (strindex < stringbuffer->num_strings && stringbuffer->strings[strindex])
4192 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, stringbuffer->strings[strindex], strlen(stringbuffer->strings[strindex]));
4193}
4194
4195/*
4196========================
4197VM_bufstr_set
4198copies a string into selected slot of buffer
4199void bufstr_set(float bufhandle, float string_index, string str) = #466;
4200========================
4201*/
4203{
4204 int strindex;
4205 prvm_stringbuffer_t *stringbuffer;
4206 const char *news;
4207
4209
4211 if(!stringbuffer)
4212 {
4213 VM_Warning(prog, "VM_bufstr_set: invalid buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM0));
4214 return;
4215 }
4216 strindex = (int)PRVM_G_FLOAT(OFS_PARM1);
4217 if(strindex < 0 || strindex >= 1000000) // huge number of strings
4218 {
4219 VM_Warning(prog, "VM_bufstr_set: invalid string index %i\n", strindex);
4220 return;
4221 }
4222
4223 news = PRVM_G_STRING(OFS_PARM2);
4224 BufStr_Set(prog, stringbuffer, strindex, news);
4225}
4226
4227/*
4228========================
4229VM_bufstr_add
4230adds string to buffer in first free slot and returns its index
4231"order == true" means that string will be added after last "full" slot
4232float bufstr_add(float bufhandle, string str, float order) = #467;
4233========================
4234*/
4236{
4237 int order, strindex;
4238 prvm_stringbuffer_t *stringbuffer;
4239 const char *string;
4240 size_t alloclen;
4241
4243
4246 if(!stringbuffer)
4247 {
4248 VM_Warning(prog, "VM_bufstr_add: invalid buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM0));
4249 return;
4250 }
4251 if(!PRVM_G_INT(OFS_PARM1)) // NULL string
4252 {
4253 VM_Warning(prog, "VM_bufstr_add: can not add an empty string to buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM0));
4254 return;
4255 }
4256 string = PRVM_G_STRING(OFS_PARM1);
4257 order = (int)PRVM_G_FLOAT(OFS_PARM2);
4258 if(order)
4259 strindex = stringbuffer->num_strings;
4260 else
4261 for (strindex = 0;strindex < stringbuffer->num_strings;strindex++)
4262 if (stringbuffer->strings[strindex] == NULL)
4263 break;
4264
4265 BufStr_Expand(prog, stringbuffer, strindex);
4266
4267 stringbuffer->num_strings = max(stringbuffer->num_strings, strindex + 1);
4268 alloclen = strlen(string) + 1;
4269 stringbuffer->strings[strindex] = (char *)Mem_Alloc(prog->progs_mempool, alloclen);
4270 memcpy(stringbuffer->strings[strindex], string, alloclen);
4271
4272 PRVM_G_FLOAT(OFS_RETURN) = strindex;
4273}
4274
4275/*
4276========================
4277VM_bufstr_free
4278delete string from buffer
4279void bufstr_free(float bufhandle, float string_index) = #468;
4280========================
4281*/
4283{
4284 int i;
4285 prvm_stringbuffer_t *stringbuffer;
4287
4289 if(!stringbuffer)
4290 {
4291 VM_Warning(prog, "VM_bufstr_free: invalid buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM0));
4292 return;
4293 }
4295 if(i < 0)
4296 {
4297 VM_Warning(prog, "VM_bufstr_free: invalid string index %i\n", i);
4298 return;
4299 }
4300
4301 if (i < stringbuffer->num_strings)
4302 {
4303 if(stringbuffer->strings[i])
4304 Mem_Free(stringbuffer->strings[i]);
4305 stringbuffer->strings[i] = NULL;
4306 }
4307
4308 BufStr_Shrink(prog, stringbuffer);
4309}
4310
4311/*
4312========================
4313VM_buf_loadfile
4314load a file into string buffer, return 0 or 1
4315float buf_loadfile(string filename, float bufhandle) = #535;
4316========================
4317*/
4319{
4320 size_t alloclen;
4321 prvm_stringbuffer_t *stringbuffer;
4322 char string[VM_TEMPSTRING_MAXSIZE];
4323 int strindex, c, end;
4324 const char *filename;
4325 char vabuf[1024];
4326 qfile_t *file;
4327
4329
4330 // get file
4331 filename = PRVM_G_STRING(OFS_PARM0);
4332 file = FS_OpenVirtualFile(va(vabuf, sizeof(vabuf), "data/%s", filename), false);
4333 if (file == NULL)
4334 file = FS_OpenVirtualFile(va(vabuf, sizeof(vabuf), "%s", filename), false);
4335 if (file == NULL)
4336 {
4338 VM_Warning(prog, "VM_buf_loadfile: failed to open file %s\n", filename);
4340 return;
4341 }
4342
4343 // get string buffer
4345 if(!stringbuffer)
4346 {
4347 VM_Warning(prog, "VM_buf_loadfile: invalid buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM1));
4349 return;
4350 }
4351
4352 // read file (append to the end of buffer)
4353 strindex = stringbuffer->num_strings;
4354 while(1)
4355 {
4356 // read line
4357 end = 0;
4358 for (;;)
4359 {
4360 c = FS_Getc(file);
4361 if (c == '\r' || c == '\n' || c < 0)
4362 break;
4363 if (end < VM_TEMPSTRING_MAXSIZE - 1)
4364 string[end++] = c;
4365 }
4366 string[end] = 0;
4367 // remove \n following \r
4368 if (c == '\r')
4369 {
4370 c = FS_Getc(file);
4371 if (c != '\n')
4372 FS_UnGetc(file, (unsigned char)c);
4373 }
4374 // add and continue
4375 if (c >= 0 || end)
4376 {
4377 BufStr_Expand(prog, stringbuffer, strindex);
4378 stringbuffer->num_strings = max(stringbuffer->num_strings, strindex + 1);
4379 alloclen = strlen(string) + 1;
4380 stringbuffer->strings[strindex] = (char *)Mem_Alloc(prog->progs_mempool, alloclen);
4381 memcpy(stringbuffer->strings[strindex], string, alloclen);
4382 strindex = stringbuffer->num_strings;
4383 }
4384 else
4385 break;
4386 }
4387
4388 // close file
4389 FS_Close(file);
4391}
4392
4393/*
4394========================
4395VM_buf_writefile
4396writes stringbuffer to a file, returns 0 or 1
4397float buf_writefile(float filehandle, float bufhandle, [, float startpos, float numstrings]) = #468;
4398========================
4399*/
4400
4402{
4403 int filenum, strindex, strnum, strlength;
4404 prvm_stringbuffer_t *stringbuffer;
4405
4407
4408 // get file
4409 filenum = (int)PRVM_G_FLOAT(OFS_PARM0);
4410 if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES)
4411 {
4412 VM_Warning(prog, "VM_buf_writefile: invalid file handle %i\n", filenum);
4413 return;
4414 }
4415 if (prog->openfiles[filenum] == NULL)
4416 {
4417 VM_Warning(prog, "VM_buf_writefile: no such file handle %i (or file has been closed)\n", filenum);
4418 return;
4419 }
4420
4421 // get string buffer
4423 if(!stringbuffer)
4424 {
4425 VM_Warning(prog, "VM_buf_writefile: invalid buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM1));
4427 return;
4428 }
4429
4430 // get start and end parms
4431 if (prog->argc > 3)
4432 {
4433 strindex = (int)PRVM_G_FLOAT(OFS_PARM2);
4434 strnum = (int)PRVM_G_FLOAT(OFS_PARM3);
4435 }
4436 else if (prog->argc > 2)
4437 {
4438 strindex = (int)PRVM_G_FLOAT(OFS_PARM2);
4439 strnum = stringbuffer->num_strings - strindex;
4440 }
4441 else
4442 {
4443 strindex = 0;
4444 strnum = stringbuffer->num_strings;
4445 }
4446 if (strindex < 0 || strindex >= stringbuffer->num_strings)
4447 {
4448 VM_Warning(prog, "VM_buf_writefile: wrong start string index %i\n", strindex);
4450 return;
4451 }
4452 if (strnum < 0)
4453 {
4454 VM_Warning(prog, "VM_buf_writefile: wrong strings count %i\n", strnum);
4456 return;
4457 }
4458
4459 // write
4460 while(strindex < stringbuffer->num_strings && strnum)
4461 {
4462 if (stringbuffer->strings[strindex])
4463 {
4464 if ((strlength = (int)strlen(stringbuffer->strings[strindex])))
4465 FS_Write(prog->openfiles[filenum], stringbuffer->strings[strindex], strlength);
4466 FS_Write(prog->openfiles[filenum], "\n", 1);
4467 }
4468 strindex++;
4469 strnum--;
4470 }
4471
4473}
4474
4475#define MATCH_AUTO 0
4476#define MATCH_WHOLE 1
4477#define MATCH_LEFT 2
4478#define MATCH_RIGHT 3
4479#define MATCH_MIDDLE 4
4480#define MATCH_PATTERN 5
4481
4482static const char *detect_match_rule(char *pattern, int *matchrule)
4483{
4484 char *ppos, *qpos;
4485 int patternlength;
4486
4487 patternlength = (int)strlen(pattern);
4488 ppos = strchr(pattern, '*');
4489 qpos = strchr(pattern, '?');
4490 // has ? - pattern
4491 if (qpos)
4492 {
4493 *matchrule = MATCH_PATTERN;
4494 return pattern;
4495 }
4496 // has * - left, mid, right or pattern
4497 if (ppos)
4498 {
4499 // starts with * - may be right/mid or pattern
4500 if ((ppos - pattern) == 0)
4501 {
4502 ppos = strchr(pattern+1, '*');
4503 // *something
4504 if (!ppos)
4505 {
4506 *matchrule = MATCH_RIGHT;
4507 return pattern+1;
4508 }
4509 // *something*
4510 if ((ppos - pattern) == patternlength)
4511 {
4512 *matchrule = MATCH_MIDDLE;
4513 *ppos = 0;
4514 return pattern+1;
4515 }
4516 // *som*thing
4517 *matchrule = MATCH_PATTERN;
4518 return pattern;
4519 }
4520 // end with * - left
4521 if ((ppos - pattern) == patternlength)
4522 {
4523 *matchrule = MATCH_LEFT;
4524 *ppos = 0;
4525 return pattern;
4526 }
4527 // som*thing
4528 *matchrule = MATCH_PATTERN;
4529 return pattern;
4530 }
4531 // have no wildcards - whole string
4532 *matchrule = MATCH_WHOLE;
4533 return pattern;
4534}
4535
4536// todo: support UTF8
4537static qbool match_rule(const char *string, int max_string, const char *pattern, int patternlength, int rule)
4538{
4539 const char *mid;
4540
4541 if (rule == 1)
4542 return !strncmp(string, pattern, max_string) ? true : false;
4543 if (rule == 2)
4544 return !strncmp(string, pattern, patternlength) ? true : false;
4545 if (rule == 3)
4546 {
4547 mid = strstr(string, pattern);
4548 return mid && !*(mid+patternlength);
4549 }
4550 if (rule == 4)
4551 return strstr(string, pattern) ? true : false;
4552 // pattern
4553 return matchpattern_with_separator(string, pattern, false, "", false) ? true : false;
4554}
4555
4556/*
4557========================
4558VM_bufstr_find
4559find an index of bufstring matching rule
4560float bufstr_find(float bufhandle, string match, float matchrule, float startpos, float step) = #468;
4561========================
4562*/
4563
4565{
4566 prvm_stringbuffer_t *stringbuffer;
4567 char string[VM_TEMPSTRING_MAXSIZE];
4568 int matchrule, matchlen, i, step;
4569 const char *match;
4570
4572
4574
4575 // get string buffer
4577 if(!stringbuffer)
4578 {
4579 VM_Warning(prog, "VM_bufstr_find: invalid buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM0));
4580 return;
4581 }
4582
4583 // get pattern/rule
4584 matchrule = (int)PRVM_G_FLOAT(OFS_PARM2);
4585 if (matchrule < 0 || matchrule > 5)
4586 {
4587 VM_Warning(prog, "VM_bufstr_find: invalid match rule %i\n", matchrule);
4588 return;
4589 }
4590 if (matchrule)
4591 match = PRVM_G_STRING(OFS_PARM1);
4592 else
4593 {
4594 dp_strlcpy(string, PRVM_G_STRING(OFS_PARM1), sizeof(string));
4595 match = detect_match_rule(string, &matchrule);
4596 }
4597 matchlen = (int)strlen(match);
4598
4599 // find
4600 i = (prog->argc > 3) ? (int)PRVM_G_FLOAT(OFS_PARM3) : 0;
4601 step = (prog->argc > 4) ? (int)PRVM_G_FLOAT(OFS_PARM4) : 1;
4602 while(i < stringbuffer->num_strings)
4603 {
4604 if (stringbuffer->strings[i] && match_rule(stringbuffer->strings[i], VM_TEMPSTRING_MAXSIZE, match, matchlen, matchrule))
4605 {
4607 break;
4608 }
4609 i += step;
4610 }
4611}
4612
4613/*
4614========================
4615VM_matchpattern
4616float matchpattern(string s, string pattern, float matchrule, float startpos) = #468;
4617========================
4618*/
4620{
4621 const char *s, *match;
4622 char string[VM_TEMPSTRING_MAXSIZE];
4623 int matchrule, l;
4624
4626
4628
4629 // get pattern/rule
4630 matchrule = (int)PRVM_G_FLOAT(OFS_PARM2);
4631 if (matchrule < 0 || matchrule > 5)
4632 {
4633 VM_Warning(prog, "VM_matchpattern: invalid match rule %i\n", matchrule);
4634 return;
4635 }
4636 if (matchrule)
4637 match = PRVM_G_STRING(OFS_PARM1);
4638 else
4639 {
4640 dp_strlcpy(string, PRVM_G_STRING(OFS_PARM1), sizeof(string));
4641 match = detect_match_rule(string, &matchrule);
4642 }
4643
4644 // offset
4645 l = (int)strlen(match);
4646 if (prog->argc > 3)
4647 s += max(0, min((unsigned int)PRVM_G_FLOAT(OFS_PARM3), strlen(s)-1));
4648
4649 // match
4650 PRVM_G_FLOAT(OFS_RETURN) = match_rule(s, VM_TEMPSTRING_MAXSIZE, match, l, matchrule);
4651}
4652
4653/*
4654========================
4655VM_buf_cvarlist
4656========================
4657*/
4658
4660{
4661 cvar_t *cvar;
4662 const char *partial, *antipartial;
4663 size_t len, antilen;
4664 size_t alloclen;
4665 qbool ispattern, antiispattern;
4666 int n;
4667 prvm_stringbuffer_t *stringbuffer;
4669
4671 if(!stringbuffer)
4672 {
4673 VM_Warning(prog, "VM_bufstr_free: invalid buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM0));
4674 return;
4675 }
4676
4677 partial = PRVM_G_STRING(OFS_PARM1);
4678 if(!partial)
4679 len = 0;
4680 else
4681 len = strlen(partial);
4682
4683 if(prog->argc == 3)
4684 antipartial = PRVM_G_STRING(OFS_PARM2);
4685 else
4686 antipartial = NULL;
4687 if(!antipartial)
4688 antilen = 0;
4689 else
4690 antilen = strlen(antipartial);
4691
4692 for (n = 0;n < stringbuffer->num_strings;n++)
4693 if (stringbuffer->strings[n])
4694 Mem_Free(stringbuffer->strings[n]);
4695 if (stringbuffer->strings)
4696 Mem_Free(stringbuffer->strings);
4697 stringbuffer->strings = NULL;
4698
4699 ispattern = partial && (strchr(partial, '*') || strchr(partial, '?'));
4700 antiispattern = antipartial && (strchr(antipartial, '*') || strchr(antipartial, '?'));
4701
4702 n = 0;
4703 for(cvar = prog->console_cmd->cvars->vars; cvar; cvar = cvar->next)
4704 {
4705 if(len && (ispattern ? !matchpattern_with_separator(cvar->name, partial, false, "", false) : strncmp(partial, cvar->name, len)))
4706 continue;
4707
4708 if(antilen && (antiispattern ? matchpattern_with_separator(cvar->name, antipartial, false, "", false) : !strncmp(antipartial, cvar->name, antilen)))
4709 continue;
4710
4711 ++n;
4712 }
4713
4714 stringbuffer->max_strings = stringbuffer->num_strings = n;
4715 if (stringbuffer->max_strings)
4716 stringbuffer->strings = (char **)Mem_Alloc(prog->progs_mempool, sizeof(stringbuffer->strings[0]) * stringbuffer->max_strings);
4717
4718 n = 0;
4719 for(cvar = prog->console_cmd->cvars->vars; cvar; cvar = cvar->next)
4720 {
4721 if(len && (ispattern ? !matchpattern_with_separator(cvar->name, partial, false, "", false) : strncmp(partial, cvar->name, len)))
4722 continue;
4723
4724 if(antilen && (antiispattern ? matchpattern_with_separator(cvar->name, antipartial, false, "", false) : !strncmp(antipartial, cvar->name, antilen)))
4725 continue;
4726
4727 alloclen = strlen(cvar->name) + 1;
4728 stringbuffer->strings[n] = (char *)Mem_Alloc(prog->progs_mempool, alloclen);
4729 memcpy(stringbuffer->strings[n], cvar->name, alloclen);
4730
4731 ++n;
4732 }
4733}
4734
4735
4736
4737
4738//=============
4739
4740/*
4741==============
4742VM_changeyaw
4743
4744This was a major timewaster in progs, so it was converted to C
4745==============
4746*/
4748{
4749 prvm_edict_t *ent;
4750 float ideal, current, move, speed;
4751
4752 // this is called (VERY HACKISHLY) by VM_SV_MoveToGoal, so it can not use any
4753 // parameters because they are the parameters to VM_SV_MoveToGoal, not this
4754 //VM_SAFEPARMCOUNT(0, VM_changeyaw);
4755
4757 if (ent == prog->edicts)
4758 {
4759 VM_Warning(prog, "changeyaw: can not modify world entity\n");
4760 return;
4761 }
4762 if (ent->free)
4763 {
4764 VM_Warning(prog, "changeyaw: can not modify free entity\n");
4765 return;
4766 }
4767 current = PRVM_gameedictvector(ent, angles)[1];
4768 current = ANGLEMOD(current);
4769 ideal = PRVM_gameedictfloat(ent, ideal_yaw);
4770 speed = PRVM_gameedictfloat(ent, yaw_speed);
4771
4772 if (current == ideal)
4773 return;
4774 move = ideal - current;
4775 if (ideal > current)
4776 {
4777 if (move >= 180)
4778 move = move - 360;
4779 }
4780 else
4781 {
4782 if (move <= -180)
4783 move = move + 360;
4784 }
4785 if (move > 0)
4786 {
4787 if (move > speed)
4788 move = speed;
4789 }
4790 else
4791 {
4792 if (move < -speed)
4793 move = -speed;
4794 }
4795
4796 current += move;
4797 PRVM_gameedictvector(ent, angles)[1] = ANGLEMOD(current);
4798}
4799
4800/*
4801==============
4802VM_changepitch
4803==============
4804*/
4806{
4807 prvm_edict_t *ent;
4808 float ideal, current, move, speed;
4809
4811
4812 ent = PRVM_G_EDICT(OFS_PARM0);
4813 if (ent == prog->edicts)
4814 {
4815 VM_Warning(prog, "changepitch: can not modify world entity\n");
4816 return;
4817 }
4818 if (ent->free)
4819 {
4820 VM_Warning(prog, "changepitch: can not modify free entity\n");
4821 return;
4822 }
4823 current = PRVM_gameedictvector(ent, angles)[0];
4824 current = ANGLEMOD(current);
4825 ideal = PRVM_gameedictfloat(ent, idealpitch);
4826 speed = PRVM_gameedictfloat(ent, pitch_speed);
4827
4828 if (current == ideal)
4829 return;
4830 move = ideal - current;
4831 if (ideal > current)
4832 {
4833 if (move >= 180)
4834 move = move - 360;
4835 }
4836 else
4837 {
4838 if (move <= -180)
4839 move = move + 360;
4840 }
4841 if (move > 0)
4842 {
4843 if (move > speed)
4844 move = speed;
4845 }
4846 else
4847 {
4848 if (move < -speed)
4849 move = -speed;
4850 }
4851
4852 current += move;
4853 PRVM_gameedictvector(ent, angles)[0] = ANGLEMOD(current);
4854}
4855
4856
4858{
4859 char szNewString[VM_TEMPSTRING_MAXSIZE];
4860 size_t szNewString_len;
4861 const char *szString;
4862
4863 // Prepare Strings
4865 szString = PRVM_G_STRING(OFS_PARM0);
4866 szNewString_len = COM_StringDecolorize(szString, 0, szNewString, sizeof(szNewString), true);
4867 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString, szNewString_len);
4868}
4869
4870// #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
4871//strstr, without generating a new string. Use in conjunction with FRIK_FILE's substring for more similar strstr.
4873{
4874 const char *instr, *match;
4875 int firstofs;
4877 instr = PRVM_G_STRING(OFS_PARM0);
4878 match = PRVM_G_STRING(OFS_PARM1);
4879 firstofs = (prog->argc > 2)?(int)PRVM_G_FLOAT(OFS_PARM2):0;
4880 firstofs = (int)u8_bytelen(instr, firstofs);
4881
4882 if (firstofs && (firstofs < 0 || firstofs > (int)strlen(instr)))
4883 {
4885 return;
4886 }
4887
4888 match = strstr(instr+firstofs, match);
4889 if (!match)
4891 else
4892 PRVM_G_FLOAT(OFS_RETURN) = u8_strnlen(instr, match-instr);
4893}
4894
4895//#222 string(string s, float index) str2chr (FTE_STRINGS)
4897{
4898 const char *s;
4899 Uchar ch;
4900 int index;
4904
4905 if((unsigned)index < strlen(s))
4906 {
4907 if (utf8_enable.integer)
4908 ch = u8_getchar_noendptr(s + index);
4909 else
4910 ch = (unsigned char)s[index];
4912 }
4913 else
4915}
4916
4917//#223 string(float c, ...) chr2str (FTE_STRINGS)
4919{
4920 /*
4921 char t[9];
4922 int i;
4923 VM_SAFEPARMCOUNTRANGE(0, 8, VM_chr2str);
4924 for(i = 0;i < prog->argc && i < (int)sizeof(t) - 1;i++)
4925 t[i] = (unsigned char)PRVM_G_FLOAT(OFS_PARM0+i*3);
4926 t[i] = 0;
4927 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, t);
4928 */
4929 char t[9 * 4 + 1];
4930 int i;
4931 size_t len = 0;
4932
4934 for(i = 0; i < prog->argc && len < sizeof(t)-1; ++i)
4935 len += u8_fromchar((Uchar)PRVM_G_FLOAT(OFS_PARM0+i*3), t + len, sizeof(t)-1);
4936 t[len] = '\0';
4937 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, t, len);
4938}
4939
4940static int chrconv_number(int i, int base, int conv)
4941{
4942 i -= base;
4943 switch (conv)
4944 {
4945 default:
4946 case 5:
4947 case 6:
4948 case 0:
4949 break;
4950 case 1:
4951 base = '0';
4952 break;
4953 case 2:
4954 base = '0'+128;
4955 break;
4956 case 3:
4957 base = '0'-30;
4958 break;
4959 case 4:
4960 base = '0'+128-30;
4961 break;
4962 }
4963 return i + base;
4964}
4965static int chrconv_punct(int i, int base, int conv)
4966{
4967 i -= base;
4968 switch (conv)
4969 {
4970 default:
4971 case 0:
4972 break;
4973 case 1:
4974 base = 0;
4975 break;
4976 case 2:
4977 base = 128;
4978 break;
4979 }
4980 return i + base;
4981}
4982
4983static int chrchar_alpha(int i, int basec, int baset, int convc, int convt, int charnum)
4984{
4985 //convert case and colour seperatly...
4986
4987 i -= baset + basec;
4988 switch (convt)
4989 {
4990 default:
4991 case 0:
4992 break;
4993 case 1:
4994 baset = 0;
4995 break;
4996 case 2:
4997 baset = 128;
4998 break;
4999
5000 case 5:
5001 case 6:
5002 baset = 128*((charnum&1) == (convt-5));
5003 break;
5004 }
5005
5006 switch (convc)
5007 {
5008 default:
5009 case 0:
5010 break;
5011 case 1:
5012 basec = 'a';
5013 break;
5014 case 2:
5015 basec = 'A';
5016 break;
5017 }
5018 return i + basec + baset;
5019}
5020// #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
5021//bulk convert a string. change case or colouring.
5023{
5024 int ccase, redalpha, rednum;
5025 unsigned i;
5026 size_t resbuf_len;
5027 unsigned char resbuf[VM_TEMPSTRING_MAXSIZE];
5028 unsigned char *result = resbuf;
5029
5031
5032 ccase = (int) PRVM_G_FLOAT(OFS_PARM0); //0 same, 1 lower, 2 upper
5033 redalpha = (int) PRVM_G_FLOAT(OFS_PARM1); //0 same, 1 white, 2 red, 5 alternate, 6 alternate-alternate
5034 rednum = (int) PRVM_G_FLOAT(OFS_PARM2); //0 same, 1 white, 2 red, 3 redspecial, 4 whitespecial, 5 alternate, 6 alternate-alternate
5035 resbuf_len = VM_VarString(prog, 3, (char *) resbuf, sizeof(resbuf));
5036
5037 for (i = 0; i < resbuf_len; i++, result++) //should this be done backwards?
5038 {
5039 if (*result >= '0' && *result <= '9') //normal numbers...
5040 *result = chrconv_number(*result, '0', rednum);
5041 else if (*result >= '0'+128 && *result <= '9'+128)
5042 *result = chrconv_number(*result, '0'+128, rednum);
5043 else if (*result >= '0'+128-30 && *result <= '9'+128-30)
5044 *result = chrconv_number(*result, '0'+128-30, rednum);
5045 else if (*result >= '0'-30 && *result <= '9'-30)
5046 *result = chrconv_number(*result, '0'-30, rednum);
5047
5048 else if (*result >= 'a' && *result <= 'z') //normal numbers...
5049 *result = chrchar_alpha(*result, 'a', 0, ccase, redalpha, i);
5050 else if (*result >= 'A' && *result <= 'Z') //normal numbers...
5051 *result = chrchar_alpha(*result, 'A', 0, ccase, redalpha, i);
5052 else if (*result >= 'a'+128 && *result <= 'z'+128) //normal numbers...
5053 *result = chrchar_alpha(*result, 'a', 128, ccase, redalpha, i);
5054 else if (*result >= 'A'+128 && *result <= 'Z'+128) //normal numbers...
5055 *result = chrchar_alpha(*result, 'A', 128, ccase, redalpha, i);
5056
5057 else if ((*result & 127) < 16 || !redalpha) //special chars..
5058 *result = *result;
5059 else if (*result < 128)
5060 *result = chrconv_punct(*result, 0, redalpha);
5061 else
5062 *result = chrconv_punct(*result, 128, redalpha);
5063 }
5064 *result = '\0';
5065
5066 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, (char *)resbuf, result - resbuf);
5067}
5068
5069// #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
5071{
5073 char destbuf[VM_TEMPSTRING_MAXSIZE];
5074 size_t destbuf_len;
5075 int pad;
5076
5078 pad = (int) PRVM_G_FLOAT(OFS_PARM0);
5079 VM_VarString(prog, 1, src, sizeof(src));
5080
5081 // note: < 0 = left padding, > 0 = right padding,
5082 // this is reverse logic of printf!
5083 destbuf_len = dpsnprintf(destbuf, sizeof(destbuf), "%*s", -pad, src);
5084
5085 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, destbuf, destbuf_len);
5086}
5087
5088// #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
5089//uses qw style \key\value strings
5091{
5092 const char *info, *key;
5094 char temp[VM_TEMPSTRING_MAXSIZE];
5095
5097 info = PRVM_G_STRING(OFS_PARM0);
5098 key = PRVM_G_STRING(OFS_PARM1);
5099 VM_VarString(prog, 2, value, sizeof(value));
5100
5101 dp_strlcpy(temp, info, VM_TEMPSTRING_MAXSIZE);
5102
5104
5105 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, temp, strlen(temp));
5106}
5107
5108// #227 string(string info, string key) infoget (FTE_STRINGS)
5109//uses qw style \key\value strings
5111{
5112 const char *info;
5113 const char *key;
5115
5117 info = PRVM_G_STRING(OFS_PARM0);
5118 key = PRVM_G_STRING(OFS_PARM1);
5119
5121
5123}
5124
5125//#228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
5126// also float(string s1, string s2) strcmp (FRIK_FILE)
5128{
5129 const char *s1, *s2;
5133 if (prog->argc > 2)
5134 {
5135 PRVM_G_FLOAT(OFS_RETURN) = strncmp(s1, s2, (size_t)PRVM_G_FLOAT(OFS_PARM2));
5136 }
5137 else
5138 {
5139 PRVM_G_FLOAT(OFS_RETURN) = strcmp(s1, s2);
5140 }
5141}
5142
5143// #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
5144// #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
5146{
5147 const char *s1, *s2;
5151 if (prog->argc > 2)
5152 {
5153 PRVM_G_FLOAT(OFS_RETURN) = strncasecmp(s1, s2, (size_t)PRVM_G_FLOAT(OFS_PARM2));
5154 }
5155 else
5156 {
5157 PRVM_G_FLOAT(OFS_RETURN) = strcasecmp(s1, s2);
5158 }
5159}
5160
5161// #494 float(float caseinsensitive, string s, ...) crc16
5163{
5164 float insensitive;
5165 char s[VM_TEMPSTRING_MAXSIZE];
5166 size_t slen;
5167
5169 insensitive = PRVM_G_FLOAT(OFS_PARM0);
5170 slen = VM_VarString(prog, 1, s, sizeof(s));
5171 PRVM_G_FLOAT(OFS_RETURN) = (unsigned short) ((insensitive ? CRC_Block_CaseInsensitive : CRC_Block) ((unsigned char *) s, slen));
5172}
5173
5174// #639 float(string digest, string data, ...) digest_hex
5176{
5177 const char *digest;
5178
5179 char out[32];
5180 char outhex[65];
5181 int outlen;
5182
5183 char s[VM_TEMPSTRING_MAXSIZE];
5184 size_t len;
5185
5187 digest = PRVM_G_STRING(OFS_PARM0);
5188 if(!digest)
5189 digest = "";
5190 len = VM_VarString(prog, 1, s, sizeof(s));
5191
5192 outlen = 0;
5193
5194 if(!strcmp(digest, "MD4"))
5195 {
5196 outlen = 16;
5197 mdfour((unsigned char *) out, (unsigned char *) s, len);
5198 }
5199 else if(!strcmp(digest, "SHA256") && Crypto_Available())
5200 {
5201 outlen = 32;
5202 sha256((unsigned char *) out, (unsigned char *) s, len);
5203 }
5204 // no warning needed on mismatch - we return string_null to QC
5205
5206 if(outlen)
5207 {
5208 int i;
5209 static const char *hexmap = "0123456789abcdef";
5210 for(i = 0; i < outlen; ++i)
5211 {
5212 outhex[2*i] = hexmap[(out[i] >> 4) & 15];
5213 outhex[2*i+1] = hexmap[(out[i] >> 0) & 15];
5214 }
5215 outhex[2*i] = '\0';
5216 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outhex, 2*i);
5217 }
5218 else
5220}
5221
5227
5244
5262
5263//=============
5264
5266{
5267 // only init the stuff for the current prog
5268 VM_Files_Init(prog);
5269 VM_Search_Init(prog);
5270}
5271
5272static void animatemodel_reset(prvm_prog_t *prog);
5273
5275{
5277 VM_Search_Reset(prog);
5278 VM_Files_CloseAll(prog);
5279 animatemodel_reset(prog);
5280}
5281
5282// #510 string(string input, ...) uri_escape (DP_QC_URI_ESCAPE)
5283// does URI escaping on a string (replace evil stuff by %AB escapes)
5285{
5287 char dest[VM_TEMPSTRING_MAXSIZE];
5288 char *p, *q;
5289 static const char *hex = "0123456789ABCDEF";
5290
5292 VM_VarString(prog, 0, src, sizeof(src));
5293
5294 for(p = src, q = dest; *p && q < dest + sizeof(dest) - 3; ++p)
5295 {
5296 if((*p >= 'A' && *p <= 'Z')
5297 || (*p >= 'a' && *p <= 'z')
5298 || (*p >= '0' && *p <= '9')
5299 || (*p == '-') || (*p == '_') || (*p == '.')
5300 || (*p == '!') || (*p == '~')
5301 || (*p == '\'') || (*p == '(') || (*p == ')'))
5302 *q++ = *p;
5303 else
5304 {
5305 *q++ = '%';
5306 *q++ = hex[(*(unsigned char *)p >> 4) & 0xF];
5307 *q++ = hex[ *(unsigned char *)p & 0xF];
5308 }
5309 }
5310 *q = '\0';
5311
5312 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, dest, q - dest);
5313}
5314
5315// #510 string(string input, ...) uri_unescape (DP_QC_URI_ESCAPE)
5316// does URI unescaping on a string (get back the evil stuff)
5318{
5320 char dest[VM_TEMPSTRING_MAXSIZE];
5321 char *p, *q;
5322 int hi, lo;
5323
5325 VM_VarString(prog, 0, src, sizeof(src));
5326
5327 for(p = src, q = dest; *p; ) // no need to check size, because unescape can't expand
5328 {
5329 if(*p == '%')
5330 {
5331 if(p[1] >= '0' && p[1] <= '9')
5332 hi = p[1] - '0';
5333 else if(p[1] >= 'a' && p[1] <= 'f')
5334 hi = p[1] - 'a' + 10;
5335 else if(p[1] >= 'A' && p[1] <= 'F')
5336 hi = p[1] - 'A' + 10;
5337 else
5338 goto nohex;
5339 if(p[2] >= '0' && p[2] <= '9')
5340 lo = p[2] - '0';
5341 else if(p[2] >= 'a' && p[2] <= 'f')
5342 lo = p[2] - 'a' + 10;
5343 else if(p[2] >= 'A' && p[2] <= 'F')
5344 lo = p[2] - 'A' + 10;
5345 else
5346 goto nohex;
5347 if(hi != 0 || lo != 0) // don't unescape NUL bytes
5348 *q++ = (char) (hi * 0x10 + lo);
5349 p += 3;
5350 continue;
5351 }
5352
5353nohex:
5354 // otherwise:
5355 *q++ = *p++;
5356 }
5357 *q = '\0';
5358
5359 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, dest, q - dest);
5360}
5361
5362// #502 string(string filename) whichpack (DP_QC_WHICHPACK)
5363// returns the name of the pack containing a file, or "" if it is not in any pack (but local or non-existant)
5365{
5366 const char *fn, *pack;
5367
5370 pack = FS_WhichPack(fn);
5371
5372 PRVM_G_INT(OFS_RETURN) = pack ? PRVM_SetTempString(prog, pack, strlen(pack)) : 0;
5373}
5374
5375typedef struct
5376{
5379 float id;
5381 char posttype[128];
5382 unsigned char *postdata; // free when uri_to_prog_t is freed
5383 size_t postlen;
5384 char *sigdata; // free when uri_to_prog_t is freed
5385 size_t siglen;
5386}
5388
5389static void uri_to_string_callback(int status, size_t length_received, unsigned char *buffer, void *cbdata)
5390{
5391 prvm_prog_t *prog;
5392 uri_to_prog_t *handle = (uri_to_prog_t *) cbdata;
5393
5394 prog = handle->prog;
5395 if(!prog->loaded)
5396 {
5397 // curl reply came too late... so just drop it
5398 if(handle->postdata)
5399 Z_Free(handle->postdata);
5400 if(handle->sigdata)
5401 Z_Free(handle->sigdata);
5402 Z_Free(handle);
5403 return;
5404 }
5405
5406 if((prog->starttime == handle->starttime) && (PRVM_allfunction(URI_Get_Callback)))
5407 {
5408 if(length_received >= sizeof(handle->buffer))
5409 length_received = sizeof(handle->buffer) - 1;
5410 handle->buffer[length_received] = '\0';
5411
5412 PRVM_G_FLOAT(OFS_PARM0) = handle->id;
5413 PRVM_G_FLOAT(OFS_PARM1) = status;
5414 PRVM_G_INT(OFS_PARM2) = PRVM_SetTempString(prog, handle->buffer, length_received);
5415 prog->ExecuteProgram(prog, PRVM_allfunction(URI_Get_Callback), "QC function URI_Get_Callback is missing");
5416 }
5417
5418 if(handle->postdata)
5419 Z_Free(handle->postdata);
5420 if(handle->sigdata)
5421 Z_Free(handle->sigdata);
5422 Z_Free(handle);
5423}
5424
5425// uri_get() gets content from an URL and calls a callback "uri_get_callback" with it set as string; an unique ID of the transfer is returned
5426// returns 1 on success, and then calls the callback with the ID, 0 or the HTTP status code, and the received data in a string
5428{
5429 const char *url;
5430 float id;
5431 qbool ret;
5432 uri_to_prog_t *handle;
5433 const char *posttype = NULL;
5434 const char *postseparator = NULL;
5435 int poststringbuffer = -1;
5436 int postkeyid = -1;
5437 const char *query_string = NULL;
5438 size_t lq;
5439
5440 if(!PRVM_allfunction(URI_Get_Callback))
5441 prog->error_cmd("uri_get called by %s without URI_Get_Callback defined", prog->name);
5442
5444
5445 url = PRVM_G_STRING(OFS_PARM0);
5446 id = PRVM_G_FLOAT(OFS_PARM1);
5447 if(prog->argc >= 3)
5448 posttype = PRVM_G_STRING(OFS_PARM2);
5449 if(prog->argc >= 4)
5450 postseparator = PRVM_G_STRING(OFS_PARM3);
5451 if(prog->argc >= 5)
5452 poststringbuffer = PRVM_G_FLOAT(OFS_PARM4);
5453 if(prog->argc >= 6)
5454 postkeyid = PRVM_G_FLOAT(OFS_PARM5);
5455 handle = (uri_to_prog_t *) Z_Malloc(sizeof(*handle)); // this can't be the prog's mem pool, as curl may call the callback later!
5456
5457 query_string = strchr(url, '?');
5458 if(query_string)
5459 ++query_string;
5460 lq = query_string ? strlen(query_string) : 0;
5461
5462 handle->prog = prog;
5463 handle->starttime = prog->starttime;
5464 handle->id = id;
5465 if(postseparator && posttype && *posttype)
5466 {
5467 size_t l = strlen(postseparator);
5468 if(poststringbuffer >= 0)
5469 {
5470 size_t ltotal;
5471 int i;
5472 // "implode"
5473 prvm_stringbuffer_t *stringbuffer;
5474 stringbuffer = (prvm_stringbuffer_t *)Mem_ExpandableArray_RecordAtIndex(&prog->stringbuffersarray, poststringbuffer);
5475 if(!stringbuffer)
5476 {
5477 VM_Warning(prog, "uri_get: invalid buffer %i\n", (int)PRVM_G_FLOAT(OFS_PARM0));
5478 return;
5479 }
5480 ltotal = 0;
5481 for(i = 0;i < stringbuffer->num_strings;i++)
5482 {
5483 if(i > 0)
5484 ltotal += l;
5485 if(stringbuffer->strings[i])
5486 ltotal += strlen(stringbuffer->strings[i]);
5487 }
5488 handle->postdata = (unsigned char *)Z_Malloc(ltotal + 1 + lq);
5489 handle->postlen = ltotal;
5490 ltotal = 0;
5491 for(i = 0;i < stringbuffer->num_strings;i++)
5492 {
5493 if(i > 0)
5494 {
5495 memcpy(handle->postdata + ltotal, postseparator, l);
5496 ltotal += l;
5497 }
5498 if(stringbuffer->strings[i])
5499 {
5500 memcpy(handle->postdata + ltotal, stringbuffer->strings[i], strlen(stringbuffer->strings[i]));
5501 ltotal += strlen(stringbuffer->strings[i]);
5502 }
5503 }
5504 if(ltotal != handle->postlen)
5505 prog->error_cmd("%s: string buffer content size mismatch, possible overrun", prog->name);
5506 }
5507 else
5508 {
5509 handle->postdata = (unsigned char *)Z_Malloc(l + 1 + lq);
5510 handle->postlen = l;
5511 memcpy(handle->postdata, postseparator, l);
5512 }
5513 handle->postdata[handle->postlen] = 0;
5514 if(query_string)
5515 memcpy(handle->postdata + handle->postlen + 1, query_string, lq);
5516 if(postkeyid >= 0)
5517 {
5518 // POST: we sign postdata \0 query string
5519 size_t ll;
5520 handle->sigdata = (char *)Z_Malloc(8192);
5521 dp_strlcpy(handle->sigdata, "X-D0-Blind-ID-Detached-Signature: ", 8192);
5522 l = strlen(handle->sigdata);
5523 handle->siglen = Crypto_SignDataDetached(handle->postdata, handle->postlen + 1 + lq, postkeyid, handle->sigdata + l, 8192 - l);
5524 if(!handle->siglen)
5525 {
5526 Z_Free(handle->sigdata);
5527 handle->sigdata = NULL;
5528 goto out1;
5529 }
5530 ll = base64_encode((unsigned char *) (handle->sigdata + l), handle->siglen, 8192 - l - 1);
5531 if(!ll)
5532 {
5533 Z_Free(handle->sigdata);
5534 handle->sigdata = NULL;
5535 goto out1;
5536 }
5537 handle->siglen = l + ll;
5538 handle->sigdata[handle->siglen] = 0;
5539 }
5540out1:
5541 dp_strlcpy(handle->posttype, posttype, sizeof(handle->posttype));
5542 ret = Curl_Begin_ToMemory_POST(url, handle->sigdata, 0, handle->posttype, handle->postdata, handle->postlen, (unsigned char *) handle->buffer, sizeof(handle->buffer), uri_to_string_callback, handle);
5543 }
5544 else
5545 {
5546 if(postkeyid >= 0 && query_string)
5547 {
5548 // GET: we sign JUST the query string
5549 size_t l, ll;
5550 handle->sigdata = (char *)Z_Malloc(8192);
5551 dp_strlcpy(handle->sigdata, "X-D0-Blind-ID-Detached-Signature: ", 8192);
5552 l = strlen(handle->sigdata);
5553 handle->siglen = Crypto_SignDataDetached(query_string, lq, postkeyid, handle->sigdata + l, 8192 - l);
5554 if(!handle->siglen)
5555 {
5556 Z_Free(handle->sigdata);
5557 handle->sigdata = NULL;
5558 goto out2;
5559 }
5560 ll = base64_encode((unsigned char *) (handle->sigdata + l), handle->siglen, 8192 - l - 1);
5561 if(!ll)
5562 {
5563 Z_Free(handle->sigdata);
5564 handle->sigdata = NULL;
5565 goto out2;
5566 }
5567 handle->siglen = l + ll;
5568 handle->sigdata[handle->siglen] = 0;
5569 }
5570out2:
5571 handle->postdata = NULL;
5572 handle->postlen = 0;
5573 ret = Curl_Begin_ToMemory_POST(url, handle->sigdata, 0, NULL, NULL, 0, (unsigned char *) handle->buffer, sizeof(handle->buffer), uri_to_string_callback, handle);
5574 }
5575 if(ret)
5576 {
5578 }
5579 else
5580 {
5581 if(handle->postdata)
5582 Z_Free(handle->postdata);
5583 if(handle->sigdata)
5584 Z_Free(handle->sigdata);
5585 Z_Free(handle);
5587 }
5588}
5589
5591{
5592 const char *ip;
5593 char normalized[128];
5594 size_t normalized_len;
5595 int port;
5597
5599
5601 port = 0;
5602 if(prog->argc > 1)
5603 port = (int) PRVM_G_FLOAT(OFS_PARM1);
5604
5605 if(LHNETADDRESS_FromString(&addr, ip, port) && (normalized_len = LHNETADDRESS_ToString(&addr, normalized, sizeof(normalized), prog->argc > 1)))
5606 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, normalized, normalized_len);
5607 else
5609}
5610
5611//string(prvm_prog_t *prog) getextresponse = #624; // returns the next extResponse packet that was sent to this client
5626
5641
5642// DP_QC_NUDGEOUTOFSOLID
5643// float(entity ent) nudgeoutofsolid = #567;
5645{
5646 prvm_edict_t *ent;
5647
5649
5650 ent = PRVM_G_EDICT(OFS_PARM0);
5651 if (ent == prog->edicts)
5652 {
5653 VM_Warning(prog, "nudgeoutofsolid: can not modify world entity\n");
5655 return;
5656 }
5657 if (ent->free)
5658 {
5659 VM_Warning(prog, "nudgeoutofsolid: can not modify free entity\n");
5661 return;
5662 }
5663
5665
5666 if (PRVM_G_FLOAT(OFS_RETURN) > 0)
5667 {
5668 if (prog == SVVM_prog)
5669 SV_LinkEdict(ent);
5670 else if (prog == CLVM_prog)
5671 CL_LinkEdict(ent);
5672 else
5673 Sys_Error("PHYS_NudgeOutOfSolid: cannot be called from %s VM\n", prog->name);
5674 }
5675}
5676
5677/*
5678=========
5679Common functions between menu.dat and clsprogs
5680=========
5681*/
5682
5683//#349 float() isdemo
5689
5690//#355 float() videoplaying
5696
5697/*
5698=========
5699VM_M_callfunction
5700
5701 callfunction(...,string function_name)
5702Extension: pass
5703=========
5704*/
5706{
5707 mfunction_t *func;
5708 const char *s;
5709
5711
5712 s = PRVM_G_STRING(OFS_PARM0+(prog->argc - 1)*3);
5713
5714 VM_CheckEmptyString(prog, s);
5715
5716 func = PRVM_ED_FindFunction(prog, s);
5717
5718 if(!func)
5719 prog->error_cmd("VM_callfunction: function %s not found !", s);
5720 else if (func->first_statement < 0)
5721 {
5722 // negative statements are built in functions
5723 int builtinnumber = -func->first_statement;
5724 prog->xfunction->builtinsprofile++;
5725 if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber])
5726 prog->builtins[builtinnumber](prog);
5727 else
5728 prog->error_cmd("No such builtin #%i in %s; most likely cause: outdated engine build. Try updating!", builtinnumber, prog->name);
5729 }
5730 else if(func - prog->functions > 0)
5731 {
5732 prog->argc--;
5733 prog->ExecuteProgram(prog, func - prog->functions,"");
5734 prog->argc++;
5735 }
5736}
5737
5738/*
5739=========
5740VM_isfunction
5741
5742float isfunction(string function_name)
5743=========
5744*/
5746{
5747 mfunction_t *func;
5748 const char *s;
5749
5751
5753
5754 VM_CheckEmptyString(prog, s);
5755
5756 func = PRVM_ED_FindFunction(prog, s);
5757
5758 if(!func)
5759 PRVM_G_FLOAT(OFS_RETURN) = false;
5760 else
5761 PRVM_G_FLOAT(OFS_RETURN) = true;
5762}
5763
5764/*
5765=========
5766VM_sprintf
5767
5768string sprintf(string format, ...)
5769=========
5770*/
5771
5773{
5774 const char *s, *s0;
5775 char outbuf[MAX_INPUTLINE];
5776 char *o = outbuf, *end = outbuf + sizeof(outbuf), *err;
5777 const char *p;
5778 int argpos = 1;
5779 int width, precision, thisarg, flags;
5780 char formatbuf[16];
5781 char *f;
5782 int isfloat;
5783 static prvm_int_t dummyivec[3] = {0, 0, 0};
5784 static prvm_vec_t dummyvec[3] = {0, 0, 0};
5785 char vabuf[1024];
5786
5787#define PRINTF_ALTERNATE 1
5788#define PRINTF_ZEROPAD 2
5789#define PRINTF_LEFT 4
5790#define PRINTF_SPACEPOSITIVE 8
5791#define PRINTF_SIGNPOSITIVE 16
5792
5793 formatbuf[0] = '%';
5794
5796
5797#define GETARG_FLOAT(a) (((a)>=1 && (a)<prog->argc) ? (PRVM_G_FLOAT(OFS_PARM0 + 3 * (a))) : 0)
5798#define GETARG_VECTOR(a) (((a)>=1 && (a)<prog->argc) ? (PRVM_G_VECTOR(OFS_PARM0 + 3 * (a))) : dummyvec)
5799#define GETARG_INT(a) (((a)>=1 && (a)<prog->argc) ? (PRVM_G_INT(OFS_PARM0 + 3 * (a))) : 0)
5800#define GETARG_INTVECTOR(a) (((a)>=1 && (a)<prog->argc) ? ((prvm_int_t*) PRVM_G_VECTOR(OFS_PARM0 + 3 * (a))) : dummyivec)
5801#define GETARG_STRING(a) (((a)>=1 && (a)<prog->argc) ? (PRVM_G_STRING(OFS_PARM0 + 3 * (a))) : "")
5802
5803 for(;;)
5804 {
5805 s0 = s;
5806 switch(*s)
5807 {
5808 case 0:
5809 goto finished;
5810 case '%':
5811 ++s;
5812
5813 if(*s == '%')
5814 goto verbatim;
5815
5816 // complete directive format:
5817 // %3$*1$.*2$ld
5818
5819 width = -1;
5820 precision = -1;
5821 thisarg = -1;
5822 flags = 0;
5823 isfloat = -1;
5824
5825 // is number following?
5826 if(*s >= '0' && *s <= '9')
5827 {
5828 width = strtol(s, &err, 10);
5829 if(!err)
5830 {
5831 VM_Warning(prog, "VM_sprintf: invalid directive: %s\n", s0);
5832 goto finished;
5833 }
5834 if(*err == '$')
5835 {
5836 thisarg = width;
5837 width = -1;
5838 s = err + 1;
5839 }
5840 else
5841 {
5842 if(*s == '0')
5843 {
5845 if(width == 0)
5846 width = -1; // it was just a flag
5847 }
5848 s = err;
5849 }
5850 }
5851
5852 if(width < 0)
5853 {
5854 for(;;)
5855 {
5856 switch(*s)
5857 {
5858 case '#': flags |= PRINTF_ALTERNATE; break;
5859 case '0': flags |= PRINTF_ZEROPAD; break;
5860 case '-': flags |= PRINTF_LEFT; break;
5861 case ' ': flags |= PRINTF_SPACEPOSITIVE; break;
5862 case '+': flags |= PRINTF_SIGNPOSITIVE; break;
5863 default:
5864 goto noflags;
5865 }
5866 ++s;
5867 }
5868noflags:
5869 if(*s == '*')
5870 {
5871 ++s;
5872 if(*s >= '0' && *s <= '9')
5873 {
5874 width = strtol(s, &err, 10);
5875 if(!err || *err != '$')
5876 {
5877 VM_Warning(prog, "VM_sprintf: invalid directive: %s\n", s0);
5878 goto finished;
5879 }
5880 s = err + 1;
5881 }
5882 else
5883 width = argpos++;
5885 if(width < 0)
5886 {
5887 flags |= PRINTF_LEFT;
5888 width = -width;
5889 }
5890 }
5891 else if(*s >= '0' && *s <= '9')
5892 {
5893 width = strtol(s, &err, 10);
5894 if(!err)
5895 {
5896 VM_Warning(prog, "VM_sprintf: invalid directive: %s\n", s0);
5897 goto finished;
5898 }
5899 s = err;
5900 if(width < 0)
5901 {
5902 flags |= PRINTF_LEFT;
5903 width = -width;
5904 }
5905 }
5906 // otherwise width stays -1
5907 }
5908
5909 if(*s == '.')
5910 {
5911 ++s;
5912 if(*s == '*')
5913 {
5914 ++s;
5915 if(*s >= '0' && *s <= '9')
5916 {
5917 precision = strtol(s, &err, 10);
5918 if(!err || *err != '$')
5919 {
5920 VM_Warning(prog, "VM_sprintf: invalid directive: %s\n", s0);
5921 goto finished;
5922 }
5923 s = err + 1;
5924 }
5925 else
5926 precision = argpos++;
5927 precision = GETARG_FLOAT(precision);
5928 }
5929 else if(*s >= '0' && *s <= '9')
5930 {
5931 precision = strtol(s, &err, 10);
5932 if(!err)
5933 {
5934 VM_Warning(prog, "VM_sprintf: invalid directive: %s\n", s0);
5935 goto finished;
5936 }
5937 s = err;
5938 }
5939 else
5940 {
5941 VM_Warning(prog, "VM_sprintf: invalid directive: %s\n", s0);
5942 goto finished;
5943 }
5944 }
5945
5946 for(;;)
5947 {
5948 switch(*s)
5949 {
5950 case 'h': isfloat = 1; break;
5951 case 'l': isfloat = 0; break;
5952 case 'L': isfloat = 0; break;
5953 case 'j': break;
5954 case 'z': break;
5955 case 't': break;
5956 default:
5957 goto nolength;
5958 }
5959 ++s;
5960 }
5961nolength:
5962
5963 // now s points to the final directive char and is no longer changed
5964 if(isfloat < 0)
5965 {
5966 if(*s == 'i')
5967 isfloat = 0;
5968 else
5969 isfloat = 1;
5970 }
5971
5972 if(thisarg < 0)
5973 thisarg = argpos++;
5974
5975 if(o < end - 1)
5976 {
5977 f = &formatbuf[1];
5978 if(*s != 's' && *s != 'c')
5979 if(flags & PRINTF_ALTERNATE) *f++ = '#';
5980 if(flags & PRINTF_ZEROPAD) *f++ = '0';
5981 if(flags & PRINTF_LEFT) *f++ = '-';
5982 if(flags & PRINTF_SPACEPOSITIVE) *f++ = ' ';
5983 if(flags & PRINTF_SIGNPOSITIVE) *f++ = '+';
5984 *f++ = '*';
5985 if(precision >= 0)
5986 {
5987 *f++ = '.';
5988 *f++ = '*';
5989 }
5990 if(*s == 'd' || *s == 'i' || *s == 'o' || *s == 'u' || *s == 'x' || *s == 'X')
5991 {
5992 // make it use a good integer type
5993 for(p = INT_LOSSLESS_FORMAT_SIZE; *p; )
5994 *f++ = *p++;
5995 }
5996 *f++ = *s;
5997 *f++ = 0;
5998
5999 if(width < 0) // not set
6000 width = 0;
6001
6002 switch(*s)
6003 {
6004 case 'd': case 'i':
6005 if(precision < 0) // not set
6006 o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? INT_LOSSLESS_FORMAT_CONVERT_S(GETARG_FLOAT(thisarg)) : INT_LOSSLESS_FORMAT_CONVERT_S(GETARG_INT(thisarg))));
6007 else
6008 o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? INT_LOSSLESS_FORMAT_CONVERT_S(GETARG_FLOAT(thisarg)) : INT_LOSSLESS_FORMAT_CONVERT_S(GETARG_INT(thisarg))));
6009 break;
6010 case 'o': case 'u': case 'x': case 'X':
6011 if(precision < 0) // not set
6012 o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? INT_LOSSLESS_FORMAT_CONVERT_U(GETARG_FLOAT(thisarg)) : INT_LOSSLESS_FORMAT_CONVERT_U(GETARG_INT(thisarg))));
6013 else
6014 o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? INT_LOSSLESS_FORMAT_CONVERT_U(GETARG_FLOAT(thisarg)) : INT_LOSSLESS_FORMAT_CONVERT_U(GETARG_INT(thisarg))));
6015 break;
6016 case 'e': case 'E': case 'f': case 'F': case 'g': case 'G':
6017 if(precision < 0) // not set
6018 o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? (double) GETARG_FLOAT(thisarg) : (double) GETARG_INT(thisarg)));
6019 else
6020 o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (double) GETARG_FLOAT(thisarg) : (double) GETARG_INT(thisarg)));
6021 break;
6022 case 'v': case 'V':
6023 f[-2] += 'g' - 'v';
6024 if(precision < 0) // not set
6025 o += dpsnprintf(o, end - o, va(vabuf, sizeof(vabuf), "%s %s %s", /* NESTED SPRINTF IS NESTED */ formatbuf, formatbuf, formatbuf),
6026 width, (isfloat ? (double) GETARG_VECTOR(thisarg)[0] : (double) GETARG_INTVECTOR(thisarg)[0]),
6027 width, (isfloat ? (double) GETARG_VECTOR(thisarg)[1] : (double) GETARG_INTVECTOR(thisarg)[1]),
6028 width, (isfloat ? (double) GETARG_VECTOR(thisarg)[2] : (double) GETARG_INTVECTOR(thisarg)[2])
6029 );
6030 else
6031 o += dpsnprintf(o, end - o, va(vabuf, sizeof(vabuf), "%s %s %s", /* NESTED SPRINTF IS NESTED */ formatbuf, formatbuf, formatbuf),
6032 width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[0] : (double) GETARG_INTVECTOR(thisarg)[0]),
6033 width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[1] : (double) GETARG_INTVECTOR(thisarg)[1]),
6034 width, precision, (isfloat ? (double) GETARG_VECTOR(thisarg)[2] : (double) GETARG_INTVECTOR(thisarg)[2])
6035 );
6036 break;
6037 case 'c':
6039 {
6040 if(precision < 0) // not set
6041 o += dpsnprintf(o, end - o, formatbuf, width, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
6042 else
6043 o += dpsnprintf(o, end - o, formatbuf, width, precision, (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg)));
6044 }
6045 else
6046 {
6047 unsigned int c = (isfloat ? (unsigned int) GETARG_FLOAT(thisarg) : (unsigned int) GETARG_INT(thisarg));
6048 char charbuf16[16];
6049 const char *buf = u8_encodech(c, NULL, charbuf16);
6050 if(!buf)
6051 buf = "";
6052 if(precision < 0) // not set
6053 precision = end - o - 1;
6054 o += u8_strpad(o, end - o, buf, (flags & PRINTF_LEFT) != 0, width, precision);
6055 }
6056 break;
6057 //spike FIXME -- 'S' for quoted tokenize-safe-or-print escaping of strings so stuff can safely survive console commands.
6058 case 's':
6060 {
6061 if(precision < 0) // not set
6062 o += dpsnprintf(o, end - o, formatbuf, width, GETARG_STRING(thisarg));
6063 else
6064 o += dpsnprintf(o, end - o, formatbuf, width, precision, GETARG_STRING(thisarg));
6065 }
6066 else
6067 {
6068 if(precision < 0) // not set
6069 precision = end - o - 1;
6071 o += u8_strpad(o, end - o, GETARG_STRING(thisarg), (flags & PRINTF_LEFT) != 0, width, precision);
6072 else
6073 o += u8_strpad_colorcodes(o, end - o, GETARG_STRING(thisarg), (flags & PRINTF_LEFT) != 0, width, precision);
6074 }
6075 break;
6076 default:
6077 VM_Warning(prog, "VM_sprintf: invalid directive: %s\n", s0);
6078 goto finished;
6079 }
6080 }
6081 ++s;
6082 break;
6083 default:
6084verbatim:
6085 if(o < end - 1)
6086 *o++ = *s;
6087 ++s;
6088 break;
6089 }
6090 }
6091
6092finished:
6093 *o = '\0';
6094 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, outbuf, o - outbuf);
6095}
6096
6097
6098// surface querying
6099
6101{
6102 if (prog == SVVM_prog)
6103 return SV_GetModelFromEdict(ed);
6104 else if (prog == CLVM_prog)
6105 return CL_GetModelFromEdict(ed);
6106 else
6107 return NULL;
6108}
6109
6126
6137
6139{
6140 skeleton_t *skeleton;
6141 int skeletonindex = -1;
6142 qbool need = false;
6144 if (!prog->animatemodel_cache)
6145 {
6146 prog->animatemodel_cache = (struct animatemodel_cache *)Mem_Alloc(prog->progs_mempool, sizeof(struct animatemodel_cache));
6147 memset(prog->animatemodel_cache, 0, sizeof(struct animatemodel_cache));
6148 }
6150 if(!(model->surfmesh.isanimated && model->AnimateVertices))
6151 {
6152 animatemodel_cache->data_vertex3f = model->surfmesh.data_vertex3f;
6153 animatemodel_cache->data_svector3f = model->surfmesh.data_svector3f;
6154 animatemodel_cache->data_tvector3f = model->surfmesh.data_tvector3f;
6155 animatemodel_cache->data_normal3f = model->surfmesh.data_normal3f;
6156 return;
6157 }
6158 need |= (animatemodel_cache->model != model);
6159 VM_GenerateFrameGroupBlend(prog, ed->priv.server->framegroupblend, ed);
6160 VM_FrameBlendFromFrameGroupBlend(ed->priv.server->frameblend, ed->priv.server->framegroupblend, model, PRVM_serverglobalfloat(time));
6161 need |= (memcmp(&animatemodel_cache->frameblend, &ed->priv.server->frameblend, sizeof(ed->priv.server->frameblend))) != 0;
6163 if (!(skeletonindex >= 0 && skeletonindex < MAX_EDICTS && (skeleton = prog->skeletons[skeletonindex]) && skeleton->model->num_bones == ed->priv.server->skeleton.model->num_bones))
6164 skeleton = NULL;
6166 if(skeleton)
6167 need |= (memcmp(&animatemodel_cache->skeleton, skeleton, sizeof(ed->priv.server->skeleton))) != 0;
6168 if(!need)
6169 return;
6170 if(model->surfmesh.num_vertices > animatemodel_cache->max_vertices)
6171 {
6172 animatemodel_cache->max_vertices = model->surfmesh.num_vertices * 2;
6181 }
6186 VM_UpdateEdictSkeleton(prog, ed, model, ed->priv.server->frameblend);
6189 memcpy(&animatemodel_cache->frameblend, &ed->priv.server->frameblend, sizeof(ed->priv.server->frameblend));
6191 if(skeleton)
6192 memcpy(&animatemodel_cache->skeleton, skeleton, sizeof(ed->priv.server->skeleton));
6193}
6194
6195static void getmatrix(prvm_prog_t *prog, prvm_edict_t *ed, matrix4x4_t *out)
6196{
6197 if (prog == SVVM_prog)
6198 SV_GetEntityMatrix(prog, ed, out, false);
6199 else if (prog == CLVM_prog)
6200 CL_GetEntityMatrix(prog, ed, out, false);
6201 else
6202 *out = identitymatrix;
6203}
6204
6205static void applytransform_forward(prvm_prog_t *prog, const vec3_t in, prvm_edict_t *ed, vec3_t out)
6206{
6207 matrix4x4_t m;
6208 getmatrix(prog, ed, &m);
6209 Matrix4x4_Transform(&m, in, out);
6210}
6211
6213{
6214 matrix4x4_t m;
6215 getmatrix(prog, ed, &m);
6216 Matrix4x4_Transform3x3(&m, in, out);
6217}
6218
6219static void applytransform_inverted(prvm_prog_t *prog, const vec3_t in, prvm_edict_t *ed, vec3_t out)
6220{
6221 matrix4x4_t m, n;
6222 getmatrix(prog, ed, &m);
6224 Matrix4x4_Transform3x3(&n, in, out);
6225}
6226
6228{
6229 matrix4x4_t m;
6230 float p[4];
6231 getmatrix(prog, ed, &m);
6232 Matrix4x4_TransformPositivePlane(&m, in[0], in[1], in[2], 0, p);
6233 VectorCopy(p, out);
6234}
6235
6237{
6238 int i, j, k;
6239 float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
6240 const int *e;
6241 animatemodel(prog, model, ed);
6242 bestdist = 1000000000;
6243 VectorCopy(p, out);
6244 for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
6245 {
6246 // clip original point to each triangle of the surface and find the
6247 // triangle that is closest
6248 v[0] = prog->animatemodel_cache->data_vertex3f + e[0] * 3;
6249 v[1] = prog->animatemodel_cache->data_vertex3f + e[1] * 3;
6250 v[2] = prog->animatemodel_cache->data_vertex3f + e[2] * 3;
6251 TriangleNormal(v[0], v[1], v[2], facenormal);
6252 VectorNormalize(facenormal);
6253 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
6254 VectorMA(p, offsetdist, facenormal, temp);
6255 for (j = 0, k = 2;j < 3;k = j, j++)
6256 {
6257 VectorSubtract(v[k], v[j], edgenormal);
6258 CrossProduct(edgenormal, facenormal, sidenormal);
6259 VectorNormalize(sidenormal);
6260 offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
6261 if (offsetdist < 0)
6262 VectorMA(temp, offsetdist, sidenormal, temp);
6263 }
6264 dist = VectorDistance2(temp, p);
6265 if (bestdist > dist)
6266 {
6267 bestdist = dist;
6268 VectorCopy(temp, out);
6269 }
6270 }
6271}
6272
6273static msurface_t *getsurface(model_t *model, int surfacenum)
6274{
6275 if (surfacenum < 0 || surfacenum >= model->submodelsurfaces_end - model->submodelsurfaces_start)
6276 return NULL;
6277 return model->data_surfaces + surfacenum + model->submodelsurfaces_start;
6278}
6279
6280
6281//PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
6283{
6284 model_t *model;
6285 msurface_t *surface;
6287 // return 0 if no such surface
6288 if (!(model = getmodel(prog, PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
6289 {
6291 return;
6292 }
6293
6294 // note: this (incorrectly) assumes it is a simple polygon
6296}
6297//PF_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
6299{
6300 prvm_edict_t *ed;
6301 model_t *model;
6302 msurface_t *surface;
6303 int pointnum;
6304 vec3_t result;
6307 ed = PRVM_G_EDICT(OFS_PARM0);
6308 if (!(model = getmodel(prog, ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
6309 return;
6310 // note: this (incorrectly) assumes it is a simple polygon
6311 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
6312 if (pointnum < 0 || pointnum >= surface->num_vertices)
6313 return;
6314 animatemodel(prog, model, ed);
6315 applytransform_forward(prog, &(prog->animatemodel_cache->data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, result);
6317}
6318//PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
6319// float SPA_POSITION = 0;
6320// float SPA_S_AXIS = 1;
6321// float SPA_T_AXIS = 2;
6322// float SPA_R_AXIS = 3; // same as SPA_NORMAL
6323// float SPA_TEXCOORDS0 = 4;
6324// float SPA_LIGHTMAP0_TEXCOORDS = 5;
6325// float SPA_LIGHTMAP0_COLOR = 6;
6327{
6328 prvm_edict_t *ed;
6329 model_t *model;
6330 msurface_t *surface;
6331 int pointnum;
6332 int attributetype;
6333 vec3_t result;
6334
6337 ed = PRVM_G_EDICT(OFS_PARM0);
6338 if (!(model = getmodel(prog, ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
6339 return;
6340 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
6341 if (pointnum < 0 || pointnum >= surface->num_vertices)
6342 return;
6343 attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
6344
6345 animatemodel(prog, model, ed);
6346
6347 switch( attributetype ) {
6348 // float SPA_POSITION = 0;
6349 case 0:
6350 applytransform_forward(prog, &(prog->animatemodel_cache->data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, result);
6352 break;
6353 // float SPA_S_AXIS = 1;
6354 case 1:
6355 applytransform_forward_direction(prog, &(prog->animatemodel_cache->data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, result);
6357 break;
6358 // float SPA_T_AXIS = 2;
6359 case 2:
6360 applytransform_forward_direction(prog, &(prog->animatemodel_cache->data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, result);
6362 break;
6363 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
6364 case 3:
6365 applytransform_forward_direction(prog, &(prog->animatemodel_cache->data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], ed, result);
6367 break;
6368 // float SPA_TEXCOORDS0 = 4;
6369 case 4: {
6370 float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
6371 result[0] = texcoord[0];
6372 result[1] = texcoord[1];
6373 result[2] = 0.0f;
6375 break;
6376 }
6377 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
6378 case 5: {
6379 float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
6380 result[0] = texcoord[0];
6381 result[1] = texcoord[1];
6382 result[2] = 0.0f;
6384 break;
6385 }
6386 // float SPA_LIGHTMAP0_COLOR = 6;
6387 case 6:
6388 // ignore alpha for now..
6389 VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
6390 break;
6391 default:
6392 VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
6393 break;
6394 }
6395}
6396//PF_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal = #436;
6398{
6399 model_t *model;
6400 msurface_t *surface;
6401 vec3_t normal;
6402 vec3_t result;
6405 if (!(model = getmodel(prog, PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
6406 return;
6407 // note: this only returns the first triangle, so it doesn't work very
6408 // well for curved surfaces or arbitrary meshes
6412 VectorNormalize(result);
6414}
6415//PF_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture = #437;
6417{
6418 model_t *model;
6419 msurface_t *surface;
6420
6423 if (!(model = getmodel(prog, PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
6424 return;
6425 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, surface->texture->name, strlen(surface->texture->name));
6426}
6427//PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
6429{
6430 int surfacenum, best;
6431 vec3_t clipped, p;
6432 vec_t dist, bestdist;
6433 prvm_edict_t *ed;
6434 model_t *model;
6435 msurface_t *surface;
6436 vec3_t point;
6439 ed = PRVM_G_EDICT(OFS_PARM0);
6441
6442 if (!ed || ed->free)
6443 return;
6444 model = getmodel(prog, ed);
6445 if (!model || !model->num_surfaces)
6446 return;
6447
6448 animatemodel(prog, model, ed);
6449
6450 applytransform_inverted(prog, point, ed, p);
6451 best = -1;
6452 bestdist = 1000000000;
6453 for (surfacenum = model->submodelsurfaces_start;surfacenum < model->submodelsurfaces_end;surfacenum++)
6454 {
6455 surface = model->data_surfaces + surfacenum;
6456 // first see if the nearest point on the surface's box is closer than the previous match
6457 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
6458 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
6459 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
6460 dist = VectorLength2(clipped);
6461 if (dist < bestdist)
6462 {
6463 // it is, check the nearest point on the actual geometry
6464 clippointtosurface(prog, ed, model, surface, p, clipped);
6465 VectorSubtract(clipped, p, clipped);
6466 dist += VectorLength2(clipped);
6467 if (dist < bestdist)
6468 {
6469 // that's closer too, store it as the best match
6470 best = surfacenum - model->submodelsurfaces_start;
6471 bestdist = dist;
6472 }
6473 }
6474 }
6475 PRVM_G_FLOAT(OFS_RETURN) = best;
6476}
6477//PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
6479{
6480 prvm_edict_t *ed;
6481 model_t *model;
6482 msurface_t *surface;
6483 vec3_t p, out, inp;
6486 ed = PRVM_G_EDICT(OFS_PARM0);
6487 if (!(model = getmodel(prog, ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
6488 return;
6489 animatemodel(prog, model, ed);
6491 applytransform_inverted(prog, inp, ed, p);
6492 clippointtosurface(prog, ed, model, surface, p, out);
6494}
6495
6496//PF_getsurfacenumtriangles, // #??? float(entity e, float s) getsurfacenumtriangles = #???;
6498{
6499 model_t *model;
6500 msurface_t *surface;
6502 // return 0 if no such surface
6503 if (!(model = getmodel(prog, PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
6504 {
6506 return;
6507 }
6508
6510}
6511//PF_getsurfacetriangle, // #??? vector(entity e, float s, float n) getsurfacetriangle = #???;
6513{
6514 const vec3_t d = {-1, -1, -1};
6515 prvm_edict_t *ed;
6516 model_t *model;
6517 msurface_t *surface;
6518 int trinum;
6521 ed = PRVM_G_EDICT(OFS_PARM0);
6522 if (!(model = getmodel(prog, ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
6523 return;
6524 trinum = (int)PRVM_G_FLOAT(OFS_PARM2);
6525 if (trinum < 0 || trinum >= surface->num_triangles)
6526 return;
6527 // FIXME: implement rotation/scaling
6528 VectorMA(&(model->surfmesh.data_element3i + 3 * surface->num_firsttriangle)[trinum * 3], surface->num_firstvertex, d, PRVM_G_VECTOR(OFS_RETURN));
6529}
6530
6531//
6532// physics builtins
6533//
6534
6535#ifdef USEODE
6536#define VM_physics_ApplyCmd(ed,f) if (!ed->priv.server->ode_body) VM_physics_newstackfunction(prog, ed, f); else World_Physics_ApplyCmd(ed, f)
6537
6538static edict_odefunc_t *VM_physics_newstackfunction(prvm_prog_t *prog, prvm_edict_t *ed, edict_odefunc_t *f)
6539{
6540 edict_odefunc_t *newfunc, *func;
6541
6542 newfunc = (edict_odefunc_t *)Mem_Alloc(prog->progs_mempool, sizeof(edict_odefunc_t));
6543 memcpy(newfunc, f, sizeof(edict_odefunc_t));
6544 newfunc->next = NULL;
6545 if (!ed->priv.server->ode_func)
6546 ed->priv.server->ode_func = newfunc;
6547 else
6548 {
6549 for (func = ed->priv.server->ode_func; func->next; func = func->next);
6550 func->next = newfunc;
6551 }
6552 return newfunc;
6553}
6554#endif
6555
6556// void(entity e, float physics_enabled) physics_enable = #;
6558{
6559#ifdef USEODE
6560 prvm_edict_t *ed;
6561 edict_odefunc_t f;
6562#endif
6564#ifdef USEODE
6565 ed = PRVM_G_EDICT(OFS_PARM0);
6566 if (!ed)
6567 {
6568 if (developer.integer > 0)
6569 VM_Warning(prog, "VM_physics_enable: null entity!\n");
6570 return;
6571 }
6572 // entity should have MOVETYPE_PHYSICS already set, this can damage memory (making leaked allocation) so warn about this even if non-developer
6574 {
6575 VM_Warning(prog, "VM_physics_enable: entity is not MOVETYPE_PHYSICS!\n");
6576 return;
6577 }
6578 f.type = PRVM_G_FLOAT(OFS_PARM1) == 0 ? ODEFUNC_DISABLE : ODEFUNC_ENABLE;
6579 VM_physics_ApplyCmd(ed, &f);
6580#endif
6581}
6582
6583// void(entity e, vector force, vector relative_ofs) physics_addforce = #;
6585{
6586#ifdef USEODE
6587 prvm_edict_t *ed;
6588 edict_odefunc_t f;
6589#endif
6591#ifdef USEODE
6592 ed = PRVM_G_EDICT(OFS_PARM0);
6593 if (!ed)
6594 {
6595 if (developer.integer > 0)
6596 VM_Warning(prog, "VM_physics_addforce: null entity!\n");
6597 return;
6598 }
6599 // entity should have MOVETYPE_PHYSICS already set, this can damage memory (making leaked allocation) so warn about this even if non-developer
6601 {
6602 VM_Warning(prog, "VM_physics_addforce: entity is not MOVETYPE_PHYSICS!\n");
6603 return;
6604 }
6605 f.type = ODEFUNC_FORCE;
6608 VM_physics_ApplyCmd(ed, &f);
6609#endif
6610}
6611
6612// void(entity e, vector torque) physics_addtorque = #;
6614{
6615#ifdef USEODE
6616 prvm_edict_t *ed;
6617 edict_odefunc_t f;
6618#endif
6620#ifdef USEODE
6621 ed = PRVM_G_EDICT(OFS_PARM0);
6622 if (!ed)
6623 {
6624 if (developer.integer > 0)
6625 VM_Warning(prog, "VM_physics_addtorque: null entity!\n");
6626 return;
6627 }
6628 // entity should have MOVETYPE_PHYSICS already set, this can damage memory (making leaked allocation) so warn about this even if non-developer
6630 {
6631 VM_Warning(prog, "VM_physics_addtorque: entity is not MOVETYPE_PHYSICS!\n");
6632 return;
6633 }
6634 f.type = ODEFUNC_TORQUE;
6636 VM_physics_ApplyCmd(ed, &f);
6637#endif
6638}
6639
6640extern cvar_t prvm_coverage;
6642{
6644 if (prog->explicit_profile[prog->xstatement]++ == 0 && (prvm_coverage.integer & 2))
6646}
model_t * CL_GetModelFromEdict(prvm_edict_t *ed)
void CL_LinkEdict(prvm_edict_t *ent)
client_static_t cls
Definition cl_main.c:116
void SCR_CenterPrint(const char *str)
Definition cl_screen.c:144
int cl_videoplaying
Definition cl_video.c:458
void CL_PurgeOwner(int owner)
Definition cl_video.c:411
#define MENUOWNER
Definition cl_video.h:11
@ ca_dedicated
Definition client.h:530
@ ca_connected
Definition client.h:532
@ ca_uninitialized
Definition client.h:529
@ ca_disconnected
Definition client.h:531
#define MAX_FRAMEBLENDS
Definition client.h:309
void CL_GetEntityMatrix(prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qbool viewmatrix)
Definition clvm_cmds.c:3230
void Cbuf_AddText(cmd_state_t *cmd, const char *text)
Definition cmd.c:264
cmd_state_t * cmd_local
command interpreter for local commands injected by SVQC, CSQC, MQC, server or client engine code uses...
Definition cmd.c:25
qbool Cmd_Exists(cmd_state_t *cmd, const char *cmd_name)
used by the cvar code to check for cvar / command name overlap
Definition cmd.c:1762
#define CF_ALLOCATED
created by Cvar_Get() (console or QC)
Definition cmd.h:64
#define CF_READONLY
cvar cannot be changed from the console or the command buffer, and is considered CF_PERSISTENT
Definition cmd.h:54
#define CF_MAXFLAGSVAL
used to determine if flags is valid
Definition cmd.h:60
#define CF_ARCHIVE
cvar should have its set value saved to config.cfg and persist across sessions
Definition cmd.h:53
#define CF_PRIVATE
cvar should not be $ expanded or sent to the server under any circumstances (rcon_password,...
Definition cmd.h:59
unsigned short CRC_Block(const unsigned char *data, size_t size)
Definition com_crc16.c:75
unsigned short CRC_Block_CaseInsensitive(const unsigned char *data, size_t size)
Definition com_crc16.c:83
void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, const char *value)
size_t InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuesize)
Returns the number of bytes written to *value excluding the \0 terminator.
void MSG_WriteString(sizebuf_t *sb, const char *s)
Definition com_msg.c:173
void MSG_WriteChar(sizebuf_t *sb, int c)
Definition com_msg.c:122
int dpvsnprintf(char *buffer, size_t buffersize, const char *format, va_list args)
Returns the number of printed characters, excluding the final '\0' or returns -1 if the buffer isn't ...
Definition common.c:1010
unsigned com_token_len
Definition common.c:40
char com_token[MAX_INPUTLINE]
Definition common.c:39
char * va(char *buf, size_t buflen, const char *format,...)
Definition common.c:972
size_t COM_StringDecolorize(const char *in, size_t size_in, char *out, size_t size_out, qbool escape_carets)
Definition common.c:1286
qbool COM_ParseToken_VM_Tokenize(const char **datapointer, qbool returnnewline)
Definition common.c:700
qbool COM_ParseToken_Console(const char **datapointer)
Definition common.c:819
size_t COM_ToUpperString(const char *in, char *out, size_t size_out)
Returns the number of bytes written to *out excluding the \0 terminator.
Definition common.c:1087
qbool COM_ParseToken_Simple(const char **datapointer, qbool returnnewline, qbool parsebackslash, qbool parsecomments)
Definition common.c:463
int dpsnprintf(char *buffer, size_t buffersize, const char *format,...)
Returns the number of printed characters, excluding the final '\0' or returns -1 if the buffer isn't ...
Definition common.c:997
size_t base64_encode(unsigned char *buf, size_t buflen, size_t outbuflen)
Definition common.c:1502
size_t COM_ToLowerString(const char *in, char *out, size_t size_out)
Returns the number of bytes written to *out excluding the \0 terminator.
Definition common.c:1051
#define dp_strlcat(dst, src, dsize)
Definition common.h:304
#define dp_strlcpy(dst, src, dsize)
Definition common.h:303
void Con_Print(const char *msg)
Prints to all appropriate console targets, and adds timestamps.
Definition console.c:1504
void Con_DPrintf(const char *fmt,...)
A Con_Printf that only shows up if the "developer" cvar is set.
Definition console.c:1544
void Con_Printf(const char *fmt,...)
Prints to all appropriate console targets.
Definition console.c:1514
#define CON_WARN
Definition console.h:101
#define CON_ERROR
Definition console.h:102
void sha256(unsigned char *out, const unsigned char *in, int n)
Definition crypto.c:383
size_t Crypto_SignDataDetached(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size)
Definition crypto.c:2645
qbool Crypto_Available(void)
Definition crypto.c:1097
vector v_up
vector size
float movetype
float flags
float frame3time
float trace_dphitcontents
float frame1time
entity trace_ent
entity self
float frame2time
float frame2
float lerpfrac
float frame3
float lerpfrac4
float trace_dpstartcontents
float frame4time
entity chain
float lerpfrac3
string trace_dphittexturename
float skeletonindex
float time
vector v_right
vector trace_endpos
float trace_startsolid
float log(float f)
float trace_inopen
vector angles
float trace_dphitq3surfaceflags
float frame4
vector v_forward
float entnum
vector origin
string model
float trace_fraction
const float true
float frame
float trace_allsolid
vector trace_plane_normal
float trace_plane_dist
float trace_inwater
float Cvar_VariableValue(cvar_state_t *cvars, const char *var_name, unsigned neededflags)
Definition cvar.c:129
const char * Cvar_VariableDescription(cvar_state_t *cvars, const char *var_name, unsigned neededflags)
Definition cvar.c:174
const char * Cvar_VariableDefString(cvar_state_t *cvars, const char *var_name, unsigned neededflags)
Definition cvar.c:159
void Cvar_SetQuick(cvar_t *var, const char *value)
Definition cvar.c:436
const char * Cvar_VariableString(cvar_state_t *cvars, const char *var_name, unsigned neededflags)
Definition cvar.c:149
cvar_t * Cvar_Get(cvar_state_t *cvars, const char *name, const char *value, unsigned flags, const char *newdescription)
allocates a cvar by name and returns its address, or merely sets its value if it already exists.
Definition cvar.c:695
cvar_t * Cvar_FindVar(cvar_state_t *cvars, const char *var_name, unsigned neededflags)
Definition cvar.c:36
const char * cvar_dummy_description
Definition cvar.c:25
float idealpitch
float pitch_speed
int matchpattern_with_separator(const char *in, const char *pattern, int caseinsensitive, const char *separators, qbool wildcard_least_one)
Definition filematch.c:23
#define n(x, y)
qfile_t * FS_OpenVirtualFile(const char *filepath, qbool quiet)
Definition fs.c:2928
fs_offset_t FS_Write(qfile_t *file, const void *data, size_t datasize)
Definition fs.c:3019
unsigned char * FS_LoadFile(const char *path, mempool_t *pool, qbool quiet, fs_offset_t *filesizepointer)
Definition fs.c:3540
void FS_FreeSearch(fssearch_t *search)
Definition fs.c:3963
fssearch_t * FS_Search(const char *pattern, int caseinsensitive, int quiet, const char *packfile)
Definition fs.c:3756
qfile_t * FS_OpenRealFile(const char *filepath, const char *mode, qbool quiet)
Definition fs.c:2901
static int(ZEXPORT *qz_inflate)(z_stream *strm
int FS_UnGetc(qfile_t *file, unsigned char c)
Definition fs.c:3341
int FS_Close(qfile_t *file)
Definition fs.c:2970
const char * FS_WhichPack(const char *filename)
Definition fs.c:4091
int FS_Getc(qfile_t *file)
Definition fs.c:3323
int FS_CheckNastyPath(const char *path, qbool isgamedir)
Definition fs.c:2618
cvar_t r_lerpsprites
Definition gl_rmain.c:202
cvar_t r_lerpmodels
Definition gl_rmain.c:203
GLenum GLuint id
Definition glquake.h:657
GLenum GLsizei width
Definition glquake.h:622
GLint GLenum GLboolean normalized
Definition glquake.h:797
GLenum mode
Definition glquake.h:718
GLsizei const GLfloat * value
Definition glquake.h:740
GLsizei const GLchar ** string
Definition glquake.h:728
GLuint buffer
Definition glquake.h:630
GLenum GLuint GLenum GLsizei length
Definition glquake.h:657
const GLdouble * v
Definition glquake.h:762
GLenum GLenum GLsizei count
Definition glquake.h:656
GLint GLint GLint GLsizei GLsizei GLenum format
Definition glquake.h:649
GLsizeiptr const GLvoid * data
Definition glquake.h:639
GLint first
Definition glquake.h:671
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition glquake.h:657
const GLchar * name
Definition glquake.h:601
GLuint index
Definition glquake.h:629
GLenum type
Definition glquake.h:656
cvar_t developer
Definition host.c:48
host_static_t host
Definition host.c:41
cvar_t developer_extra
Definition host.c:49
void Key_FindKeysForCommand(const char *command, int *keys, int numkeys, int bindmap)
Definition keys.c:1760
qbool Key_SetBinding(int keynum, int bindmap, const char *binding)
Definition keys.c:1409
qbool Key_SetBindMap(int fg, int bg)
Definition keys.c:1443
void Key_GetBindMap(int *fg, int *bg)
Definition keys.c:1435
const char * Key_KeynumToString(int keynum, char *tinystr, size_t tinystrlength)
Definition keys.c:1383
const char * Key_GetBind(int key, int bindmap)
Definition keys.c:1740
int Key_StringToKeynum(const char *str)
Definition keys.c:1354
#define TINYSTR_LEN
Definition keys.h:46
int LHNETADDRESS_ToString(const lhnetaddress_t *vaddress, char *string, int stringbuffersize, int includeport)
Returns the number of bytes written to *string excluding the \0 terminator.
Definition lhnet.c:540
int LHNETADDRESS_FromString(lhnetaddress_t *vaddress, const char *string, int defaultport)
Definition lhnet.c:204
qbool Curl_Begin_ToMemory_POST(const char *URL, const char *extraheaders, double maxspeed, const char *post_content_type, const unsigned char *postbuf, size_t postbufsize, unsigned char *buf, size_t bufsize, curl_callback_t callback, void *cbdata)
Definition libcurl.c:1121
qbool Curl_Available(void)
Definition libcurl.c:840
int Math_atov(const char *s, prvm_vec3_t out)
Definition mathlib.c:856
void AnglesFromVectors(vec3_t angles, const vec3_t forward, const vec3_t up, qbool flippitch)
LadyHavoc: calculates pitch/yaw/roll angles from forward and up vectors.
Definition mathlib.c:650
void AngleVectors(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
Definition mathlib.c:444
void VectorVectors(const vec3_t forward, vec3_t right, vec3_t up)
LadyHavoc: like AngleVectors, but taking a forward vector instead of angles, useful!
Definition mathlib.c:199
#define ANGLEMOD(a)
Definition mathlib.h:67
#define max(A, B)
Definition mathlib.h:38
#define VectorRandom(v)
Definition mathlib.h:119
#define min(A, B)
Definition mathlib.h:37
#define VectorNormalize(v)
Definition mathlib.h:104
#define VectorClear(a)
Definition mathlib.h:97
#define bound(min, num, max)
Definition mathlib.h:34
#define VectorLength(a)
Definition mathlib.h:109
#define lhrandom(MIN, MAX)
LadyHavoc: this function never returns exactly MIN or exactly MAX, because of a QuakeC bug in id1 whe...
Definition mathlib.h:48
#define VectorLength2(a)
Definition mathlib.h:110
#define VectorSet(vec, x, y, z)
Definition mathlib.h:96
#define VectorNormalize2(v, dest)
Definition mathlib.h:105
#define VectorDistance2(a, b)
Definition mathlib.h:107
#define VectorSubtract(a, b, out)
Definition mathlib.h:99
#define CrossProduct(a, b, out)
Definition mathlib.h:103
#define TriangleNormal(a, b, c, n)
Definition mathlib.h:126
#define DotProduct(a, b)
Definition mathlib.h:98
#define VectorCopy(in, out)
Definition mathlib.h:101
#define VectorScale(in, scale, out)
Definition mathlib.h:111
#define VectorAdd(a, b, out)
Definition mathlib.h:100
#define M_PI
Definition mathlib.h:28
#define VectorMA(a, scale, b, out)
Definition mathlib.h:114
void Matrix4x4_TransformPositivePlane(const matrix4x4_t *in, float x, float y, float z, float d, float *o)
Definition matrixlib.c:1699
void Matrix4x4_Transform(const matrix4x4_t *in, const float v[3], float out[3])
Definition matrixlib.c:1657
void Matrix4x4_Transform3x3(const matrix4x4_t *in, const float v[3], float out[3])
Definition matrixlib.c:1685
int Matrix4x4_Invert_Full(matrix4x4_t *out, const matrix4x4_t *in1)
Definition matrixlib.c:145
const matrix4x4_t identitymatrix
Definition matrixlib.c:9
void mdfour(unsigned char *out, const unsigned char *in, int n)
Definition mdfour.c:182
float pow(float a, float b)
float ceil(float f)
float strlen(string s)
float cvar(string name)
float cos(float f)
const string cvar_string(string name)
float sqrt(float f)
void cmd(string command,...)
float sin(float f)
float fabs(float f)
float floor(float f)
const string cvar_defstring(string name)
@ mod_sprite
unsigned cl_net_extresponse_last
Definition netconn.c:162
unsigned sv_net_extresponse_count
Definition netconn.c:165
char sv_net_extresponse[NET_EXTRESPONSE_MAX][1400]
Definition netconn.c:164
unsigned sv_net_extresponse_last
Definition netconn.c:166
unsigned cl_net_extresponse_count
Definition netconn.c:161
char cl_net_extresponse[NET_EXTRESPONSE_MAX][1400]
Definition netconn.c:160
#define NET_EXTRESPONSE_MAX
Definition netconn.h:48
unstickresult_t PHYS_NudgeOutOfSolid(prvm_prog_t *prog, prvm_edict_t *ent)
Definition phys.c:136
#define OFS_NULL
Definition pr_comp.h:32
#define OFS_PARM4
Definition pr_comp.h:38
#define OFS_PARM2
Definition pr_comp.h:36
#define OFS_PARM3
Definition pr_comp.h:37
#define OFS_RETURN
Definition pr_comp.h:33
#define OFS_PARM5
Definition pr_comp.h:39
etype_t
Definition pr_comp.h:29
#define OFS_PARM0
Definition pr_comp.h:34
#define OFS_PARM1
Definition pr_comp.h:35
float ideal_yaw
Definition progsdefs.qc:184
float yaw_speed
Definition progsdefs.qc:185
#define PRVM_gameedictvector(ed, fieldname)
Definition progsvm.h:161
#define PRVM_gameedictfloat(ed, fieldname)
Definition progsvm.h:160
void PRVM_ED_LoadFromFile(prvm_prog_t *prog, const char *data)
#define CLVM_prog
Definition progsvm.h:767
#define PRVM_serveredictvector(ed, fieldname)
Definition progsvm.h:173
#define STRINGBUFFER_QCFLAGS
Definition progsvm.h:497
int PRVM_SetTempString(prvm_prog_t *prog, const char *s, size_t slen)
Takes an strlen (not a buffer size).
char * PRVM_UglyValueString(prvm_prog_t *prog, etype_t type, prvm_eval_t *val, char *line, size_t linelength)
Definition prvm_edict.c:513
#define PRVM_gameglobalvector(fieldname)
Definition progsvm.h:166
#define PRVM_E_FLOAT(e, o)
Definition progsvm.h:891
void PRVM_ED_Write(prvm_prog_t *prog, struct qfile_s *f, prvm_edict_t *ed)
#define STRINGBUFFER_TEMP
Definition progsvm.h:498
#define PRVM_EDICT_TO_PROG(e)
Definition progsvm.h:875
#define PRVM_MAX_OPENFILES
Definition progsvm.h:251
mfunction_t * PRVM_ED_FindFunction(prvm_prog_t *prog, const char *name)
Definition prvm_edict.c:425
#define PRVM_gameglobaledict(fieldname)
Definition progsvm.h:168
void PRVM_ED_PrintNum(prvm_prog_t *prog, int ent, const char *wildcard_fieldname)
Definition prvm_edict.c:788
#define PRVM_G_EDICTNUM(o)
Definition progsvm.h:885
#define PRVM_EDICT_NUM(n)
Definition progsvm.h:867
void PRVM_FreeString(prvm_prog_t *prog, int num)
qbool PRVM_ED_ParseEpair(prvm_prog_t *prog, prvm_edict_t *ent, mdef_t *key, const char *s, qbool parsebackslash)
Definition prvm_edict.c:991
#define PRVM_NEXT_EDICT(e)
Definition progsvm.h:873
const char * PRVM_ED_ParseEdict(prvm_prog_t *prog, const char *data, prvm_edict_t *ent, qbool saveload)
int PRVM_AllocString(prvm_prog_t *prog, size_t bufferlength, char **pointer)
const char * PRVM_GetString(prvm_prog_t *prog, int num)
#define PRVM_EDICTFIELDEDICT(ed, fieldoffset)
Definition progsvm.h:213
#define PRVM_allfunction(funcname)
Definition progsvm.h:146
int prvm_type_size[8]
for consistency : I think a goal of this sub-project is to make the new vm mostly independent from th...
Definition prvm_edict.c:29
#define PRVM_NUM_FOR_EDICT(e)
Definition progsvm.h:870
#define PRVM_Free(buffer)
Definition progsvm.h:819
#define PRVM_gameglobalfloat(fieldname)
Definition progsvm.h:165
#define PRVM_PROG_TO_EDICT(n)
Definition progsvm.h:877
void PRVM_ExplicitCoverageEvent(prvm_prog_t *prog, mfunction_t *func, int statement)
Definition prvm_exec.c:924
#define PRVM_serverglobalfloat(fieldname)
Definition progsvm.h:177
#define PRVM_serveredictfloat(ed, fieldname)
Definition progsvm.h:172
#define PRVM_MAX_OPENSEARCHES
Definition progsvm.h:252
#define PRVM_gameglobalstring(fieldname)
Definition progsvm.h:167
#define PRVM_G_STRING(o)
Definition progsvm.h:887
void PRVM_ED_Free(prvm_prog_t *prog, prvm_edict_t *ed)
Definition prvm_edict.c:314
#define PRVM_E_STRING(e, o)
Definition progsvm.h:894
#define PRVM_allglobaledict(fieldname)
Definition progsvm.h:144
void PRVM_ED_Print(prvm_prog_t *prog, prvm_edict_t *ed, const char *wildcard_fieldname)
Definition prvm_edict.c:657
void PRVM_StackTrace(prvm_prog_t *prog)
Definition prvm_exec.c:436
#define PRVM_G_FLOAT(o)
Definition progsvm.h:882
#define PRVM_G_EDICT(o)
Definition progsvm.h:884
void PRVM_PrintState(prvm_prog_t *prog, int stack_index)
Definition prvm_exec.c:726
#define PRVM_G_VECTOR(o)
Definition progsvm.h:886
#define SVVM_prog
Definition progsvm.h:766
const char * PRVM_AllocationOrigin(prvm_prog_t *prog)
Definition prvm_edict.c:223
prvm_edict_t * PRVM_ED_Alloc(prvm_prog_t *prog)
Definition prvm_edict.c:269
#define PRVM_G_INT(o)
Definition progsvm.h:883
#define svc_print
Definition protocol.h:222
#define MAX_FRAMEGROUPBLENDS
Definition protocol.h:408
void VM_strunzone(prvm_prog_t *prog)
Definition prvm_cmds.c:2642
#define MATCH_RIGHT
Definition prvm_cmds.c:4478
void VM_vectorvectors(prvm_prog_t *prog)
Definition prvm_cmds.c:3582
#define GETARG_INT(a)
size_t VM_VarString(prvm_prog_t *prog, int first, char *out, size_t outsize)
Returns the length of the *out string excluding the \0 terminator.
Definition prvm_cmds.c:280
static void getmatrix(prvm_prog_t *prog, prvm_edict_t *ed, matrix4x4_t *out)
Definition prvm_cmds.c:6195
void VM_substring(prvm_prog_t *prog)
Definition prvm_cmds.c:2397
void VM_entityfieldname(prvm_prog_t *prog)
Definition prvm_cmds.c:2129
void VM_altstr_prepare(prvm_prog_t *prog)
Definition prvm_cmds.c:3651
#define MATCH_MIDDLE
Definition prvm_cmds.c:4479
void VM_buf_writefile(prvm_prog_t *prog)
Definition prvm_cmds.c:4401
void VM_getsoundtime(prvm_prog_t *prog)
Definition prvm_cmds.c:2994
void VM_objerror(prvm_prog_t *prog)
Definition prvm_cmds.c:403
static void clippointtosurface(prvm_prog_t *prog, prvm_edict_t *ed, model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
Definition prvm_cmds.c:6236
void VM_fabs(prvm_prog_t *prog)
Definition prvm_cmds.c:899
void VM_isserver(prvm_prog_t *prog)
Definition prvm_cmds.c:2864
void VM_nudgeoutofsolid(prvm_prog_t *prog)
Definition prvm_cmds.c:5644
void VM_dprint(prvm_prog_t *prog)
Definition prvm_cmds.c:854
void VM_uri_get(prvm_prog_t *prog)
Definition prvm_cmds.c:5427
void VM_chr2str(prvm_prog_t *prog)
Definition prvm_cmds.c:4918
void VM_digest_hex(prvm_prog_t *prog)
Definition prvm_cmds.c:5175
void VM_clientcount(prvm_prog_t *prog)
Definition prvm_cmds.c:2878
cvar_t prvm_coverage
Definition prvm_edict.c:39
void BufStr_Set(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer, int strindex, const char *str)
Definition prvm_cmds.c:3902
void VM_soundlength(prvm_prog_t *prog)
Definition prvm_cmds.c:3023
void VM_strncmp(prvm_prog_t *prog)
Definition prvm_cmds.c:5127
void VM_strtolower(prvm_prog_t *prog)
Definition prvm_cmds.c:2329
void VM_fgets(prvm_prog_t *prog)
Definition prvm_cmds.c:1996
void VM_Cmd_Init(prvm_prog_t *prog)
Definition prvm_cmds.c:5265
void VM_physics_addtorque(prvm_prog_t *prog)
Definition prvm_cmds.c:6613
void VM_search_getsize(prvm_prog_t *prog)
Definition prvm_cmds.c:3238
void VM_findkeysforcommand(prvm_prog_t *prog)
Definition prvm_cmds.c:3352
void VM_tan(prvm_prog_t *prog)
Definition prvm_cmds.c:1704
void VM_modulo(prvm_prog_t *prog)
Definition prvm_cmds.c:3116
void VM_sqrt(prvm_prog_t *prog)
Definition prvm_cmds.c:1643
void VM_stov(prvm_prog_t *prog)
Definition prvm_cmds.c:2603
void VM_random(prvm_prog_t *prog)
Definition prvm_cmds.c:611
void VM_gecko_navigate(prvm_prog_t *prog)
Definition prvm_cmds.c:3500
static void applytransform_inverted(prvm_prog_t *prog, const vec3_t in, prvm_edict_t *ed, vec3_t out)
Definition prvm_cmds.c:6219
void VM_eprint(prvm_prog_t *prog)
Definition prvm_cmds.c:1494
void VM_bitshift(prvm_prog_t *prog)
Definition prvm_cmds.c:3594
void VM_precache_sound(prvm_prog_t *prog)
Definition prvm_cmds.c:1381
#define PRINTF_SPACEPOSITIVE
void VM_CL_getextresponse(prvm_prog_t *prog)
Definition prvm_cmds.c:5612
void VM_buf_getsize(prvm_prog_t *prog)
Definition prvm_cmds.c:4016
void VM_getsurfacetexture(prvm_prog_t *prog)
Definition prvm_cmds.c:6416
static void animatemodel(prvm_prog_t *prog, model_t *model, prvm_edict_t *ed)
Definition prvm_cmds.c:6138
static void BufStr_Expand(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer, int strindex)
Definition prvm_cmds.c:3815
void VM_search_end(prvm_prog_t *prog)
Definition prvm_cmds.c:3207
void VM_getentityfieldstring(prvm_prog_t *prog)
Definition prvm_cmds.c:2177
void VM_bufstr_get(prvm_prog_t *prog)
Definition prvm_cmds.c:4172
void VM_altstr_get(prvm_prog_t *prog)
Definition prvm_cmds.c:3683
void VM_gecko_movemouse(prvm_prog_t *prog)
Definition prvm_cmds.c:3523
static qbool PRVM_Cvar_ReadOk(prvm_prog_t *prog, const char *string)
Definition prvm_cmds.c:686
void VM_cvar_type(prvm_prog_t *prog)
Definition prvm_cmds.c:722
static int chrconv_number(int i, int base, int conv)
Definition prvm_cmds.c:4940
void VM_makevectors(prvm_prog_t *prog)
Definition prvm_cmds.c:3563
static qbool match_rule(const char *string, int max_string, const char *pattern, int patternlength, int rule)
Definition prvm_cmds.c:4537
void VM_vlen(prvm_prog_t *prog)
Definition prvm_cmds.c:544
void VM_gecko_destroy(prvm_prog_t *prog)
Definition prvm_cmds.c:3489
#define PRINTF_ALTERNATE
void VM_CheckEmptyString(prvm_prog_t *prog, const char *s)
Definition prvm_cmds.c:62
void VM_physics_addforce(prvm_prog_t *prog)
Definition prvm_cmds.c:6584
void VM_gecko_get_texture_extent(prvm_prog_t *prog)
Definition prvm_cmds.c:3547
void VM_search_getfilename(prvm_prog_t *prog)
Definition prvm_cmds.c:3266
void VM_itof(prvm_prog_t *prog)
Definition prvm_cmds.c:969
static void VM_Search_Reset(prvm_prog_t *prog)
Definition prvm_cmds.c:3142
void VM_centerprint(prvm_prog_t *prog)
Definition prvm_cmds.c:499
#define MATCH_WHOLE
Definition prvm_cmds.c:4476
void VM_coverage(prvm_prog_t *prog)
Definition prvm_cmds.c:6641
void VM_break(prvm_prog_t *prog)
Definition prvm_cmds.c:661
void VM_uncolorstring(prvm_prog_t *prog)
Definition prvm_cmds.c:4857
void VM_strlennocol(prvm_prog_t *prog)
Definition prvm_cmds.c:2305
void VM_tokenize(prvm_prog_t *prog)
Definition prvm_cmds.c:2663
#define PRINTF_ZEROPAD
void VM_numentityfields(prvm_prog_t *prog)
Definition prvm_cmds.c:2115
void VM_SetTraceGlobals(prvm_prog_t *prog, const trace_t *trace)
Definition prvm_cmds.c:5228
void VM_vtos(prvm_prog_t *prog)
Definition prvm_cmds.c:917
static int BufStr_SortStringsUP(const void *in1, const void *in2)
Definition prvm_cmds.c:3847
void VM_getsurfacenumpoints(prvm_prog_t *prog)
Definition prvm_cmds.c:6282
void VM_argv_start_index(prvm_prog_t *prog)
Definition prvm_cmds.c:2822
void VM_Cmd_Reset(prvm_prog_t *prog)
Definition prvm_cmds.c:5274
static void VM_Search_Init(prvm_prog_t *prog)
Definition prvm_cmds.c:3135
void VM_getsurfacepointattribute(prvm_prog_t *prog)
Definition prvm_cmds.c:6326
static qbool checkextension(prvm_prog_t *prog, const char *name)
Definition prvm_cmds.c:323
void VM_setbindmaps(prvm_prog_t *prog)
Definition prvm_cmds.c:3461
void VM_CL_videoplaying(prvm_prog_t *prog)
Definition prvm_cmds.c:5691
void VM_registercvar(prvm_prog_t *prog)
Definition prvm_cmds.c:1736
void VM_uri_unescape(prvm_prog_t *prog)
Definition prvm_cmds.c:5317
void VM_infoget(prvm_prog_t *prog)
Definition prvm_cmds.c:5110
void VM_randomvec(prvm_prog_t *prog)
Definition prvm_cmds.c:1719
void VM_matchpattern(prvm_prog_t *prog)
Definition prvm_cmds.c:4619
void BufStr_Flush(prvm_prog_t *prog)
Definition prvm_cmds.c:3943
void VM_setkeybind(prvm_prog_t *prog)
Definition prvm_cmds.c:3423
void VM_atan2(prvm_prog_t *prog)
Definition prvm_cmds.c:1692
void VM_etos(prvm_prog_t *prog)
Definition prvm_cmds.c:936
void VM_cvar_defstring(prvm_prog_t *prog)
Definition prvm_cmds.c:786
void VM_stackdump(prvm_prog_t *prog)
Definition prvm_cmds.c:1437
static int chrchar_alpha(int i, int basec, int baset, int convc, int convt, int charnum)
Definition prvm_cmds.c:4983
void VM_altstr_count(prvm_prog_t *prog)
Definition prvm_cmds.c:3621
void VM_asin(prvm_prog_t *prog)
Definition prvm_cmds.c:1656
void VM_vectoyaw(prvm_prog_t *prog)
Definition prvm_cmds.c:557
void VM_strlen(prvm_prog_t *prog)
Definition prvm_cmds.c:2265
static void uri_to_string_callback(int status, size_t length_received, unsigned char *buffer, void *cbdata)
Definition prvm_cmds.c:5389
void VM_strconv(prvm_prog_t *prog)
Definition prvm_cmds.c:5022
void VM_rint(prvm_prog_t *prog)
Definition prvm_cmds.c:1508
void VM_bound(prvm_prog_t *prog)
Definition prvm_cmds.c:1829
void VM_argv_end_index(prvm_prog_t *prog)
Definition prvm_cmds.c:2840
void VM_buf_implode(prvm_prog_t *prog)
Definition prvm_cmds.c:4128
#define MATCH_PATTERN
Definition prvm_cmds.c:4480
void VM_precache_file(prvm_prog_t *prog)
Definition prvm_cmds.c:1407
void VM_spawn(prvm_prog_t *prog)
Definition prvm_cmds.c:1063
void VM_GenerateFrameGroupBlend(prvm_prog_t *prog, framegroupblend_t *framegroupblend, const prvm_edict_t *ed)
Definition prvm_cmds.c:96
void VM_ClearTraceGlobals(prvm_prog_t *prog)
Definition prvm_cmds.c:5245
void VM_tokenize_console(prvm_prog_t *prog)
Definition prvm_cmds.c:2694
void VM_sprintf(prvm_prog_t *prog)
Definition prvm_cmds.c:5772
void VM_localsound(prvm_prog_t *prog)
Definition prvm_cmds.c:625
void VM_buf_cvarlist(prvm_prog_t *prog)
Definition prvm_cmds.c:4659
static int tokens_endpos[VM_TEMPSTRING_MAXSIZE/2]
Definition prvm_cmds.c:2661
void VM_find(prvm_prog_t *prog)
Definition prvm_cmds.c:1110
void VM_stof(prvm_prog_t *prog)
Definition prvm_cmds.c:954
void VM_getsurfacetriangle(prvm_prog_t *prog)
Definition prvm_cmds.c:6512
void VM_fputs(prvm_prog_t *prog)
Definition prvm_cmds.c:2049
void VM_bufstr_add(prvm_prog_t *prog)
Definition prvm_cmds.c:4235
void VM_strdecolorize(prvm_prog_t *prog)
Definition prvm_cmds.c:2282
void VM_uri_escape(prvm_prog_t *prog)
Definition prvm_cmds.c:5284
void VM_findchainflags(prvm_prog_t *prog)
Definition prvm_cmds.c:1334
void VM_netaddress_resolve(prvm_prog_t *prog)
Definition prvm_cmds.c:5590
void VM_writetofile(prvm_prog_t *prog)
Definition prvm_cmds.c:2082
void VM_physics_enable(prvm_prog_t *prog)
Definition prvm_cmds.c:6557
void VM_putentityfieldstring(prvm_prog_t *prog)
Definition prvm_cmds.c:2229
void VM_etof(prvm_prog_t *prog)
Definition prvm_cmds.c:1001
void VM_nextent(prvm_prog_t *prog)
Definition prvm_cmds.c:1556
void VM_parseentitydata(prvm_prog_t *prog)
Definition prvm_cmds.c:3054
#define PRINTF_SIGNPOSITIVE
void VM_gecko_resize(prvm_prog_t *prog)
Definition prvm_cmds.c:3535
static const char * detect_match_rule(char *pattern, int *matchrule)
Definition prvm_cmds.c:4482
static int tokens_startpos[VM_TEMPSTRING_MAXSIZE/2]
Definition prvm_cmds.c:2660
void VM_fclose(prvm_prog_t *prog)
Definition prvm_cmds.c:1963
void VM_Warning(prvm_prog_t *prog, const char *fmt,...)
Definition prvm_cmds.c:25
void VM_ftoe(prvm_prog_t *prog)
Definition prvm_cmds.c:982
void VM_findfloat(prvm_prog_t *prog)
Definition prvm_cmds.c:1155
void VM_strcat(prvm_prog_t *prog)
Definition prvm_cmds.c:2377
void VM_atan(prvm_prog_t *prog)
Definition prvm_cmds.c:1680
void VM_ceil(prvm_prog_t *prog)
Definition prvm_cmds.c:1541
void VM_buf_del(prvm_prog_t *prog)
Definition prvm_cmds.c:3995
void VM_strpad(prvm_prog_t *prog)
Definition prvm_cmds.c:5070
void VM_strtoupper(prvm_prog_t *prog)
Definition prvm_cmds.c:2352
void VM_altstr_ins(prvm_prog_t *prog)
Definition prvm_cmds.c:3775
void VM_normalize(prvm_prog_t *prog)
Definition prvm_cmds.c:515
void VM_changeyaw(prvm_prog_t *prog)
Definition prvm_cmds.c:4747
void VM_tokenizebyseparator(prvm_prog_t *prog)
Definition prvm_cmds.c:2738
static qfile_t * VM_GetFileHandle(prvm_prog_t *prog, int index)
Definition prvm_cmds.c:1874
void VM_getkeybind(prvm_prog_t *prog)
Definition prvm_cmds.c:3402
void VM_getbindmaps(prvm_prog_t *prog)
Definition prvm_cmds.c:3444
void VM_strftime(prvm_prog_t *prog)
Definition prvm_cmds.c:1014
void VM_floor(prvm_prog_t *prog)
Definition prvm_cmds.c:1527
void VM_cos(prvm_prog_t *prog)
Definition prvm_cmds.c:1630
void VM_RemoveEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed)
Definition prvm_cmds.c:261
void VM_FrameBlendFromFrameGroupBlend(frameblend_t *frameblend, const framegroupblend_t *framegroupblend, const model_t *model, double curtime)
Definition prvm_cmds.c:125
static int chrconv_punct(int i, int base, int conv)
Definition prvm_cmds.c:4965
void VM_whichpack(prvm_prog_t *prog)
Definition prvm_cmds.c:5364
void VM_CL_isdemo(prvm_prog_t *prog)
Definition prvm_cmds.c:5684
void VM_buf_sort(prvm_prog_t *prog)
Definition prvm_cmds.c:4093
void VM_bufstr_find(prvm_prog_t *prog)
Definition prvm_cmds.c:4564
void VM_strzone(prvm_prog_t *prog)
Definition prvm_cmds.c:2621
void BufStr_Del(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer)
Definition prvm_cmds.c:3926
void VM_cvar_set(prvm_prog_t *prog)
Definition prvm_cmds.c:823
void VM_isfunction(prvm_prog_t *prog)
Definition prvm_cmds.c:5745
void VM_getostype(prvm_prog_t *prog)
Definition prvm_cmds.c:2921
static size_t stringbuffers_sortlength
Definition prvm_cmds.c:3813
void VM_bprint(prvm_prog_t *prog)
Definition prvm_cmds.c:442
void VM_argv(prvm_prog_t *prog)
Definition prvm_cmds.c:2804
void M_FindKeysForCommand(const char *command, int *keys)
static void applytransform_forward_direction(prvm_prog_t *prog, const vec3_t in, prvm_edict_t *ed, vec3_t out)
Definition prvm_cmds.c:6212
void VM_strreplace(prvm_prog_t *prog)
Definition prvm_cmds.c:2469
void VM_min(prvm_prog_t *prog)
Definition prvm_cmds.c:1777
void VM_changepitch(prvm_prog_t *prog)
Definition prvm_cmds.c:4805
qbool PRVM_ConsoleCommand(prvm_prog_t *prog, const char *text, size_t textlen, int *func, qbool preserve_self, int curself, double ptime, const char *error_message)
Definition prvm_cmds.c:68
static void BufStr_Shrink(prvm_prog_t *prog, prvm_stringbuffer_t *stringbuffer)
Definition prvm_cmds.c:3831
prvm_stringbuffer_t * BufStr_FindCreateReplace(prvm_prog_t *prog, int bufindex, unsigned flags, const char *format)
Definition prvm_cmds.c:3867
void VM_checkextension(prvm_prog_t *prog)
Definition prvm_cmds.c:363
void VM_clientstate(prvm_prog_t *prog)
Definition prvm_cmds.c:2892
void VM_ftos(prvm_prog_t *prog)
Definition prvm_cmds.c:874
void VM_bufstr_set(prvm_prog_t *prog)
Definition prvm_cmds.c:4202
static model_t * getmodel(prvm_prog_t *prog, prvm_edict_t *ed)
Definition prvm_cmds.c:6100
void VM_findflags(prvm_prog_t *prog)
Definition prvm_cmds.c:1294
void VM_getsurfacenumtriangles(prvm_prog_t *prog)
Definition prvm_cmds.c:6497
#define GETARG_VECTOR(a)
void VM_acos(prvm_prog_t *prog)
Definition prvm_cmds.c:1668
void VM_loadfromfile(prvm_prog_t *prog)
Definition prvm_cmds.c:3082
static void animatemodel_reset(prvm_prog_t *prog)
Definition prvm_cmds.c:6127
void VM_gecko_create(prvm_prog_t *prog)
Definition prvm_cmds.c:3477
void VM_altstr_set(prvm_prog_t *prog)
Definition prvm_cmds.c:3731
void VM_gettime(prvm_prog_t *prog)
Definition prvm_cmds.c:2948
void VM_findchainfloat(prvm_prog_t *prog)
Definition prvm_cmds.c:1248
void VM_findchain(prvm_prog_t *prog)
Definition prvm_cmds.c:1193
void VM_getsurfaceclippedpoint(prvm_prog_t *prog)
Definition prvm_cmds.c:6478
void VM_traceon(prvm_prog_t *prog)
Definition prvm_cmds.c:1466
void VM_strstrofs(prvm_prog_t *prog)
Definition prvm_cmds.c:4872
void VM_fopen(prvm_prog_t *prog)
Definition prvm_cmds.c:1899
static void applytransform_forward_normal(prvm_prog_t *prog, const vec3_t in, prvm_edict_t *ed, vec3_t out)
Definition prvm_cmds.c:6227
void VM_max(prvm_prog_t *prog)
Definition prvm_cmds.c:1803
cvar_t prvm_backtraceforwarnings
Definition prvm_edict.c:40
static char tokenize_string[VM_TEMPSTRING_MAXSIZE]
Definition prvm_cmds.c:2662
void VM_bufstr_free(prvm_prog_t *prog)
Definition prvm_cmds.c:4282
void VM_getsurfacepoint(prvm_prog_t *prog)
Definition prvm_cmds.c:6298
void VM_getsurfacenearpoint(prvm_prog_t *prog)
Definition prvm_cmds.c:6428
#define FKFC_NUMKEYS
Definition prvm_cmds.c:3350
void VM_buf_copy(prvm_prog_t *prog)
Definition prvm_cmds.c:4039
void VM_cvar_description(prvm_prog_t *prog)
Definition prvm_cmds.c:805
void VM_search_begin(prvm_prog_t *prog)
Definition prvm_cmds.c:3161
#define GETARG_FLOAT(a)
void VM_crc16(prvm_prog_t *prog)
Definition prvm_cmds.c:5162
void VM_stringtokeynum(prvm_prog_t *prog)
Definition prvm_cmds.c:3388
void VM_remove(prvm_prog_t *prog)
Definition prvm_cmds.c:1080
void VM_UpdateEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed, const model_t *edmodel, const frameblend_t *frameblend)
Definition prvm_cmds.c:226
void VM_error(prvm_prog_t *prog)
Definition prvm_cmds.c:380
float CDAudio_GetPosition(void)
Definition cd_shared.c:220
void VM_buf_create(prvm_prog_t *prog)
Definition prvm_cmds.c:3964
void VM_str2chr(prvm_prog_t *prog)
Definition prvm_cmds.c:4896
#define MATCH_LEFT
Definition prvm_cmds.c:4477
void VM_print(prvm_prog_t *prog)
Definition prvm_cmds.c:425
#define PRINTF_LEFT
void VM_cvar(prvm_prog_t *prog)
Definition prvm_cmds.c:700
void VM_cvar_string(prvm_prog_t *prog)
Definition prvm_cmds.c:762
void VM_gecko_keyevent(prvm_prog_t *prog)
Definition prvm_cmds.c:3511
void VM_changelevel(prvm_prog_t *prog)
Definition prvm_cmds.c:1592
void VM_crash(prvm_prog_t *prog)
Definition prvm_cmds.c:1452
void VM_Files_CloseAll(prvm_prog_t *prog)
Definition prvm_cmds.c:1863
void VM_SV_getextresponse(prvm_prog_t *prog)
Definition prvm_cmds.c:5627
static int BufStr_SortStringsDOWN(const void *in1, const void *in2)
Definition prvm_cmds.c:3857
void VM_traceoff(prvm_prog_t *prog)
Definition prvm_cmds.c:1480
void VM_callfunction(prvm_prog_t *prog)
Definition prvm_cmds.c:5705
void VM_infoadd(prvm_prog_t *prog)
Definition prvm_cmds.c:5090
#define GETARG_INTVECTOR(a)
void VM_wasfreed(prvm_prog_t *prog)
Definition prvm_cmds.c:5222
void VM_chr(prvm_prog_t *prog)
Definition prvm_cmds.c:3303
void VM_sprint(prvm_prog_t *prog)
Definition prvm_cmds.c:465
void VM_buf_loadfile(prvm_prog_t *prog)
Definition prvm_cmds.c:4318
void VM_localcmd(prvm_prog_t *prog)
Definition prvm_cmds.c:678
void VM_sin(prvm_prog_t *prog)
Definition prvm_cmds.c:1618
void VM_getsurfacenormal(prvm_prog_t *prog)
Definition prvm_cmds.c:6397
void VM_pow(prvm_prog_t *prog)
Definition prvm_cmds.c:1844
void VM_log(prvm_prog_t *prog)
Definition prvm_cmds.c:1850
void VM_coredump(prvm_prog_t *prog)
Definition prvm_cmds.c:1421
void VM_strireplace(prvm_prog_t *prog)
Definition prvm_cmds.c:2536
void VM_keynumtostring(prvm_prog_t *prog)
Definition prvm_cmds.c:3331
static int tokens[VM_TEMPSTRING_MAXSIZE/2]
Definition prvm_cmds.c:2659
void VM_strncasecmp(prvm_prog_t *prog)
Definition prvm_cmds.c:5145
void VM_loadfromdata(prvm_prog_t *prog)
Definition prvm_cmds.c:3040
void VM_vectoangles(prvm_prog_t *prog)
Definition prvm_cmds.c:586
static void applytransform_forward(prvm_prog_t *prog, const vec3_t in, prvm_edict_t *ed, vec3_t out)
Definition prvm_cmds.c:6205
static msurface_t * getsurface(model_t *model, int surfacenum)
Definition prvm_cmds.c:6273
void VM_entityfieldtype(prvm_prog_t *prog)
Definition prvm_cmds.c:2153
#define GETARG_STRING(a)
void VM_Files_Init(prvm_prog_t *prog)
Definition prvm_cmds.c:1856
static int num_tokens
Definition prvm_cmds.c:2658
#define VM_RETURN_EDICT(e)
Definition prvm_cmds.h:213
#define VM_TEMPSTRING_MAXSIZE
Definition prvm_cmds.h:215
#define VM_SAFEPARMCOUNT(p, f)
Definition prvm_cmds.h:207
#define VM_SAFEPARMCOUNTRANGE(p1, p2, f)
Definition prvm_cmds.h:206
prvm_eval_t * src
prvm_uint_t addr
int i
#define MAX_INPUTLINE
maximum size of console commandline, QuakeC strings, and many other text processing buffers
Definition qdefs.h:94
#define MAX_EDICTS
max number of objects in game world at once (32768 protocol limit)
Definition qdefs.h:105
#define MAX_BINDMAPS
Definition qdefs.h:152
#define ISWHITESPACE(ch)
Definition qdefs.h:184
#define INT_LOSSLESS_FORMAT_CONVERT_U(x)
Definition qdefs.h:206
#define INT_LOSSLESS_FORMAT_CONVERT_S(x)
Definition qdefs.h:205
#define INT_LOSSLESS_FORMAT_SIZE
Definition qdefs.h:204
#define NULL
Definition qtypes.h:12
float vec_t
Definition qtypes.h:68
vec_t vec3_t[3]
Definition qtypes.h:71
bool qbool
Definition qtypes.h:9
float prvm_vec_t
Definition qtypes.h:55
int32_t prvm_int_t
Definition qtypes.h:56
#define MOVETYPE_PHYSICS
indicates this object is physics controlled
Definition server.h:326
server_t sv
local server
Definition sv_main.c:223
void SV_LinkEdict(prvm_edict_t *ent)
Definition sv_phys.c:804
void SV_GetEntityMatrix(prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qbool viewmatrix)
Definition svvm_cmds.c:2518
model_t * SV_GetModelFromEdict(prvm_edict_t *ed)
Definition sv_main.c:1612
server_static_t svs
persistant server info
Definition sv_main.c:224
void SV_BroadcastPrint(const char *msg)
Definition sv_send.c:91
dp_FragColor r
return ret
dp_FragColor g
float f
vec3 normal
dp_FragColor b
ret a
qbool S_LocalSound(const char *sound)
Definition snd_main.c:2246
cvar_t snd_initialized
Definition snd_main.c:167
float S_SoundLength(const char *name)
Definition snd_main.c:1085
float S_GetEntChannelPosition(int entnum, int entchannel)
Definition snd_main.c:1790
qbool S_LocalSoundEx(const char *sound, int chan, float fvol)
Definition snd_main.c:2217
sfx_t * S_PrecacheSound(const char *name, qbool complain, qbool levelsound)
Definition snd_main.c:1048
#define CHAN_USER2ENGINE(c)
Definition sound.h:90
#define IS_CHAN(n)
Definition sound.h:82
frameblend_t frameblend[MAX_FRAMEBLENDS]
Definition prvm_cmds.c:6113
skeleton_t skeleton
Definition prvm_cmds.c:6115
skeleton_t * skeleton_p
Definition prvm_cmds.c:6114
float framerate
qbool demoplayback
Definition client.h:587
cactive_t state
Definition client.h:568
netconn_t * netconnection
communications handle
Definition server.h:210
Definition cvar.h:66
int integer
Definition cvar.h:73
float lerp
Definition client.h:313
int subframe
Definition client.h:312
double dirtytime
the main loop wall time for this frame, equal to Sys_DirtyTime() at the start of this host frame
Definition host.h:47
double realtime
the accumulated mainloop time since application started (with filtering), without any slowmo or clamp...
Definition host.h:46
uint32_t ofs
Definition pr_comp.h:416
int32_t s_name
Definition pr_comp.h:417
uint32_t type
Definition pr_comp.h:414
int32_t first_statement
Definition pr_comp.h:444
double builtinsprofile
Definition pr_comp.h:452
int32_t s_name
Definition pr_comp.h:460
describes the textures to use on a range of triangles in the model, and mins/maxs (AABB) for culling.
int num_firsttriangle
int num_triangles
range of triangles and vertices in model->surfmesh
texture_t * texture
the texture to use on the surface
int num_firstvertex
vec3_t mins
bounding box for onscreen checks
sizebuf_t message
writing buffer to send to peer as the next reliable message can be added to at any time,...
Definition netconn.h:161
prvm_vec_t * fp
Definition progsvm.h:102
union prvm_edict_t::@30 fields
qbool free
true if this edict is unused
Definition progsvm.h:93
union prvm_edict_t::@29 priv
struct edict_engineprivate_s * server
FIXME: this server pointer really means world, not server (it is used by both server qc and client qc...
Definition progsvm.h:106
struct animatemodel_cache * animatemodel_cache
Definition progsvm.h:719
struct qfile_s * openfiles[PRVM_MAX_OPENFILES]
Definition progsvm.h:636
int numfielddefs
Definition progsvm.h:565
prvm_builtin_t * builtins
Definition progsvm.h:604
qbool loaded
used to indicate whether a prog is loaded
Definition progsvm.h:710
mfunction_t * functions
Definition progsvm.h:541
const char * name
name of the prog, e.g. "Server", "Client" or "Menu" (used for text output)
Definition progsvm.h:700
void(* error_cmd)(const char *format,...) DP_FUNC_PRINTF(1) DP_FUNC_NORETURN
[INIT]
Definition progsvm.h:747
int num_edicts
copies of some vars that were former read from sv
Definition progsvm.h:671
prvm_prog_fieldoffsets_t fieldoffsets
Definition progsvm.h:691
const char * opensearches_origin[PRVM_MAX_OPENSEARCHES]
Definition progsvm.h:639
prvm_edict_t * edicts
Definition progsvm.h:680
double * explicit_profile
only incremented if prvm_statementprofiling is on
Definition progsvm.h:575
mempool_t * progs_mempool
all memory allocations related to this vm_prog (code, edicts, strings)
Definition progsvm.h:602
struct fssearch_s * opensearches[PRVM_MAX_OPENSEARCHES]
Definition progsvm.h:638
memexpandablearray_t stringbuffersarray
Definition progsvm.h:596
int xstatement
Definition progsvm.h:621
struct cmd_state_s * console_cmd
points to the relevant console command interpreter for this vm (cmd_local or &cmd_server),...
Definition progsvm.h:641
int max_edicts
number of edicts for which space has been (should be) allocated
Definition progsvm.h:673
void(* ExecuteProgram)(struct prvm_prog_s *prog, func_t fnum, const char *errormessage)
pointer to one of the *VM_ExecuteProgram functions
Definition progsvm.h:749
struct skeleton_s * skeletons[MAX_EDICTS]
Definition progsvm.h:640
sizebuf_t tempstringsbuf
buffer for storing all tempstrings created during one invocation of ExecuteProgram
Definition progsvm.h:644
const char * openfiles_origin[PRVM_MAX_OPENFILES]
Definition progsvm.h:637
mfunction_t * xfunction
Definition progsvm.h:620
mdef_t * fielddefs
Definition progsvm.h:545
const char ** extensionstring
Definition progsvm.h:705
double starttime
system time when PRVM_Prog_Load was called
Definition progsvm.h:538
int reserved_edicts
number of reserved edicts (allocated from 1)
Definition progsvm.h:678
const char * origin
Definition progsvm.h:504
unsigned char flags
Definition progsvm.h:505
struct client_s * clients
client slots
Definition server.h:30
qbool changelevel_issued
cleared when at SV_SpawnServer
Definition server.h:34
int maxclients
number of svs.clients slots (updated by maxplayers command)
Definition server.h:28
qbool active
false if only a net client
Definition server.h:66
int cursize
Definition common.h:54
const struct model_s * model
Definition protocol.h:425
struct matrix4x4_s * relativetransforms
Definition protocol.h:426
int outfd
Definition sys.h:149
char name[64]
void * ent
Definition collision.h:47
const struct texture_s * hittexture
Definition collision.h:62
double fraction
Definition collision.h:40
int hitq3surfaceflags
Definition collision.h:60
double endpos[3]
Definition collision.h:42
qbool inopen
Definition collision.h:33
int startsupercontents
Definition collision.h:56
qbool allsolid
Definition collision.h:24
plane_t plane
Definition collision.h:44
qbool startsolid
Definition collision.h:26
int hitsupercontents
Definition collision.h:58
qbool inwater
Definition collision.h:36
unsigned char * postdata
Definition prvm_cmds.c:5382
char buffer[MAX_INPUTLINE]
Definition prvm_cmds.c:5380
char posttype[128]
Definition prvm_cmds.c:5381
double starttime
Definition prvm_cmds.c:5378
prvm_prog_t * prog
Definition prvm_cmds.c:5377
static vec3_t forward
Definition sv_user.c:305
static vec3_t right
Definition sv_user.c:305
static vec3_t up
Definition sv_user.c:305
void Sys_Error(const char *error,...) DP_FUNC_PRINTF(1) DP_FUNC_NORETURN
Causes the entire program to exit ASAP.
Definition sys_shared.c:724
void * dllhandle_t
Definition sys.h:169
double Sys_DirtyTime(void)
Definition sys_shared.c:417
sys_t sys
Definition sys_shared.c:42
vec_t dist
Definition collision.h:14
vec3_t normal
Definition collision.h:13
prvm_int_t ivector[3]
Definition progsvm.h:66
char * u8_encodech(Uchar ch, size_t *l, char *buf16)
uses u8_fromchar on a static buffer
Definition utf8lib.c:697
size_t u8_strpad(char *out, size_t outsize, const char *in, qbool leftalign, size_t minwidth, size_t maxwidth)
Pads a utf-8 string.
Definition utf8lib.c:881
size_t u8_COM_StringLengthNoColors(const char *_s, size_t size_s, qbool *valid)
Definition utf8lib.c:777
size_t u8_bytelen(const char *_s, size_t n)
Get the number of bytes used in a string to represent an amount of characters.
Definition utf8lib.c:340
cvar_t utf8_enable
Definition utf8lib.c:11
size_t u8_strpad_colorcodes(char *out, size_t outsize, const char *in, qbool leftalign, size_t minwidth, size_t maxwidth)
Definition utf8lib.c:899
size_t u8_strlen(const char *_s)
Get the number of characters in an UTF-8 string.
Definition utf8lib.c:195
int u8_byteofs(const char *_s, size_t i, size_t *len)
Get the byte-index for a character-index.
Definition utf8lib.c:425
int u8_fromchar(Uchar w, char *to, size_t maxlen)
Encode a wide-character into utf-8.
Definition utf8lib.c:628
size_t u8_strnlen(const char *_s, size_t n)
Get the number of characters in a part of an UTF-8 string.
Definition utf8lib.c:249
int32_t Uchar
Definition utf8lib.h:35
#define u8_getchar_noendptr(c)
Definition utf8lib.h:72
size_t Mem_ExpandableArray_IndexRange(const memexpandablearray_t *l)
Definition zone.c:763
void Mem_ExpandableArray_NewArray(memexpandablearray_t *l, mempool_t *mempool, size_t recordsize, int numrecordsperarray)
Definition zone.c:675
void Mem_ExpandableArray_FreeRecord(memexpandablearray_t *l, void *record)
Definition zone.c:743
void * Mem_ExpandableArray_AllocRecord(memexpandablearray_t *l)
Definition zone.c:695
void * Mem_ExpandableArray_RecordAtIndex(const memexpandablearray_t *l, size_t index)
Definition zone.c:780
mempool_t * tempmempool
Definition zone.c:794
#define Mem_Free(mem)
Definition zone.h:96
#define Mem_Alloc(pool, size)
Definition zone.h:92
#define Z_Malloc(size)
Definition zone.h:161
#define Z_Free(data)
Definition zone.h:164