5 #include "cl_collision.h"
10 //============================================================================
12 //[515]: unsolved PROBLEMS
13 //- finish player physics code (cs_runplayerphysics)
15 //- RF_DEPTHHACK is not like it should be
16 //- add builtin that sets cl.viewangles instead of reading "input_angles" global
17 //- finish lines support for R_Polygon***
18 //- insert selecttraceline into traceline somehow
20 //4 feature darkplaces csqc: add builtin to clientside qc for reading triangles of model meshes (useful to orient a ui along a triangle of a model mesh)
21 //4 feature darkplaces csqc: add builtins to clientside qc for gl calls
23 extern cvar_t v_flipped;
25 r_refdef_view_t csqc_original_r_refdef_view;
26 r_refdef_view_t csqc_main_r_refdef_view;
28 // #1 void(vector ang) makevectors
29 static void VM_CL_makevectors (prvm_prog_t *prog)
31 vec3_t angles, forward, right, up;
32 VM_SAFEPARMCOUNT(1, VM_CL_makevectors);
33 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), angles);
34 AngleVectors(angles, forward, right, up);
35 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
36 VectorCopy(right, PRVM_clientglobalvector(v_right));
37 VectorCopy(up, PRVM_clientglobalvector(v_up));
40 // #2 void(entity e, vector o) setorigin
41 static void VM_CL_setorigin (prvm_prog_t *prog)
45 VM_SAFEPARMCOUNT(2, VM_CL_setorigin);
47 e = PRVM_G_EDICT(OFS_PARM0);
48 if (e == prog->edicts)
50 VM_Warning(prog, "setorigin: can not modify world entity\n");
53 if (e->priv.required->free)
55 VM_Warning(prog, "setorigin: can not modify free entity\n");
58 org = PRVM_G_VECTOR(OFS_PARM1);
59 VectorCopy (org, PRVM_clientedictvector(e, origin));
60 if(e->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN)
61 e->priv.required->mark = PRVM_EDICT_MARK_SETORIGIN_CAUGHT;
65 static void SetMinMaxSizePRVM (prvm_prog_t *prog, prvm_edict_t *e, prvm_vec_t *min, prvm_vec_t *max)
71 prog->error_cmd("SetMinMaxSize: backwards mins/maxs");
74 VectorCopy (min, PRVM_clientedictvector(e, mins));
75 VectorCopy (max, PRVM_clientedictvector(e, maxs));
76 VectorSubtract (max, min, PRVM_clientedictvector(e, size));
81 static void SetMinMaxSize (prvm_prog_t *prog, prvm_edict_t *e, const vec_t *min, const vec_t *max)
83 prvm_vec3_t mins, maxs;
84 VectorCopy(min, mins);
85 VectorCopy(max, maxs);
86 SetMinMaxSizePRVM(prog, e, mins, maxs);
89 // #3 void(entity e, string m) setmodel
90 static void VM_CL_setmodel (prvm_prog_t *prog)
97 VM_SAFEPARMCOUNT(2, VM_CL_setmodel);
99 e = PRVM_G_EDICT(OFS_PARM0);
100 PRVM_clientedictfloat(e, modelindex) = 0;
101 PRVM_clientedictstring(e, model) = 0;
103 m = PRVM_G_STRING(OFS_PARM1);
105 for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
107 if (!strcmp(cl.csqc_model_precache[i]->name, m))
109 mod = cl.csqc_model_precache[i];
110 PRVM_clientedictstring(e, model) = PRVM_SetEngineString(prog, mod->name);
111 PRVM_clientedictfloat(e, modelindex) = -(i+1);
117 for (i = 0;i < MAX_MODELS;i++)
119 mod = cl.model_precache[i];
120 if (mod && !strcmp(mod->name, m))
122 PRVM_clientedictstring(e, model) = PRVM_SetEngineString(prog, mod->name);
123 PRVM_clientedictfloat(e, modelindex) = i;
130 // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black]
131 // LadyHavoc: erm you broke it by commenting this out - setmodel must do setsize or else the qc can't find out the model size, and ssqc does this by necessity, consistency.
132 SetMinMaxSize (prog, e, mod->normalmins, mod->normalmaxs);
136 SetMinMaxSize (prog, e, vec3_origin, vec3_origin);
137 VM_Warning(prog, "setmodel: model '%s' not precached\n", m);
141 // #4 void(entity e, vector min, vector max) setsize
142 static void VM_CL_setsize (prvm_prog_t *prog)
146 VM_SAFEPARMCOUNT(3, VM_CL_setsize);
148 e = PRVM_G_EDICT(OFS_PARM0);
149 if (e == prog->edicts)
151 VM_Warning(prog, "setsize: can not modify world entity\n");
154 if (e->priv.server->free)
156 VM_Warning(prog, "setsize: can not modify free entity\n");
159 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), mins);
160 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), maxs);
162 SetMinMaxSize( prog, e, mins, maxs );
167 // #8 void(entity e, float chan, string samp, float volume, float atten[, float pitchchange[, float flags]]) sound
168 static void VM_CL_sound (prvm_prog_t *prog)
172 prvm_edict_t *entity;
180 VM_SAFEPARMCOUNTRANGE(5, 7, VM_CL_sound);
182 entity = PRVM_G_EDICT(OFS_PARM0);
183 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
184 sample = PRVM_G_STRING(OFS_PARM2);
185 fvolume = PRVM_G_FLOAT(OFS_PARM3);
186 attenuation = PRVM_G_FLOAT(OFS_PARM4);
188 if (fvolume < 0 || fvolume > 1)
190 VM_Warning(prog, "VM_CL_sound: volume must be in range 0-1\n");
194 if (attenuation < 0 || attenuation > 4)
196 VM_Warning(prog, "VM_CL_sound: attenuation must be in range 0-4\n");
203 pitchchange = PRVM_G_FLOAT(OFS_PARM5);
209 // LadyHavoc: we only let the qc set certain flags, others are off-limits
210 flags = (int)PRVM_G_FLOAT(OFS_PARM6) & (CHANNELFLAG_RELIABLE | CHANNELFLAG_FORCELOOP | CHANNELFLAG_PAUSED | CHANNELFLAG_FULLVOLUME);
213 // sound_starttime exists instead of sound_startposition because in a
214 // networking sense you might not know when something is being received,
215 // so making sounds match up in sync would be impossible if relative
217 if (PRVM_clientglobalfloat(sound_starttime))
218 startposition = cl.time - PRVM_clientglobalfloat(sound_starttime);
222 if (!IS_CHAN(channel))
224 VM_Warning(prog, "VM_CL_sound: channel must be in range 0-127\n");
228 CL_VM_GetEntitySoundOrigin(MAX_EDICTS + PRVM_NUM_FOR_EDICT(entity), org);
229 S_StartSound_StartPosition_Flags(MAX_EDICTS + PRVM_NUM_FOR_EDICT(entity), channel, S_FindName(sample), org, fvolume, attenuation, startposition, flags, pitchchange > 0.0f ? pitchchange * 0.01f : 1.0f);
232 // #483 void(vector origin, string sample, float volume, float attenuation) pointsound
233 static void VM_CL_pointsound(prvm_prog_t *prog)
240 VM_SAFEPARMCOUNT(4, VM_CL_pointsound);
242 VectorCopy( PRVM_G_VECTOR(OFS_PARM0), org);
243 sample = PRVM_G_STRING(OFS_PARM1);
244 fvolume = PRVM_G_FLOAT(OFS_PARM2);
245 attenuation = PRVM_G_FLOAT(OFS_PARM3);
247 if (fvolume < 0 || fvolume > 1)
249 VM_Warning(prog, "VM_CL_pointsound: volume must be in range 0-1\n");
253 if (attenuation < 0 || attenuation > 4)
255 VM_Warning(prog, "VM_CL_pointsound: attenuation must be in range 0-4\n");
259 // Send World Entity as Entity to Play Sound (for CSQC, that is MAX_EDICTS)
260 S_StartSound(MAX_EDICTS, 0, S_FindName(sample), org, fvolume, attenuation);
263 // #14 entity() spawn
264 static void VM_CL_spawn (prvm_prog_t *prog)
267 ed = PRVM_ED_Alloc(prog);
271 static void CL_VM_SetTraceGlobals(prvm_prog_t *prog, const trace_t *trace, int svent)
273 VM_SetTraceGlobals(prog, trace);
274 PRVM_clientglobalfloat(trace_networkentity) = svent;
277 #define CL_HitNetworkBrushModels(move) !((move) == MOVE_WORLDONLY)
278 #define CL_HitNetworkPlayers(move) !((move) == MOVE_WORLDONLY || (move) == MOVE_NOMONSTERS)
280 // #16 void(vector v1, vector v2, float movetype, entity ignore) traceline
281 static void VM_CL_traceline (prvm_prog_t *prog)
288 // R_TimeReport("pretraceline");
290 VM_SAFEPARMCOUNTRANGE(4, 4, VM_CL_traceline);
292 prog->xfunction->builtinsprofile += 30;
294 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
295 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), v2);
296 move = (int)PRVM_G_FLOAT(OFS_PARM2);
297 ent = PRVM_G_EDICT(OFS_PARM3);
299 if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2]))
300 prog->error_cmd("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", prog->name, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
302 trace = CL_TraceLine(v1, v2, move, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtracelinelength.value, CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true, false);
304 CL_VM_SetTraceGlobals(prog, &trace, svent);
305 // R_TimeReport("traceline");
312 Used for use tracing and shot targeting
313 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
314 if the tryents flag is set.
316 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
319 // LadyHavoc: added this for my own use, VERY useful, similar to traceline
320 static void VM_CL_tracebox (prvm_prog_t *prog)
322 vec3_t v1, v2, m1, m2;
327 // R_TimeReport("pretracebox");
328 VM_SAFEPARMCOUNTRANGE(6, 8, VM_CL_tracebox); // allow more parameters for future expansion
330 prog->xfunction->builtinsprofile += 30;
332 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), v1);
333 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), m1);
334 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), m2);
335 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), v2);
336 move = (int)PRVM_G_FLOAT(OFS_PARM4);
337 ent = PRVM_G_EDICT(OFS_PARM5);
339 if (VEC_IS_NAN(v1[0]) || VEC_IS_NAN(v1[1]) || VEC_IS_NAN(v1[2]) || VEC_IS_NAN(v2[0]) || VEC_IS_NAN(v2[1]) || VEC_IS_NAN(v2[2]))
340 prog->error_cmd("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", prog->name, v1[0], v1[1], v1[2], m1[0], m1[1], m1[2], m2[0], m2[1], m2[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
342 trace = CL_TraceBox(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendtraceboxlength.value, CL_HitNetworkBrushModels(move), CL_HitNetworkPlayers(move), &svent, true);
344 CL_VM_SetTraceGlobals(prog, &trace, svent);
345 // R_TimeReport("tracebox");
348 static trace_t CL_Trace_Toss (prvm_prog_t *prog, prvm_edict_t *tossent, prvm_edict_t *ignore, int *svent)
352 vec3_t start, end, mins, maxs, move;
353 vec3_t original_origin;
354 vec3_t original_velocity;
355 vec3_t original_angles;
356 vec3_t original_avelocity;
359 VectorCopy(PRVM_clientedictvector(tossent, origin) , original_origin );
360 VectorCopy(PRVM_clientedictvector(tossent, velocity) , original_velocity );
361 VectorCopy(PRVM_clientedictvector(tossent, angles) , original_angles );
362 VectorCopy(PRVM_clientedictvector(tossent, avelocity), original_avelocity);
364 gravity = PRVM_clientedictfloat(tossent, gravity);
367 gravity *= cl.movevars_gravity * 0.05;
369 for (i = 0;i < 200;i++) // LadyHavoc: sanity check; never trace more than 10 seconds
371 PRVM_clientedictvector(tossent, velocity)[2] -= gravity;
372 VectorMA (PRVM_clientedictvector(tossent, angles), 0.05, PRVM_clientedictvector(tossent, avelocity), PRVM_clientedictvector(tossent, angles));
373 VectorScale (PRVM_clientedictvector(tossent, velocity), 0.05, move);
374 VectorAdd (PRVM_clientedictvector(tossent, origin), move, end);
375 VectorCopy(PRVM_clientedictvector(tossent, origin), start);
376 VectorCopy(PRVM_clientedictvector(tossent, mins), mins);
377 VectorCopy(PRVM_clientedictvector(tossent, maxs), maxs);
378 trace = CL_TraceBox(start, mins, maxs, end, MOVE_NORMAL, tossent, CL_GenericHitSuperContentsMask(tossent), 0, 0, collision_extendmovelength.value, true, true, NULL, true);
379 VectorCopy (trace.endpos, PRVM_clientedictvector(tossent, origin));
381 if (trace.fraction < 1)
385 VectorCopy(original_origin , PRVM_clientedictvector(tossent, origin) );
386 VectorCopy(original_velocity , PRVM_clientedictvector(tossent, velocity) );
387 VectorCopy(original_angles , PRVM_clientedictvector(tossent, angles) );
388 VectorCopy(original_avelocity, PRVM_clientedictvector(tossent, avelocity));
393 static void VM_CL_tracetoss (prvm_prog_t *prog)
397 prvm_edict_t *ignore;
400 prog->xfunction->builtinsprofile += 600;
402 VM_SAFEPARMCOUNT(2, VM_CL_tracetoss);
404 ent = PRVM_G_EDICT(OFS_PARM0);
405 if (ent == prog->edicts)
407 VM_Warning(prog, "tracetoss: can not use world entity\n");
410 ignore = PRVM_G_EDICT(OFS_PARM1);
412 trace = CL_Trace_Toss (prog, ent, ignore, &svent);
414 CL_VM_SetTraceGlobals(prog, &trace, svent);
418 // #20 void(string s) precache_model
419 static void VM_CL_precache_model (prvm_prog_t *prog)
425 VM_SAFEPARMCOUNT(1, VM_CL_precache_model);
427 name = PRVM_G_STRING(OFS_PARM0);
428 for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
430 if(!strcmp(cl.csqc_model_precache[i]->name, name))
432 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
436 PRVM_G_FLOAT(OFS_RETURN) = 0;
437 m = Mod_ForName(name, false, false, name[0] == '*' ? cl.model_name[1] : NULL);
440 for (i = 0;i < MAX_MODELS;i++)
442 if (!cl.csqc_model_precache[i])
444 cl.csqc_model_precache[i] = (model_t*)m;
445 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
449 VM_Warning(prog, "VM_CL_precache_model: no free models\n");
452 VM_Warning(prog, "VM_CL_precache_model: model \"%s\" not found\n", name);
455 // #22 entity(vector org, float rad) findradius
456 static void VM_CL_findradius (prvm_prog_t *prog)
458 prvm_edict_t *ent, *chain;
459 vec_t radius, radius2;
460 vec3_t org, eorg, mins, maxs;
461 int i, numtouchedicts;
462 static prvm_edict_t *touchedicts[MAX_EDICTS];
465 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_findradius);
468 chainfield = PRVM_G_INT(OFS_PARM2);
470 chainfield = prog->fieldoffsets.chain;
472 prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
474 chain = (prvm_edict_t *)prog->edicts;
476 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
477 radius = PRVM_G_FLOAT(OFS_PARM1);
478 radius2 = radius * radius;
480 mins[0] = org[0] - (radius + 1);
481 mins[1] = org[1] - (radius + 1);
482 mins[2] = org[2] - (radius + 1);
483 maxs[0] = org[0] + (radius + 1);
484 maxs[1] = org[1] + (radius + 1);
485 maxs[2] = org[2] + (radius + 1);
486 numtouchedicts = World_EntitiesInBox(&cl.world, mins, maxs, MAX_EDICTS, touchedicts);
487 if (numtouchedicts > MAX_EDICTS)
489 // this never happens //[515]: for what then ?
490 Con_Printf("CSQC_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
491 numtouchedicts = MAX_EDICTS;
493 for (i = 0;i < numtouchedicts;i++)
495 ent = touchedicts[i];
496 // Quake did not return non-solid entities but darkplaces does
497 // (note: this is the reason you can't blow up fallen zombies)
498 if (PRVM_clientedictfloat(ent, solid) == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
500 // LadyHavoc: compare against bounding box rather than center so it
501 // doesn't miss large objects, and use DotProduct instead of Length
502 // for a major speedup
503 VectorSubtract(org, PRVM_clientedictvector(ent, origin), eorg);
504 if (sv_gameplayfix_findradiusdistancetobox.integer)
506 eorg[0] -= bound(PRVM_clientedictvector(ent, mins)[0], eorg[0], PRVM_clientedictvector(ent, maxs)[0]);
507 eorg[1] -= bound(PRVM_clientedictvector(ent, mins)[1], eorg[1], PRVM_clientedictvector(ent, maxs)[1]);
508 eorg[2] -= bound(PRVM_clientedictvector(ent, mins)[2], eorg[2], PRVM_clientedictvector(ent, maxs)[2]);
511 VectorMAMAM(1, eorg, -0.5f, PRVM_clientedictvector(ent, mins), -0.5f, PRVM_clientedictvector(ent, maxs), eorg);
512 if (DotProduct(eorg, eorg) < radius2)
514 PRVM_EDICTFIELDEDICT(ent, chainfield) = PRVM_EDICT_TO_PROG(chain);
519 VM_RETURN_EDICT(chain);
522 // #34 float() droptofloor
523 static void VM_CL_droptofloor (prvm_prog_t *prog)
526 vec3_t start, end, mins, maxs;
529 VM_SAFEPARMCOUNTRANGE(0, 2, VM_CL_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
531 // assume failure if it returns early
532 PRVM_G_FLOAT(OFS_RETURN) = 0;
534 ent = PRVM_PROG_TO_EDICT(PRVM_clientglobaledict(self));
535 if (ent == prog->edicts)
537 VM_Warning(prog, "droptofloor: can not modify world entity\n");
540 if (ent->priv.server->free)
542 VM_Warning(prog, "droptofloor: can not modify free entity\n");
546 VectorCopy(PRVM_clientedictvector(ent, origin), start);
547 VectorCopy(PRVM_clientedictvector(ent, mins), mins);
548 VectorCopy(PRVM_clientedictvector(ent, maxs), maxs);
549 VectorCopy(PRVM_clientedictvector(ent, origin), end);
552 trace = CL_TraceBox(start, mins, maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, true, NULL, true);
554 if (trace.fraction != 1)
556 VectorCopy (trace.endpos, PRVM_clientedictvector(ent, origin));
557 PRVM_clientedictfloat(ent, flags) = (int)PRVM_clientedictfloat(ent, flags) | FL_ONGROUND;
558 PRVM_clientedictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
559 PRVM_G_FLOAT(OFS_RETURN) = 1;
560 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
561 // ent->priv.server->suspendedinairflag = true;
565 // #35 void(float style, string value) lightstyle
566 static void VM_CL_lightstyle (prvm_prog_t *prog)
571 VM_SAFEPARMCOUNT(2, VM_CL_lightstyle);
573 i = (int)PRVM_G_FLOAT(OFS_PARM0);
574 c = PRVM_G_STRING(OFS_PARM1);
575 if (i >= cl.max_lightstyle)
577 VM_Warning(prog, "VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
580 strlcpy (cl.lightstyle[i].map, c, sizeof (cl.lightstyle[i].map));
581 cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
582 cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
585 // #40 float(entity e) checkbottom
586 static void VM_CL_checkbottom (prvm_prog_t *prog)
588 static int cs_yes, cs_no;
590 vec3_t mins, maxs, start, stop;
593 float mid, bottom, stepheight;
595 VM_SAFEPARMCOUNT(1, VM_CL_checkbottom);
596 ent = PRVM_G_EDICT(OFS_PARM0);
597 PRVM_G_FLOAT(OFS_RETURN) = 0;
599 stepheight = sv_stepheight.value + PRVM_clientedictfloat(ent, stepheight_delta);
600 VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, mins), mins);
601 VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, maxs), maxs);
603 // if all of the points under the corners are solid world, don't bother
604 // with the tougher checks
605 // the corners must be within 16 of the midpoint
606 start[2] = mins[2] - 1;
607 for (x=0 ; x<=1 ; x++)
608 for (y=0 ; y<=1 ; y++)
610 start[0] = x ? maxs[0] : mins[0];
611 start[1] = y ? maxs[1] : mins[1];
612 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
617 PRVM_G_FLOAT(OFS_RETURN) = true;
618 return; // we got out easy
623 // check it for real...
627 // the midpoint must be within 16 of the bottom
628 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
629 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
630 stop[2] = start[2] - 2*stepheight;
631 trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, true, NULL, true, false);
633 if (trace.fraction == 1.0)
636 mid = bottom = trace.endpos[2];
638 // the corners must be within 16 of the midpoint
639 for (x=0 ; x<=1 ; x++)
640 for (y=0 ; y<=1 ; y++)
642 start[0] = stop[0] = x ? maxs[0] : mins[0];
643 start[1] = stop[1] = y ? maxs[1] : mins[1];
645 trace = CL_TraceLine(start, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, true, NULL, true, false);
647 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
648 bottom = trace.endpos[2];
649 if (trace.fraction == 1.0 || mid - trace.endpos[2] > stepheight)
654 PRVM_G_FLOAT(OFS_RETURN) = true;
657 // #41 float(vector v) pointcontents
658 static void VM_CL_pointcontents (prvm_prog_t *prog)
661 VM_SAFEPARMCOUNT(1, VM_CL_pointcontents);
662 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), point);
663 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(CL_PointSuperContents(point));
666 // #48 void(vector o, vector d, float color, float count) particle
667 static void VM_CL_particle (prvm_prog_t *prog)
672 VM_SAFEPARMCOUNT(4, VM_CL_particle);
674 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
675 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir);
676 color = (int)PRVM_G_FLOAT(OFS_PARM2);
677 count = (int)PRVM_G_FLOAT(OFS_PARM3);
678 CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color);
681 // #74 void(vector pos, string samp, float vol, float atten) ambientsound
682 static void VM_CL_ambientsound (prvm_prog_t *prog)
686 VM_SAFEPARMCOUNT(4, VM_CL_ambientsound);
687 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), f);
688 s = S_FindName(PRVM_G_STRING(OFS_PARM1));
689 S_StaticSound (s, f, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3)*64);
692 // #92 vector(vector org[, float lpflag]) getlight (DP_QC_GETLIGHT)
693 static void VM_CL_getlight (prvm_prog_t *prog)
695 vec3_t ambientcolor, diffusecolor, diffusenormal;
697 int flags = prog->argc >= 2 ? PRVM_G_FLOAT(OFS_PARM1) : LP_LIGHTMAP;
699 VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getlight);
701 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), p);
702 R_CompleteLightPoint(ambientcolor, diffusecolor, diffusenormal, p, flags, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
703 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
704 if (PRVM_clientglobalvector(getlight_ambient))
705 VectorCopy(ambientcolor, PRVM_clientglobalvector(getlight_ambient));
706 if (PRVM_clientglobalvector(getlight_diffuse))
707 VectorCopy(diffusecolor, PRVM_clientglobalvector(getlight_diffuse));
708 if (PRVM_clientglobalvector(getlight_dir))
709 VectorCopy(diffusenormal, PRVM_clientglobalvector(getlight_dir));
712 //============================================================================
713 //[515]: SCENE MANAGER builtins
715 extern cvar_t v_yshearing;
716 void CSQC_R_RecalcView (void)
718 extern matrix4x4_t viewmodelmatrix_nobob;
719 extern matrix4x4_t viewmodelmatrix_withbob;
720 Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, cl.csqc_vieworigin[0], cl.csqc_vieworigin[1], cl.csqc_vieworigin[2], cl.csqc_viewangles[0], cl.csqc_viewangles[1], cl.csqc_viewangles[2], 1);
721 if (v_yshearing.value > 0)
722 Matrix4x4_QuakeToDuke3D(&r_refdef.view.matrix, &r_refdef.view.matrix, v_yshearing.value);
723 Matrix4x4_Copy(&viewmodelmatrix_nobob, &r_refdef.view.matrix);
724 Matrix4x4_ConcatScale(&viewmodelmatrix_nobob, cl_viewmodel_scale.value);
725 Matrix4x4_Concat(&viewmodelmatrix_withbob, &r_refdef.view.matrix, &cl.csqc_viewmodelmatrixfromengine);
728 //#300 void() clearscene (EXT_CSQC)
729 static void VM_CL_R_ClearScene (prvm_prog_t *prog)
731 VM_SAFEPARMCOUNT(0, VM_CL_R_ClearScene);
732 // clear renderable entity and light lists
733 r_refdef.scene.numentities = 0;
734 r_refdef.scene.numlights = 0;
735 // restore the view settings to the values that VM_CL_UpdateView received from the client code
736 r_refdef.view = csqc_original_r_refdef_view;
737 // polygonbegin without draw2d arg has to guess
738 prog->polygonbegin_guess2d = false;
739 VectorCopy(cl.csqc_vieworiginfromengine, cl.csqc_vieworigin);
740 VectorCopy(cl.csqc_viewanglesfromengine, cl.csqc_viewangles);
741 cl.csqc_vidvars.drawworld = r_drawworld.integer != 0;
742 cl.csqc_vidvars.drawenginesbar = false;
743 cl.csqc_vidvars.drawcrosshair = false;
745 // clear the CL_Mesh_Scene() used for CSQC polygons and engine effects, they will be added by CSQC_RelinkAllEntities and manually created by CSQC
746 CL_MeshEntities_Scene_Clear();
749 //#301 void(float mask) addentities (EXT_CSQC)
750 static void VM_CL_R_AddEntities (prvm_prog_t *prog)
752 double t = Sys_DirtyTime();
755 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
756 drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
757 CSQC_RelinkAllEntities(drawmask);
759 PRVM_clientglobalfloat(time) = cl.time;
760 for(i=1;i<prog->num_edicts;i++)
762 // so we can easily check if CSQC entity #edictnum is currently drawn
763 cl.csqcrenderentities[i].entitynumber = 0;
764 ed = &prog->edicts[i];
765 if(ed->priv.required->free)
768 if(ed->priv.required->free)
770 // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict
772 if(ed->priv.required->free)
774 if(!((int)PRVM_clientedictfloat(ed, drawmask) & drawmask))
776 CSQC_AddRenderEdict(ed, i);
779 // callprofile fixing hack: do not include this time in what is counted for CSQC_UpdateView
780 t = Sys_DirtyTime() - t;if (t < 0 || t >= 1800) t = 0;
781 prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= t;
784 //#302 void(entity ent) addentity (EXT_CSQC)
785 static void VM_CL_R_AddEntity (prvm_prog_t *prog)
787 double t = Sys_DirtyTime();
788 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
789 CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0), 0);
790 t = Sys_DirtyTime() - t;if (t < 0 || t >= 1800) t = 0;
791 prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= t;
794 //#303 float(float property, ...) setproperty (EXT_CSQC)
795 //#303 float(float property) getproperty
796 //#303 vector(float property) getpropertyvec
797 //#309 float(float property) getproperty
798 //#309 vector(float property) getpropertyvec
799 // VorteX: make this function be able to return previously set property if new value is not given
800 static void VM_CL_R_SetView (prvm_prog_t *prog)
806 VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_R_SetView);
808 c = (int)PRVM_G_FLOAT(OFS_PARM0);
816 VectorSet(PRVM_G_VECTOR(OFS_RETURN), r_refdef.view.x, r_refdef.view.y, 0);
819 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.x;
822 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.y;
825 VectorSet(PRVM_G_VECTOR(OFS_RETURN), r_refdef.view.width, r_refdef.view.height, 0);
828 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.width;
831 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.height;
834 VM_Warning(prog, "VM_CL_R_GetView : VF_VIEWPORT can't be retrieved, use VF_MIN/VF_SIZE instead\n");
837 VectorSet(PRVM_G_VECTOR(OFS_RETURN), r_refdef.view.ortho_x, r_refdef.view.ortho_y, 0);
840 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.ortho_x;
843 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.ortho_y;
846 VectorCopy(cl.csqc_vieworigin, PRVM_G_VECTOR(OFS_RETURN));
849 PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[0];
852 PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[1];
855 PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vieworigin[2];
858 VectorCopy(cl.csqc_viewangles, PRVM_G_VECTOR(OFS_RETURN));
861 PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[0];
864 PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[1];
867 PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_viewangles[2];
870 PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vidvars.drawworld;
872 case VF_DRAWENGINESBAR:
873 PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vidvars.drawenginesbar;
875 case VF_DRAWCROSSHAIR:
876 PRVM_G_FLOAT(OFS_RETURN) = cl.csqc_vidvars.drawcrosshair;
878 case VF_CL_VIEWANGLES:
879 VectorCopy(cl.viewangles, PRVM_G_VECTOR(OFS_RETURN));;
881 case VF_CL_VIEWANGLES_X:
882 PRVM_G_FLOAT(OFS_RETURN) = cl.viewangles[0];
884 case VF_CL_VIEWANGLES_Y:
885 PRVM_G_FLOAT(OFS_RETURN) = cl.viewangles[1];
887 case VF_CL_VIEWANGLES_Z:
888 PRVM_G_FLOAT(OFS_RETURN) = cl.viewangles[2];
891 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.useperspective;
894 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.isoverlay;
897 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.ismain;
900 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_density;
903 PRVM_G_VECTOR(OFS_RETURN)[0] = r_refdef.fog_red;
904 PRVM_G_VECTOR(OFS_RETURN)[1] = r_refdef.fog_green;
905 PRVM_G_VECTOR(OFS_RETURN)[2] = r_refdef.fog_blue;
908 PRVM_G_VECTOR(OFS_RETURN)[0] = r_refdef.fog_red;
911 PRVM_G_VECTOR(OFS_RETURN)[1] = r_refdef.fog_green;
914 PRVM_G_VECTOR(OFS_RETURN)[2] = r_refdef.fog_blue;
917 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_alpha;
920 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_start;
923 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_end;
926 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_height;
928 case VF_FOG_FADEDEPTH:
929 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.fog_fadedepth;
931 case VF_MINFPS_QUALITY:
932 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.quality;
935 PRVM_G_FLOAT(OFS_RETURN) = 0;
936 VM_Warning(prog, "VM_CL_R_GetView : unknown parm %i\n", c);
942 f = PRVM_G_VECTOR(OFS_PARM1);
943 k = PRVM_G_FLOAT(OFS_PARM1);
947 r_refdef.view.x = (int)(f[0]);
948 r_refdef.view.y = (int)(f[1]);
952 r_refdef.view.x = (int)(k);
956 r_refdef.view.y = (int)(k);
960 r_refdef.view.width = (int)(f[0]);
961 r_refdef.view.height = (int)(f[1]);
965 r_refdef.view.width = (int)(k);
969 r_refdef.view.height = (int)(k);
973 r_refdef.view.x = (int)(f[0]);
974 r_refdef.view.y = (int)(f[1]);
975 f = PRVM_G_VECTOR(OFS_PARM2);
976 r_refdef.view.width = (int)(f[0]);
977 r_refdef.view.height = (int)(f[1]);
981 r_refdef.view.frustum_x = tan(f[0] * M_PI / 360.0);r_refdef.view.ortho_x = f[0];
982 r_refdef.view.frustum_y = tan(f[1] * M_PI / 360.0);r_refdef.view.ortho_y = f[1];
985 r_refdef.view.frustum_x = tan(k * M_PI / 360.0);r_refdef.view.ortho_x = k;
988 r_refdef.view.frustum_y = tan(k * M_PI / 360.0);r_refdef.view.ortho_y = k;
991 VectorCopy(f, cl.csqc_vieworigin);
995 cl.csqc_vieworigin[0] = k;
999 cl.csqc_vieworigin[1] = k;
1000 CSQC_R_RecalcView();
1003 cl.csqc_vieworigin[2] = k;
1004 CSQC_R_RecalcView();
1007 VectorCopy(f, cl.csqc_viewangles);
1008 CSQC_R_RecalcView();
1011 cl.csqc_viewangles[0] = k;
1012 CSQC_R_RecalcView();
1015 cl.csqc_viewangles[1] = k;
1016 CSQC_R_RecalcView();
1019 cl.csqc_viewangles[2] = k;
1020 CSQC_R_RecalcView();
1023 cl.csqc_vidvars.drawworld = ((k != 0) && r_drawworld.integer);
1025 case VF_DRAWENGINESBAR:
1026 cl.csqc_vidvars.drawenginesbar = k != 0;
1028 case VF_DRAWCROSSHAIR:
1029 cl.csqc_vidvars.drawcrosshair = k != 0;
1031 case VF_CL_VIEWANGLES:
1032 VectorCopy(f, cl.viewangles);
1034 case VF_CL_VIEWANGLES_X:
1035 cl.viewangles[0] = k;
1037 case VF_CL_VIEWANGLES_Y:
1038 cl.viewangles[1] = k;
1040 case VF_CL_VIEWANGLES_Z:
1041 cl.viewangles[2] = k;
1043 case VF_PERSPECTIVE:
1044 r_refdef.view.useperspective = k != 0;
1046 case VF_CLEARSCREEN:
1047 r_refdef.view.isoverlay = !k;
1050 PRVM_G_FLOAT(OFS_RETURN) = r_refdef.view.ismain;
1052 case VF_FOG_DENSITY:
1053 r_refdef.fog_density = k;
1056 r_refdef.fog_red = f[0];
1057 r_refdef.fog_green = f[1];
1058 r_refdef.fog_blue = f[2];
1060 case VF_FOG_COLOR_R:
1061 r_refdef.fog_red = k;
1063 case VF_FOG_COLOR_G:
1064 r_refdef.fog_green = k;
1066 case VF_FOG_COLOR_B:
1067 r_refdef.fog_blue = k;
1070 r_refdef.fog_alpha = k;
1073 r_refdef.fog_start = k;
1076 r_refdef.fog_end = k;
1079 r_refdef.fog_height = k;
1081 case VF_FOG_FADEDEPTH:
1082 r_refdef.fog_fadedepth = k;
1084 case VF_MINFPS_QUALITY:
1085 r_refdef.view.quality = k;
1088 PRVM_G_FLOAT(OFS_RETURN) = 0;
1089 VM_Warning(prog, "VM_CL_R_SetView : unknown parm %i\n", c);
1092 PRVM_G_FLOAT(OFS_RETURN) = 1;
1095 //#305 void(vector org, float radius, vector lightcolours[, float style, string cubemapname, float pflags]) adddynamiclight (EXT_CSQC)
1096 static void VM_CL_R_AddDynamicLight (prvm_prog_t *prog)
1098 double t = Sys_DirtyTime();
1103 const char *cubemapname = NULL;
1104 int pflags = PFLAGS_CORONA | PFLAGS_FULLDYNAMIC;
1105 float coronaintensity = 1;
1106 float coronasizescale = 0.25;
1107 qbool castshadow = true;
1108 float ambientscale = 0;
1109 float diffusescale = 1;
1110 float specularscale = 1;
1112 vec3_t forward, left, up;
1113 VM_SAFEPARMCOUNTRANGE(3, 8, VM_CL_R_AddDynamicLight);
1115 // if we've run out of dlights, just return
1116 if (r_refdef.scene.numlights >= MAX_DLIGHTS)
1119 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
1120 radius = PRVM_G_FLOAT(OFS_PARM1);
1121 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), col);
1122 if (prog->argc >= 4)
1124 style = (int)PRVM_G_FLOAT(OFS_PARM3);
1125 if (style >= MAX_LIGHTSTYLES)
1127 Con_DPrintf("VM_CL_R_AddDynamicLight: out of bounds lightstyle index %i\n", style);
1131 if (prog->argc >= 5)
1132 cubemapname = PRVM_G_STRING(OFS_PARM4);
1133 if (prog->argc >= 6)
1134 pflags = (int)PRVM_G_FLOAT(OFS_PARM5);
1135 coronaintensity = (pflags & PFLAGS_CORONA) != 0;
1136 castshadow = (pflags & PFLAGS_NOSHADOW) == 0;
1138 VectorScale(PRVM_clientglobalvector(v_forward), radius, forward);
1139 VectorScale(PRVM_clientglobalvector(v_right), -radius, left);
1140 VectorScale(PRVM_clientglobalvector(v_up), radius, up);
1141 Matrix4x4_FromVectors(&matrix, forward, left, up, org);
1143 R_RTLight_Update(&r_refdef.scene.templights[r_refdef.scene.numlights], false, &matrix, col, style, cubemapname, castshadow, coronaintensity, coronasizescale, ambientscale, diffusescale, specularscale, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1144 r_refdef.scene.lights[r_refdef.scene.numlights] = &r_refdef.scene.templights[r_refdef.scene.numlights];r_refdef.scene.numlights++;
1145 t = Sys_DirtyTime() - t;if (t < 0 || t >= 1800) t = 0;
1146 prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= t;
1149 //============================================================================
1151 //#310 vector (vector v) cs_unproject (EXT_CSQC)
1152 static void VM_CL_unproject (prvm_prog_t *prog)
1158 VM_SAFEPARMCOUNT(1, VM_CL_unproject);
1159 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), f);
1162 (-1.0 + 2.0 * (f[0] / vid_conwidth.integer)) * f[2] * -r_refdef.view.frustum_x,
1163 (-1.0 + 2.0 * (f[1] / vid_conheight.integer)) * f[2] * -r_refdef.view.frustum_y);
1164 if(v_flipped.integer)
1166 Matrix4x4_Transform(&r_refdef.view.matrix, temp, result);
1167 VectorCopy(result, PRVM_G_VECTOR(OFS_RETURN));
1170 //#311 vector (vector v) cs_project (EXT_CSQC)
1171 static void VM_CL_project (prvm_prog_t *prog)
1177 VM_SAFEPARMCOUNT(1, VM_CL_project);
1178 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), f);
1179 Matrix4x4_Invert_Full(&m, &r_refdef.view.matrix);
1180 Matrix4x4_Transform(&m, f, v);
1181 if(v_flipped.integer)
1183 VectorSet(PRVM_G_VECTOR(OFS_RETURN),
1184 vid_conwidth.integer * (0.5*(1.0+v[1]/v[0]/-r_refdef.view.frustum_x)),
1185 vid_conheight.integer * (0.5*(1.0+v[2]/v[0]/-r_refdef.view.frustum_y)),
1188 // after transforming, relative position to viewport (0..1) = 0.5 * (1 + v[2]/v[0]/-frustum_{x \or y})
1189 // as 2D drawing honors the viewport too, to get the same pixel, we simply multiply this by conwidth/height
1192 //=============================================================================
1193 // Draw builtins (client & menu)
1196 ========================
1199 void drawline(float width, vector pos1, vector pos2, vector rgb, float alpha, float flags)
1200 ========================
1202 void VM_drawline (prvm_prog_t *prog)
1204 prvm_vec_t *c1, *c2, *rgb;
1206 unsigned char flags;
1208 VM_SAFEPARMCOUNT(6, VM_drawline);
1210 // polygonbegin without draw2d arg has to guess
1211 prog->polygonbegin_guess2d = true;
1213 width = PRVM_G_FLOAT(OFS_PARM0);
1214 c1 = PRVM_G_VECTOR(OFS_PARM1);
1215 c2 = PRVM_G_VECTOR(OFS_PARM2);
1216 rgb = PRVM_G_VECTOR(OFS_PARM3);
1217 alpha = PRVM_G_FLOAT(OFS_PARM4);
1218 flags = (int)PRVM_G_FLOAT(OFS_PARM5);
1219 DrawQ_Line(width, c1[0], c1[1], c2[0], c2[1], rgb[0], rgb[1], rgb[2], alpha, flags);
1226 float iscachedpic(string pic)
1229 void VM_iscachedpic(prvm_prog_t *prog)
1231 VM_SAFEPARMCOUNT(1,VM_iscachedpic);
1233 // drawq hasnt such a function, thus always return true
1234 PRVM_G_FLOAT(OFS_RETURN) = false;
1241 string precache_pic(string pic)
1244 #define PRECACHE_PIC_FROMWAD 1 /* FTEQW, not supported here */
1245 #define PRECACHE_PIC_NOTPERSISTENT 2
1246 //#define PRECACHE_PIC_NOCLAMP 4
1247 #define PRECACHE_PIC_MIPMAP 8
1248 void VM_precache_pic(prvm_prog_t *prog)
1251 int flags = CACHEPICFLAG_FAILONMISSING;
1253 VM_SAFEPARMCOUNTRANGE(1, 2, VM_precache_pic);
1255 s = PRVM_G_STRING(OFS_PARM0);
1256 PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
1257 VM_CheckEmptyString(prog, s);
1261 int f = PRVM_G_FLOAT(OFS_PARM1);
1262 if(f & PRECACHE_PIC_NOTPERSISTENT)
1263 flags |= CACHEPICFLAG_NOTPERSISTENT;
1264 //if(f & PRECACHE_PIC_NOCLAMP)
1265 // flags |= CACHEPICFLAG_NOCLAMP;
1266 if(f & PRECACHE_PIC_MIPMAP)
1267 flags |= CACHEPICFLAG_MIPMAP;
1270 if( !Draw_IsPicLoaded(Draw_CachePic_Flags(s, flags | CACHEPICFLAG_QUIET)) )
1271 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1281 void VM_freepic(prvm_prog_t *prog)
1285 VM_SAFEPARMCOUNT(1,VM_freepic);
1287 s = PRVM_G_STRING(OFS_PARM0);
1288 VM_CheckEmptyString(prog, s);
1293 static void getdrawfontscale(prvm_prog_t *prog, float *sx, float *sy)
1297 VectorCopy(PRVM_drawglobalvector(drawfontscale), v);
1298 if(VectorLength2(v) > 0)
1305 static dp_font_t *getdrawfont(prvm_prog_t *prog)
1307 int f = (int) PRVM_drawglobalfloat(drawfont);
1308 if(f < 0 || f >= dp_fonts.maxsize)
1309 return FONT_DEFAULT;
1310 return &dp_fonts.f[f];
1317 float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag)
1320 void VM_drawcharacter(prvm_prog_t *prog)
1322 prvm_vec_t *pos,*scale,*rgb;
1326 VM_SAFEPARMCOUNT(6,VM_drawcharacter);
1328 // polygonbegin without draw2d arg has to guess
1329 prog->polygonbegin_guess2d = true;
1331 character = (char) PRVM_G_FLOAT(OFS_PARM1);
1334 PRVM_G_FLOAT(OFS_RETURN) = -1;
1335 VM_Warning(prog, "VM_drawcharacter: %s passed null character !\n",prog->name);
1339 pos = PRVM_G_VECTOR(OFS_PARM0);
1340 scale = PRVM_G_VECTOR(OFS_PARM2);
1341 rgb = PRVM_G_VECTOR(OFS_PARM3);
1342 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
1344 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
1346 PRVM_G_FLOAT(OFS_RETURN) = -2;
1347 VM_Warning(prog, "VM_drawcharacter: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
1351 if(pos[2] || scale[2])
1352 VM_Warning(prog, "VM_drawcharacter: z value%c from %s discarded\n",(pos[2] && scale[2]) ? 's' : 0,((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale")));
1354 if(!scale[0] || !scale[1])
1356 PRVM_G_FLOAT(OFS_RETURN) = -3;
1357 VM_Warning(prog, "VM_drawcharacter: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
1361 getdrawfontscale(prog, &sx, &sy);
1362 DrawQ_String_Scale(pos[0], pos[1], &character, 1, scale[0], scale[1], sx, sy, rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag, NULL, true, getdrawfont(prog));
1363 PRVM_G_FLOAT(OFS_RETURN) = 1;
1370 float drawstring(vector position, string text, vector scale, vector rgb, float alpha[, float flag])
1373 void VM_drawstring(prvm_prog_t *prog)
1375 prvm_vec_t *pos,*scale,*rgb;
1379 VM_SAFEPARMCOUNTRANGE(5,6,VM_drawstring);
1381 // polygonbegin without draw2d arg has to guess
1382 prog->polygonbegin_guess2d = true;
1384 string = PRVM_G_STRING(OFS_PARM1);
1385 pos = PRVM_G_VECTOR(OFS_PARM0);
1386 scale = PRVM_G_VECTOR(OFS_PARM2);
1387 rgb = PRVM_G_VECTOR(OFS_PARM3);
1388 if (prog->argc >= 6)
1389 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
1391 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
1393 PRVM_G_FLOAT(OFS_RETURN) = -2;
1394 VM_Warning(prog, "VM_drawstring: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
1398 if(!scale[0] || !scale[1])
1400 PRVM_G_FLOAT(OFS_RETURN) = -3;
1401 VM_Warning(prog, "VM_drawstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
1405 if(pos[2] || scale[2])
1406 VM_Warning(prog, "VM_drawstring: z value%s from %s discarded\n",(pos[2] && scale[2]) ? "s" : " ",((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale")));
1408 getdrawfontscale(prog, &sx, &sy);
1409 DrawQ_String_Scale(pos[0], pos[1], string, 0, scale[0], scale[1], sx, sy, rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag, NULL, true, getdrawfont(prog));
1410 //Font_DrawString(pos[0], pos[1], string, 0, scale[0], scale[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag, NULL, true);
1411 PRVM_G_FLOAT(OFS_RETURN) = 1;
1416 VM_drawcolorcodedstring
1418 float drawcolorcodedstring(vector position, string text, vector scale, float alpha, float flag)
1420 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag)
1423 void VM_drawcolorcodedstring(prvm_prog_t *prog)
1425 prvm_vec_t *pos, *scale;
1429 float sx, sy, alpha;
1431 VM_SAFEPARMCOUNTRANGE(5,6,VM_drawcolorcodedstring);
1433 // polygonbegin without draw2d arg has to guess
1434 prog->polygonbegin_guess2d = true;
1436 if (prog->argc == 6) // full 6 parms, like normal drawstring
1438 pos = PRVM_G_VECTOR(OFS_PARM0);
1439 string = PRVM_G_STRING(OFS_PARM1);
1440 scale = PRVM_G_VECTOR(OFS_PARM2);
1441 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), rgb);
1442 alpha = PRVM_G_FLOAT(OFS_PARM4);
1443 flag = (int)PRVM_G_FLOAT(OFS_PARM5);
1447 pos = PRVM_G_VECTOR(OFS_PARM0);
1448 string = PRVM_G_STRING(OFS_PARM1);
1449 scale = PRVM_G_VECTOR(OFS_PARM2);
1453 alpha = PRVM_G_FLOAT(OFS_PARM3);
1454 flag = (int)PRVM_G_FLOAT(OFS_PARM4);
1457 if(flag < DRAWFLAG_NORMAL || flag >= DRAWFLAG_NUMFLAGS)
1459 PRVM_G_FLOAT(OFS_RETURN) = -2;
1460 VM_Warning(prog, "VM_drawcolorcodedstring: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
1464 if(!scale[0] || !scale[1])
1466 PRVM_G_FLOAT(OFS_RETURN) = -3;
1467 VM_Warning(prog, "VM_drawcolorcodedstring: scale %s is null !\n", (scale[0] == 0) ? ((scale[1] == 0) ? "x and y" : "x") : "y");
1471 if(pos[2] || scale[2])
1472 VM_Warning(prog, "VM_drawcolorcodedstring: z value%s from %s discarded\n",(pos[2] && scale[2]) ? "s" : " ",((pos[2] && scale[2]) ? "pos and scale" : (pos[2] ? "pos" : "scale")));
1474 getdrawfontscale(prog, &sx, &sy);
1475 DrawQ_String_Scale(pos[0], pos[1], string, 0, scale[0], scale[1], sx, sy, rgb[0], rgb[1], rgb[2], alpha, flag, NULL, false, getdrawfont(prog));
1476 if (prog->argc == 6) // also return vector of last color
1477 VectorCopy(DrawQ_Color, PRVM_G_VECTOR(OFS_RETURN));
1479 PRVM_G_FLOAT(OFS_RETURN) = 1;
1485 float stringwidth(string text, float allowColorCodes, float size)
1488 void VM_stringwidth(prvm_prog_t *prog)
1492 float mult; // sz is intended font size so we can later add freetype support, mult is font size multiplier in pixels per character cell
1496 VM_SAFEPARMCOUNTRANGE(2, 3, VM_stringwidth);
1498 getdrawfontscale(prog, &sx, &sy);
1501 Vector2Copy(PRVM_G_VECTOR(OFS_PARM2), szv);
1506 // we want the width for 8x8 font size, divided by 8
1507 Vector2Set(szv, 8, 8);
1509 // to make sure snapping is turned off, ALWAYS use a nontrivial scale in this case
1510 if(sx >= 0.9 && sx <= 1.1)
1518 string = PRVM_G_STRING(OFS_PARM0);
1519 colors = (int)PRVM_G_FLOAT(OFS_PARM1);
1521 PRVM_G_FLOAT(OFS_RETURN) = DrawQ_TextWidth_UntilWidth_TrackColors_Scale(string, &maxlen, szv[0], szv[1], sx, sy, NULL, !colors, getdrawfont(prog), 1000000000) * mult;
1525 mult = sz = PRVM_G_FLOAT(OFS_PARM2);
1533 string = PRVM_G_STRING(OFS_PARM0);
1534 colors = (int)PRVM_G_FLOAT(OFS_PARM1);
1536 PRVM_G_FLOAT(OFS_RETURN) = DrawQ_TextWidth(string, 0, !colors, getdrawfont()) * mult; // 1x1 characters, don't actually draw
1544 float findfont(string s)
1548 static float getdrawfontnum(const char *fontname)
1552 for(i = 0; i < dp_fonts.maxsize; ++i)
1553 if(!strcmp(dp_fonts.f[i].title, fontname))
1558 void VM_findfont(prvm_prog_t *prog)
1560 VM_SAFEPARMCOUNT(1,VM_findfont);
1561 PRVM_G_FLOAT(OFS_RETURN) = getdrawfontnum(PRVM_G_STRING(OFS_PARM0));
1568 float loadfont(string fontname, string fontmaps, string sizes, float slot)
1572 void VM_loadfont(prvm_prog_t *prog)
1574 const char *fontname, *filelist, *sizes, *c, *cm;
1575 char mainfont[MAX_QPATH];
1577 float sz, scale, voffset;
1580 VM_SAFEPARMCOUNTRANGE(3,6,VM_loadfont);
1582 fontname = PRVM_G_STRING(OFS_PARM0);
1584 fontname = "default";
1586 filelist = PRVM_G_STRING(OFS_PARM1);
1588 filelist = "gfx/conchars";
1590 sizes = PRVM_G_STRING(OFS_PARM2);
1596 if (prog->argc >= 4)
1598 i = PRVM_G_FLOAT(OFS_PARM3);
1599 if (i >= 0 && i < dp_fonts.maxsize)
1602 strlcpy(f->title, fontname, sizeof(f->title)); // replace name
1606 f = FindFont(fontname, true);
1609 PRVM_G_FLOAT(OFS_RETURN) = -1;
1610 return; // something go wrong
1613 memset(f->fallbacks, 0, sizeof(f->fallbacks));
1614 memset(f->fallback_faces, 0, sizeof(f->fallback_faces));
1616 // first font is handled "normally"
1617 c = strchr(filelist, ':');
1618 cm = strchr(filelist, ',');
1619 if(c && (!cm || c < cm))
1620 f->req_face = atoi(c+1);
1626 if(!c || (c - filelist) > MAX_QPATH)
1627 strlcpy(mainfont, filelist, sizeof(mainfont));
1630 memcpy(mainfont, filelist, c - filelist);
1631 mainfont[c - filelist] = 0;
1635 for(i = 0; i < MAX_FONT_FALLBACKS; ++i)
1637 c = strchr(filelist, ',');
1643 c = strchr(filelist, ':');
1644 cm = strchr(filelist, ',');
1645 if(c && (!cm || c < cm))
1646 f->fallback_faces[i] = atoi(c+1);
1649 f->fallback_faces[i] = 0; // f->req_face; could make it stick to the default-font's face index
1652 if(!c || (c-filelist) > MAX_QPATH)
1654 strlcpy(f->fallbacks[i], filelist, sizeof(mainfont));
1658 memcpy(f->fallbacks[i], filelist, c - filelist);
1659 f->fallbacks[i][c - filelist] = 0;
1664 for(i = 0; i < MAX_FONT_SIZES; ++i)
1665 f->req_sizes[i] = -1;
1666 for (numsizes = 0,c = sizes;;)
1668 if (!COM_ParseToken_VM_Tokenize(&c, 0))
1670 sz = atof(com_token);
1672 if (sz < 0.001f || sz > 1000.0f)
1674 VM_Warning(prog, "VM_loadfont: crap size %s", com_token);
1678 if (numsizes == MAX_FONT_SIZES)
1680 VM_Warning(prog, "VM_loadfont: MAX_FONT_SIZES = %i exceeded", MAX_FONT_SIZES);
1683 f->req_sizes[numsizes] = sz;
1687 // additional scale/hoffset parms
1690 if (prog->argc >= 5)
1692 scale = PRVM_G_FLOAT(OFS_PARM4);
1696 if (prog->argc >= 6)
1697 voffset = PRVM_G_FLOAT(OFS_PARM5);
1700 LoadFont(true, mainfont, f, scale, voffset);
1702 // return index of loaded font
1703 PRVM_G_FLOAT(OFS_RETURN) = (f - dp_fonts.f);
1710 float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag)
1713 void VM_drawpic(prvm_prog_t *prog)
1715 const char *picname;
1716 prvm_vec_t *size, *pos, *rgb;
1719 VM_SAFEPARMCOUNTRANGE(5,6,VM_drawpic);
1721 // polygonbegin without draw2d arg has to guess
1722 prog->polygonbegin_guess2d = true;
1724 picname = PRVM_G_STRING(OFS_PARM1);
1725 VM_CheckEmptyString(prog, picname);
1727 // is pic cached ? no function yet for that
1730 PRVM_G_FLOAT(OFS_RETURN) = -4;
1731 VM_Warning(prog, "VM_drawpic: %s: %s not cached !\n", prog->name, picname);
1735 pos = PRVM_G_VECTOR(OFS_PARM0);
1736 size = PRVM_G_VECTOR(OFS_PARM2);
1737 rgb = PRVM_G_VECTOR(OFS_PARM3);
1738 if (prog->argc >= 6)
1739 flag = (int) PRVM_G_FLOAT(OFS_PARM5);
1741 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
1743 PRVM_G_FLOAT(OFS_RETURN) = -2;
1744 VM_Warning(prog, "VM_drawpic: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
1748 if(pos[2] || size[2])
1749 VM_Warning(prog, "VM_drawpic: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size")));
1751 DrawQ_Pic(pos[0], pos[1], Draw_CachePic_Flags (picname, CACHEPICFLAG_NOTPERSISTENT), size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM4), flag);
1752 PRVM_G_FLOAT(OFS_RETURN) = 1;
1758 float drawrotpic(vector position, string pic, vector size, vector org, float angle, vector rgb, float alpha, float flag)
1761 void VM_drawrotpic(prvm_prog_t *prog)
1763 const char *picname;
1764 prvm_vec_t *size, *pos, *org, *rgb;
1767 VM_SAFEPARMCOUNT(8,VM_drawrotpic);
1769 // polygonbegin without draw2d arg has to guess
1770 prog->polygonbegin_guess2d = true;
1772 picname = PRVM_G_STRING(OFS_PARM1);
1773 VM_CheckEmptyString(prog, picname);
1775 // is pic cached ? no function yet for that
1778 PRVM_G_FLOAT(OFS_RETURN) = -4;
1779 VM_Warning(prog, "VM_drawrotpic: %s: %s not cached !\n", prog->name, picname);
1783 pos = PRVM_G_VECTOR(OFS_PARM0);
1784 size = PRVM_G_VECTOR(OFS_PARM2);
1785 org = PRVM_G_VECTOR(OFS_PARM3);
1786 rgb = PRVM_G_VECTOR(OFS_PARM5);
1787 flag = (int) PRVM_G_FLOAT(OFS_PARM7);
1789 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
1791 PRVM_G_FLOAT(OFS_RETURN) = -2;
1792 VM_Warning(prog, "VM_drawrotpic: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
1796 if(pos[2] || size[2] || org[2])
1797 VM_Warning(prog, "VM_drawrotpic: z value from pos/size/org discarded\n");
1799 DrawQ_RotPic(pos[0], pos[1], Draw_CachePic_Flags(picname, CACHEPICFLAG_NOTPERSISTENT), size[0], size[1], org[0], org[1], PRVM_G_FLOAT(OFS_PARM4), rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM6), flag);
1800 PRVM_G_FLOAT(OFS_RETURN) = 1;
1806 float drawsubpic(vector position, vector size, string pic, vector srcPos, vector srcSize, vector rgb, float alpha, float flag)
1810 void VM_drawsubpic(prvm_prog_t *prog)
1812 const char *picname;
1813 prvm_vec_t *size, *pos, *rgb, *srcPos, *srcSize, alpha;
1816 VM_SAFEPARMCOUNT(8,VM_drawsubpic);
1818 // polygonbegin without draw2d arg has to guess
1819 prog->polygonbegin_guess2d = true;
1821 picname = PRVM_G_STRING(OFS_PARM2);
1822 VM_CheckEmptyString(prog, picname);
1824 // is pic cached ? no function yet for that
1827 PRVM_G_FLOAT(OFS_RETURN) = -4;
1828 VM_Warning(prog, "VM_drawsubpic: %s: %s not cached !\n", prog->name, picname);
1832 pos = PRVM_G_VECTOR(OFS_PARM0);
1833 size = PRVM_G_VECTOR(OFS_PARM1);
1834 srcPos = PRVM_G_VECTOR(OFS_PARM3);
1835 srcSize = PRVM_G_VECTOR(OFS_PARM4);
1836 rgb = PRVM_G_VECTOR(OFS_PARM5);
1837 alpha = PRVM_G_FLOAT(OFS_PARM6);
1838 flag = (int) PRVM_G_FLOAT(OFS_PARM7);
1840 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
1842 PRVM_G_FLOAT(OFS_RETURN) = -2;
1843 VM_Warning(prog, "VM_drawsubpic: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
1847 if(pos[2] || size[2])
1848 VM_Warning(prog, "VM_drawsubpic: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size")));
1850 DrawQ_SuperPic(pos[0], pos[1], Draw_CachePic_Flags (picname, CACHEPICFLAG_NOTPERSISTENT),
1852 srcPos[0], srcPos[1], rgb[0], rgb[1], rgb[2], alpha,
1853 srcPos[0] + srcSize[0], srcPos[1], rgb[0], rgb[1], rgb[2], alpha,
1854 srcPos[0], srcPos[1] + srcSize[1], rgb[0], rgb[1], rgb[2], alpha,
1855 srcPos[0] + srcSize[0], srcPos[1] + srcSize[1], rgb[0], rgb[1], rgb[2], alpha,
1857 PRVM_G_FLOAT(OFS_RETURN) = 1;
1864 float drawfill(vector position, vector size, vector rgb, float alpha, float flag)
1867 void VM_drawfill(prvm_prog_t *prog)
1869 prvm_vec_t *size, *pos, *rgb;
1872 VM_SAFEPARMCOUNT(5,VM_drawfill);
1874 // polygonbegin without draw2d arg has to guess
1875 prog->polygonbegin_guess2d = true;
1877 pos = PRVM_G_VECTOR(OFS_PARM0);
1878 size = PRVM_G_VECTOR(OFS_PARM1);
1879 rgb = PRVM_G_VECTOR(OFS_PARM2);
1880 flag = (int) PRVM_G_FLOAT(OFS_PARM4);
1882 if(flag < DRAWFLAG_NORMAL || flag >=DRAWFLAG_NUMFLAGS)
1884 PRVM_G_FLOAT(OFS_RETURN) = -2;
1885 VM_Warning(prog, "VM_drawfill: %s: wrong DRAWFLAG %i !\n",prog->name,flag);
1889 if(pos[2] || size[2])
1890 VM_Warning(prog, "VM_drawfill: z value%s from %s discarded\n",(pos[2] && size[2]) ? "s" : " ",((pos[2] && size[2]) ? "pos and size" : (pos[2] ? "pos" : "size")));
1892 DrawQ_Fill(pos[0], pos[1], size[0], size[1], rgb[0], rgb[1], rgb[2], PRVM_G_FLOAT(OFS_PARM3), flag);
1893 PRVM_G_FLOAT(OFS_RETURN) = 1;
1900 drawsetcliparea(float x, float y, float width, float height)
1903 void VM_drawsetcliparea(prvm_prog_t *prog)
1906 VM_SAFEPARMCOUNT(4,VM_drawsetcliparea);
1908 // polygonbegin without draw2d arg has to guess
1909 prog->polygonbegin_guess2d = true;
1911 x = bound(0, PRVM_G_FLOAT(OFS_PARM0), vid_conwidth.integer);
1912 y = bound(0, PRVM_G_FLOAT(OFS_PARM1), vid_conheight.integer);
1913 w = bound(0, PRVM_G_FLOAT(OFS_PARM2) + PRVM_G_FLOAT(OFS_PARM0) - x, (vid_conwidth.integer - x));
1914 h = bound(0, PRVM_G_FLOAT(OFS_PARM3) + PRVM_G_FLOAT(OFS_PARM1) - y, (vid_conheight.integer - y));
1916 DrawQ_SetClipArea(x, y, w, h);
1921 VM_drawresetcliparea
1926 void VM_drawresetcliparea(prvm_prog_t *prog)
1928 VM_SAFEPARMCOUNT(0,VM_drawresetcliparea);
1930 // polygonbegin without draw2d arg has to guess
1931 prog->polygonbegin_guess2d = true;
1933 DrawQ_ResetClipArea();
1940 vector getimagesize(string pic)
1943 void VM_getimagesize(prvm_prog_t *prog)
1948 VM_SAFEPARMCOUNT(1,VM_getimagesize);
1950 p = PRVM_G_STRING(OFS_PARM0);
1951 VM_CheckEmptyString(prog, p);
1953 pic = Draw_CachePic_Flags (p, CACHEPICFLAG_QUIET | CACHEPICFLAG_NOTPERSISTENT);
1954 if (!Draw_IsPicLoaded(pic))
1956 PRVM_G_VECTOR(OFS_RETURN)[0] = 0;
1957 PRVM_G_VECTOR(OFS_RETURN)[1] = 0;
1961 PRVM_G_VECTOR(OFS_RETURN)[0] = Draw_GetPicWidth(pic);
1962 PRVM_G_VECTOR(OFS_RETURN)[1] = Draw_GetPicHeight(pic);
1964 PRVM_G_VECTOR(OFS_RETURN)[2] = 0;
1967 //#330 float(float stnum) getstatf (EXT_CSQC)
1968 static void VM_CL_getstatf (prvm_prog_t *prog)
1976 VM_SAFEPARMCOUNT(1, VM_CL_getstatf);
1977 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1978 if(i < 0 || i >= MAX_CL_STATS)
1980 VM_Warning(prog, "VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
1983 dat.l = cl.stats[i];
1984 PRVM_G_FLOAT(OFS_RETURN) = dat.f;
1987 //#331 float(float stnum) getstati (EXT_CSQC)
1988 static void VM_CL_getstati (prvm_prog_t *prog)
1991 int firstbit, bitcount;
1993 VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getstati);
1995 index = (int)PRVM_G_FLOAT(OFS_PARM0);
1998 firstbit = (int)PRVM_G_FLOAT(OFS_PARM1);
2000 bitcount = (int)PRVM_G_FLOAT(OFS_PARM2);
2010 if(index < 0 || index >= MAX_CL_STATS)
2012 VM_Warning(prog, "VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
2015 i = cl.stats[index];
2016 if (bitcount != 32) //32 causes the mask to overflow, so there's nothing to subtract from.
2017 i = (((unsigned int)i)&(((1<<bitcount)-1)<<firstbit))>>firstbit;
2018 PRVM_G_FLOAT(OFS_RETURN) = i;
2021 //#332 string(float firststnum) getstats (EXT_CSQC)
2022 static void VM_CL_getstats (prvm_prog_t *prog)
2026 VM_SAFEPARMCOUNT(1, VM_CL_getstats);
2027 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2028 if(i < 0 || i > MAX_CL_STATS-4)
2030 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2031 VM_Warning(prog, "VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
2034 strlcpy(t, (char*)&cl.stats[i], sizeof(t));
2035 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, t);
2038 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2039 static void VM_CL_setmodelindex (prvm_prog_t *prog)
2043 struct model_s *model;
2045 VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex);
2047 t = PRVM_G_EDICT(OFS_PARM0);
2049 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2051 PRVM_clientedictstring(t, model) = 0;
2052 PRVM_clientedictfloat(t, modelindex) = 0;
2057 model = CL_GetModelByIndex(i);
2060 VM_Warning(prog, "VM_CL_setmodelindex: null model\n");
2063 PRVM_clientedictstring(t, model) = PRVM_SetEngineString(prog, model->name);
2064 PRVM_clientedictfloat(t, modelindex) = i;
2066 // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black]
2069 SetMinMaxSize (prog, t, model->normalmins, model->normalmaxs);
2072 SetMinMaxSize (prog, t, vec3_origin, vec3_origin);
2075 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2076 static void VM_CL_modelnameforindex (prvm_prog_t *prog)
2080 VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
2082 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2083 model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
2084 PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(prog, model->name) : 0;
2087 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
2088 static void VM_CL_particleeffectnum (prvm_prog_t *prog)
2091 VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
2092 i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
2095 PRVM_G_FLOAT(OFS_RETURN) = i;
2098 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
2099 static void VM_CL_trailparticles (prvm_prog_t *prog)
2102 vec3_t start, end, velocity;
2104 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles);
2106 t = PRVM_G_EDICT(OFS_PARM0);
2107 i = (int)PRVM_G_FLOAT(OFS_PARM1);
2108 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), start);
2109 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), end);
2110 VectorCopy(PRVM_clientedictvector(t, velocity), velocity);
2114 CL_ParticleTrail(i, 1, start, end, velocity, velocity, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0, true, true, NULL, NULL, 1);
2117 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
2118 static void VM_CL_pointparticles (prvm_prog_t *prog)
2123 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
2124 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2125 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), f);
2126 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), v);
2127 n = PRVM_G_FLOAT(OFS_PARM3);
2130 CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
2133 //#502 void(float effectnum, entity own, vector origin_from, vector origin_to, vector dir_from, vector dir_to, float count, float extflags) boxparticles (DP_CSQC_BOXPARTICLES)
2134 static void VM_CL_boxparticles (prvm_prog_t *prog)
2137 // prvm_edict_t *own;
2138 vec3_t origin_from, origin_to, dir_from, dir_to;
2142 float tintmins[4], tintmaxs[4], fade;
2143 VM_SAFEPARMCOUNTRANGE(7, 8, VM_CL_boxparticles);
2145 effectnum = (int)PRVM_G_FLOAT(OFS_PARM0);
2148 // own = PRVM_G_EDICT(OFS_PARM1); // TODO find use for this
2149 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin_from);
2150 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin_to );
2151 VectorCopy(PRVM_G_VECTOR(OFS_PARM4), dir_from );
2152 VectorCopy(PRVM_G_VECTOR(OFS_PARM5), dir_to );
2153 count = PRVM_G_FLOAT(OFS_PARM6);
2155 flags = PRVM_G_FLOAT(OFS_PARM7);
2159 Vector4Set(tintmins, 1, 1, 1, 1);
2160 Vector4Set(tintmaxs, 1, 1, 1, 1);
2164 if(flags & 1) // read alpha
2166 tintmins[3] = PRVM_clientglobalfloat(particles_alphamin);
2167 tintmaxs[3] = PRVM_clientglobalfloat(particles_alphamax);
2169 if(flags & 2) // read color
2171 VectorCopy(PRVM_clientglobalvector(particles_colormin), tintmins);
2172 VectorCopy(PRVM_clientglobalvector(particles_colormax), tintmaxs);
2174 if(flags & 4) // read fade
2176 fade = PRVM_clientglobalfloat(particles_fade);
2178 if(flags & 128) // draw as trail
2184 CL_ParticleTrail(effectnum, count, origin_from, origin_to, dir_from, dir_to, NULL, 0, true, true, tintmins, tintmaxs, fade);
2186 CL_ParticleBox(effectnum, count, origin_from, origin_to, dir_from, dir_to, NULL, 0, true, true, tintmins, tintmaxs, fade);
2189 //#531 void(float pause) setpause
2190 static void VM_CL_setpause(prvm_prog_t *prog)
2192 VM_SAFEPARMCOUNT(1, VM_CL_setpause);
2195 if ((int)PRVM_G_FLOAT(OFS_PARM0) != 0)
2198 host.paused = false;
2202 //#343 void(float usecursor) setcursormode (DP_CSQC)
2203 static void VM_CL_setcursormode (prvm_prog_t *prog)
2205 VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
2206 cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0) != 0;
2207 cl_ignoremousemoves = 2;
2210 //#344 vector() getmousepos (DP_CSQC)
2211 static void VM_CL_getmousepos(prvm_prog_t *prog)
2213 VM_SAFEPARMCOUNT(0,VM_CL_getmousepos);
2215 if (key_consoleactive || key_dest != key_game)
2216 VectorSet(PRVM_G_VECTOR(OFS_RETURN), 0, 0, 0);
2217 else if (cl.csqc_wantsmousemove)
2218 VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_windowmouse_x * vid_conwidth.integer / vid.width, in_windowmouse_y * vid_conheight.integer / vid.height, 0);
2220 VectorSet(PRVM_G_VECTOR(OFS_RETURN), in_mouse_x * vid_conwidth.integer / vid.width, in_mouse_y * vid_conheight.integer / vid.height, 0);
2223 //#345 float(float framenum) getinputstate (EXT_CSQC)
2224 static void VM_CL_getinputstate (prvm_prog_t *prog)
2226 unsigned int i, frame;
2227 VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
2228 frame = (unsigned int)PRVM_G_FLOAT(OFS_PARM0);
2229 PRVM_G_FLOAT(OFS_RETURN) = false;
2230 for (i = 0;i < CL_MAX_USERCMDS;i++)
2232 if (cl.movecmd[i].sequence == frame)
2234 VectorCopy(cl.movecmd[i].viewangles, PRVM_clientglobalvector(input_angles));
2235 PRVM_clientglobalfloat(input_buttons) = cl.movecmd[i].buttons; // FIXME: this should not be directly exposed to csqc (translation layer needed?)
2236 PRVM_clientglobalvector(input_movevalues)[0] = cl.movecmd[i].forwardmove;
2237 PRVM_clientglobalvector(input_movevalues)[1] = cl.movecmd[i].sidemove;
2238 PRVM_clientglobalvector(input_movevalues)[2] = cl.movecmd[i].upmove;
2239 PRVM_clientglobalfloat(input_timelength) = cl.movecmd[i].frametime;
2240 // this probably shouldn't be here
2241 if(cl.movecmd[i].crouch)
2243 VectorCopy(cl.playercrouchmins, PRVM_clientglobalvector(pmove_mins));
2244 VectorCopy(cl.playercrouchmaxs, PRVM_clientglobalvector(pmove_maxs));
2248 VectorCopy(cl.playerstandmins, PRVM_clientglobalvector(pmove_mins));
2249 VectorCopy(cl.playerstandmaxs, PRVM_clientglobalvector(pmove_maxs));
2251 PRVM_G_FLOAT(OFS_RETURN) = true;
2256 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
2257 static void VM_CL_setsensitivityscale (prvm_prog_t *prog)
2259 VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
2260 cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
2263 //#347 void() runstandardplayerphysics (EXT_CSQC)
2264 #define PMF_JUMP_HELD 1 // matches FTEQW
2265 #define PMF_LADDER 2 // not used by DP, FTEQW sets this in runplayerphysics but does not read it
2266 #define PMF_DUCKED 4 // FIXME FTEQW doesn't have this for Q1 like movement because Q1 cannot crouch
2267 #define PMF_ONGROUND 8 // FIXME FTEQW doesn't have this for Q1 like movement and expects CSQC code to do its own trace, this is stupid CPU waste
2268 static void VM_CL_runplayerphysics (prvm_prog_t *prog)
2270 cl_clientmovement_state_t s;
2273 memset(&s, 0, sizeof(s));
2275 VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_runplayerphysics);
2277 ent = (prog->argc == 1 ? PRVM_G_EDICT(OFS_PARM0) : prog->edicts);
2278 if(ent == prog->edicts)
2282 VectorCopy(PRVM_clientglobalvector(pmove_org), s.origin);
2283 VectorCopy(PRVM_clientglobalvector(pmove_vel), s.velocity);
2284 VectorCopy(PRVM_clientglobalvector(pmove_mins), s.mins);
2285 VectorCopy(PRVM_clientglobalvector(pmove_maxs), s.maxs);
2287 s.waterjumptime = PRVM_clientglobalfloat(pmove_waterjumptime);
2288 s.cmd.canjump = (int)PRVM_clientglobalfloat(pmove_jump_held) == 0;
2294 VectorCopy(PRVM_clientedictvector(ent, origin), s.origin);
2295 VectorCopy(PRVM_clientedictvector(ent, velocity), s.velocity);
2296 VectorCopy(PRVM_clientedictvector(ent, mins), s.mins);
2297 VectorCopy(PRVM_clientedictvector(ent, maxs), s.maxs);
2298 s.crouched = ((int)PRVM_clientedictfloat(ent, pmove_flags) & PMF_DUCKED) != 0;
2299 s.waterjumptime = 0; // FIXME where do we get this from? FTEQW lacks support for this too
2300 s.cmd.canjump = ((int)PRVM_clientedictfloat(ent, pmove_flags) & PMF_JUMP_HELD) == 0;
2303 VectorCopy(PRVM_clientglobalvector(input_angles), s.cmd.viewangles);
2304 s.cmd.forwardmove = PRVM_clientglobalvector(input_movevalues)[0];
2305 s.cmd.sidemove = PRVM_clientglobalvector(input_movevalues)[1];
2306 s.cmd.upmove = PRVM_clientglobalvector(input_movevalues)[2];
2307 s.cmd.buttons = PRVM_clientglobalfloat(input_buttons);
2308 s.cmd.frametime = PRVM_clientglobalfloat(input_timelength);
2309 s.cmd.jump = (s.cmd.buttons & 2) != 0;
2310 s.cmd.crouch = (s.cmd.buttons & 16) != 0;
2312 CL_ClientMovement_PlayerMove_Frame(&s);
2314 if(ent == prog->edicts)
2317 VectorCopy(s.origin, PRVM_clientglobalvector(pmove_org));
2318 VectorCopy(s.velocity, PRVM_clientglobalvector(pmove_vel));
2319 PRVM_clientglobalfloat(pmove_jump_held) = !s.cmd.canjump;
2320 PRVM_clientglobalfloat(pmove_waterjumptime) = s.waterjumptime;
2325 VectorCopy(s.origin, PRVM_clientedictvector(ent, origin));
2326 VectorCopy(s.velocity, PRVM_clientedictvector(ent, velocity));
2327 PRVM_clientedictfloat(ent, pmove_flags) =
2328 (s.crouched ? PMF_DUCKED : 0) |
2329 (s.cmd.canjump ? 0 : PMF_JUMP_HELD) |
2330 (s.onground ? PMF_ONGROUND : 0);
2334 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
2335 static void VM_CL_getplayerkey (prvm_prog_t *prog)
2341 VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
2343 i = (int)PRVM_G_FLOAT(OFS_PARM0);
2344 c = PRVM_G_STRING(OFS_PARM1);
2345 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
2349 i = Sbar_GetSortedPlayerIndex(-1-i);
2350 if(i < 0 || i >= cl.maxclients)
2355 if(!strcasecmp(c, "name"))
2356 strlcpy(t, cl.scores[i].name, sizeof(t));
2358 if(!strcasecmp(c, "frags"))
2359 dpsnprintf(t, sizeof(t), "%i", cl.scores[i].frags);
2361 if(!strcasecmp(c, "ping"))
2362 dpsnprintf(t, sizeof(t), "%i", cl.scores[i].qw_ping);
2364 if(!strcasecmp(c, "pl"))
2365 dpsnprintf(t, sizeof(t), "%i", cl.scores[i].qw_packetloss);
2367 if(!strcasecmp(c, "movementloss"))
2368 dpsnprintf(t, sizeof(t), "%i", cl.scores[i].qw_movementloss);
2370 if(!strcasecmp(c, "entertime"))
2371 dpsnprintf(t, sizeof(t), "%f", cl.scores[i].qw_entertime);
2373 if(!strcasecmp(c, "colors"))
2374 dpsnprintf(t, sizeof(t), "%i", cl.scores[i].colors);
2376 if(!strcasecmp(c, "topcolor"))
2377 dpsnprintf(t, sizeof(t), "%i", cl.scores[i].colors & 0xf0);
2379 if(!strcasecmp(c, "bottomcolor"))
2380 dpsnprintf(t, sizeof(t), "%i", (cl.scores[i].colors &15)<<4);
2382 if(!strcasecmp(c, "viewentity"))
2383 dpsnprintf(t, sizeof(t), "%i", i+1);
2386 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, t);
2389 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
2390 static void VM_CL_setlistener (prvm_prog_t *prog)
2392 vec3_t origin, forward, left, up;
2393 VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
2394 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), origin);
2395 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), forward);
2396 VectorNegate(PRVM_G_VECTOR(OFS_PARM2), left);
2397 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), up);
2398 Matrix4x4_FromVectors(&cl.csqc_listenermatrix, forward, left, up, origin);
2399 cl.csqc_usecsqclistener = true; //use csqc listener at this frame
2402 //#352 void(string cmdname) registercommand (EXT_CSQC)
2403 static void VM_CL_registercmd (prvm_prog_t *prog)
2405 VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
2406 if(!Cmd_Exists(cmd_local, PRVM_G_STRING(OFS_PARM0)))
2407 Cmd_AddCommand(CF_CLIENT, PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
2410 //#360 float() readbyte (EXT_CSQC)
2411 static void VM_CL_ReadByte (prvm_prog_t *prog)
2413 VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
2414 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte(&cl_message);
2417 //#361 float() readchar (EXT_CSQC)
2418 static void VM_CL_ReadChar (prvm_prog_t *prog)
2420 VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
2421 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar(&cl_message);
2424 //#362 float() readshort (EXT_CSQC)
2425 static void VM_CL_ReadShort (prvm_prog_t *prog)
2427 VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
2428 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort(&cl_message);
2431 //#363 float() readlong (EXT_CSQC)
2432 static void VM_CL_ReadLong (prvm_prog_t *prog)
2434 VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
2435 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong(&cl_message);
2438 //#364 float() readcoord (EXT_CSQC)
2439 static void VM_CL_ReadCoord (prvm_prog_t *prog)
2441 VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
2442 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(&cl_message, cls.protocol);
2445 //#365 float() readangle (EXT_CSQC)
2446 static void VM_CL_ReadAngle (prvm_prog_t *prog)
2448 VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
2449 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(&cl_message, cls.protocol);
2452 //#366 string() readstring (EXT_CSQC)
2453 static void VM_CL_ReadString (prvm_prog_t *prog)
2455 VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
2456 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring)));
2459 //#367 float() readfloat (EXT_CSQC)
2460 static void VM_CL_ReadFloat (prvm_prog_t *prog)
2462 VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
2463 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat(&cl_message);
2466 //#501 string() readpicture (DP_CSQC_READWRITEPICTURE)
2467 extern cvar_t cl_readpicture_force;
2468 static void VM_CL_ReadPicture (prvm_prog_t *prog)
2471 unsigned char *data;
2473 unsigned short size;
2477 VM_SAFEPARMCOUNT(0, VM_CL_ReadPicture);
2479 name = MSG_ReadString(&cl_message, cl_readstring, sizeof(cl_readstring));
2480 size = (unsigned short) MSG_ReadShort(&cl_message);
2482 // check if a texture of that name exists
2483 // if yes, it is used and the data is discarded
2484 // if not, the (low quality) data is used to build a new texture, whose name will get returned
2486 pic = Draw_CachePic_Flags(name, CACHEPICFLAG_NOTPERSISTENT | CACHEPICFLAG_FAILONMISSING);
2490 if (Draw_IsPicLoaded(pic) && !cl_readpicture_force.integer)
2492 // texture found and loaded
2493 // skip over the jpeg as we don't need it
2494 for(i = 0; i < size; ++i)
2495 (void) MSG_ReadByte(&cl_message);
2499 // texture not found
2500 // use the attached jpeg as texture
2501 buf = (unsigned char *) Mem_Alloc(tempmempool, size);
2502 MSG_ReadBytes(&cl_message, size, buf);
2503 data = JPEG_LoadImage_BGRA(buf, size, NULL);
2505 Draw_NewPic(name, image_width, image_height, data, TEXTYPE_BGRA, TEXF_CLAMP);
2510 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, name);
2513 //////////////////////////////////////////////////////////
2515 static void VM_CL_makestatic (prvm_prog_t *prog)
2519 VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
2521 ent = PRVM_G_EDICT(OFS_PARM0);
2522 if (ent == prog->edicts)
2524 VM_Warning(prog, "makestatic: can not modify world entity\n");
2527 if (ent->priv.server->free)
2529 VM_Warning(prog, "makestatic: can not modify free entity\n");
2533 if (cl.num_static_entities < cl.max_static_entities)
2536 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
2538 // copy it to the current state
2539 memset(staticent, 0, sizeof(*staticent));
2540 staticent->render.model = CL_GetModelByIndex((int)PRVM_clientedictfloat(ent, modelindex));
2541 staticent->render.framegroupblend[0].frame = (int)PRVM_clientedictfloat(ent, frame);
2542 staticent->render.framegroupblend[0].lerp = 1;
2543 // make torchs play out of sync
2544 staticent->render.framegroupblend[0].start = lhrandom(-10, -1);
2545 staticent->render.skinnum = (int)PRVM_clientedictfloat(ent, skin);
2546 staticent->render.effects = (int)PRVM_clientedictfloat(ent, effects);
2547 staticent->render.alpha = PRVM_clientedictfloat(ent, alpha);
2548 staticent->render.scale = PRVM_clientedictfloat(ent, scale);
2549 VectorCopy(PRVM_clientedictvector(ent, colormod), staticent->render.colormod);
2550 VectorCopy(PRVM_clientedictvector(ent, glowmod), staticent->render.glowmod);
2553 if (!staticent->render.alpha)
2554 staticent->render.alpha = 1.0f;
2555 if (!staticent->render.scale)
2556 staticent->render.scale = 1.0f;
2557 if (!VectorLength2(staticent->render.colormod))
2558 VectorSet(staticent->render.colormod, 1, 1, 1);
2559 if (!VectorLength2(staticent->render.glowmod))
2560 VectorSet(staticent->render.glowmod, 1, 1, 1);
2562 renderflags = (int)PRVM_clientedictfloat(ent, renderflags);
2563 if (renderflags & RF_USEAXIS)
2565 vec3_t forward, left, up, origin;
2566 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
2567 VectorNegate(PRVM_clientglobalvector(v_right), left);
2568 VectorCopy(PRVM_clientglobalvector(v_up), up);
2569 VectorCopy(PRVM_clientedictvector(ent, origin), origin);
2570 Matrix4x4_FromVectors(&staticent->render.matrix, forward, left, up, origin);
2571 Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
2574 Matrix4x4_CreateFromQuakeEntity(&staticent->render.matrix, PRVM_clientedictvector(ent, origin)[0], PRVM_clientedictvector(ent, origin)[1], PRVM_clientedictvector(ent, origin)[2], PRVM_clientedictvector(ent, angles)[0], PRVM_clientedictvector(ent, angles)[1], PRVM_clientedictvector(ent, angles)[2], staticent->render.scale);
2576 // either fullbright or lit
2577 if(!r_fullbright.integer)
2579 if (!(staticent->render.effects & EF_FULLBRIGHT))
2580 staticent->render.flags |= RENDER_LIGHT;
2582 // turn off shadows from transparent objects
2583 if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
2584 staticent->render.flags |= RENDER_SHADOW;
2585 if (staticent->render.effects & EF_NODEPTHTEST)
2586 staticent->render.flags |= RENDER_NODEPTHTEST;
2587 if (staticent->render.effects & EF_ADDITIVE)
2588 staticent->render.flags |= RENDER_ADDITIVE;
2589 if (staticent->render.effects & EF_DOUBLESIDED)
2590 staticent->render.flags |= RENDER_DOUBLESIDED;
2592 staticent->render.allowdecals = true;
2593 CL_UpdateRenderEntity(&staticent->render);
2596 Con_Printf("Too many static entities");
2598 // throw the entity away now
2599 PRVM_ED_Free(prog, ent);
2602 //=================================================================//
2608 copies data from one entity to another
2610 copyentity(src, dst)
2613 static void VM_CL_copyentity (prvm_prog_t *prog)
2615 prvm_edict_t *in, *out;
2616 VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
2617 in = PRVM_G_EDICT(OFS_PARM0);
2618 if (in == prog->edicts)
2620 VM_Warning(prog, "copyentity: can not read world entity\n");
2623 if (in->priv.server->free)
2625 VM_Warning(prog, "copyentity: can not read free entity\n");
2628 out = PRVM_G_EDICT(OFS_PARM1);
2629 if (out == prog->edicts)
2631 VM_Warning(prog, "copyentity: can not modify world entity\n");
2634 if (out->priv.server->free)
2636 VM_Warning(prog, "copyentity: can not modify free entity\n");
2639 memcpy(out->fields.fp, in->fields.fp, prog->entityfields * sizeof(prvm_vec_t));
2641 if (VectorCompare(PRVM_clientedictvector(out, absmin), PRVM_clientedictvector(out, absmax)))
2646 //=================================================================//
2648 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
2649 static void VM_CL_effect (prvm_prog_t *prog)
2653 VM_SAFEPARMCOUNT(5, VM_CL_effect);
2654 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
2656 model = Mod_FindName(PRVM_G_STRING(OFS_PARM1), NULL);
2658 CL_Effect(org, model, (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4));
2660 Con_Printf(CON_ERROR "VM_CL_effect: Could not load model '%s'\n", PRVM_G_STRING(OFS_PARM1));
2663 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
2664 static void VM_CL_te_blood (prvm_prog_t *prog)
2666 vec3_t pos, vel, pos2;
2667 VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
2668 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
2670 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2671 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), vel);
2672 CL_FindNonSolidLocation(pos, pos2, 4);
2673 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, vel, vel, NULL, 0);
2676 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
2677 static void VM_CL_te_bloodshower (prvm_prog_t *prog)
2680 vec3_t mincorner, maxcorner, vel1, vel2;
2681 VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
2682 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
2684 speed = PRVM_G_FLOAT(OFS_PARM2);
2691 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), mincorner);
2692 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), maxcorner);
2693 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), mincorner, maxcorner, vel1, vel2, NULL, 0);
2696 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
2697 static void VM_CL_te_explosionrgb (prvm_prog_t *prog)
2701 matrix4x4_t tempmatrix;
2702 VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
2703 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2704 CL_FindNonSolidLocation(pos, pos2, 10);
2705 CL_ParticleExplosion(pos2);
2706 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
2707 CL_AllocLightFlash(NULL, &tempmatrix, 350, PRVM_G_VECTOR(OFS_PARM1)[0], PRVM_G_VECTOR(OFS_PARM1)[1], PRVM_G_VECTOR(OFS_PARM1)[2], 700, 0.5, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
2710 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
2711 static void VM_CL_te_particlecube (prvm_prog_t *prog)
2713 vec3_t mincorner, maxcorner, vel;
2714 VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
2715 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), mincorner);
2716 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), maxcorner);
2717 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
2718 CL_ParticleCube(mincorner, maxcorner, vel, (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4), PRVM_G_FLOAT(OFS_PARM5), PRVM_G_FLOAT(OFS_PARM6));
2721 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
2722 static void VM_CL_te_particlerain (prvm_prog_t *prog)
2724 vec3_t mincorner, maxcorner, vel;
2725 VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
2726 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), mincorner);
2727 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), maxcorner);
2728 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
2729 CL_ParticleRain(mincorner, maxcorner, vel, (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4), 0);
2732 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
2733 static void VM_CL_te_particlesnow (prvm_prog_t *prog)
2735 vec3_t mincorner, maxcorner, vel;
2736 VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
2737 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), mincorner);
2738 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), maxcorner);
2739 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), vel);
2740 CL_ParticleRain(mincorner, maxcorner, vel, (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4), 1);
2743 // #411 void(vector org, vector vel, float howmany) te_spark
2744 static void VM_CL_te_spark (prvm_prog_t *prog)
2746 vec3_t pos, pos2, vel;
2747 VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
2749 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2750 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), vel);
2751 CL_FindNonSolidLocation(pos, pos2, 4);
2752 CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, vel, vel, NULL, 0);
2755 extern cvar_t cl_sound_ric_gunshot;
2756 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
2757 static void VM_CL_te_gunshotquad (prvm_prog_t *prog)
2761 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
2763 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2764 CL_FindNonSolidLocation(pos, pos2, 4);
2765 CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2766 if(cl_sound_ric_gunshot.integer >= 2)
2768 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
2772 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
2773 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
2774 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
2779 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
2780 static void VM_CL_te_spikequad (prvm_prog_t *prog)
2784 VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
2786 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2787 CL_FindNonSolidLocation(pos, pos2, 4);
2788 CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2789 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
2793 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
2794 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
2795 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
2799 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
2800 static void VM_CL_te_superspikequad (prvm_prog_t *prog)
2804 VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
2806 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2807 CL_FindNonSolidLocation(pos, pos2, 4);
2808 CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2809 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
2813 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
2814 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
2815 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
2819 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
2820 static void VM_CL_te_explosionquad (prvm_prog_t *prog)
2823 VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
2825 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2826 CL_FindNonSolidLocation(pos, pos2, 10);
2827 CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2828 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
2831 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
2832 static void VM_CL_te_smallflash (prvm_prog_t *prog)
2835 VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
2837 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2838 CL_FindNonSolidLocation(pos, pos2, 10);
2839 CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2842 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
2843 static void VM_CL_te_customflash (prvm_prog_t *prog)
2846 matrix4x4_t tempmatrix;
2847 VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
2849 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2850 CL_FindNonSolidLocation(pos, pos2, 4);
2851 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
2852 CL_AllocLightFlash(NULL, &tempmatrix, PRVM_G_FLOAT(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM3)[0], PRVM_G_VECTOR(OFS_PARM3)[1], PRVM_G_VECTOR(OFS_PARM3)[2], PRVM_G_FLOAT(OFS_PARM1) / PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM2), NULL, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
2855 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
2856 static void VM_CL_te_gunshot (prvm_prog_t *prog)
2860 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
2862 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2863 CL_FindNonSolidLocation(pos, pos2, 4);
2864 CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2865 if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
2867 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
2871 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
2872 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
2873 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
2878 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
2879 static void VM_CL_te_spike (prvm_prog_t *prog)
2883 VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
2885 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2886 CL_FindNonSolidLocation(pos, pos2, 4);
2887 CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2888 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
2892 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
2893 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
2894 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
2898 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
2899 static void VM_CL_te_superspike (prvm_prog_t *prog)
2903 VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
2905 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2906 CL_FindNonSolidLocation(pos, pos2, 4);
2907 CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2908 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
2912 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
2913 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
2914 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
2918 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
2919 static void VM_CL_te_explosion (prvm_prog_t *prog)
2922 VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
2924 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2925 CL_FindNonSolidLocation(pos, pos2, 10);
2926 CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2927 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
2930 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
2931 static void VM_CL_te_tarexplosion (prvm_prog_t *prog)
2934 VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
2936 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2937 CL_FindNonSolidLocation(pos, pos2, 10);
2938 CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2939 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
2942 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
2943 static void VM_CL_te_wizspike (prvm_prog_t *prog)
2946 VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
2948 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2949 CL_FindNonSolidLocation(pos, pos2, 4);
2950 CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2951 S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
2954 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
2955 static void VM_CL_te_knightspike (prvm_prog_t *prog)
2958 VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
2960 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2961 CL_FindNonSolidLocation(pos, pos2, 4);
2962 CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
2963 S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
2966 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
2967 static void VM_CL_te_lavasplash (prvm_prog_t *prog)
2970 VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
2971 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2972 CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
2975 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
2976 static void VM_CL_te_teleport (prvm_prog_t *prog)
2979 VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
2980 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2981 CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, pos, pos, vec3_origin, vec3_origin, NULL, 0);
2984 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
2985 static void VM_CL_te_explosion2 (prvm_prog_t *prog)
2987 vec3_t pos, pos2, color;
2988 matrix4x4_t tempmatrix;
2989 int colorStart, colorLength;
2990 unsigned char *tempcolor;
2991 VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
2993 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
2994 colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
2995 colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
2996 CL_FindNonSolidLocation(pos, pos2, 10);
2997 CL_ParticleExplosion2(pos2, colorStart, colorLength);
2998 tempcolor = palette_rgb[(rand()%colorLength) + colorStart];
2999 color[0] = tempcolor[0] * (2.0f / 255.0f);
3000 color[1] = tempcolor[1] * (2.0f / 255.0f);
3001 color[2] = tempcolor[2] * (2.0f / 255.0f);
3002 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
3003 CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, NULL, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
3004 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
3008 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3009 static void VM_CL_te_lightning1 (prvm_prog_t *prog)
3012 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
3013 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), start);
3014 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), end);
3015 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), start, end, cl.model_bolt, true);
3018 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3019 static void VM_CL_te_lightning2 (prvm_prog_t *prog)
3022 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
3023 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), start);
3024 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), end);
3025 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), start, end, cl.model_bolt2, true);
3028 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3029 static void VM_CL_te_lightning3 (prvm_prog_t *prog)
3032 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
3033 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), start);
3034 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), end);
3035 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), start, end, cl.model_bolt3, false);
3038 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3039 static void VM_CL_te_beam (prvm_prog_t *prog)
3042 VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
3043 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), start);
3044 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), end);
3045 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), start, end, cl.model_beam, false);
3048 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3049 static void VM_CL_te_plasmaburn (prvm_prog_t *prog)
3052 VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
3054 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
3055 CL_FindNonSolidLocation(pos, pos2, 4);
3056 CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
3059 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
3060 static void VM_CL_te_flamejet (prvm_prog_t *prog)
3062 vec3_t pos, pos2, vel;
3063 VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
3064 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
3066 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), pos);
3067 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), vel);
3068 CL_FindNonSolidLocation(pos, pos2, 4);
3069 CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, vel, vel, NULL, 0);
3073 // #443 void(entity e, entity tagentity, string tagname) setattachment
3074 static void VM_CL_setattachment (prvm_prog_t *prog)
3077 prvm_edict_t *tagentity;
3078 const char *tagname;
3082 VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
3084 e = PRVM_G_EDICT(OFS_PARM0);
3085 tagentity = PRVM_G_EDICT(OFS_PARM1);
3086 tagname = PRVM_G_STRING(OFS_PARM2);
3088 if (e == prog->edicts)
3090 VM_Warning(prog, "setattachment: can not modify world entity\n");
3093 if (e->priv.server->free)
3095 VM_Warning(prog, "setattachment: can not modify free entity\n");
3099 if (tagentity == NULL)
3100 tagentity = prog->edicts;
3103 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
3105 modelindex = (int)PRVM_clientedictfloat(tagentity, modelindex);
3106 model = CL_GetModelByIndex(modelindex);
3109 tagindex = Mod_Alias_GetTagIndexForName(model, (int)PRVM_clientedictfloat(tagentity, skin), tagname);
3111 Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity), model->name);
3114 Con_DPrintf("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity));
3117 PRVM_clientedictedict(e, tag_entity) = PRVM_EDICT_TO_PROG(tagentity);
3118 PRVM_clientedictfloat(e, tag_index) = tagindex;
3121 /////////////////////////////////////////
3122 // DP_MD3_TAGINFO extension coded by VorteX
3124 static int CL_GetTagIndex (prvm_prog_t *prog, prvm_edict_t *e, const char *tagname)
3126 model_t *model = CL_GetModelFromEdict(e);
3128 return Mod_Alias_GetTagIndexForName(model, (int)PRVM_clientedictfloat(e, skin), tagname);
3133 static int CL_GetExtendedTagInfo (prvm_prog_t *prog, prvm_edict_t *e, int tagindex, int *parentindex, const char **tagname, matrix4x4_t *tag_localmatrix)
3140 Matrix4x4_CreateIdentity(tag_localmatrix);
3143 && (model = CL_GetModelFromEdict(e))
3144 && model->animscenes)
3146 r = Mod_Alias_GetExtendedTagInfoForIndex(model, (int)PRVM_clientedictfloat(e, skin), e->priv.server->frameblend, &e->priv.server->skeleton, tagindex - 1, parentindex, tagname, tag_localmatrix);
3157 int CL_GetPitchSign(prvm_prog_t *prog, prvm_edict_t *ent)
3160 if ((model = CL_GetModelFromEdict(ent)) && model->type == mod_alias)
3165 void CL_GetEntityMatrix (prvm_prog_t *prog, prvm_edict_t *ent, matrix4x4_t *out, qbool viewmatrix)
3168 float pitchsign = 1;
3170 scale = PRVM_clientedictfloat(ent, scale);
3175 *out = r_refdef.view.matrix;
3176 else if ((int)PRVM_clientedictfloat(ent, renderflags) & RF_USEAXIS)
3182 VectorScale(PRVM_clientglobalvector(v_forward), scale, forward);
3183 VectorScale(PRVM_clientglobalvector(v_right), -scale, left);
3184 VectorScale(PRVM_clientglobalvector(v_up), scale, up);
3185 VectorCopy(PRVM_clientedictvector(ent, origin), origin);
3186 Matrix4x4_FromVectors(out, forward, left, up, origin);
3190 pitchsign = CL_GetPitchSign(prog, ent);
3191 Matrix4x4_CreateFromQuakeEntity(out, PRVM_clientedictvector(ent, origin)[0], PRVM_clientedictvector(ent, origin)[1], PRVM_clientedictvector(ent, origin)[2], pitchsign * PRVM_clientedictvector(ent, angles)[0], PRVM_clientedictvector(ent, angles)[1], PRVM_clientedictvector(ent, angles)[2], scale);
3195 static int CL_GetEntityLocalTagMatrix(prvm_prog_t *prog, prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
3199 && (model = CL_GetModelFromEdict(ent))
3200 && model->animscenes)
3202 VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
3203 VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, cl.time);
3204 VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
3205 return Mod_Alias_GetTagMatrix(model, ent->priv.server->frameblend, &ent->priv.server->skeleton, tagindex, out);
3207 *out = identitymatrix;
3211 // Warnings/errors code:
3212 // 0 - normal (everything all-right)
3215 // 3 - null or non-precached model
3216 // 4 - no tags with requested index
3217 // 5 - runaway loop at attachment chain
3218 extern cvar_t cl_bob;
3219 extern cvar_t cl_bobcycle;
3220 extern cvar_t cl_bobup;
3221 int CL_GetTagMatrix (prvm_prog_t *prog, matrix4x4_t *out, prvm_edict_t *ent, int tagindex, prvm_vec_t *returnshadingorigin)
3225 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
3227 vec3_t shadingorigin;
3229 *out = identitymatrix; // warnings and errors return identical matrix
3231 if (ent == prog->edicts)
3233 if (ent->priv.server->free)
3236 model = CL_GetModelFromEdict(ent);
3240 tagmatrix = identitymatrix;
3244 if(attachloop >= 256)
3246 // apply transformation by child's tagindex on parent entity and then
3247 // by parent entity itself
3248 ret = CL_GetEntityLocalTagMatrix(prog, ent, tagindex - 1, &attachmatrix);
3249 if(ret && attachloop == 0)
3251 CL_GetEntityMatrix(prog, ent, &entitymatrix, false);
3252 Matrix4x4_Concat(&tagmatrix, &attachmatrix, out);
3253 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3254 // next iteration we process the parent entity
3255 if (PRVM_clientedictedict(ent, tag_entity))
3257 tagindex = (int)PRVM_clientedictfloat(ent, tag_index);
3258 ent = PRVM_EDICT_NUM(PRVM_clientedictedict(ent, tag_entity));
3265 // RENDER_VIEWMODEL magic
3266 if ((int)PRVM_clientedictfloat(ent, renderflags) & RF_VIEWMODEL)
3268 Matrix4x4_Copy(&tagmatrix, out);
3270 CL_GetEntityMatrix(prog, prog->edicts, &entitymatrix, true);
3271 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
3274 // Cl_bob, ported from rendering code
3275 if (PRVM_clientedictfloat(ent, health) > 0 && cl_bob.value && cl_bobcycle.value)
3278 // LadyHavoc: this code is *weird*, but not replacable (I think it
3279 // should be done in QC on the server, but oh well, quake is quake)
3280 // LadyHavoc: figured out bobup: the time at which the sin is at 180
3281 // degrees (which allows lengthening or squishing the peak or valley)
3282 cycle = cl.time/cl_bobcycle.value;
3283 cycle -= (int)cycle;
3284 if (cycle < cl_bobup.value)
3285 cycle = sin(M_PI * cycle / cl_bobup.value);
3287 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
3288 // bob is proportional to velocity in the xy plane
3289 // (don't count Z, or jumping messes it up)
3290 bob = sqrt(PRVM_clientedictvector(ent, velocity)[0]*PRVM_clientedictvector(ent, velocity)[0] + PRVM_clientedictvector(ent, velocity)[1]*PRVM_clientedictvector(ent, velocity)[1])*cl_bob.value;
3291 bob = bob*0.3 + bob*0.7*cycle;
3292 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
3296 // return the origin of the view
3297 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, shadingorigin);
3301 // return the origin of the root entity in the chain
3302 Matrix4x4_OriginFromMatrix(out, shadingorigin);
3304 if (returnshadingorigin)
3305 VectorCopy(shadingorigin, returnshadingorigin);
3309 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3310 static void VM_CL_gettagindex (prvm_prog_t *prog)
3313 const char *tag_name;
3316 VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
3318 ent = PRVM_G_EDICT(OFS_PARM0);
3319 tag_name = PRVM_G_STRING(OFS_PARM1);
3320 if (ent == prog->edicts)
3322 VM_Warning(prog, "VM_CL_gettagindex(entity #%i): can't affect world entity\n", PRVM_NUM_FOR_EDICT(ent));
3325 if (ent->priv.server->free)
3327 VM_Warning(prog, "VM_CL_gettagindex(entity #%i): can't affect free entity\n", PRVM_NUM_FOR_EDICT(ent));
3332 if (!CL_GetModelFromEdict(ent))
3333 Con_DPrintf("VM_CL_gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
3336 tag_index = CL_GetTagIndex(prog, ent, tag_name);
3338 if(developer_extra.integer)
3339 Con_DPrintf("VM_CL_gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
3341 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
3344 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3345 static void VM_CL_gettaginfo (prvm_prog_t *prog)
3349 matrix4x4_t tag_matrix;
3350 matrix4x4_t tag_localmatrix;
3352 const char *tagname;
3354 vec3_t forward, left, up, origin;
3355 const model_t *model;
3357 VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
3359 e = PRVM_G_EDICT(OFS_PARM0);
3360 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
3361 returncode = CL_GetTagMatrix(prog, &tag_matrix, e, tagindex, NULL);
3362 Matrix4x4_ToVectors(&tag_matrix, forward, left, up, origin);
3363 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3364 VectorScale(left, -1, PRVM_clientglobalvector(v_right));
3365 VectorCopy(up, PRVM_clientglobalvector(v_up));
3366 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
3367 model = CL_GetModelFromEdict(e);
3368 VM_GenerateFrameGroupBlend(prog, e->priv.server->framegroupblend, e);
3369 VM_FrameBlendFromFrameGroupBlend(e->priv.server->frameblend, e->priv.server->framegroupblend, model, cl.time);
3370 VM_UpdateEdictSkeleton(prog, e, model, e->priv.server->frameblend);
3371 CL_GetExtendedTagInfo(prog, e, tagindex, &parentindex, &tagname, &tag_localmatrix);
3372 Matrix4x4_ToVectors(&tag_localmatrix, forward, left, up, origin);
3374 PRVM_clientglobalfloat(gettaginfo_parent) = parentindex;
3375 PRVM_clientglobalstring(gettaginfo_name) = tagname ? PRVM_SetTempString(prog, tagname) : 0;
3376 VectorCopy(forward, PRVM_clientglobalvector(gettaginfo_forward));
3377 VectorScale(left, -1, PRVM_clientglobalvector(gettaginfo_right));
3378 VectorCopy(up, PRVM_clientglobalvector(gettaginfo_up));
3379 VectorCopy(origin, PRVM_clientglobalvector(gettaginfo_offset));
3384 VM_Warning(prog, "gettagindex: can't affect world entity\n");
3387 VM_Warning(prog, "gettagindex: can't affect free entity\n");
3390 Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
3393 Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
3396 Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
3401 //============================================================================
3403 //====================
3404 // DP_CSQC_SPAWNPARTICLE
3405 // a QC hook to engine's CL_NewParticle
3406 //====================
3408 // particle theme struct
3409 typedef struct vmparticletheme_s
3411 unsigned short typeindex;
3414 porientation_t orientation;
3425 float liquidfriction;
3427 float velocityjitter;
3428 qbool qualityreduction;
3437 float delaycollision;
3443 typedef struct vmparticlespawner_s
3448 vmparticletheme_t *themes;
3450 }vmparticlespawner_t;
3452 vmparticlespawner_t vmpartspawner;
3454 // TODO: automatic max_themes grow
3455 static void VM_InitParticleSpawner (prvm_prog_t *prog, int maxthemes)
3457 // bound max themes to not be an insane value
3460 if (maxthemes > 2048)
3462 // allocate and set up structure
3463 if (vmpartspawner.initialized) // reallocate
3465 Mem_FreePool(&vmpartspawner.pool);
3466 memset(&vmpartspawner, 0, sizeof(vmparticlespawner_t));
3468 vmpartspawner.pool = Mem_AllocPool("VMPARTICLESPAWNER", 0, NULL);
3469 vmpartspawner.themes = (vmparticletheme_t *)Mem_Alloc(vmpartspawner.pool, sizeof(vmparticletheme_t)*maxthemes);
3470 vmpartspawner.max_themes = maxthemes;
3471 vmpartspawner.initialized = true;
3472 vmpartspawner.verified = true;
3475 // reset particle theme to default values
3476 static void VM_ResetParticleTheme (vmparticletheme_t *theme)
3478 theme->initialized = true;
3479 theme->typeindex = pt_static;
3480 theme->blendmode = PBLEND_ADD;
3481 theme->orientation = PARTICLE_BILLBOARD;
3482 theme->color1 = 0x808080;
3483 theme->color2 = 0xFFFFFF;
3486 theme->sizeincrease = 0;
3488 theme->alphafade = 512;
3489 theme->gravity = 0.0f;
3490 theme->bounce = 0.0f;
3491 theme->airfriction = 1.0f;
3492 theme->liquidfriction = 4.0f;
3493 theme->originjitter = 0.0f;
3494 theme->velocityjitter = 0.0f;
3495 theme->qualityreduction = false;
3496 theme->lifetime = 4;
3498 theme->staincolor1 = -1;
3499 theme->staincolor2 = -1;
3500 theme->staintex = -1;
3501 theme->delayspawn = 0.0f;
3502 theme->delaycollision = 0.0f;
3503 theme->angle = 0.0f;
3507 // particle theme -> QC globals
3508 static void VM_CL_ParticleThemeToGlobals(vmparticletheme_t *theme, prvm_prog_t *prog)
3510 PRVM_clientglobalfloat(particle_type) = theme->typeindex;
3511 PRVM_clientglobalfloat(particle_blendmode) = theme->blendmode;
3512 PRVM_clientglobalfloat(particle_orientation) = theme->orientation;
3513 // VorteX: int only can store 0-255, not 0-256 which means 0 - 0,99609375...
3514 VectorSet(PRVM_clientglobalvector(particle_color1), (theme->color1 >> 16) & 0xFF, (theme->color1 >> 8) & 0xFF, (theme->color1 >> 0) & 0xFF);
3515 VectorSet(PRVM_clientglobalvector(particle_color2), (theme->color2 >> 16) & 0xFF, (theme->color2 >> 8) & 0xFF, (theme->color2 >> 0) & 0xFF);
3516 PRVM_clientglobalfloat(particle_tex) = (prvm_vec_t)theme->tex;
3517 PRVM_clientglobalfloat(particle_size) = theme->size;
3518 PRVM_clientglobalfloat(particle_sizeincrease) = theme->sizeincrease;
3519 PRVM_clientglobalfloat(particle_alpha) = theme->alpha/256;
3520 PRVM_clientglobalfloat(particle_alphafade) = theme->alphafade/256;
3521 PRVM_clientglobalfloat(particle_time) = theme->lifetime;
3522 PRVM_clientglobalfloat(particle_gravity) = theme->gravity;
3523 PRVM_clientglobalfloat(particle_bounce) = theme->bounce;
3524 PRVM_clientglobalfloat(particle_airfriction) = theme->airfriction;
3525 PRVM_clientglobalfloat(particle_liquidfriction) = theme->liquidfriction;
3526 PRVM_clientglobalfloat(particle_originjitter) = theme->originjitter;
3527 PRVM_clientglobalfloat(particle_velocityjitter) = theme->velocityjitter;
3528 PRVM_clientglobalfloat(particle_qualityreduction) = theme->qualityreduction;
3529 PRVM_clientglobalfloat(particle_stretch) = theme->stretch;
3530 VectorSet(PRVM_clientglobalvector(particle_staincolor1), ((int)theme->staincolor1 >> 16) & 0xFF, ((int)theme->staincolor1 >> 8) & 0xFF, ((int)theme->staincolor1 >> 0) & 0xFF);
3531 VectorSet(PRVM_clientglobalvector(particle_staincolor2), ((int)theme->staincolor2 >> 16) & 0xFF, ((int)theme->staincolor2 >> 8) & 0xFF, ((int)theme->staincolor2 >> 0) & 0xFF);
3532 PRVM_clientglobalfloat(particle_staintex) = (prvm_vec_t)theme->staintex;
3533 PRVM_clientglobalfloat(particle_stainalpha) = (prvm_vec_t)theme->stainalpha/256;
3534 PRVM_clientglobalfloat(particle_stainsize) = (prvm_vec_t)theme->stainsize;
3535 PRVM_clientglobalfloat(particle_delayspawn) = theme->delayspawn;
3536 PRVM_clientglobalfloat(particle_delaycollision) = theme->delaycollision;
3537 PRVM_clientglobalfloat(particle_angle) = theme->angle;
3538 PRVM_clientglobalfloat(particle_spin) = theme->spin;
3541 // QC globals -> particle theme
3542 static void VM_CL_ParticleThemeFromGlobals(vmparticletheme_t *theme, prvm_prog_t *prog)
3544 theme->typeindex = (unsigned short)PRVM_clientglobalfloat(particle_type);
3545 theme->blendmode = (pblend_t)(int)PRVM_clientglobalfloat(particle_blendmode);
3546 theme->orientation = (porientation_t)(int)PRVM_clientglobalfloat(particle_orientation);
3547 theme->color1 = ((int)PRVM_clientglobalvector(particle_color1)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color1)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color1)[2]);
3548 theme->color2 = ((int)PRVM_clientglobalvector(particle_color2)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color2)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color2)[2]);
3549 theme->tex = (int)PRVM_clientglobalfloat(particle_tex);
3550 theme->size = PRVM_clientglobalfloat(particle_size);
3551 theme->sizeincrease = PRVM_clientglobalfloat(particle_sizeincrease);
3552 theme->alpha = PRVM_clientglobalfloat(particle_alpha)*256;
3553 theme->alphafade = PRVM_clientglobalfloat(particle_alphafade)*256;
3554 theme->lifetime = PRVM_clientglobalfloat(particle_time);
3555 theme->gravity = PRVM_clientglobalfloat(particle_gravity);
3556 theme->bounce = PRVM_clientglobalfloat(particle_bounce);
3557 theme->airfriction = PRVM_clientglobalfloat(particle_airfriction);
3558 theme->liquidfriction = PRVM_clientglobalfloat(particle_liquidfriction);
3559 theme->originjitter = PRVM_clientglobalfloat(particle_originjitter);
3560 theme->velocityjitter = PRVM_clientglobalfloat(particle_velocityjitter);
3561 theme->qualityreduction = PRVM_clientglobalfloat(particle_qualityreduction) != 0 ? true : false;
3562 theme->stretch = PRVM_clientglobalfloat(particle_stretch);
3563 theme->staincolor1 = ((int)PRVM_clientglobalvector(particle_staincolor1)[0])*65536 + (int)(PRVM_clientglobalvector(particle_staincolor1)[1])*256 + (int)(PRVM_clientglobalvector(particle_staincolor1)[2]);
3564 theme->staincolor2 = (int)(PRVM_clientglobalvector(particle_staincolor2)[0])*65536 + (int)(PRVM_clientglobalvector(particle_staincolor2)[1])*256 + (int)(PRVM_clientglobalvector(particle_staincolor2)[2]);
3565 theme->staintex =(int)PRVM_clientglobalfloat(particle_staintex);
3566 theme->stainalpha = PRVM_clientglobalfloat(particle_stainalpha)*256;
3567 theme->stainsize = PRVM_clientglobalfloat(particle_stainsize);
3568 theme->delayspawn = PRVM_clientglobalfloat(particle_delayspawn);
3569 theme->delaycollision = PRVM_clientglobalfloat(particle_delaycollision);
3570 theme->angle = PRVM_clientglobalfloat(particle_angle);
3571 theme->spin = PRVM_clientglobalfloat(particle_spin);
3574 // init particle spawner interface
3575 // # float(float max_themes) initparticlespawner
3576 static void VM_CL_InitParticleSpawner (prvm_prog_t *prog)
3578 VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_InitParticleSpawner);
3579 VM_InitParticleSpawner(prog, (int)PRVM_G_FLOAT(OFS_PARM0));
3580 vmpartspawner.themes[0].initialized = true;
3581 VM_ResetParticleTheme(&vmpartspawner.themes[0]);
3582 PRVM_G_FLOAT(OFS_RETURN) = (vmpartspawner.verified == true) ? 1 : 0;
3585 // void() resetparticle
3586 static void VM_CL_ResetParticle (prvm_prog_t *prog)
3588 VM_SAFEPARMCOUNT(0, VM_CL_ResetParticle);
3589 if (vmpartspawner.verified == false)
3591 VM_Warning(prog, "VM_CL_ResetParticle: particle spawner not initialized\n");
3594 VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0], prog);
3597 // void(float themenum) particletheme
3598 static void VM_CL_ParticleTheme (prvm_prog_t *prog)
3602 VM_SAFEPARMCOUNT(1, VM_CL_ParticleTheme);
3603 if (vmpartspawner.verified == false)
3605 VM_Warning(prog, "VM_CL_ParticleTheme: particle spawner not initialized\n");
3608 themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
3609 if (themenum < 0 || themenum >= vmpartspawner.max_themes)
3611 VM_Warning(prog, "VM_CL_ParticleTheme: bad theme number %i\n", themenum);
3612 VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0], prog);
3615 if (vmpartspawner.themes[themenum].initialized == false)
3617 VM_Warning(prog, "VM_CL_ParticleTheme: theme #%i not exists\n", themenum);
3618 VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0], prog);
3621 // load particle theme into globals
3622 VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[themenum], prog);
3625 // float() saveparticletheme
3626 // void(float themenum) updateparticletheme
3627 static void VM_CL_ParticleThemeSave (prvm_prog_t *prog)
3631 VM_SAFEPARMCOUNTRANGE(0, 1, VM_CL_ParticleThemeSave);
3632 if (vmpartspawner.verified == false)
3634 VM_Warning(prog, "VM_CL_ParticleThemeSave: particle spawner not initialized\n");
3637 // allocate new theme, save it and return
3640 for (themenum = 0; themenum < vmpartspawner.max_themes; themenum++)
3641 if (vmpartspawner.themes[themenum].initialized == false)
3643 if (themenum >= vmpartspawner.max_themes)
3645 if (vmpartspawner.max_themes == 2048)
3646 VM_Warning(prog, "VM_CL_ParticleThemeSave: no free theme slots\n");
3648 VM_Warning(prog, "VM_CL_ParticleThemeSave: no free theme slots, try initparticlespawner() with highter max_themes\n");
3649 PRVM_G_FLOAT(OFS_RETURN) = -1;
3652 vmpartspawner.themes[themenum].initialized = true;
3653 VM_CL_ParticleThemeFromGlobals(&vmpartspawner.themes[themenum], prog);
3654 PRVM_G_FLOAT(OFS_RETURN) = themenum;
3657 // update existing theme
3658 themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
3659 if (themenum < 0 || themenum >= vmpartspawner.max_themes)
3661 VM_Warning(prog, "VM_CL_ParticleThemeSave: bad theme number %i\n", themenum);
3664 vmpartspawner.themes[themenum].initialized = true;
3665 VM_CL_ParticleThemeFromGlobals(&vmpartspawner.themes[themenum], prog);
3668 // void(float themenum) freeparticletheme
3669 static void VM_CL_ParticleThemeFree (prvm_prog_t *prog)
3673 VM_SAFEPARMCOUNT(1, VM_CL_ParticleThemeFree);
3674 if (vmpartspawner.verified == false)
3676 VM_Warning(prog, "VM_CL_ParticleThemeFree: particle spawner not initialized\n");
3679 themenum = (int)PRVM_G_FLOAT(OFS_PARM0);
3681 if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
3683 VM_Warning(prog, "VM_CL_ParticleThemeFree: bad theme number %i\n", themenum);
3686 if (vmpartspawner.themes[themenum].initialized == false)
3688 VM_Warning(prog, "VM_CL_ParticleThemeFree: theme #%i already freed\n", themenum);
3689 VM_CL_ParticleThemeToGlobals(&vmpartspawner.themes[0], prog);
3693 VM_ResetParticleTheme(&vmpartspawner.themes[themenum]);
3694 vmpartspawner.themes[themenum].initialized = false;
3697 // float(vector org, vector dir, [float theme]) particle
3698 // returns 0 if failed, 1 if succesful
3699 static void VM_CL_SpawnParticle (prvm_prog_t *prog)
3702 vmparticletheme_t *theme;
3706 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_SpawnParticle);
3707 if (vmpartspawner.verified == false)
3709 VM_Warning(prog, "VM_CL_SpawnParticle: particle spawner not initialized\n");
3710 PRVM_G_FLOAT(OFS_RETURN) = 0;
3713 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
3714 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir);
3716 if (prog->argc < 3) // global-set particle
3718 part = CL_NewParticle(org,
3719 (unsigned short)PRVM_clientglobalfloat(particle_type),
3720 ((int)PRVM_clientglobalvector(particle_color1)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color1)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color1)[2]),
3721 ((int)PRVM_clientglobalvector(particle_color2)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color2)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color2)[2]),
3722 (int)PRVM_clientglobalfloat(particle_tex),
3723 PRVM_clientglobalfloat(particle_size),
3724 PRVM_clientglobalfloat(particle_sizeincrease),
3725 PRVM_clientglobalfloat(particle_alpha)*256,
3726 PRVM_clientglobalfloat(particle_alphafade)*256,
3727 PRVM_clientglobalfloat(particle_gravity),
3728 PRVM_clientglobalfloat(particle_bounce),
3735 PRVM_clientglobalfloat(particle_airfriction),
3736 PRVM_clientglobalfloat(particle_liquidfriction),
3737 PRVM_clientglobalfloat(particle_originjitter),
3738 PRVM_clientglobalfloat(particle_velocityjitter),
3739 (PRVM_clientglobalfloat(particle_qualityreduction)) ? true : false,
3740 PRVM_clientglobalfloat(particle_time),
3741 PRVM_clientglobalfloat(particle_stretch),
3742 (pblend_t)(int)PRVM_clientglobalfloat(particle_blendmode),
3743 (porientation_t)(int)PRVM_clientglobalfloat(particle_orientation),
3744 (int)(PRVM_clientglobalvector(particle_staincolor1)[0])*65536 + (int)(PRVM_clientglobalvector(particle_staincolor1)[1])*256 + (int)(PRVM_clientglobalvector(particle_staincolor1)[2]),
3745 (int)(PRVM_clientglobalvector(particle_staincolor2)[0])*65536 + (int)(PRVM_clientglobalvector(particle_staincolor2)[1])*256 + (int)(PRVM_clientglobalvector(particle_staincolor2)[2]),
3746 (int)PRVM_clientglobalfloat(particle_staintex),
3747 PRVM_clientglobalfloat(particle_stainalpha)*256,
3748 PRVM_clientglobalfloat(particle_stainsize),
3749 PRVM_clientglobalfloat(particle_angle),
3750 PRVM_clientglobalfloat(particle_spin),
3754 PRVM_G_FLOAT(OFS_RETURN) = 0;
3757 if (PRVM_clientglobalfloat(particle_delayspawn))
3758 part->delayedspawn = cl.time + PRVM_clientglobalfloat(particle_delayspawn);
3759 //if (PRVM_clientglobalfloat(particle_delaycollision))
3760 // part->delayedcollisions = cl.time + PRVM_clientglobalfloat(particle_delaycollision);
3762 else // quick themed particle
3764 themenum = (int)PRVM_G_FLOAT(OFS_PARM2);
3765 if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
3767 VM_Warning(prog, "VM_CL_SpawnParticle: bad theme number %i\n", themenum);
3768 PRVM_G_FLOAT(OFS_RETURN) = 0;
3771 theme = &vmpartspawner.themes[themenum];
3772 part = CL_NewParticle(org,
3778 theme->sizeincrease,
3790 theme->liquidfriction,
3791 theme->originjitter,
3792 theme->velocityjitter,
3793 theme->qualityreduction,
3808 PRVM_G_FLOAT(OFS_RETURN) = 0;
3811 if (theme->delayspawn)
3812 part->delayedspawn = cl.time + theme->delayspawn;
3813 //if (theme->delaycollision)
3814 // part->delayedcollisions = cl.time + theme->delaycollision;
3816 PRVM_G_FLOAT(OFS_RETURN) = 1;
3819 // float(vector org, vector dir, float spawndelay, float collisiondelay, [float theme]) delayedparticle
3820 // returns 0 if failed, 1 if success
3821 static void VM_CL_SpawnParticleDelayed (prvm_prog_t *prog)
3824 vmparticletheme_t *theme;
3828 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_SpawnParticleDelayed);
3829 if (vmpartspawner.verified == false)
3831 VM_Warning(prog, "VM_CL_SpawnParticleDelayed: particle spawner not initialized\n");
3832 PRVM_G_FLOAT(OFS_RETURN) = 0;
3835 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
3836 VectorCopy(PRVM_G_VECTOR(OFS_PARM1), dir);
3837 if (prog->argc < 5) // global-set particle
3838 part = CL_NewParticle(org,
3839 (unsigned short)PRVM_clientglobalfloat(particle_type),
3840 ((int)PRVM_clientglobalvector(particle_color1)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color1)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color1)[2]),
3841 ((int)PRVM_clientglobalvector(particle_color2)[0] << 16) + ((int)PRVM_clientglobalvector(particle_color2)[1] << 8) + ((int)PRVM_clientglobalvector(particle_color2)[2]),
3842 (int)PRVM_clientglobalfloat(particle_tex),
3843 PRVM_clientglobalfloat(particle_size),
3844 PRVM_clientglobalfloat(particle_sizeincrease),
3845 PRVM_clientglobalfloat(particle_alpha)*256,
3846 PRVM_clientglobalfloat(particle_alphafade)*256,
3847 PRVM_clientglobalfloat(particle_gravity),
3848 PRVM_clientglobalfloat(particle_bounce),
3855 PRVM_clientglobalfloat(particle_airfriction),
3856 PRVM_clientglobalfloat(particle_liquidfriction),
3857 PRVM_clientglobalfloat(particle_originjitter),
3858 PRVM_clientglobalfloat(particle_velocityjitter),
3859 (PRVM_clientglobalfloat(particle_qualityreduction)) ? true : false,
3860 PRVM_clientglobalfloat(particle_time),
3861 PRVM_clientglobalfloat(particle_stretch),
3862 (pblend_t)(int)PRVM_clientglobalfloat(particle_blendmode),
3863 (porientation_t)(int)PRVM_clientglobalfloat(particle_orientation),
3864 ((int)PRVM_clientglobalvector(particle_staincolor1)[0] << 16) + ((int)PRVM_clientglobalvector(particle_staincolor1)[1] << 8) + ((int)PRVM_clientglobalvector(particle_staincolor1)[2]),
3865 ((int)PRVM_clientglobalvector(particle_staincolor2)[0] << 16) + ((int)PRVM_clientglobalvector(particle_staincolor2)[1] << 8) + ((int)PRVM_clientglobalvector(particle_staincolor2)[2]),
3866 (int)PRVM_clientglobalfloat(particle_staintex),
3867 PRVM_clientglobalfloat(particle_stainalpha)*256,
3868 PRVM_clientglobalfloat(particle_stainsize),
3869 PRVM_clientglobalfloat(particle_angle),
3870 PRVM_clientglobalfloat(particle_spin),
3872 else // themed particle
3874 themenum = (int)PRVM_G_FLOAT(OFS_PARM4);
3875 if (themenum <= 0 || themenum >= vmpartspawner.max_themes)
3877 VM_Warning(prog, "VM_CL_SpawnParticleDelayed: bad theme number %i\n", themenum);
3878 PRVM_G_FLOAT(OFS_RETURN) = 0;
3881 theme = &vmpartspawner.themes[themenum];
3882 part = CL_NewParticle(org,
3888 theme->sizeincrease,
3900 theme->liquidfriction,
3901 theme->originjitter,
3902 theme->velocityjitter,
3903 theme->qualityreduction,
3919 PRVM_G_FLOAT(OFS_RETURN) = 0;
3922 part->delayedspawn = cl.time + PRVM_G_FLOAT(OFS_PARM2);
3923 //part->delayedcollisions = cl.time + PRVM_G_FLOAT(OFS_PARM3);
3924 PRVM_G_FLOAT(OFS_RETURN) = 0;
3927 //====================
3928 //CSQC engine entities query
3929 //====================
3931 // float(float entitynum, float whatfld) getentity;
3932 // vector(float entitynum, float whatfld) getentityvec;
3933 // querying engine-drawn entity
3934 // VorteX: currently it's only tested with whatfld = 1..7
3935 static void VM_CL_GetEntity (prvm_prog_t *prog)
3937 int entnum, fieldnum;
3938 vec3_t forward, left, up, org;
3939 VM_SAFEPARMCOUNT(2, VM_CL_GetEntity);
3941 entnum = PRVM_G_FLOAT(OFS_PARM0);
3942 if (entnum < 0 || entnum >= cl.num_entities)
3944 PRVM_G_FLOAT(OFS_RETURN) = 0;
3947 fieldnum = PRVM_G_FLOAT(OFS_PARM1);
3950 case 0: // active state
3951 PRVM_G_FLOAT(OFS_RETURN) = cl.entities_active[entnum];
3954 Matrix4x4_OriginFromMatrix(&cl.entities[entnum].render.matrix, org);
3955 VectorCopy(org, PRVM_G_VECTOR(OFS_RETURN));
3958 Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, forward, left, up, org);
3959 VectorCopy(forward, PRVM_G_VECTOR(OFS_RETURN));
3962 Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, forward, left, up, org);
3963 VectorNegate(left, PRVM_G_VECTOR(OFS_RETURN));
3966 Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, forward, left, up, org);
3967 VectorCopy(up, PRVM_G_VECTOR(OFS_RETURN));
3970 PRVM_G_FLOAT(OFS_RETURN) = Matrix4x4_ScaleFromMatrix(&cl.entities[entnum].render.matrix);
3972 case 6: // origin + v_forward, v_right, v_up
3973 Matrix4x4_ToVectors(&cl.entities[entnum].render.matrix, forward, left, up, org);
3974 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
3975 VectorNegate(left, PRVM_clientglobalvector(v_right));
3976 VectorCopy(up, PRVM_clientglobalvector(v_up));
3977 VectorCopy(org, PRVM_G_VECTOR(OFS_RETURN));
3980 PRVM_G_FLOAT(OFS_RETURN) = cl.entities[entnum].render.alpha;
3983 VectorCopy(cl.entities[entnum].render.colormod, PRVM_G_VECTOR(OFS_RETURN));
3985 case 9: // pants colormod
3986 VectorCopy(cl.entities[entnum].render.colormap_pantscolor, PRVM_G_VECTOR(OFS_RETURN));
3988 case 10: // shirt colormod
3989 VectorCopy(cl.entities[entnum].render.colormap_shirtcolor, PRVM_G_VECTOR(OFS_RETURN));
3992 PRVM_G_FLOAT(OFS_RETURN) = cl.entities[entnum].render.skinnum;
3995 VectorCopy(cl.entities[entnum].render.mins, PRVM_G_VECTOR(OFS_RETURN));
3998 VectorCopy(cl.entities[entnum].render.maxs, PRVM_G_VECTOR(OFS_RETURN));
4001 Matrix4x4_OriginFromMatrix(&cl.entities[entnum].render.matrix, org);
4002 VectorAdd(cl.entities[entnum].render.mins, org, PRVM_G_VECTOR(OFS_RETURN));
4005 Matrix4x4_OriginFromMatrix(&cl.entities[entnum].render.matrix, org);
4006 VectorAdd(cl.entities[entnum].render.maxs, org, PRVM_G_VECTOR(OFS_RETURN));
4009 VectorMA(cl.entities[entnum].render.render_modellight_ambient, 0.5, cl.entities[entnum].render.render_modellight_diffuse, PRVM_G_VECTOR(OFS_RETURN));
4012 PRVM_G_FLOAT(OFS_RETURN) = 0;
4017 //====================
4018 //QC POLYGON functions
4019 //====================
4021 //#304 void() renderscene (EXT_CSQC)
4022 // moved that here to reset the polygons,
4023 // resetting them earlier causes R_Mesh_Draw to be called with numvertices = 0
4025 static void VM_CL_R_RenderScene (prvm_prog_t *prog)
4027 qbool ismain = r_refdef.view.ismain;
4028 double t = Sys_DirtyTime();
4029 VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
4034 // set the main view
4035 csqc_main_r_refdef_view = r_refdef.view;
4038 // now after all of the predraw we know the geometry in the scene mesh and can finalize it for rendering
4039 CL_MeshEntities_Scene_FinalizeRenderEntity();
4041 // we need to update any RENDER_VIEWMODEL entities at this point because
4042 // csqc supplies its own view matrix
4043 CL_UpdateViewEntities();
4044 CL_UpdateEntityShading();
4047 R_RenderView(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
4049 // callprofile fixing hack: do not include this time in what is counted for CSQC_UpdateView
4050 t = Sys_DirtyTime() - t;if (t < 0 || t >= 1800) t = 0;
4051 prog->functions[PRVM_clientfunction(CSQC_UpdateView)].totaltime -= t;
4053 // polygonbegin without draw2d arg has to guess
4054 prog->polygonbegin_guess2d = false;
4059 // clear the flags so no other view becomes "main" unless CSQC sets VF_MAINVIEW
4060 r_refdef.view.ismain = false;
4061 csqc_original_r_refdef_view.ismain = false;
4065 //void(string texturename, float flag[, float is2d]) R_BeginPolygon
4066 static void VM_CL_R_PolygonBegin (prvm_prog_t *prog)
4068 const char *texname;
4073 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_PolygonBegin);
4075 texname = PRVM_G_STRING(OFS_PARM0);
4076 drawflags = (int)PRVM_G_FLOAT(OFS_PARM1);
4077 if (prog->argc >= 3)
4078 draw2d = PRVM_G_FLOAT(OFS_PARM2) != 0;
4081 // weird hacky way to figure out if this is a 2D HUD polygon or a scene
4082 // polygon, for compatibility with mods aimed at old darkplaces versions
4083 // - polygonbegin_guess2d is 0 if the most recent major call was
4084 // clearscene, 1 if the most recent major call was drawpic (and similar)
4086 draw2d = prog->polygonbegin_guess2d;
4089 // we need to remember whether this is a 2D or 3D mesh we're adding to
4090 mod = draw2d ? CL_Mesh_UI() : CL_Mesh_Scene();
4091 prog->polygonbegin_model = mod;
4092 if (texname == NULL || texname[0] == 0)
4093 texname = "$whiteimage";
4094 strlcpy(prog->polygonbegin_texname, texname, sizeof(prog->polygonbegin_texname));
4095 prog->polygonbegin_drawflags = drawflags;
4096 prog->polygonbegin_numvertices = 0;
4099 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
4100 static void VM_CL_R_PolygonVertex (prvm_prog_t *prog)
4102 const prvm_vec_t *v = PRVM_G_VECTOR(OFS_PARM0);
4103 const prvm_vec_t *tc = PRVM_G_VECTOR(OFS_PARM1);
4104 const prvm_vec_t *c = PRVM_G_VECTOR(OFS_PARM2);
4105 const prvm_vec_t a = PRVM_G_FLOAT(OFS_PARM3);
4107 model_t *mod = prog->polygonbegin_model;
4109 VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
4113 VM_Warning(prog, "VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
4117 if (prog->polygonbegin_maxvertices <= prog->polygonbegin_numvertices)
4119 prog->polygonbegin_maxvertices = max(16, prog->polygonbegin_maxvertices * 2);
4120 prog->polygonbegin_vertexdata = (float *)Mem_Realloc(prog->progs_mempool, prog->polygonbegin_vertexdata, prog->polygonbegin_maxvertices * sizeof(float[10]));
4122 o = prog->polygonbegin_vertexdata + prog->polygonbegin_numvertices++ * 10;
4136 //void() R_EndPolygon
4137 static void VM_CL_R_PolygonEnd (prvm_prog_t *prog)
4142 int e0 = 0, e1 = 0, e2 = 0;
4144 model_t *mod = prog->polygonbegin_model;
4149 VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
4152 VM_Warning(prog, "VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
4156 // determine if vertex alpha is being used so we can provide that hint to GetTexture...
4159 for (i = 0; i < prog->polygonbegin_numvertices; i++)
4161 o = prog->polygonbegin_vertexdata + 10 * i;
4162 if (o[6] != 1.0f || o[7] != 1.0f || o[8] != 1.0f)
4168 // create the surface, looking up the best matching texture/shader
4169 materialflags = MATERIALFLAG_WALL;
4170 if (csqc_polygons_defaultmaterial_nocullface.integer)
4171 materialflags |= MATERIALFLAG_NOCULLFACE;
4173 materialflags |= MATERIALFLAG_VERTEXCOLOR;
4175 materialflags |= MATERIALFLAG_ALPHAGEN_VERTEX | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
4176 tex = Mod_Mesh_GetTexture(mod, prog->polygonbegin_texname, prog->polygonbegin_drawflags, TEXF_ALPHA, materialflags);
4177 surf = Mod_Mesh_AddSurface(mod, tex, false);
4178 // create triangle fan
4179 for (i = 0; i < prog->polygonbegin_numvertices; i++)
4181 o = prog->polygonbegin_vertexdata + 10 * i;
4182 e2 = Mod_Mesh_IndexForVertex(mod, surf, o[0], o[1], o[2], 0, 0, 0, o[3], o[4], 0, 0, o[6], o[7], o[8], o[9]);
4184 Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
4189 // build normals (since they are not provided)
4190 Mod_BuildNormals(surf->num_firstvertex, surf->num_vertices, surf->num_triangles, mod->surfmesh.data_vertex3f, mod->surfmesh.data_element3i + 3 * surf->num_firsttriangle, mod->surfmesh.data_normal3f, true);
4193 prog->polygonbegin_model = NULL;
4194 prog->polygonbegin_texname[0] = 0;
4195 prog->polygonbegin_drawflags = 0;
4196 prog->polygonbegin_numvertices = 0;
4203 Returns false if any part of the bottom of the entity is off an edge that
4208 static qbool CL_CheckBottom (prvm_edict_t *ent)
4210 prvm_prog_t *prog = CLVM_prog;
4211 vec3_t mins, maxs, start, stop;
4214 float mid, bottom, stepheight;
4216 stepheight = sv_stepheight.value + PRVM_clientedictfloat(ent, stepheight_delta);
4217 VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, mins), mins);
4218 VectorAdd (PRVM_clientedictvector(ent, origin), PRVM_clientedictvector(ent, maxs), maxs);
4220 // if all of the points under the corners are solid world, don't bother
4221 // with the tougher checks
4222 // the corners must be within 16 of the midpoint
4223 start[2] = mins[2] - 1;
4224 for (x=0 ; x<=1 ; x++)
4225 for (y=0 ; y<=1 ; y++)
4227 start[0] = x ? maxs[0] : mins[0];
4228 start[1] = y ? maxs[1] : mins[1];
4229 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
4233 return true; // we got out easy
4237 // check it for real...
4241 // the midpoint must be within 16 of the bottom
4242 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
4243 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
4244 stop[2] = start[2] - 2*stepheight;
4245 trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, false, NULL, true, false);
4247 if (trace.fraction == 1.0)
4249 mid = bottom = trace.endpos[2];
4251 // the corners must be within 16 of the midpoint
4252 for (x=0 ; x<=1 ; x++)
4253 for (y=0 ; y<=1 ; y++)
4255 start[0] = stop[0] = x ? maxs[0] : mins[0];
4256 start[1] = stop[1] = y ? maxs[1] : mins[1];
4258 trace = CL_TraceLine(start, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, false, NULL, true, false);
4260 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
4261 bottom = trace.endpos[2];
4262 if (trace.fraction == 1.0 || mid - trace.endpos[2] > stepheight)
4273 Called by monster program code.
4274 The move will be adjusted for slopes and stairs, but if the move isn't
4275 possible, no move is done and false is returned
4278 static qbool CL_movestep (prvm_edict_t *ent, vec3_t move, qbool relink, qbool noenemy, qbool settrace)
4280 prvm_prog_t *prog = CLVM_prog;
4281 float dz, stepheight;
4282 vec3_t oldorg, neworg, end, traceendpos;
4283 vec3_t mins, maxs, start;
4286 prvm_edict_t *enemy;
4288 stepheight = sv_stepheight.value + PRVM_clientedictfloat(ent, stepheight_delta);
4291 VectorCopy(PRVM_clientedictvector(ent, mins), mins);
4292 VectorCopy(PRVM_clientedictvector(ent, maxs), maxs);
4293 VectorCopy (PRVM_clientedictvector(ent, origin), oldorg);
4294 VectorAdd (PRVM_clientedictvector(ent, origin), move, neworg);
4296 // flying monsters don't step up
4297 if ( (int)PRVM_clientedictfloat(ent, flags) & (FL_SWIM | FL_FLY) )
4299 // try one move with vertical motion, then one without
4300 for (i=0 ; i<2 ; i++)
4302 VectorAdd (PRVM_clientedictvector(ent, origin), move, neworg);
4303 enemy = PRVM_PROG_TO_EDICT(PRVM_clientedictedict(ent, enemy));
4304 if (i == 0 && enemy != prog->edicts)
4306 dz = PRVM_clientedictvector(ent, origin)[2] - PRVM_clientedictvector(PRVM_PROG_TO_EDICT(PRVM_clientedictedict(ent, enemy)), origin)[2];
4312 VectorCopy(PRVM_clientedictvector(ent, origin), start);
4313 trace = CL_TraceBox(start, mins, maxs, neworg, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, true, &svent, true);
4315 CL_VM_SetTraceGlobals(prog, &trace, svent);
4317 if (trace.fraction == 1)
4319 VectorCopy(trace.endpos, traceendpos);
4320 if (((int)PRVM_clientedictfloat(ent, flags) & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
4321 return false; // swim monster left water
4323 VectorCopy (traceendpos, PRVM_clientedictvector(ent, origin));
4329 if (enemy == prog->edicts)
4336 // push down from a step height above the wished position
4337 neworg[2] += stepheight;
4338 VectorCopy (neworg, end);
4339 end[2] -= stepheight*2;
4341 trace = CL_TraceBox(neworg, mins, maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, true, &svent, true);
4343 CL_VM_SetTraceGlobals(prog, &trace, svent);
4345 if (trace.startsolid)
4347 neworg[2] -= stepheight;
4348 trace = CL_TraceBox(neworg, mins, maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value, true, true, &svent, true);
4350 CL_VM_SetTraceGlobals(prog, &trace, svent);
4351 if (trace.startsolid)
4354 if (trace.fraction == 1)
4356 // if monster had the ground pulled out, go ahead and fall
4357 if ( (int)PRVM_clientedictfloat(ent, flags) & FL_PARTIALGROUND )
4359 VectorAdd (PRVM_clientedictvector(ent, origin), move, PRVM_clientedictvector(ent, origin));
4362 PRVM_clientedictfloat(ent, flags) = (int)PRVM_clientedictfloat(ent, flags) & ~FL_ONGROUND;
4366 return false; // walked off an edge
4369 // check point traces down for dangling corners
4370 VectorCopy (trace.endpos, PRVM_clientedictvector(ent, origin));
4372 if (!CL_CheckBottom (ent))
4374 if ( (int)PRVM_clientedictfloat(ent, flags) & FL_PARTIALGROUND )
4375 { // entity had floor mostly pulled out from underneath it
4376 // and is trying to correct
4381 VectorCopy (oldorg, PRVM_clientedictvector(ent, origin));
4385 if ( (int)PRVM_clientedictfloat(ent, flags) & FL_PARTIALGROUND )
4386 PRVM_clientedictfloat(ent, flags) = (int)PRVM_clientedictfloat(ent, flags) & ~FL_PARTIALGROUND;
4388 PRVM_clientedictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
4400 float(float yaw, float dist[, settrace]) walkmove
4403 static void VM_CL_walkmove (prvm_prog_t *prog)
4412 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
4414 // assume failure if it returns early
4415 PRVM_G_FLOAT(OFS_RETURN) = 0;
4417 ent = PRVM_PROG_TO_EDICT(PRVM_clientglobaledict(self));
4418 if (ent == prog->edicts)
4420 VM_Warning(prog, "walkmove: can not modify world entity\n");
4423 if (ent->priv.server->free)
4425 VM_Warning(prog, "walkmove: can not modify free entity\n");
4428 yaw = PRVM_G_FLOAT(OFS_PARM0);
4429 dist = PRVM_G_FLOAT(OFS_PARM1);
4430 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
4432 if ( !( (int)PRVM_clientedictfloat(ent, flags) & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
4435 yaw = yaw*M_PI*2 / 360;
4437 move[0] = cos(yaw)*dist;
4438 move[1] = sin(yaw)*dist;
4441 // save program state, because CL_movestep may call other progs
4442 oldf = prog->xfunction;
4443 oldself = PRVM_clientglobaledict(self);
4445 PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
4448 // restore program state
4449 prog->xfunction = oldf;
4450 PRVM_clientglobaledict(self) = oldself;
4457 string(string key) serverkey
4460 static void VM_CL_serverkey(prvm_prog_t *prog)
4462 char string[VM_STRINGTEMP_LENGTH];
4463 VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
4464 InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
4465 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
4472 Checks if an entity is in a point's PVS.
4473 Should be fast but can be inexact.
4475 float checkpvs(vector viewpos, entity viewee) = #240;
4478 static void VM_CL_checkpvs (prvm_prog_t *prog)
4481 prvm_edict_t *viewee;
4487 unsigned char fatpvs[MAX_MAP_LEAFS/8];
4490 VM_SAFEPARMCOUNT(2, VM_CL_checkpvs);
4491 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), viewpos);
4492 viewee = PRVM_G_EDICT(OFS_PARM1);
4494 if(viewee->priv.required->free)
4496 VM_Warning(prog, "checkpvs: can not check free entity\n");
4497 PRVM_G_FLOAT(OFS_RETURN) = 4;
4501 VectorAdd(PRVM_serveredictvector(viewee, origin), PRVM_serveredictvector(viewee, mins), mi);
4502 VectorAdd(PRVM_serveredictvector(viewee, origin), PRVM_serveredictvector(viewee, maxs), ma);
4505 if(!cl.worldmodel || !cl.worldmodel->brush.GetPVS || !cl.worldmodel->brush.BoxTouchingPVS)
4507 // no PVS support on this worldmodel... darn
4508 PRVM_G_FLOAT(OFS_RETURN) = 3;
4511 pvs = cl.worldmodel->brush.GetPVS(cl.worldmodel, viewpos);
4514 // viewpos isn't in any PVS... darn
4515 PRVM_G_FLOAT(OFS_RETURN) = 2;
4518 PRVM_G_FLOAT(OFS_RETURN) = cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, pvs, mi, ma);
4520 // using fat PVS like FTEQW does (slow)
4521 if(!cl.worldmodel || !cl.worldmodel->brush.FatPVS || !cl.worldmodel->brush.BoxTouchingPVS)
4523 // no PVS support on this worldmodel... darn
4524 PRVM_G_FLOAT(OFS_RETURN) = 3;
4527 fatpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, viewpos, 8, fatpvs, sizeof(fatpvs), false);
4530 // viewpos isn't in any PVS... darn
4531 PRVM_G_FLOAT(OFS_RETURN) = 2;
4534 PRVM_G_FLOAT(OFS_RETURN) = cl.worldmodel->brush.BoxTouchingPVS(cl.worldmodel, fatpvs, mi, ma);
4538 // #263 float(float modlindex) skel_create = #263; // (FTE_CSQC_SKELETONOBJECTS) create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex.
4539 static void VM_CL_skel_create(prvm_prog_t *prog)
4541 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
4542 model_t *model = CL_GetModelByIndex(modelindex);
4543 skeleton_t *skeleton;
4545 PRVM_G_FLOAT(OFS_RETURN) = 0;
4546 if (!model || !model->num_bones)
4548 for (i = 0;i < MAX_EDICTS;i++)
4549 if (!prog->skeletons[i])
4551 if (i == MAX_EDICTS)
4553 prog->skeletons[i] = skeleton = (skeleton_t *)Mem_Alloc(cls.levelmempool, sizeof(skeleton_t) + model->num_bones * sizeof(matrix4x4_t));
4554 PRVM_G_FLOAT(OFS_RETURN) = i + 1;
4555 skeleton->model = model;
4556 skeleton->relativetransforms = (matrix4x4_t *)(skeleton+1);
4557 // initialize to identity matrices
4558 for (i = 0;i < skeleton->model->num_bones;i++)
4559 skeleton->relativetransforms[i] = identitymatrix;
4562 // #264 float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // (FTE_CSQC_SKELETONOBJECTS) blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure
4563 static void VM_CL_skel_build(prvm_prog_t *prog)
4565 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4566 skeleton_t *skeleton;
4567 prvm_edict_t *ed = PRVM_G_EDICT(OFS_PARM1);
4568 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM2);
4569 float retainfrac = PRVM_G_FLOAT(OFS_PARM3);
4570 int firstbone = PRVM_G_FLOAT(OFS_PARM4) - 1;
4571 int lastbone = PRVM_G_FLOAT(OFS_PARM5) - 1;
4572 model_t *model = CL_GetModelByIndex(modelindex);
4576 framegroupblend_t framegroupblend[MAX_FRAMEGROUPBLENDS];
4577 frameblend_t frameblend[MAX_FRAMEBLENDS];
4578 matrix4x4_t bonematrix;
4580 PRVM_G_FLOAT(OFS_RETURN) = 0;
4581 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4583 firstbone = max(0, firstbone);
4584 lastbone = min(lastbone, model->num_bones - 1);
4585 lastbone = min(lastbone, skeleton->model->num_bones - 1);
4586 VM_GenerateFrameGroupBlend(prog, framegroupblend, ed);
4587 VM_FrameBlendFromFrameGroupBlend(frameblend, framegroupblend, model, cl.time);
4588 for (numblends = 0;numblends < MAX_FRAMEBLENDS && frameblend[numblends].lerp;numblends++)
4590 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
4592 memset(&bonematrix, 0, sizeof(bonematrix));
4593 for (blendindex = 0;blendindex < numblends;blendindex++)
4595 Matrix4x4_FromBonePose7s(&matrix, model->num_posescale, model->data_poses7s + 7 * (frameblend[blendindex].subframe * model->num_bones + bonenum));
4596 Matrix4x4_Accumulate(&bonematrix, &matrix, frameblend[blendindex].lerp);
4598 Matrix4x4_Normalize3(&bonematrix, &bonematrix);
4599 Matrix4x4_Interpolate(&skeleton->relativetransforms[bonenum], &bonematrix, &skeleton->relativetransforms[bonenum], retainfrac);
4601 PRVM_G_FLOAT(OFS_RETURN) = skeletonindex + 1;
4604 // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
4605 static void VM_CL_skel_get_numbones(prvm_prog_t *prog)
4607 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4608 skeleton_t *skeleton;
4609 PRVM_G_FLOAT(OFS_RETURN) = 0;
4610 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4612 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->num_bones;
4615 // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
4616 static void VM_CL_skel_get_bonename(prvm_prog_t *prog)
4618 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4619 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
4620 skeleton_t *skeleton;
4621 PRVM_G_INT(OFS_RETURN) = 0;
4622 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4624 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
4626 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, skeleton->model->data_bones[bonenum].name);
4629 // #267 float(float skel, float bonenum) skel_get_boneparent = #267; // (FTE_CSQC_SKELETONOBJECTS) returns parent num for supplied bonenum, 0 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this)
4630 static void VM_CL_skel_get_boneparent(prvm_prog_t *prog)
4632 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4633 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
4634 skeleton_t *skeleton;
4635 PRVM_G_FLOAT(OFS_RETURN) = 0;
4636 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4638 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
4640 PRVM_G_FLOAT(OFS_RETURN) = skeleton->model->data_bones[bonenum].parent + 1;
4643 // #268 float(float skel, string tagname) skel_find_bone = #268; // (FTE_CSQC_SKELETONOBJECTS) get number of bone with specified name, 0 on failure, tagindex (bonenum+1) on success, same as using gettagindex on the modelindex
4644 static void VM_CL_skel_find_bone(prvm_prog_t *prog)
4646 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4647 const char *tagname = PRVM_G_STRING(OFS_PARM1);
4648 skeleton_t *skeleton;
4649 PRVM_G_FLOAT(OFS_RETURN) = 0;
4650 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4652 PRVM_G_FLOAT(OFS_RETURN) = Mod_Alias_GetTagIndexForName(skeleton->model, 0, tagname);
4655 // #269 vector(float skel, float bonenum) skel_get_bonerel = #269; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone)
4656 static void VM_CL_skel_get_bonerel(prvm_prog_t *prog)
4658 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4659 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
4660 skeleton_t *skeleton;
4662 vec3_t forward, left, up, origin;
4663 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
4664 VectorClear(PRVM_clientglobalvector(v_forward));
4665 VectorClear(PRVM_clientglobalvector(v_right));
4666 VectorClear(PRVM_clientglobalvector(v_up));
4667 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4669 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
4671 matrix = skeleton->relativetransforms[bonenum];
4672 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
4673 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
4674 VectorNegate(left, PRVM_clientglobalvector(v_right));
4675 VectorCopy(up, PRVM_clientglobalvector(v_up));
4676 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
4679 // #270 vector(float skel, float bonenum) skel_get_boneabs = #270; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity)
4680 static void VM_CL_skel_get_boneabs(prvm_prog_t *prog)
4682 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4683 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
4684 skeleton_t *skeleton;
4687 vec3_t forward, left, up, origin;
4688 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
4689 VectorClear(PRVM_clientglobalvector(v_forward));
4690 VectorClear(PRVM_clientglobalvector(v_right));
4691 VectorClear(PRVM_clientglobalvector(v_up));
4692 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4694 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
4696 matrix = skeleton->relativetransforms[bonenum];
4697 // convert to absolute
4698 while ((bonenum = skeleton->model->data_bones[bonenum].parent) >= 0)
4701 Matrix4x4_Concat(&matrix, &skeleton->relativetransforms[bonenum], &temp);
4703 Matrix4x4_ToVectors(&matrix, forward, left, up, origin);
4704 VectorCopy(forward, PRVM_clientglobalvector(v_forward));
4705 VectorNegate(left, PRVM_clientglobalvector(v_right));
4706 VectorCopy(up, PRVM_clientglobalvector(v_up));
4707 VectorCopy(origin, PRVM_G_VECTOR(OFS_RETURN));
4710 // #271 void(float skel, float bonenum, vector org) skel_set_bone = #271; // (FTE_CSQC_SKELETONOBJECTS) set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
4711 static void VM_CL_skel_set_bone(prvm_prog_t *prog)
4713 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4714 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
4715 vec3_t forward, left, up, origin;
4716 skeleton_t *skeleton;
4718 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4720 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
4722 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
4723 VectorNegate(PRVM_clientglobalvector(v_right), left);
4724 VectorCopy(PRVM_clientglobalvector(v_up), up);
4725 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
4726 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
4727 skeleton->relativetransforms[bonenum] = matrix;
4730 // #272 void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
4731 static void VM_CL_skel_mul_bone(prvm_prog_t *prog)
4733 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4734 int bonenum = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
4735 vec3_t forward, left, up, origin;
4736 skeleton_t *skeleton;
4739 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4741 if (bonenum < 0 || bonenum >= skeleton->model->num_bones)
4743 VectorCopy(PRVM_G_VECTOR(OFS_PARM2), origin);
4744 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
4745 VectorNegate(PRVM_clientglobalvector(v_right), left);
4746 VectorCopy(PRVM_clientglobalvector(v_up), up);
4747 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
4748 temp = skeleton->relativetransforms[bonenum];
4749 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
4752 // #273 void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones)
4753 static void VM_CL_skel_mul_bones(prvm_prog_t *prog)
4755 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4756 int firstbone = PRVM_G_FLOAT(OFS_PARM1) - 1;
4757 int lastbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
4759 vec3_t forward, left, up, origin;
4760 skeleton_t *skeleton;
4763 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4765 VectorCopy(PRVM_G_VECTOR(OFS_PARM3), origin);
4766 VectorCopy(PRVM_clientglobalvector(v_forward), forward);
4767 VectorNegate(PRVM_clientglobalvector(v_right), left);
4768 VectorCopy(PRVM_clientglobalvector(v_up), up);
4769 Matrix4x4_FromVectors(&matrix, forward, left, up, origin);
4770 firstbone = max(0, firstbone);
4771 lastbone = min(lastbone, skeleton->model->num_bones - 1);
4772 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
4774 temp = skeleton->relativetransforms[bonenum];
4775 Matrix4x4_Concat(&skeleton->relativetransforms[bonenum], &matrix, &temp);
4779 // #274 void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // (FTE_CSQC_SKELETONOBJECTS) copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse
4780 static void VM_CL_skel_copybones(prvm_prog_t *prog)
4782 int skeletonindexdst = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4783 int skeletonindexsrc = (int)PRVM_G_FLOAT(OFS_PARM1) - 1;
4784 int firstbone = PRVM_G_FLOAT(OFS_PARM2) - 1;
4785 int lastbone = PRVM_G_FLOAT(OFS_PARM3) - 1;
4787 skeleton_t *skeletondst;
4788 skeleton_t *skeletonsrc;
4789 if (skeletonindexdst < 0 || skeletonindexdst >= MAX_EDICTS || !(skeletondst = prog->skeletons[skeletonindexdst]))
4791 if (skeletonindexsrc < 0 || skeletonindexsrc >= MAX_EDICTS || !(skeletonsrc = prog->skeletons[skeletonindexsrc]))
4793 firstbone = max(0, firstbone);
4794 lastbone = min(lastbone, skeletondst->model->num_bones - 1);
4795 lastbone = min(lastbone, skeletonsrc->model->num_bones - 1);
4796 for (bonenum = firstbone;bonenum <= lastbone;bonenum++)
4797 skeletondst->relativetransforms[bonenum] = skeletonsrc->relativetransforms[bonenum];
4800 // #275 void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS) deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work)
4801 static void VM_CL_skel_delete(prvm_prog_t *prog)
4803 int skeletonindex = (int)PRVM_G_FLOAT(OFS_PARM0) - 1;
4804 skeleton_t *skeleton;
4805 if (skeletonindex < 0 || skeletonindex >= MAX_EDICTS || !(skeleton = prog->skeletons[skeletonindex]))
4808 prog->skeletons[skeletonindex] = NULL;
4811 // #276 float(float modlindex, string framename) frameforname = #276; // (FTE_CSQC_SKELETONOBJECTS) finds number of a specified frame in the animation, returns -1 if no match found
4812 static void VM_CL_frameforname(prvm_prog_t *prog)
4814 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
4815 model_t *model = CL_GetModelByIndex(modelindex);
4816 const char *name = PRVM_G_STRING(OFS_PARM1);
4818 PRVM_G_FLOAT(OFS_RETURN) = -1;
4819 if (!model || !model->animscenes)
4821 for (i = 0;i < model->numframes;i++)
4823 if (!strcasecmp(model->animscenes[i].name, name))
4825 PRVM_G_FLOAT(OFS_RETURN) = i;
4831 // #277 float(float modlindex, float framenum) frameduration = #277; // (FTE_CSQC_SKELETONOBJECTS) returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0.
4832 static void VM_CL_frameduration(prvm_prog_t *prog)
4834 int modelindex = (int)PRVM_G_FLOAT(OFS_PARM0);
4835 model_t *model = CL_GetModelByIndex(modelindex);
4836 int framenum = (int)PRVM_G_FLOAT(OFS_PARM1);
4837 PRVM_G_FLOAT(OFS_RETURN) = 0;
4838 if (!model || !model->animscenes || framenum < 0 || framenum >= model->numframes)
4840 if (model->animscenes[framenum].framerate)
4841 PRVM_G_FLOAT(OFS_RETURN) = model->animscenes[framenum].framecount / model->animscenes[framenum].framerate;
4844 static void VM_CL_RotateMoves(prvm_prog_t *prog)
4847 * Obscure builtin used by GAME_XONOTIC.
4849 * Edits the input history of cl_movement by rotating all move commands
4850 * currently in the queue using the given transform.
4852 * The vector passed is an "angles transform" as used by warpzonelib, i.e.
4853 * v_angle-like (non-inverted) euler angles that perform the rotation
4854 * of the space that is to be done.
4856 * This is meant to be used as a fixangle replacement after passing
4857 * through a warpzone/portal: the client is told about the warp transform,
4858 * and calls this function in the same frame as the one on which the
4859 * client's origin got changed by the serverside teleport. Then this code
4860 * transforms the pre-warp input (which matches the empty space behind
4861 * the warp plane) into post-warp input (which matches the target area
4862 * of the warp). Also, at the same time, the client has to use
4863 * R_SetView to adjust VF_CL_VIEWANGLES according to the same transform.
4865 * This together allows warpzone motion to be perfectly predicted by
4868 * Furthermore, for perfect warpzone behaviour, the server side also
4869 * has to detect input the client sent before it received the origin
4870 * update, but after the warp occurred on the server, and has to adjust
4871 * input appropriately.
4874 vec3_t v = {0, 0, 0};
4876 VM_SAFEPARMCOUNT(1, VM_CL_RotateMoves);
4877 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), a);
4878 AngleVectorsFLU(a, x, y, z);
4879 Matrix4x4_FromVectors(&m, x, y, z, v);
4883 // #358 void(string cubemapname) loadcubemap
4884 static void VM_CL_loadcubemap(prvm_prog_t *prog)
4888 VM_SAFEPARMCOUNT(1, VM_CL_loadcubemap);
4889 name = PRVM_G_STRING(OFS_PARM0);
4893 #define REFDEFFLAG_TELEPORTED 1
4894 #define REFDEFFLAG_JUMPING 2
4895 #define REFDEFFLAG_DEAD 4
4896 #define REFDEFFLAG_INTERMISSION 8
4897 static void VM_CL_V_CalcRefdef(prvm_prog_t *prog)
4899 matrix4x4_t entrendermatrix;
4900 vec3_t clviewangles;
4906 float clstatsviewheight;
4910 VM_SAFEPARMCOUNT(2, VM_CL_V_CalcRefdef);
4911 ent = PRVM_G_EDICT(OFS_PARM0);
4912 flags = PRVM_G_FLOAT(OFS_PARM1);
4914 // use the CL_GetTagMatrix function on self to ensure consistent behavior (duplicate code would be bad)
4915 CL_GetTagMatrix(prog, &entrendermatrix, ent, 0, NULL);
4917 VectorCopy(cl.csqc_viewangles, clviewangles);
4918 teleported = (flags & REFDEFFLAG_TELEPORTED) != 0;
4919 clonground = ((int)PRVM_clientedictfloat(ent, pmove_flags) & PMF_ONGROUND) != 0;
4920 clcmdjump = (flags & REFDEFFLAG_JUMPING) != 0;
4921 clstatsviewheight = PRVM_clientedictvector(ent, view_ofs)[2];
4922 cldead = (flags & REFDEFFLAG_DEAD) != 0;
4923 cl.intermission = (flags & REFDEFFLAG_INTERMISSION) != 0;
4924 VectorCopy(PRVM_clientedictvector(ent, velocity), clvelocity);
4926 V_CalcRefdefUsing(&entrendermatrix, clviewangles, teleported, clonground, clcmdjump, clstatsviewheight, cldead, clvelocity);
4928 VectorCopy(cl.csqc_vieworiginfromengine, cl.csqc_vieworigin);
4929 VectorCopy(cl.csqc_viewanglesfromengine, cl.csqc_viewangles);
4930 CSQC_R_RecalcView();
4933 //============================================================================
4935 // To create a almost working builtin file from this replace:
4936 // "^NULL.*" with ""
4937 // "^{.*//.*}:Wh\(.*\)" with "\1"
4939 // "^.*//:Wh{\#:d*}:Wh{.*}" with "\2 = \1;"
4940 // "\n\n+" with "\n\n"
4942 prvm_builtin_t vm_cl_builtins[] = {
4943 NULL, // #0 NULL function (not callable) (QUAKE)
4944 VM_CL_makevectors, // #1 void(vector ang) makevectors (QUAKE)
4945 VM_CL_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
4946 VM_CL_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
4947 VM_CL_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
4948 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
4949 VM_break, // #6 void() break (QUAKE)
4950 VM_random, // #7 float() random (QUAKE)
4951 VM_CL_sound, // #8 void(entity e, float chan, string samp, float volume, float atten[, float pitchchange[, float flags]]) sound (QUAKE)
4952 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
4953 VM_error, // #10 void(string e) error (QUAKE)
4954 VM_objerror, // #11 void(string e) objerror (QUAKE)
4955 VM_vlen, // #12 float(vector v) vlen (QUAKE)
4956 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
4957 VM_CL_spawn, // #14 entity() spawn (QUAKE)
4958 VM_remove, // #15 void(entity e) remove (QUAKE)
4959 VM_CL_traceline, // #16 void(vector v1, vector v2, float tryents, entity ignoreentity) traceline (QUAKE)
4960 NULL, // #17 entity() checkclient (QUAKE)
4961 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
4962 VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
4963 VM_CL_precache_model, // #20 void(string s) precache_model (QUAKE)
4964 NULL, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
4965 VM_CL_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
4966 NULL, // #23 void(string s, ...) bprint (QUAKE)
4967 NULL, // #24 void(entity client, string s, ...) sprint (QUAKE)
4968 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
4969 VM_ftos, // #26 string(float f) ftos (QUAKE)
4970 VM_vtos, // #27 string(vector v) vtos (QUAKE)
4971 VM_coredump, // #28 void() coredump (QUAKE)
4972 VM_traceon, // #29 void() traceon (QUAKE)
4973 VM_traceoff, // #30 void() traceoff (QUAKE)
4974 VM_eprint, // #31 void(entity e) eprint (QUAKE)
4975 VM_CL_walkmove, // #32 float(float yaw, float dist[, float settrace]) walkmove (QUAKE)
4976 NULL, // #33 (QUAKE)
4977 VM_CL_droptofloor, // #34 float() droptofloor (QUAKE)
4978 VM_CL_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
4979 VM_rint, // #36 float(float v) rint (QUAKE)
4980 VM_floor, // #37 float(float v) floor (QUAKE)
4981 VM_ceil, // #38 float(float v) ceil (QUAKE)
4982 NULL, // #39 (QUAKE)
4983 VM_CL_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
4984 VM_CL_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
4985 NULL, // #42 (QUAKE)
4986 VM_fabs, // #43 float(float f) fabs (QUAKE)
4987 NULL, // #44 vector(entity e, float speed) aim (QUAKE)
4988 VM_cvar, // #45 float(string s) cvar (QUAKE)
4989 VM_localcmd_local, // #46 void(string s) localcmd (QUAKE)
4990 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
4991 VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
4992 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
4993 NULL, // #50 (QUAKE)
4994 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
4995 NULL, // #52 void(float to, float f) WriteByte (QUAKE)
4996 NULL, // #53 void(float to, float f) WriteChar (QUAKE)
4997 NULL, // #54 void(float to, float f) WriteShort (QUAKE)
4998 NULL, // #55 void(float to, float f) WriteLong (QUAKE)
4999 NULL, // #56 void(float to, float f) WriteCoord (QUAKE)
5000 NULL, // #57 void(float to, float f) WriteAngle (QUAKE)
5001 NULL, // #58 void(float to, string s) WriteString (QUAKE)
5002 NULL, // #59 (QUAKE)
5003 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
5004 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
5005 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
5006 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
5007 VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
5008 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
5009 NULL, // #66 (QUAKE)
5010 NULL, // #67 void(float step) movetogoal (QUAKE)
5011 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
5012 VM_CL_makestatic, // #69 void(entity e) makestatic (QUAKE)
5013 NULL, // #70 void(string s) changelevel (QUAKE)
5014 NULL, // #71 (QUAKE)
5015 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
5016 NULL, // #73 void(entity client, strings) centerprint (QUAKE)
5017 VM_CL_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
5018 VM_CL_precache_model, // #75 string(string s) precache_model2 (QUAKE)
5019 VM_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
5020 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
5021 NULL, // #78 void(entity e) setspawnparms (QUAKE)
5022 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
5023 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
5024 VM_stof, // #81 float(string s) stof (FRIK_FILE)
5025 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
5026 NULL, // #83 (QUAKE)
5027 NULL, // #84 (QUAKE)
5028 NULL, // #85 (QUAKE)
5029 NULL, // #86 (QUAKE)
5030 NULL, // #87 (QUAKE)
5031 NULL, // #88 (QUAKE)
5032 NULL, // #89 (QUAKE)
5033 VM_CL_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
5034 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
5035 VM_CL_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
5036 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
5037 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
5038 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
5039 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
5040 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
5041 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
5042 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
5043 // FrikaC and Telejano range #100-#199
5054 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
5055 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
5056 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
5057 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
5058 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
5059 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
5060 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
5061 VM_stov, // #117 vector(string) stov (FRIK_FILE)
5062 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
5063 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
5144 // FTEQW range #200-#299
5163 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
5166 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
5167 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
5168 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
5169 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
5170 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
5171 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
5172 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
5173 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
5174 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
5175 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
5177 NULL, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
5185 VM_CL_checkpvs, // #240
5208 VM_CL_skel_create, // #263 float(float modlindex) skel_create = #263; // (FTE_CSQC_SKELETONOBJECTS) create a skeleton (be sure to assign this value into .skeletonindex for use), returns skeleton index (1 or higher) on success, returns 0 on failure (for example if the modelindex is not skeletal), it is recommended that you create a new skeleton if you change modelindex.
5209 VM_CL_skel_build, // #264 float(float skel, entity ent, float modlindex, float retainfrac, float firstbone, float lastbone) skel_build = #264; // (FTE_CSQC_SKELETONOBJECTS) blend in a percentage of standard animation, 0 replaces entirely, 1 does nothing, 0.5 blends half, etc, and this only alters the bones in the specified range for which out of bounds values like 0,100000 are safe (uses .frame, .frame2, .frame3, .frame4, .lerpfrac, .lerpfrac3, .lerpfrac4, .frame1time, .frame2time, .frame3time, .frame4time), returns skel on success, 0 on failure
5210 VM_CL_skel_get_numbones, // #265 float(float skel) skel_get_numbones = #265; // (FTE_CSQC_SKELETONOBJECTS) returns how many bones exist in the created skeleton
5211 VM_CL_skel_get_bonename, // #266 string(float skel, float bonenum) skel_get_bonename = #266; // (FTE_CSQC_SKELETONOBJECTS) returns name of bone (as a tempstring)
5212 VM_CL_skel_get_boneparent, // #267 float(float skel, float bonenum) skel_get_boneparent = #267; // (FTE_CSQC_SKELETONOBJECTS) returns parent num for supplied bonenum, -1 if bonenum has no parent or bone does not exist (returned value is always less than bonenum, you can loop on this)
5213 VM_CL_skel_find_bone, // #268 float(float skel, string tagname) skel_find_bone = #268; // (FTE_CSQC_SKELETONOBJECTS) get number of bone with specified name, 0 on failure, tagindex (bonenum+1) on success, same as using gettagindex on the modelindex
5214 VM_CL_skel_get_bonerel, // #269 vector(float skel, float bonenum) skel_get_bonerel = #269; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton relative to its parent - sets v_forward, v_right, v_up, returns origin (relative to parent bone)
5215 VM_CL_skel_get_boneabs, // #270 vector(float skel, float bonenum) skel_get_boneabs = #270; // (FTE_CSQC_SKELETONOBJECTS) get matrix of bone in skeleton in model space - sets v_forward, v_right, v_up, returns origin (relative to entity)
5216 VM_CL_skel_set_bone, // #271 void(float skel, float bonenum, vector org) skel_set_bone = #271; // (FTE_CSQC_SKELETONOBJECTS) set matrix of bone relative to its parent, reads v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
5217 VM_CL_skel_mul_bone, // #272 void(float skel, float bonenum, vector org) skel_mul_bone = #272; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrix (relative to its parent) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bone)
5218 VM_CL_skel_mul_bones, // #273 void(float skel, float startbone, float endbone, vector org) skel_mul_bones = #273; // (FTE_CSQC_SKELETONOBJECTS) transform bone matrices (relative to their parents) by the supplied matrix in v_forward, v_right, v_up, takes origin as parameter (relative to parent bones)
5219 VM_CL_skel_copybones, // #274 void(float skeldst, float skelsrc, float startbone, float endbone) skel_copybones = #274; // (FTE_CSQC_SKELETONOBJECTS) copy bone matrices (relative to their parents) from one skeleton to another, useful for copying a skeleton to a corpse
5220 VM_CL_skel_delete, // #275 void(float skel) skel_delete = #275; // (FTE_CSQC_SKELETONOBJECTS) deletes skeleton at the beginning of the next frame (you can add the entity, delete the skeleton, renderscene, and it will still work)
5221 VM_CL_frameforname, // #276 float(float modlindex, string framename) frameforname = #276; // (FTE_CSQC_SKELETONOBJECTS) finds number of a specified frame in the animation, returns -1 if no match found
5222 VM_CL_frameduration, // #277 float(float modlindex, float framenum) frameduration = #277; // (FTE_CSQC_SKELETONOBJECTS) returns the intended play time (in seconds) of the specified framegroup, if it does not exist the result is 0, if it is a single frame it may be a small value around 0.1 or 0.
5245 // CSQC range #300-#399
5246 VM_CL_R_ClearScene, // #300 void() clearscene (EXT_CSQC)
5247 VM_CL_R_AddEntities, // #301 void(float mask) addentities (EXT_CSQC)
5248 VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC)
5249 VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC)
5250 VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC)
5251 VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
5252 VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag, float is2d[NYI: , float lines]) R_BeginPolygon
5253 VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
5254 VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon
5255 VM_CL_R_SetView, // #309 float(float property) getproperty (EXT_CSQC)
5256 VM_CL_unproject, // #310 vector (vector v) cs_unproject (EXT_CSQC)
5257 VM_CL_project, // #311 vector (vector v) cs_project (EXT_CSQC)
5261 VM_drawline, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
5262 VM_iscachedpic, // #316 float(string name) iscachedpic (EXT_CSQC)
5263 VM_precache_pic, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
5264 VM_getimagesize, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
5265 VM_freepic, // #319 void(string name) freepic (EXT_CSQC)
5266 VM_drawcharacter, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
5267 VM_drawstring, // #321 float(vector position, string text, vector scale, vector rgb, float alpha[, float flag]) drawstring (EXT_CSQC, DP_CSQC)
5268 VM_drawpic, // #322 float(vector position, string pic, vector size, vector rgb, float alpha[, float flag]) drawpic (EXT_CSQC)
5269 VM_drawfill, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
5270 VM_drawsetcliparea, // #324 void(float x, float y, float width, float height) drawsetcliparea
5271 VM_drawresetcliparea, // #325 void(void) drawresetcliparea
5272 VM_drawcolorcodedstring, // #326 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) (EXT_CSQC)
5273 VM_stringwidth, // #327 // FIXME is this okay?
5274 VM_drawsubpic, // #328 // FIXME is this okay?
5275 VM_drawrotpic, // #329 // FIXME is this okay?
5276 VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
5277 VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
5278 VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
5279 VM_CL_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
5280 VM_CL_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
5281 VM_CL_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
5282 VM_CL_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
5283 VM_CL_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
5284 VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC)
5285 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
5286 VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC)
5287 VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
5288 VM_getkeybind, // #342 string(float keynum[, float bindmap]) getkeybind (EXT_CSQC)
5289 VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (DP_CSQC)
5290 VM_CL_getmousepos, // #344 vector() getmousepos (DP_CSQC)
5291 VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC)
5292 VM_CL_setsensitivityscale, // #346 void(float sens) setsensitivityscale (EXT_CSQC)
5293 VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC)
5294 VM_CL_getplayerkey, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
5295 VM_CL_isdemo, // #349 float() isdemo (EXT_CSQC)
5296 VM_isserver, // #350 float() isserver (EXT_CSQC)
5297 VM_CL_setlistener, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
5298 VM_CL_registercmd, // #352 void(string cmdname) registercommand (EXT_CSQC)
5299 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
5300 VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
5301 VM_CL_videoplaying, // #355
5302 VM_findfont, // #356 float(string fontname) loadfont (DP_GFX_FONTS)
5303 VM_loadfont, // #357 float(string fontname, string fontmaps, string sizes, float slot) loadfont (DP_GFX_FONTS)
5304 VM_CL_loadcubemap, // #358 void(string cubemapname) loadcubemap (DP_GFX_)
5306 VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC)
5307 VM_CL_ReadChar, // #361 float() readchar (EXT_CSQC)
5308 VM_CL_ReadShort, // #362 float() readshort (EXT_CSQC)
5309 VM_CL_ReadLong, // #363 float() readlong (EXT_CSQC)
5310 VM_CL_ReadCoord, // #364 float() readcoord (EXT_CSQC)
5311 VM_CL_ReadAngle, // #365 float() readangle (EXT_CSQC)
5312 VM_CL_ReadString, // #366 string() readstring (EXT_CSQC)
5313 VM_CL_ReadFloat, // #367 float() readfloat (EXT_CSQC)
5346 // LadyHavoc's range #400-#499
5347 VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
5348 NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
5349 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
5350 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
5351 VM_CL_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
5352 VM_CL_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
5353 VM_CL_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
5354 VM_CL_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
5355 VM_CL_te_particlecube, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
5356 VM_CL_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
5357 VM_CL_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
5358 VM_CL_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
5359 VM_CL_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
5360 VM_CL_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
5361 VM_CL_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
5362 VM_CL_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
5363 VM_CL_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
5364 VM_CL_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
5365 VM_CL_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
5366 VM_CL_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
5367 VM_CL_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
5368 VM_CL_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
5369 VM_CL_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
5370 VM_CL_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
5371 VM_CL_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
5372 VM_CL_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
5373 VM_CL_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
5374 VM_CL_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
5375 VM_CL_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
5376 VM_CL_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
5377 VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
5378 VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
5379 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
5380 VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
5381 VM_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
5382 VM_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
5383 VM_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
5384 VM_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
5385 VM_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
5386 VM_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
5387 NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
5388 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
5389 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
5390 VM_CL_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
5391 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
5392 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
5393 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
5394 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
5395 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
5396 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
5397 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
5398 VM_CL_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
5399 VM_CL_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
5400 NULL, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
5401 NULL, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
5402 NULL, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
5403 NULL, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
5404 VM_CL_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet (DP_TE_FLAMEJET)
5406 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
5407 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
5408 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
5409 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
5410 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
5411 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
5412 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
5413 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
5414 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
5415 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
5416 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
5417 NULL, // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
5418 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
5419 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
5420 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
5421 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
5422 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
5423 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
5424 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
5425 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
5426 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
5427 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
5428 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
5429 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
5430 VM_CL_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) pointsound (DP_SV_POINTSOUND)
5431 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
5432 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
5433 VM_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute
5434 VM_gecko_create, // #487 float gecko_create( string name )
5435 VM_gecko_destroy, // #488 void gecko_destroy( string name )
5436 VM_gecko_navigate, // #489 void gecko_navigate( string name, string URI )
5437 VM_gecko_keyevent, // #490 float gecko_keyevent( string name, float key, float eventtype )
5438 VM_gecko_movemouse, // #491 void gecko_mousemove( string name, float x, float y )
5439 VM_gecko_resize, // #492 void gecko_resize( string name, float w, float h )
5440 VM_gecko_get_texture_extent, // #493 vector gecko_get_texture_extent( string name )
5441 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
5442 VM_cvar_type, // #495 float(string name) cvar_type = #495; (DP_QC_CVAR_TYPE)
5443 VM_numentityfields, // #496 float() numentityfields = #496; (QP_QC_ENTITYDATA)
5444 VM_entityfieldname, // #497 string(float fieldnum) entityfieldname = #497; (DP_QC_ENTITYDATA)
5445 VM_entityfieldtype, // #498 float(float fieldnum) entityfieldtype = #498; (DP_QC_ENTITYDATA)
5446 VM_getentityfieldstring, // #499 string(float fieldnum, entity ent) getentityfieldstring = #499; (DP_QC_ENTITYDATA)
5447 VM_putentityfieldstring, // #500 float(float fieldnum, entity ent, string s) putentityfieldstring = #500; (DP_QC_ENTITYDATA)
5448 VM_CL_ReadPicture, // #501 string() ReadPicture = #501;
5449 VM_CL_boxparticles, // #502 void(float effectnum, entity own, vector origin_from, vector origin_to, vector dir_from, vector dir_to, float count) boxparticles (DP_CSQC_BOXPARTICLES)
5450 VM_whichpack, // #503 string(string) whichpack = #503;
5451 VM_CL_GetEntity, // #504 float(float entitynum, float fldnum) getentity = #504; vector(float entitynum, float fldnum) getentityvec = #504;
5457 VM_uri_escape, // #510 string(string in) uri_escape = #510;
5458 VM_uri_unescape, // #511 string(string in) uri_unescape = #511;
5459 VM_etof, // #512 float(entity ent) num_for_edict = #512 (DP_QC_NUM_FOR_EDICT)
5460 VM_uri_get, // #513 float(string uri, float id, [string post_contenttype, string post_delim, [float buf]]) uri_get = #513; (DP_QC_URI_GET, DP_QC_URI_POST)
5461 VM_tokenize_console, // #514 float(string str) tokenize_console = #514; (DP_QC_TOKENIZE_CONSOLE)
5462 VM_argv_start_index, // #515 float(float idx) argv_start_index = #515; (DP_QC_TOKENIZE_CONSOLE)
5463 VM_argv_end_index, // #516 float(float idx) argv_end_index = #516; (DP_QC_TOKENIZE_CONSOLE)
5464 VM_buf_cvarlist, // #517 void(float buf, string prefix, string antiprefix) buf_cvarlist = #517; (DP_QC_STRINGBUFFERS_CVARLIST)
5465 VM_cvar_description, // #518 float(string name) cvar_description = #518; (DP_QC_CVAR_DESCRIPTION)
5466 VM_gettime, // #519 float(float timer) gettime = #519; (DP_QC_GETTIME)
5467 VM_keynumtostring, // #520 string keynumtostring(float keynum)
5468 VM_findkeysforcommand, // #521 string findkeysforcommand(string command[, float bindmap])
5469 VM_CL_InitParticleSpawner, // #522 void(float max_themes) initparticlespawner (DP_CSQC_SPAWNPARTICLE)
5470 VM_CL_ResetParticle, // #523 void() resetparticle (DP_CSQC_SPAWNPARTICLE)
5471 VM_CL_ParticleTheme, // #524 void(float theme) particletheme (DP_CSQC_SPAWNPARTICLE)
5472 VM_CL_ParticleThemeSave, // #525 void() particlethemesave, void(float theme) particlethemeupdate (DP_CSQC_SPAWNPARTICLE)
5473 VM_CL_ParticleThemeFree, // #526 void() particlethemefree (DP_CSQC_SPAWNPARTICLE)
5474 VM_CL_SpawnParticle, // #527 float(vector org, vector vel, [float theme]) particle (DP_CSQC_SPAWNPARTICLE)
5475 VM_CL_SpawnParticleDelayed, // #528 float(vector org, vector vel, float delay, float collisiondelay, [float theme]) delayedparticle (DP_CSQC_SPAWNPARTICLE)
5476 VM_loadfromdata, // #529
5477 VM_loadfromfile, // #530
5478 VM_CL_setpause, // #531 float(float ispaused) setpause = #531 (DP_CSQC_SETPAUSE)
5480 VM_getsoundtime, // #533 float(entity e, float channel) getsoundtime = #533; (DP_SND_GETSOUNDTIME)
5481 VM_soundlength, // #534 float(string sample) soundlength = #534; (DP_SND_GETSOUNDTIME)
5482 VM_buf_loadfile, // #535 float(string filename, float bufhandle) buf_loadfile (DP_QC_STRINGBUFFERS_EXT_WIP)
5483 VM_buf_writefile, // #536 float(float filehandle, float bufhandle, float startpos, float numstrings) buf_writefile (DP_QC_STRINGBUFFERS_EXT_WIP)
5484 VM_bufstr_find, // #537 float(float bufhandle, string match, float matchrule, float startpos) bufstr_find (DP_QC_STRINGBUFFERS_EXT_WIP)
5485 VM_matchpattern, // #538 float(string s, string pattern, float matchrule) matchpattern (DP_QC_STRINGBUFFERS_EXT_WIP)
5487 VM_physics_enable, // #540 void(entity e, float physics_enabled) physics_enable = #540; (DP_PHYSICS_ODE)
5488 VM_physics_addforce, // #541 void(entity e, vector force, vector relative_ofs) physics_addforce = #541; (DP_PHYSICS_ODE)
5489 VM_physics_addtorque, // #542 void(entity e, vector torque) physics_addtorque = #542; (DP_PHYSICS_ODE)
5552 VM_callfunction, // #605
5553 VM_writetofile, // #606
5554 VM_isfunction, // #607
5557 VM_findkeysforcommand, // #610 string findkeysforcommand(string command[, float bindmap])
5560 VM_parseentitydata, // #613
5571 VM_CL_getextresponse, // #624 string getextresponse(void)
5574 VM_sprintf, // #627 string sprintf(string format, ...)
5575 VM_getsurfacenumtriangles, // #628 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACETRIANGLE)
5576 VM_getsurfacetriangle, // #629 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACETRIANGLE)
5577 VM_setkeybind, // #630 float(float key, string bind[, float bindmap]) setkeybind
5578 VM_getbindmaps, // #631 vector(void) getbindmap
5579 VM_setbindmaps, // #632 float(vector bm) setbindmap
5585 VM_CL_RotateMoves, // #638
5586 VM_digest_hex, // #639
5587 VM_CL_V_CalcRefdef, // #640 void(entity e) V_CalcRefdef (DP_CSQC_V_CALCREFDEF)
5589 VM_coverage, // #642
5597 // WRATH range (#650-#???)
5598 VM_fcopy, // #650 float(string fnfrom, string fnto) fcopy (EXT_WRATH)
5599 VM_frename, // #651 float (string fnold, string fnnew) frename (EXT_WRATH)
5600 VM_fremove, // #652 float (string fname) fremove (EXT_WRATH)
5601 VM_fexists, // #653 float (string fname) fexists (EXT_WRATH)
5602 VM_rmtree, // #654 float (string path) rmtree (EXT_WRATH)
5701 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
5703 void CLVM_init_cmd(prvm_prog_t *prog)
5706 prog->polygonbegin_model = NULL;
5707 prog->polygonbegin_guess2d = 0;
5710 void CLVM_reset_cmd(prvm_prog_t *prog)
5712 World_End(&cl.world);
5714 prog->polygonbegin_model = NULL;
5715 prog->polygonbegin_guess2d = 0;