5 #include "cl_collision.h"
8 //============================================================================
10 //[515]: unsolved PROBLEMS
11 //- finish player physics code (cs_runplayerphysics)
13 //- RF_DEPTHHACK is not like it should be
14 //- add builtin that sets cl.viewangles instead of reading "input_angles" global
15 //- finish lines support for R_Polygon***
16 //- insert selecttraceline into traceline somehow
18 //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)
19 //4 feature darkplaces csqc: add builtins to clientside qc for gl calls
21 sfx_t *S_FindName(const char *name);
22 int Sbar_GetPlayer (int index);
23 void Sbar_SortFrags (void);
24 void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius);
25 void CSQC_RelinkAllEntities (int drawmask);
26 void CSQC_RelinkCSQCEntities (void);
27 const char *Key_GetBind (int key);
29 // #1 void(vector ang) makevectors
30 static void VM_CL_makevectors (void)
32 VM_SAFEPARMCOUNT(1, VM_CL_makevectors);
33 AngleVectors (PRVM_G_VECTOR(OFS_PARM0), prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up);
36 // #2 void(entity e, vector o) setorigin
37 void VM_CL_setorigin (void)
41 VM_SAFEPARMCOUNT(2, VM_CL_setorigin);
43 e = PRVM_G_EDICT(OFS_PARM0);
44 if (e == prog->edicts)
46 VM_Warning("setorigin: can not modify world entity\n");
49 if (e->priv.required->free)
51 VM_Warning("setorigin: can not modify free entity\n");
54 org = PRVM_G_VECTOR(OFS_PARM1);
55 VectorCopy (org, e->fields.client->origin);
59 static void SetMinMaxSize (prvm_edict_t *e, float *min, float *max)
65 PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
68 VectorCopy (min, e->fields.client->mins);
69 VectorCopy (max, e->fields.client->maxs);
70 VectorSubtract (max, min, e->fields.client->size);
75 // #3 void(entity e, string m) setmodel
76 void VM_CL_setmodel (void)
83 VM_SAFEPARMCOUNT(2, VM_CL_setmodel);
85 e = PRVM_G_EDICT(OFS_PARM0);
86 m = PRVM_G_STRING(OFS_PARM1);
87 for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
89 if (!strcmp(cl.csqc_model_precache[i]->name, m))
91 e->fields.client->model = PRVM_SetEngineString(cl.csqc_model_precache[i]->name);
92 e->fields.client->modelindex = -(i+1);
97 for (i = 0;i < MAX_MODELS;i++)
99 mod = cl.model_precache[i];
100 if (mod && !strcmp(mod->name, m))
102 e->fields.client->model = PRVM_SetEngineString(mod->name);
103 e->fields.client->modelindex = i;
108 e->fields.client->modelindex = 0;
109 e->fields.client->model = 0;
110 VM_Warning ("setmodel: model '%s' not precached\n", m);
112 // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black]
115 SetMinMaxSize (e, mod->normalmins, mod->normalmaxs);
118 SetMinMaxSize (e, vec3_origin, vec3_origin);
121 // #4 void(entity e, vector min, vector max) setsize
122 static void VM_CL_setsize (void)
126 VM_SAFEPARMCOUNT(3, VM_CL_setsize);
128 e = PRVM_G_EDICT(OFS_PARM0);
129 if (e == prog->edicts)
131 VM_Warning("setsize: can not modify world entity\n");
134 if (e->priv.server->free)
136 VM_Warning("setsize: can not modify free entity\n");
139 min = PRVM_G_VECTOR(OFS_PARM1);
140 max = PRVM_G_VECTOR(OFS_PARM2);
142 SetMinMaxSize( e, min, max );
147 // #8 void(entity e, float chan, string samp, float volume, float atten) sound
148 static void VM_CL_sound (void)
152 prvm_edict_t *entity;
156 VM_SAFEPARMCOUNT(5, VM_CL_sound);
158 entity = PRVM_G_EDICT(OFS_PARM0);
159 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
160 sample = PRVM_G_STRING(OFS_PARM2);
161 volume = PRVM_G_FLOAT(OFS_PARM3);
162 attenuation = PRVM_G_FLOAT(OFS_PARM4);
164 if (volume < 0 || volume > 1)
166 VM_Warning("VM_CL_sound: volume must be in range 0-1\n");
170 if (attenuation < 0 || attenuation > 4)
172 VM_Warning("VM_CL_sound: attenuation must be in range 0-4\n");
176 if (channel < 0 || channel > 7)
178 VM_Warning("VM_CL_sound: channel must be in range 0-7\n");
182 S_StartSound(32768 + PRVM_NUM_FOR_EDICT(entity), channel, S_FindName(sample), entity->fields.client->origin, volume, attenuation);
185 // #483 void(vector origin, string sample, float volume, float attenuation) pointsound
186 static void VM_CL_pointsound(void)
193 VM_SAFEPARMCOUNT(4, VM_CL_pointsound);
195 VectorCopy( PRVM_G_VECTOR(OFS_PARM0), org);
196 sample = PRVM_G_STRING(OFS_PARM1);
197 volume = PRVM_G_FLOAT(OFS_PARM2);
198 attenuation = PRVM_G_FLOAT(OFS_PARM3);
200 if (volume < 0 || volume > 1)
202 VM_Warning("VM_CL_pointsound: volume must be in range 0-1\n");
206 if (attenuation < 0 || attenuation > 4)
208 VM_Warning("VM_CL_pointsound: attenuation must be in range 0-4\n");
212 // Send World Entity as Entity to Play Sound (for CSQC, that is 32768)
213 S_StartSound(32768, 0, S_FindName(sample), org, volume, attenuation);
216 // #14 entity() spawn
217 static void VM_CL_spawn (void)
220 ed = PRVM_ED_Alloc();
224 // #16 float(vector v1, vector v2, float movetype, entity ignore) traceline
225 static void VM_CL_traceline (void)
232 VM_SAFEPARMCOUNTRANGE(4, 4, VM_CL_traceline);
234 prog->xfunction->builtinsprofile += 30;
236 v1 = PRVM_G_VECTOR(OFS_PARM0);
237 v2 = PRVM_G_VECTOR(OFS_PARM1);
238 move = (int)PRVM_G_FLOAT(OFS_PARM2);
239 ent = PRVM_G_EDICT(OFS_PARM3);
241 if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || IS_NAN(v2[2]))
242 PRVM_ERROR("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_NAME, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent));
244 trace = CL_Move(v1, vec3_origin, vec3_origin, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
246 VM_SetTraceGlobals(&trace);
253 Used for use tracing and shot targeting
254 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
255 if the tryents flag is set.
257 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
260 // LordHavoc: added this for my own use, VERY useful, similar to traceline
261 static void VM_CL_tracebox (void)
263 float *v1, *v2, *m1, *m2;
268 VM_SAFEPARMCOUNTRANGE(6, 8, VM_CL_tracebox); // allow more parameters for future expansion
270 prog->xfunction->builtinsprofile += 30;
272 v1 = PRVM_G_VECTOR(OFS_PARM0);
273 m1 = PRVM_G_VECTOR(OFS_PARM1);
274 m2 = PRVM_G_VECTOR(OFS_PARM2);
275 v2 = PRVM_G_VECTOR(OFS_PARM3);
276 move = (int)PRVM_G_FLOAT(OFS_PARM4);
277 ent = PRVM_G_EDICT(OFS_PARM5);
279 if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || IS_NAN(v2[2]))
280 PRVM_ERROR("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", PRVM_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));
282 trace = CL_Move(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
284 VM_SetTraceGlobals(&trace);
287 trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
292 vec3_t original_origin;
293 vec3_t original_velocity;
294 vec3_t original_angles;
295 vec3_t original_avelocity;
299 VectorCopy(tossent->fields.client->origin , original_origin );
300 VectorCopy(tossent->fields.client->velocity , original_velocity );
301 VectorCopy(tossent->fields.client->angles , original_angles );
302 VectorCopy(tossent->fields.client->avelocity, original_avelocity);
304 val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
305 if (val != NULL && val->_float != 0)
306 gravity = val->_float;
309 gravity *= cl.movevars_gravity * 0.05;
311 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
313 tossent->fields.client->velocity[2] -= gravity;
314 VectorMA (tossent->fields.client->angles, 0.05, tossent->fields.client->avelocity, tossent->fields.client->angles);
315 VectorScale (tossent->fields.client->velocity, 0.05, move);
316 VectorAdd (tossent->fields.client->origin, move, end);
317 trace = CL_Move (tossent->fields.client->origin, tossent->fields.client->mins, tossent->fields.client->maxs, end, MOVE_NORMAL, tossent, CL_GenericHitSuperContentsMask(tossent), true, true, NULL, true);
318 VectorCopy (trace.endpos, tossent->fields.client->origin);
320 if (trace.fraction < 1)
324 VectorCopy(original_origin , tossent->fields.client->origin );
325 VectorCopy(original_velocity , tossent->fields.client->velocity );
326 VectorCopy(original_angles , tossent->fields.client->angles );
327 VectorCopy(original_avelocity, tossent->fields.client->avelocity);
332 static void VM_CL_tracetoss (void)
336 prvm_edict_t *ignore;
338 prog->xfunction->builtinsprofile += 600;
340 VM_SAFEPARMCOUNT(2, VM_CL_tracetoss);
342 ent = PRVM_G_EDICT(OFS_PARM0);
343 if (ent == prog->edicts)
345 VM_Warning("tracetoss: can not use world entity\n");
348 ignore = PRVM_G_EDICT(OFS_PARM1);
350 trace = CL_Trace_Toss (ent, ignore);
352 VM_SetTraceGlobals(&trace);
356 // #20 void(string s) precache_model
357 void VM_CL_precache_model (void)
363 VM_SAFEPARMCOUNT(1, VM_CL_precache_model);
365 name = PRVM_G_STRING(OFS_PARM0);
366 for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
368 if(!strcmp(cl.csqc_model_precache[i]->name, name))
370 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
374 PRVM_G_FLOAT(OFS_RETURN) = 0;
375 m = Mod_ForName(name, false, false, false);
378 for (i = 0;i < MAX_MODELS;i++)
380 if (!cl.csqc_model_precache[i])
382 cl.csqc_model_precache[i] = (model_t*)m;
383 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
387 VM_Warning("VM_CL_precache_model: no free models\n");
390 VM_Warning("VM_CL_precache_model: model \"%s\" not found\n", name);
393 int CSQC_EntitiesInBox (vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **list)
398 ent = PRVM_NEXT_EDICT(prog->edicts);
399 for(k=0,i=1; i<prog->num_edicts ;i++, ent = PRVM_NEXT_EDICT(ent))
401 if (ent->priv.required->free)
403 if(BoxesOverlap(mins, maxs, ent->fields.client->absmin, ent->fields.client->absmax))
409 // #22 entity(vector org, float rad) findradius
410 static void VM_CL_findradius (void)
412 prvm_edict_t *ent, *chain;
413 vec_t radius, radius2;
414 vec3_t org, eorg, mins, maxs;
415 int i, numtouchedicts;
416 prvm_edict_t *touchedicts[MAX_EDICTS];
418 VM_SAFEPARMCOUNT(2, VM_CL_findradius);
420 chain = (prvm_edict_t *)prog->edicts;
422 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
423 radius = PRVM_G_FLOAT(OFS_PARM1);
424 radius2 = radius * radius;
426 mins[0] = org[0] - (radius + 1);
427 mins[1] = org[1] - (radius + 1);
428 mins[2] = org[2] - (radius + 1);
429 maxs[0] = org[0] + (radius + 1);
430 maxs[1] = org[1] + (radius + 1);
431 maxs[2] = org[2] + (radius + 1);
432 numtouchedicts = CSQC_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
433 if (numtouchedicts > MAX_EDICTS)
435 // this never happens //[515]: for what then ?
436 Con_Printf("CSQC_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
437 numtouchedicts = MAX_EDICTS;
439 for (i = 0;i < numtouchedicts;i++)
441 ent = touchedicts[i];
442 // Quake did not return non-solid entities but darkplaces does
443 // (note: this is the reason you can't blow up fallen zombies)
444 if (ent->fields.client->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
446 // LordHavoc: compare against bounding box rather than center so it
447 // doesn't miss large objects, and use DotProduct instead of Length
448 // for a major speedup
449 VectorSubtract(org, ent->fields.client->origin, eorg);
450 if (sv_gameplayfix_findradiusdistancetobox.integer)
452 eorg[0] -= bound(ent->fields.client->mins[0], eorg[0], ent->fields.client->maxs[0]);
453 eorg[1] -= bound(ent->fields.client->mins[1], eorg[1], ent->fields.client->maxs[1]);
454 eorg[2] -= bound(ent->fields.client->mins[2], eorg[2], ent->fields.client->maxs[2]);
457 VectorMAMAM(1, eorg, -0.5f, ent->fields.client->mins, -0.5f, ent->fields.client->maxs, eorg);
458 if (DotProduct(eorg, eorg) < radius2)
460 ent->fields.client->chain = PRVM_EDICT_TO_PROG(chain);
465 VM_RETURN_EDICT(chain);
468 // #34 float() droptofloor
469 static void VM_CL_droptofloor (void)
476 VM_SAFEPARMCOUNTRANGE(0, 2, VM_CL_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
478 // assume failure if it returns early
479 PRVM_G_FLOAT(OFS_RETURN) = 0;
481 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
482 if (ent == prog->edicts)
484 VM_Warning("droptofloor: can not modify world entity\n");
487 if (ent->priv.server->free)
489 VM_Warning("droptofloor: can not modify free entity\n");
493 VectorCopy (ent->fields.client->origin, end);
496 trace = CL_Move(ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
498 if (trace.fraction != 1)
500 VectorCopy (trace.endpos, ent->fields.client->origin);
501 ent->fields.client->flags = (int)ent->fields.client->flags | FL_ONGROUND;
502 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
503 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
504 PRVM_G_FLOAT(OFS_RETURN) = 1;
505 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
506 // ent->priv.server->suspendedinairflag = true;
510 // #35 void(float style, string value) lightstyle
511 static void VM_CL_lightstyle (void)
516 VM_SAFEPARMCOUNT(2, VM_CL_lightstyle);
518 i = (int)PRVM_G_FLOAT(OFS_PARM0);
519 c = PRVM_G_STRING(OFS_PARM1);
520 if (i >= cl.max_lightstyle)
522 VM_Warning("VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
525 strlcpy (cl.lightstyle[i].map, MSG_ReadString(), sizeof (cl.lightstyle[i].map));
526 cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
527 cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
530 // #40 float(entity e) checkbottom
531 static void VM_CL_checkbottom (void)
533 static int cs_yes, cs_no;
535 vec3_t mins, maxs, start, stop;
540 VM_SAFEPARMCOUNT(1, VM_CL_checkbottom);
541 ent = PRVM_G_EDICT(OFS_PARM0);
542 PRVM_G_FLOAT(OFS_RETURN) = 0;
544 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
545 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
547 // if all of the points under the corners are solid world, don't bother
548 // with the tougher checks
549 // the corners must be within 16 of the midpoint
550 start[2] = mins[2] - 1;
551 for (x=0 ; x<=1 ; x++)
552 for (y=0 ; y<=1 ; y++)
554 start[0] = x ? maxs[0] : mins[0];
555 start[1] = y ? maxs[1] : mins[1];
556 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
561 PRVM_G_FLOAT(OFS_RETURN) = true;
562 return; // we got out easy
567 // check it for real...
571 // the midpoint must be within 16 of the bottom
572 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
573 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
574 stop[2] = start[2] - 2*sv_stepheight.value;
575 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
577 if (trace.fraction == 1.0)
580 mid = bottom = trace.endpos[2];
582 // the corners must be within 16 of the midpoint
583 for (x=0 ; x<=1 ; x++)
584 for (y=0 ; y<=1 ; y++)
586 start[0] = stop[0] = x ? maxs[0] : mins[0];
587 start[1] = stop[1] = y ? maxs[1] : mins[1];
589 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
591 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
592 bottom = trace.endpos[2];
593 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
598 PRVM_G_FLOAT(OFS_RETURN) = true;
601 // #41 float(vector v) pointcontents
602 static void VM_CL_pointcontents (void)
604 VM_SAFEPARMCOUNT(1, VM_CL_pointcontents);
605 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, CL_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
608 // #48 void(vector o, vector d, float color, float count) particle
609 static void VM_CL_particle (void)
614 VM_SAFEPARMCOUNT(4, VM_CL_particle);
616 org = PRVM_G_VECTOR(OFS_PARM0);
617 dir = PRVM_G_VECTOR(OFS_PARM1);
618 color = (int)PRVM_G_FLOAT(OFS_PARM2);
619 count = (int)PRVM_G_FLOAT(OFS_PARM3);
620 CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color);
623 // #74 void(vector pos, string samp, float vol, float atten) ambientsound
624 static void VM_CL_ambientsound (void)
628 VM_SAFEPARMCOUNT(4, VM_CL_ambientsound);
629 s = S_FindName(PRVM_G_STRING(OFS_PARM0));
630 f = PRVM_G_VECTOR(OFS_PARM1);
631 S_StaticSound (s, f, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3)*64);
634 // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
635 static void VM_CL_getlight (void)
637 vec3_t ambientcolor, diffusecolor, diffusenormal;
640 VM_SAFEPARMCOUNT(1, VM_CL_getlight);
642 p = PRVM_G_VECTOR(OFS_PARM0);
643 VectorClear(ambientcolor);
644 VectorClear(diffusecolor);
645 VectorClear(diffusenormal);
646 if (cl.worldmodel && cl.worldmodel->brush.LightPoint)
647 cl.worldmodel->brush.LightPoint(cl.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
648 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
652 //============================================================================
653 //[515]: SCENE MANAGER builtins
654 extern qboolean CSQC_AddRenderEdict (prvm_edict_t *ed);//csprogs.c
656 static void CSQC_R_RecalcView (void)
658 extern matrix4x4_t viewmodelmatrix;
659 Matrix4x4_CreateFromQuakeEntity(&r_refdef.view.matrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], 1);
660 Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], cl_viewmodel_scale.value);
663 void CL_RelinkLightFlashes(void);
664 //#300 void() clearscene (EXT_CSQC)
665 void VM_CL_R_ClearScene (void)
667 VM_SAFEPARMCOUNT(0, VM_CL_R_ClearScene);
668 // clear renderable entity and light lists
669 r_refdef.scene.numentities = 0;
670 r_refdef.scene.numlights = 0;
671 // FIXME: restore these to the values from VM_CL_UpdateView
675 r_refdef.view.width = vid.width;
676 r_refdef.view.height = vid.height;
677 r_refdef.view.depth = 1;
678 // FIXME: restore frustum_x/frustum_y
679 r_refdef.view.useperspective = true;
680 r_refdef.view.frustum_y = tan(scr_fov.value * M_PI / 360.0) * (3.0/4.0) * cl.viewzoom;
681 r_refdef.view.frustum_x = r_refdef.view.frustum_y * (float)r_refdef.view.width / (float)r_refdef.view.height / vid_pixelheight.value;
682 r_refdef.view.frustum_x *= r_refdef.frustumscale_x;
683 r_refdef.view.frustum_y *= r_refdef.frustumscale_y;
684 r_refdef.view.ortho_x = scr_fov.value * (3.0 / 4.0) * (float)r_refdef.view.width / (float)r_refdef.view.height / vid_pixelheight.value;
685 r_refdef.view.ortho_y = scr_fov.value * (3.0 / 4.0);
686 r_refdef.view.clear = true;
687 // FIXME: restore cl.csqc_origin
688 // FIXME: restore cl.csqc_angles
689 cl.csqc_vidvars.drawworld = true;
690 cl.csqc_vidvars.drawenginesbar = false;
691 cl.csqc_vidvars.drawcrosshair = false;
694 //#301 void(float mask) addentities (EXT_CSQC)
695 extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
696 extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
697 void VM_CL_R_AddEntities (void)
701 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
702 drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
703 CSQC_RelinkAllEntities(drawmask);
704 CL_RelinkLightFlashes();
706 prog->globals.client->time = cl.time;
707 for(i=1;i<prog->num_edicts;i++)
709 ed = &prog->edicts[i];
710 if(ed->priv.required->free)
713 if(ed->priv.required->free)
715 // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict
717 if(ed->priv.required->free)
719 if(!((int)ed->fields.client->drawmask & drawmask))
721 CSQC_AddRenderEdict(ed);
725 //#302 void(entity ent) addentity (EXT_CSQC)
726 void VM_CL_R_AddEntity (void)
728 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
729 CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
732 //#303 float(float property, ...) setproperty (EXT_CSQC)
733 void VM_CL_R_SetView (void)
739 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_SetView);
741 c = (int)PRVM_G_FLOAT(OFS_PARM0);
742 f = PRVM_G_VECTOR(OFS_PARM1);
743 k = PRVM_G_FLOAT(OFS_PARM1);
748 r_refdef.view.x = (int)(f[0] * vid.width / vid_conwidth.value);
749 r_refdef.view.y = (int)(f[1] * vid.height / vid_conheight.value);
752 r_refdef.view.x = (int)(k * vid.width / vid_conwidth.value);
755 r_refdef.view.y = (int)(k * vid.height / vid_conheight.value);
758 r_refdef.view.width = (int)(f[0] * vid.width / vid_conwidth.value);
759 r_refdef.view.height = (int)(f[1] * vid.height / vid_conheight.value);
762 r_refdef.view.width = (int)(k * vid.width / vid_conwidth.value);
765 r_refdef.view.height = (int)(k * vid.height / vid_conheight.value);
768 r_refdef.view.x = (int)(f[0] * vid.width / vid_conwidth.value);
769 r_refdef.view.y = (int)(f[1] * vid.height / vid_conheight.value);
770 f = PRVM_G_VECTOR(OFS_PARM2);
771 r_refdef.view.width = (int)(f[0] * vid.width / vid_conwidth.value);
772 r_refdef.view.height = (int)(f[1] * vid.height / vid_conheight.value);
775 r_refdef.view.frustum_x = tan(f[0] * M_PI / 360.0);r_refdef.view.ortho_x = f[0];
776 r_refdef.view.frustum_y = tan(f[1] * M_PI / 360.0);r_refdef.view.ortho_y = f[1];
779 r_refdef.view.frustum_x = tan(k * M_PI / 360.0);r_refdef.view.ortho_x = k;
782 r_refdef.view.frustum_y = tan(k * M_PI / 360.0);r_refdef.view.ortho_y = k;
785 VectorCopy(f, cl.csqc_origin);
789 cl.csqc_origin[0] = k;
793 cl.csqc_origin[1] = k;
797 cl.csqc_origin[2] = k;
801 VectorCopy(f, cl.csqc_angles);
805 cl.csqc_angles[0] = k;
809 cl.csqc_angles[1] = k;
813 cl.csqc_angles[2] = k;
817 cl.csqc_vidvars.drawworld = k;
819 case VF_DRAWENGINESBAR:
820 cl.csqc_vidvars.drawenginesbar = k;
822 case VF_DRAWCROSSHAIR:
823 cl.csqc_vidvars.drawcrosshair = k;
825 case VF_CL_VIEWANGLES:
826 VectorCopy(f, cl.viewangles);
828 case VF_CL_VIEWANGLES_X:
829 cl.viewangles[0] = k;
831 case VF_CL_VIEWANGLES_Y:
832 cl.viewangles[1] = k;
834 case VF_CL_VIEWANGLES_Z:
835 cl.viewangles[2] = k;
838 r_refdef.view.useperspective = k != 0;
841 r_refdef.view.clear = k ? true : false;
844 PRVM_G_FLOAT(OFS_RETURN) = 0;
845 VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c);
848 PRVM_G_FLOAT(OFS_RETURN) = 1;
851 //#304 void() renderscene (EXT_CSQC)
852 void VM_CL_R_RenderScene (void)
854 VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
855 // we need to update any RENDER_VIEWMODEL entities at this point because
856 // csqc supplies its own view matrix
857 CL_UpdateViewEntities();
862 //#305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
863 void VM_CL_R_AddDynamicLight (void)
867 VM_SAFEPARMCOUNTRANGE(3, 3, VM_CL_R_AddDynamicLight);
869 // if we've run out of dlights, just return
870 if (r_refdef.scene.numlights >= MAX_DLIGHTS)
873 pos = PRVM_G_VECTOR(OFS_PARM0);
874 col = PRVM_G_VECTOR(OFS_PARM2);
875 Matrix4x4_CreateFromQuakeEntity(&matrix, pos[0], pos[1], pos[2], 0, 0, 0, PRVM_G_FLOAT(OFS_PARM1));
876 R_RTLight_Update(&r_refdef.scene.lights[r_refdef.scene.numlights++], false, &matrix, col, -1, NULL, true, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
879 //============================================================================
881 //#310 vector (vector v) cs_unproject (EXT_CSQC)
882 static void VM_CL_unproject (void)
887 VM_SAFEPARMCOUNT(1, VM_CL_unproject);
888 f = PRVM_G_VECTOR(OFS_PARM0);
889 VectorSet(temp, f[2], f[0] * f[2] * -r_refdef.view.frustum_x * 2.0 / r_refdef.view.width, f[1] * f[2] * -r_refdef.view.frustum_y * 2.0 / r_refdef.view.height);
890 Matrix4x4_Transform(&r_refdef.view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
893 //#311 vector (vector v) cs_project (EXT_CSQC)
894 static void VM_CL_project (void)
900 VM_SAFEPARMCOUNT(1, VM_CL_project);
901 f = PRVM_G_VECTOR(OFS_PARM0);
902 Matrix4x4_Invert_Simple(&m, &r_refdef.view.matrix);
903 Matrix4x4_Transform(&m, f, v);
904 VectorSet(PRVM_G_VECTOR(OFS_RETURN), v[1]/v[0]/-r_refdef.view.frustum_x*0.5*r_refdef.view.width, v[2]/v[0]/-r_refdef.view.frustum_y*r_refdef.view.height*0.5, v[0]);
907 //#330 float(float stnum) getstatf (EXT_CSQC)
908 static void VM_CL_getstatf (void)
916 VM_SAFEPARMCOUNT(1, VM_CL_getstatf);
917 i = (int)PRVM_G_FLOAT(OFS_PARM0);
918 if(i < 0 || i >= MAX_CL_STATS)
920 VM_Warning("VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
924 PRVM_G_FLOAT(OFS_RETURN) = dat.f;
927 //#331 float(float stnum) getstati (EXT_CSQC)
928 static void VM_CL_getstati (void)
931 int firstbit, bitcount;
933 VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getstati);
935 index = (int)PRVM_G_FLOAT(OFS_PARM0);
938 firstbit = (int)PRVM_G_FLOAT(OFS_PARM1);
940 bitcount = (int)PRVM_G_FLOAT(OFS_PARM2);
950 if(index < 0 || index >= MAX_CL_STATS)
952 VM_Warning("VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
956 if (bitcount != 32) //32 causes the mask to overflow, so there's nothing to subtract from.
957 i = (((unsigned int)i)&(((1<<bitcount)-1)<<firstbit))>>firstbit;
958 PRVM_G_FLOAT(OFS_RETURN) = i;
961 //#332 string(float firststnum) getstats (EXT_CSQC)
962 static void VM_CL_getstats (void)
966 VM_SAFEPARMCOUNT(1, VM_CL_getstats);
967 i = (int)PRVM_G_FLOAT(OFS_PARM0);
968 if(i < 0 || i > MAX_CL_STATS-4)
970 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
971 VM_Warning("VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
974 strlcpy(t, (char*)&cl.stats[i], sizeof(t));
975 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
978 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
979 static void VM_CL_setmodelindex (void)
983 struct model_s *model;
985 VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex);
987 t = PRVM_G_EDICT(OFS_PARM0);
989 i = (int)PRVM_G_FLOAT(OFS_PARM1);
991 t->fields.client->model = 0;
992 t->fields.client->modelindex = 0;
997 model = CL_GetModelByIndex(i);
1000 VM_Warning("VM_CL_setmodelindex: null model\n");
1003 t->fields.client->model = PRVM_SetEngineString(model->name);
1004 t->fields.client->modelindex = i;
1006 // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black]
1009 SetMinMaxSize (t, model->normalmins, model->normalmaxs);
1012 SetMinMaxSize (t, vec3_origin, vec3_origin);
1015 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
1016 static void VM_CL_modelnameforindex (void)
1020 VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
1022 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1023 model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
1024 PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(model->name) : 0;
1027 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
1028 static void VM_CL_particleeffectnum (void)
1031 VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
1032 i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
1035 PRVM_G_FLOAT(OFS_RETURN) = i;
1038 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
1039 static void VM_CL_trailparticles (void)
1044 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles);
1046 t = PRVM_G_EDICT(OFS_PARM0);
1047 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1048 start = PRVM_G_VECTOR(OFS_PARM2);
1049 end = PRVM_G_VECTOR(OFS_PARM3);
1051 CL_ParticleEffect(i, VectorDistance(start, end), start, end, t->fields.client->velocity, t->fields.client->velocity, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
1054 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
1055 static void VM_CL_pointparticles (void)
1059 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
1060 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1061 f = PRVM_G_VECTOR(OFS_PARM1);
1062 v = PRVM_G_VECTOR(OFS_PARM2);
1063 n = (int)PRVM_G_FLOAT(OFS_PARM3);
1064 CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
1067 //#342 string(float keynum) getkeybind (EXT_CSQC)
1068 static void VM_CL_getkeybind (void)
1070 VM_SAFEPARMCOUNT(1, VM_CL_getkeybind);
1071 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0)));
1074 //#343 void(float usecursor) setcursormode (EXT_CSQC)
1075 static void VM_CL_setcursormode (void)
1077 VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
1078 cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
1079 cl_ignoremousemoves = 2;
1082 //#345 float(float framenum) getinputstate (EXT_CSQC)
1083 static void VM_CL_getinputstate (void)
1086 VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
1087 frame = (int)PRVM_G_FLOAT(OFS_PARM0);
1088 for (i = 0;i < cl.movement_numqueue;i++)
1089 if (cl.movement_queue[i].sequence == frame)
1091 VectorCopy(cl.movement_queue[i].viewangles, prog->globals.client->input_angles);
1092 //prog->globals.client->input_buttons = cl.movement_queue[i].//FIXME
1093 VectorCopy(cl.movement_queue[i].move, prog->globals.client->input_movevalues);
1094 prog->globals.client->input_timelength = cl.movement_queue[i].frametime;
1095 if(cl.movement_queue[i].crouch)
1097 VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
1098 VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
1102 VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
1103 VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
1108 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
1109 static void VM_CL_setsensitivityscale (void)
1111 VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
1112 cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
1115 //#347 void() runstandardplayerphysics (EXT_CSQC)
1116 static void VM_CL_runplayerphysics (void)
1120 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
1121 static void VM_CL_getplayerkey (void)
1127 VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
1129 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1130 c = PRVM_G_STRING(OFS_PARM1);
1131 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1134 i = Sbar_GetPlayer(i);
1140 if(!strcasecmp(c, "name"))
1141 strlcpy(t, cl.scores[i].name, sizeof(t));
1143 if(!strcasecmp(c, "frags"))
1144 sprintf(t, "%i", cl.scores[i].frags);
1146 if(!strcasecmp(c, "ping"))
1147 sprintf(t, "%i", cl.scores[i].qw_ping);
1149 if(!strcasecmp(c, "pl"))
1150 sprintf(t, "%i", cl.scores[i].qw_packetloss);
1152 if(!strcasecmp(c, "entertime"))
1153 sprintf(t, "%f", cl.scores[i].qw_entertime);
1155 if(!strcasecmp(c, "colors"))
1156 sprintf(t, "%i", cl.scores[i].colors);
1158 if(!strcasecmp(c, "topcolor"))
1159 sprintf(t, "%i", cl.scores[i].colors & 0xf0);
1161 if(!strcasecmp(c, "bottomcolor"))
1162 sprintf(t, "%i", (cl.scores[i].colors &15)<<4);
1164 if(!strcasecmp(c, "viewentity"))
1165 sprintf(t, "%i", i+1);
1168 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1171 //#349 float() isdemo (EXT_CSQC)
1172 static void VM_CL_isdemo (void)
1174 VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
1175 PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
1178 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
1179 static void VM_CL_setlistener (void)
1181 VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
1182 Matrix4x4_FromVectors(&cl.csqc_listenermatrix, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), PRVM_G_VECTOR(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0));
1183 cl.csqc_usecsqclistener = true; //use csqc listener at this frame
1186 //#352 void(string cmdname) registercommand (EXT_CSQC)
1187 static void VM_CL_registercmd (void)
1190 VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
1191 if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0)))
1195 alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1;
1196 t = (char *)Z_Malloc(alloclen);
1197 memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen);
1198 Cmd_AddCommand(t, NULL, "console command created by QuakeC");
1201 Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
1205 //#360 float() readbyte (EXT_CSQC)
1206 static void VM_CL_ReadByte (void)
1208 VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
1209 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte();
1212 //#361 float() readchar (EXT_CSQC)
1213 static void VM_CL_ReadChar (void)
1215 VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
1216 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar();
1219 //#362 float() readshort (EXT_CSQC)
1220 static void VM_CL_ReadShort (void)
1222 VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
1223 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort();
1226 //#363 float() readlong (EXT_CSQC)
1227 static void VM_CL_ReadLong (void)
1229 VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
1230 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong();
1233 //#364 float() readcoord (EXT_CSQC)
1234 static void VM_CL_ReadCoord (void)
1236 VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
1237 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(cls.protocol);
1240 //#365 float() readangle (EXT_CSQC)
1241 static void VM_CL_ReadAngle (void)
1243 VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
1244 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(cls.protocol);
1247 //#366 string() readstring (EXT_CSQC)
1248 static void VM_CL_ReadString (void)
1250 VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
1251 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_ReadString());
1254 //#367 float() readfloat (EXT_CSQC)
1255 static void VM_CL_ReadFloat (void)
1257 VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
1258 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
1261 //////////////////////////////////////////////////////////
1263 static void VM_CL_makestatic (void)
1267 VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
1269 ent = PRVM_G_EDICT(OFS_PARM0);
1270 if (ent == prog->edicts)
1272 VM_Warning("makestatic: can not modify world entity\n");
1275 if (ent->priv.server->free)
1277 VM_Warning("makestatic: can not modify free entity\n");
1281 if (cl.num_static_entities < cl.max_static_entities)
1285 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
1287 // copy it to the current state
1288 memset(staticent, 0, sizeof(*staticent));
1289 staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
1290 staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
1291 staticent->render.framelerp = 0;
1292 // make torchs play out of sync
1293 staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
1294 staticent->render.skinnum = (int)ent->fields.client->skin;
1295 staticent->render.effects = (int)ent->fields.client->effects;
1296 staticent->render.alpha = 1;
1297 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float;
1298 staticent->render.scale = 1;
1299 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
1300 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
1303 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
1304 if (renderflags & RF_USEAXIS)
1307 VectorNegate(prog->globals.client->v_right, left);
1308 Matrix4x4_FromVectors(&staticent->render.matrix, prog->globals.client->v_forward, left, prog->globals.client->v_up, ent->fields.client->origin);
1309 Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
1312 Matrix4x4_CreateFromQuakeEntity(&staticent->render.matrix, ent->fields.client->origin[0], ent->fields.client->origin[1], ent->fields.client->origin[2], ent->fields.client->angles[0], ent->fields.client->angles[1], ent->fields.client->angles[2], staticent->render.scale);
1314 // either fullbright or lit
1315 if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
1316 staticent->render.flags |= RENDER_LIGHT;
1317 // turn off shadows from transparent objects
1318 if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
1319 staticent->render.flags |= RENDER_SHADOW;
1321 CL_UpdateRenderEntity(&staticent->render);
1324 Con_Printf("Too many static entities");
1326 // throw the entity away now
1330 //=================================================================//
1336 copies data from one entity to another
1338 copyentity(src, dst)
1341 static void VM_CL_copyentity (void)
1343 prvm_edict_t *in, *out;
1344 VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
1345 in = PRVM_G_EDICT(OFS_PARM0);
1346 if (in == prog->edicts)
1348 VM_Warning("copyentity: can not read world entity\n");
1351 if (in->priv.server->free)
1353 VM_Warning("copyentity: can not read free entity\n");
1356 out = PRVM_G_EDICT(OFS_PARM1);
1357 if (out == prog->edicts)
1359 VM_Warning("copyentity: can not modify world entity\n");
1362 if (out->priv.server->free)
1364 VM_Warning("copyentity: can not modify free entity\n");
1367 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1371 //=================================================================//
1373 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
1374 static void VM_CL_effect (void)
1376 VM_SAFEPARMCOUNT(5, VM_CL_effect);
1377 CL_Effect(PRVM_G_VECTOR(OFS_PARM0), (int)PRVM_G_FLOAT(OFS_PARM1), (int)PRVM_G_FLOAT(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4));
1380 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
1381 static void VM_CL_te_blood (void)
1385 VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
1386 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1388 pos = PRVM_G_VECTOR(OFS_PARM0);
1389 CL_FindNonSolidLocation(pos, pos2, 4);
1390 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1393 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
1394 static void VM_CL_te_bloodshower (void)
1398 VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
1399 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1401 speed = PRVM_G_FLOAT(OFS_PARM2);
1408 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), vel1, vel2, NULL, 0);
1411 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
1412 static void VM_CL_te_explosionrgb (void)
1416 matrix4x4_t tempmatrix;
1417 VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
1418 pos = PRVM_G_VECTOR(OFS_PARM0);
1419 CL_FindNonSolidLocation(pos, pos2, 10);
1420 CL_ParticleExplosion(pos2);
1421 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1422 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, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1425 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
1426 static void VM_CL_te_particlecube (void)
1428 VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
1429 CL_ParticleCube(PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4), PRVM_G_FLOAT(OFS_PARM5), PRVM_G_FLOAT(OFS_PARM6));
1432 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
1433 static void VM_CL_te_particlerain (void)
1435 VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
1436 CL_ParticleRain(PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4), 0);
1439 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
1440 static void VM_CL_te_particlesnow (void)
1442 VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
1443 CL_ParticleRain(PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), (int)PRVM_G_FLOAT(OFS_PARM3), (int)PRVM_G_FLOAT(OFS_PARM4), 1);
1446 // #411 void(vector org, vector vel, float howmany) te_spark
1447 static void VM_CL_te_spark (void)
1451 VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
1453 pos = PRVM_G_VECTOR(OFS_PARM0);
1454 CL_FindNonSolidLocation(pos, pos2, 4);
1455 CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1458 extern cvar_t cl_sound_ric_gunshot;
1459 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
1460 static void VM_CL_te_gunshotquad (void)
1465 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
1467 pos = PRVM_G_VECTOR(OFS_PARM0);
1468 CL_FindNonSolidLocation(pos, pos2, 4);
1469 CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1470 if(cl_sound_ric_gunshot.integer >= 2)
1472 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1476 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1477 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1478 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1483 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
1484 static void VM_CL_te_spikequad (void)
1489 VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
1491 pos = PRVM_G_VECTOR(OFS_PARM0);
1492 CL_FindNonSolidLocation(pos, pos2, 4);
1493 CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1494 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1498 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1499 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1500 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1504 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
1505 static void VM_CL_te_superspikequad (void)
1510 VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
1512 pos = PRVM_G_VECTOR(OFS_PARM0);
1513 CL_FindNonSolidLocation(pos, pos2, 4);
1514 CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1515 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1519 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1520 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1521 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1525 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
1526 static void VM_CL_te_explosionquad (void)
1530 VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
1532 pos = PRVM_G_VECTOR(OFS_PARM0);
1533 CL_FindNonSolidLocation(pos, pos2, 10);
1534 CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1535 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1538 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
1539 static void VM_CL_te_smallflash (void)
1543 VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
1545 pos = PRVM_G_VECTOR(OFS_PARM0);
1546 CL_FindNonSolidLocation(pos, pos2, 10);
1547 CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1550 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
1551 static void VM_CL_te_customflash (void)
1555 matrix4x4_t tempmatrix;
1556 VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
1558 pos = PRVM_G_VECTOR(OFS_PARM0);
1559 CL_FindNonSolidLocation(pos, pos2, 4);
1560 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1561 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), 0, -1, true, 1, 0.25, 1, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1564 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
1565 static void VM_CL_te_gunshot (void)
1570 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
1572 pos = PRVM_G_VECTOR(OFS_PARM0);
1573 CL_FindNonSolidLocation(pos, pos2, 4);
1574 CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1575 if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
1577 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1581 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1582 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1583 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1588 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
1589 static void VM_CL_te_spike (void)
1594 VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
1596 pos = PRVM_G_VECTOR(OFS_PARM0);
1597 CL_FindNonSolidLocation(pos, pos2, 4);
1598 CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1599 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1603 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1604 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1605 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1609 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
1610 static void VM_CL_te_superspike (void)
1615 VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
1617 pos = PRVM_G_VECTOR(OFS_PARM0);
1618 CL_FindNonSolidLocation(pos, pos2, 4);
1619 CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1620 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1624 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1625 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1626 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1630 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
1631 static void VM_CL_te_explosion (void)
1635 VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
1637 pos = PRVM_G_VECTOR(OFS_PARM0);
1638 CL_FindNonSolidLocation(pos, pos2, 10);
1639 CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1640 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1643 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
1644 static void VM_CL_te_tarexplosion (void)
1648 VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
1650 pos = PRVM_G_VECTOR(OFS_PARM0);
1651 CL_FindNonSolidLocation(pos, pos2, 10);
1652 CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1653 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1656 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
1657 static void VM_CL_te_wizspike (void)
1661 VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
1663 pos = PRVM_G_VECTOR(OFS_PARM0);
1664 CL_FindNonSolidLocation(pos, pos2, 4);
1665 CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1666 S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
1669 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
1670 static void VM_CL_te_knightspike (void)
1674 VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
1676 pos = PRVM_G_VECTOR(OFS_PARM0);
1677 CL_FindNonSolidLocation(pos, pos2, 4);
1678 CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1679 S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
1682 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
1683 static void VM_CL_te_lavasplash (void)
1685 VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
1686 CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1689 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
1690 static void VM_CL_te_teleport (void)
1692 VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
1693 CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1696 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
1697 static void VM_CL_te_explosion2 (void)
1701 matrix4x4_t tempmatrix;
1702 int colorStart, colorLength;
1703 unsigned char *tempcolor;
1704 VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
1706 pos = PRVM_G_VECTOR(OFS_PARM0);
1707 colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
1708 colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
1709 CL_FindNonSolidLocation(pos, pos2, 10);
1710 CL_ParticleExplosion2(pos2, colorStart, colorLength);
1711 tempcolor = palette_rgb[(rand()%colorLength) + colorStart];
1712 color[0] = tempcolor[0] * (2.0f / 255.0f);
1713 color[1] = tempcolor[1] * (2.0f / 255.0f);
1714 color[2] = tempcolor[2] * (2.0f / 255.0f);
1715 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1716 CL_AllocLightFlash(NULL, &tempmatrix, 350, color[0], color[1], color[2], 700, 0.5, 0, -1, true, 1, 0.25, 0.25, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
1717 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1721 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
1722 static void VM_CL_te_lightning1 (void)
1724 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
1725 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
1728 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
1729 static void VM_CL_te_lightning2 (void)
1731 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
1732 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
1735 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
1736 static void VM_CL_te_lightning3 (void)
1738 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
1739 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
1742 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
1743 static void VM_CL_te_beam (void)
1745 VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
1746 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
1749 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
1750 static void VM_CL_te_plasmaburn (void)
1754 VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
1756 pos = PRVM_G_VECTOR(OFS_PARM0);
1757 CL_FindNonSolidLocation(pos, pos2, 4);
1758 CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1761 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
1762 static void VM_CL_te_flamejet (void)
1766 VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
1767 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1769 pos = PRVM_G_VECTOR(OFS_PARM0);
1770 CL_FindNonSolidLocation(pos, pos2, 4);
1771 CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1775 //====================================================================
1778 extern void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
1780 static msurface_t *cl_getsurface(model_t *model, int surfacenum)
1782 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1784 return model->data_surfaces + surfacenum + model->firstmodelsurface;
1787 // #434 float(entity e, float s) getsurfacenumpoints
1788 static void VM_CL_getsurfacenumpoints(void)
1791 msurface_t *surface;
1792 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
1793 // return 0 if no such surface
1794 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1796 PRVM_G_FLOAT(OFS_RETURN) = 0;
1800 // note: this (incorrectly) assumes it is a simple polygon
1801 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1804 // #435 vector(entity e, float s, float n) getsurfacepoint
1805 static void VM_CL_getsurfacepoint(void)
1809 msurface_t *surface;
1811 VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1812 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1813 ed = PRVM_G_EDICT(OFS_PARM0);
1814 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1816 // note: this (incorrectly) assumes it is a simple polygon
1817 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1818 if (pointnum < 0 || pointnum >= surface->num_vertices)
1820 // FIXME: implement rotation/scaling
1821 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1823 //PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
1824 // float SPA_POSITION = 0;
1825 // float SPA_S_AXIS = 1;
1826 // float SPA_T_AXIS = 2;
1827 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
1828 // float SPA_TEXCOORDS0 = 4;
1829 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
1830 // float SPA_LIGHTMAP0_COLOR = 6;
1831 // TODO: add some wrapper code and merge VM_CL/SV_getsurface* [12/16/2007 Black]
1832 static void VM_CL_getsurfacepointattribute(void)
1836 msurface_t *surface;
1840 VM_SAFEPARMCOUNT(4, VM_CL_getsurfacenumpoints);
1841 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1842 ed = PRVM_G_EDICT(OFS_PARM0);
1843 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1845 // note: this (incorrectly) assumes it is a simple polygon
1846 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1847 if (pointnum < 0 || pointnum >= surface->num_vertices)
1850 // FIXME: implement rotation/scaling
1851 attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
1853 switch( attributetype ) {
1854 // float SPA_POSITION = 0;
1856 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
1858 // float SPA_S_AXIS = 1;
1860 VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1862 // float SPA_T_AXIS = 2;
1864 VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1866 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
1868 VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1870 // float SPA_TEXCOORDS0 = 4;
1872 float *ret = PRVM_G_VECTOR(OFS_RETURN);
1873 float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
1874 ret[0] = texcoord[0];
1875 ret[1] = texcoord[1];
1879 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
1881 float *ret = PRVM_G_VECTOR(OFS_RETURN);
1882 float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
1883 ret[0] = texcoord[0];
1884 ret[1] = texcoord[1];
1888 // float SPA_LIGHTMAP0_COLOR = 6;
1890 // ignore alpha for now..
1891 VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
1894 VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
1898 // #436 vector(entity e, float s) getsurfacenormal
1899 static void VM_CL_getsurfacenormal(void)
1902 msurface_t *surface;
1904 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
1905 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1906 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1908 // FIXME: implement rotation/scaling
1909 // note: this (incorrectly) assumes it is a simple polygon
1910 // note: this only returns the first triangle, so it doesn't work very
1911 // well for curved surfaces or arbitrary meshes
1912 TriangleNormal((model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex), (model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + 3, (model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + 6, normal);
1913 VectorNormalize(normal);
1914 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1917 // #437 string(entity e, float s) getsurfacetexture
1918 static void VM_CL_getsurfacetexture(void)
1921 msurface_t *surface;
1922 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
1923 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1924 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1926 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
1929 // #438 float(entity e, vector p) getsurfacenearpoint
1930 static void VM_CL_getsurfacenearpoint(void)
1932 int surfacenum, best;
1934 vec_t dist, bestdist;
1936 model_t *model = NULL;
1937 msurface_t *surface;
1939 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
1940 PRVM_G_FLOAT(OFS_RETURN) = -1;
1941 ed = PRVM_G_EDICT(OFS_PARM0);
1942 if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces)
1945 // FIXME: implement rotation/scaling
1946 point = PRVM_G_VECTOR(OFS_PARM1);
1947 VectorSubtract(point, ed->fields.client->origin, p);
1949 bestdist = 1000000000;
1950 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1952 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1953 // first see if the nearest point on the surface's box is closer than the previous match
1954 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1955 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1956 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1957 dist = VectorLength2(clipped);
1958 if (dist < bestdist)
1960 // it is, check the nearest point on the actual geometry
1961 clippointtosurface(model, surface, p, clipped);
1962 VectorSubtract(clipped, p, clipped);
1963 dist += VectorLength2(clipped);
1964 if (dist < bestdist)
1966 // that's closer too, store it as the best match
1972 PRVM_G_FLOAT(OFS_RETURN) = best;
1975 // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint
1976 static void VM_CL_getsurfaceclippedpoint(void)
1980 msurface_t *surface;
1982 VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
1983 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1984 ed = PRVM_G_EDICT(OFS_PARM0);
1985 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1987 // FIXME: implement rotation/scaling
1988 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
1989 clippointtosurface(model, surface, p, out);
1990 // FIXME: implement rotation/scaling
1991 VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1994 // #443 void(entity e, entity tagentity, string tagname) setattachment
1995 void VM_CL_setattachment (void)
1998 prvm_edict_t *tagentity;
1999 const char *tagname;
2003 VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
2005 e = PRVM_G_EDICT(OFS_PARM0);
2006 tagentity = PRVM_G_EDICT(OFS_PARM1);
2007 tagname = PRVM_G_STRING(OFS_PARM2);
2009 if (e == prog->edicts)
2011 VM_Warning("setattachment: can not modify world entity\n");
2014 if (e->priv.server->free)
2016 VM_Warning("setattachment: can not modify free entity\n");
2020 if (tagentity == NULL)
2021 tagentity = prog->edicts;
2023 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
2025 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2027 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
2030 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2032 modelindex = (int)tagentity->fields.client->modelindex;
2033 model = CL_GetModelByIndex(modelindex);
2036 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
2038 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);
2041 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));
2045 /////////////////////////////////////////
2046 // DP_MD3_TAGINFO extension coded by VorteX
2048 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
2050 model_t *model = CL_GetModelFromEdict(e);
2052 return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
2057 // Warnings/errors code:
2058 // 0 - normal (everything all-right)
2061 // 3 - null or non-precached model
2062 // 4 - no tags with requested index
2063 // 5 - runaway loop at attachment chain
2064 extern cvar_t cl_bob;
2065 extern cvar_t cl_bobcycle;
2066 extern cvar_t cl_bobup;
2067 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2070 int reqframe, attachloop;
2071 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2072 prvm_edict_t *attachent;
2076 *out = identitymatrix; // warnings and errors return identical matrix
2078 if (ent == prog->edicts)
2080 if (ent->priv.server->free)
2083 model = CL_GetModelFromEdict(ent);
2088 if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
2089 reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
2091 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
2093 // get initial tag matrix
2096 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
2101 tagmatrix = identitymatrix;
2103 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
2104 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2108 attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
2109 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
2111 model = CL_GetModelFromEdict(attachent);
2113 if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
2114 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
2116 attachmatrix = identitymatrix;
2118 // apply transformation by child entity matrix
2120 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2121 if (val && val->_float != 0)
2122 scale = val->_float;
2123 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->fields.client->origin[0], ent->fields.client->origin[1], ent->fields.client->origin[2], -ent->fields.client->angles[0], ent->fields.client->angles[1], ent->fields.client->angles[2], scale);
2124 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2125 Matrix4x4_Copy(&tagmatrix, out);
2127 // finally transformate by matrix of tag on parent entity
2128 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
2129 Matrix4x4_Copy(&tagmatrix, out);
2133 if (attachloop > 255) // prevent runaway looping
2136 while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
2139 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
2141 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2142 if (val && val->_float != 0)
2143 scale = val->_float;
2144 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
2145 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, ent->fields.client->origin[0], ent->fields.client->origin[1], ent->fields.client->origin[2], -ent->fields.client->angles[0], ent->fields.client->angles[1], ent->fields.client->angles[2], scale);
2146 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2148 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
2149 {// RENDER_VIEWMODEL magic
2150 Matrix4x4_Copy(&tagmatrix, out);
2153 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2154 if (val && val->_float != 0)
2155 scale = val->_float;
2157 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], scale);
2158 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2161 // Cl_bob, ported from rendering code
2162 if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
2165 // LordHavoc: this code is *weird*, but not replacable (I think it
2166 // should be done in QC on the server, but oh well, quake is quake)
2167 // LordHavoc: figured out bobup: the time at which the sin is at 180
2168 // degrees (which allows lengthening or squishing the peak or valley)
2169 cycle = cl.time/cl_bobcycle.value;
2170 cycle -= (int)cycle;
2171 if (cycle < cl_bobup.value)
2172 cycle = sin(M_PI * cycle / cl_bobup.value);
2174 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2175 // bob is proportional to velocity in the xy plane
2176 // (don't count Z, or jumping messes it up)
2177 bob = sqrt(ent->fields.client->velocity[0]*ent->fields.client->velocity[0] + ent->fields.client->velocity[1]*ent->fields.client->velocity[1])*cl_bob.value;
2178 bob = bob*0.3 + bob*0.7*cycle;
2179 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2186 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
2187 void VM_CL_gettagindex (void)
2190 const char *tag_name;
2191 int modelindex, tag_index;
2193 VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
2195 ent = PRVM_G_EDICT(OFS_PARM0);
2196 tag_name = PRVM_G_STRING(OFS_PARM1);
2197 if (ent == prog->edicts)
2199 VM_Warning("gettagindex: can't affect world entity\n");
2202 if (ent->priv.server->free)
2204 VM_Warning("gettagindex: can't affect free entity\n");
2208 modelindex = (int)ent->fields.client->modelindex;
2210 if (modelindex >= MAX_MODELS || (modelindex <= -MAX_MODELS /* client models */))
2211 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2214 tag_index = CL_GetTagIndex(ent, tag_name);
2216 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2218 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2221 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2222 void VM_CL_gettaginfo (void)
2226 matrix4x4_t tag_matrix;
2229 VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2231 e = PRVM_G_EDICT(OFS_PARM0);
2232 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2233 returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2234 Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2239 VM_Warning("gettagindex: can't affect world entity\n");
2242 VM_Warning("gettagindex: can't affect free entity\n");
2245 Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2248 Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2251 Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2256 //============================================================================
2258 //====================
2259 //QC POLYGON functions
2260 //====================
2262 #define VMPOLYGONS_MAXPOINTS 64
2264 typedef struct vmpolygons_triangle_s
2266 rtexture_t *texture;
2269 }vmpolygons_triangle_t;
2271 typedef struct vmpolygons_s
2274 qboolean initialized;
2278 float *data_vertex3f;
2279 float *data_color4f;
2280 float *data_texcoord2f;
2284 vmpolygons_triangle_t *data_triangles;
2285 int *data_sortedelement3i;
2287 qboolean begin_active;
2288 rtexture_t *begin_texture;
2291 float begin_vertex[VMPOLYGONS_MAXPOINTS][3];
2292 float begin_color[VMPOLYGONS_MAXPOINTS][4];
2293 float begin_texcoord[VMPOLYGONS_MAXPOINTS][2];
2296 // FIXME: make VM_CL_R_Polygon functions use Debug_Polygon functions?
2297 vmpolygons_t vmpolygons[PRVM_MAXPROGS];
2299 static void VM_ResizePolygons(vmpolygons_t *polys)
2301 float *oldvertex3f = polys->data_vertex3f;
2302 float *oldcolor4f = polys->data_color4f;
2303 float *oldtexcoord2f = polys->data_texcoord2f;
2304 vmpolygons_triangle_t *oldtriangles = polys->data_triangles;
2305 int *oldsortedelement3i = polys->data_sortedelement3i;
2306 polys->max_vertices = polys->max_triangles*3;
2307 polys->data_vertex3f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[3]));
2308 polys->data_color4f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[4]));
2309 polys->data_texcoord2f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[2]));
2310 polys->data_triangles = (vmpolygons_triangle_t *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(vmpolygons_triangle_t));
2311 polys->data_sortedelement3i = (int *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(int[3]));
2312 if (polys->num_vertices)
2314 memcpy(polys->data_vertex3f, oldvertex3f, polys->num_vertices*sizeof(float[3]));
2315 memcpy(polys->data_color4f, oldcolor4f, polys->num_vertices*sizeof(float[4]));
2316 memcpy(polys->data_texcoord2f, oldtexcoord2f, polys->num_vertices*sizeof(float[2]));
2318 if (polys->num_triangles)
2320 memcpy(polys->data_triangles, oldtriangles, polys->num_triangles*sizeof(vmpolygons_triangle_t));
2321 memcpy(polys->data_sortedelement3i, oldsortedelement3i, polys->num_triangles*sizeof(int[3]));
2324 Mem_Free(oldvertex3f);
2326 Mem_Free(oldcolor4f);
2328 Mem_Free(oldtexcoord2f);
2330 Mem_Free(oldtriangles);
2331 if (oldsortedelement3i)
2332 Mem_Free(oldsortedelement3i);
2335 static void VM_InitPolygons (vmpolygons_t* polys)
2337 memset(polys, 0, sizeof(*polys));
2338 polys->pool = Mem_AllocPool("VMPOLY", 0, NULL);
2339 polys->max_triangles = 1024;
2340 VM_ResizePolygons(polys);
2341 polys->initialized = true;
2344 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2346 int surfacelistindex;
2347 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2348 R_Mesh_Matrix(&identitymatrix);
2349 GL_CullFace(GL_NONE);
2350 R_Mesh_VertexPointer(polys->data_vertex3f, 0, 0);
2351 R_Mesh_ColorPointer(polys->data_color4f, 0, 0);
2352 R_Mesh_TexCoordPointer(0, 2, polys->data_texcoord2f, 0, 0);
2353 R_SetupGenericShader(true);
2354 for (surfacelistindex = 0;surfacelistindex < numsurfaces;)
2356 int numtriangles = 0;
2357 rtexture_t *tex = polys->data_triangles[surfacelist[surfacelistindex]].texture;
2358 int drawflag = polys->data_triangles[surfacelist[surfacelistindex]].drawflag;
2359 if(drawflag == DRAWFLAG_ADDITIVE)
2360 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2361 else if(drawflag == DRAWFLAG_MODULATE)
2362 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2363 else if(drawflag == DRAWFLAG_2XMODULATE)
2364 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2366 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2367 R_Mesh_TexBind(0, R_GetTexture(tex));
2369 for (;surfacelistindex < numsurfaces;surfacelistindex++)
2371 if (polys->data_triangles[surfacelist[surfacelistindex]].texture != tex || polys->data_triangles[surfacelist[surfacelistindex]].drawflag != drawflag)
2373 VectorCopy(polys->data_triangles[surfacelist[surfacelistindex]].element3i, polys->data_sortedelement3i + 3*numtriangles);
2376 R_Mesh_Draw(0, polys->num_vertices, numtriangles, polys->data_sortedelement3i, 0, 0);
2380 void VMPolygons_Store(vmpolygons_t *polys)
2382 if (r_refdef.draw2dstage)
2384 // draw the polygon as 2D immediately
2385 drawqueuemesh_t mesh;
2386 mesh.texture = polys->begin_texture;
2387 mesh.num_vertices = polys->begin_vertices;
2388 mesh.num_triangles = polys->begin_vertices-2;
2389 mesh.data_element3i = polygonelements;
2390 mesh.data_vertex3f = polys->begin_vertex[0];
2391 mesh.data_color4f = polys->begin_color[0];
2392 mesh.data_texcoord2f = polys->begin_texcoord[0];
2393 DrawQ_Mesh(&mesh, polys->begin_drawflag);
2397 // queue the polygon as 3D for sorted transparent rendering later
2399 if (polys->max_triangles < polys->num_triangles + polys->begin_vertices-2)
2401 polys->max_triangles *= 2;
2402 VM_ResizePolygons(polys);
2404 memcpy(polys->data_vertex3f + polys->num_vertices * 3, polys->begin_vertex[0], polys->num_vertices * sizeof(float[3]));
2405 memcpy(polys->data_color4f + polys->num_vertices * 4, polys->begin_color[0], polys->num_vertices * sizeof(float[4]));
2406 memcpy(polys->data_texcoord2f + polys->num_vertices * 2, polys->begin_texcoord[0], polys->num_vertices * sizeof(float[2]));
2407 for (i = 0;i < polys->begin_vertices-2;i++)
2409 polys->data_triangles[polys->num_triangles].texture = polys->begin_texture;
2410 polys->data_triangles[polys->num_triangles].drawflag = polys->begin_drawflag;
2411 polys->data_triangles[polys->num_triangles].element3i[0] = polys->num_vertices;
2412 polys->data_triangles[polys->num_triangles].element3i[1] = polys->num_vertices + i+1;
2413 polys->data_triangles[polys->num_triangles].element3i[2] = polys->num_vertices + i+2;
2414 polys->num_triangles++;
2416 polys->num_vertices += polys->begin_vertices;
2418 polys->begin_active = false;
2421 // TODO: move this into the client code and clean-up everything else, too! [1/6/2008 Black]
2422 // LordHavoc: agreed, this is a mess
2423 void VM_CL_AddPolygonsToMeshQueue (void)
2426 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2429 // only add polygons of the currently active prog to the queue - if there is none, we're done
2433 if (!polys->num_triangles)
2436 for (i = 0;i < polys->num_triangles;i++)
2438 VectorMAMAM(1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].element3i[0], 1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].element3i[1], 1.0f / 3.0f, polys->data_vertex3f + 3*polys->data_triangles[i].element3i[2], center);
2439 R_MeshQueue_AddTransparent(center, VM_DrawPolygonCallback, NULL, i, NULL);
2442 polys->num_triangles = 0;
2443 polys->num_vertices = 0;
2446 //void(string texturename, float flag) R_BeginPolygon
2447 void VM_CL_R_PolygonBegin (void)
2449 const char *picname;
2450 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2452 VM_SAFEPARMCOUNT(2, VM_CL_R_PolygonBegin);
2454 if (!polys->initialized)
2455 VM_InitPolygons(polys);
2456 if (polys->begin_active)
2458 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonBegin after first\n");
2461 picname = PRVM_G_STRING(OFS_PARM0);
2462 polys->begin_texture = picname[0] ? Draw_CachePic(picname, true)->tex : r_texture_white;
2463 polys->begin_drawflag = (int)PRVM_G_FLOAT(OFS_PARM1);
2464 polys->begin_vertices = 0;
2465 polys->begin_active = true;
2468 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2469 void VM_CL_R_PolygonVertex (void)
2471 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2473 VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2475 if (!polys->begin_active)
2477 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2481 if (polys->begin_vertices >= VMPOLYGONS_MAXPOINTS)
2483 VM_Warning("VM_CL_R_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
2487 polys->begin_vertex[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM0)[0];
2488 polys->begin_vertex[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM0)[1];
2489 polys->begin_vertex[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM0)[2];
2490 polys->begin_texcoord[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM1)[0];
2491 polys->begin_texcoord[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM1)[1];
2492 polys->begin_color[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM2)[0];
2493 polys->begin_color[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM2)[1];
2494 polys->begin_color[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM2)[2];
2495 polys->begin_color[polys->begin_vertices][3] = PRVM_G_FLOAT(OFS_PARM3);
2496 polys->begin_vertices++;
2499 //void() R_EndPolygon
2500 void VM_CL_R_PolygonEnd (void)
2502 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2504 VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2505 if (!polys->begin_active)
2507 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2510 polys->begin_active = false;
2511 if (polys->begin_vertices >= 3)
2512 VMPolygons_Store(polys);
2514 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", polys->begin_vertices);
2517 static vmpolygons_t debugPolys;
2519 void Debug_PolygonBegin(const char *picname, int drawflag)
2521 if(!debugPolys.initialized)
2522 VM_InitPolygons(&debugPolys);
2523 if(debugPolys.begin_active)
2525 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2528 debugPolys.begin_texture = picname[0] ? Draw_CachePic(picname, true)->tex : r_texture_white;
2529 debugPolys.begin_drawflag = drawflag;
2530 debugPolys.begin_vertices = 0;
2531 debugPolys.begin_active = true;
2534 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2536 if(!debugPolys.begin_active)
2538 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2542 if(debugPolys.begin_vertices > VMPOLYGONS_MAXPOINTS)
2544 Con_Printf("Debug_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
2548 debugPolys.begin_vertex[debugPolys.begin_vertices][0] = x;
2549 debugPolys.begin_vertex[debugPolys.begin_vertices][1] = y;
2550 debugPolys.begin_vertex[debugPolys.begin_vertices][2] = z;
2551 debugPolys.begin_texcoord[debugPolys.begin_vertices][0] = s;
2552 debugPolys.begin_texcoord[debugPolys.begin_vertices][1] = t;
2553 debugPolys.begin_color[debugPolys.begin_vertices][0] = r;
2554 debugPolys.begin_color[debugPolys.begin_vertices][1] = g;
2555 debugPolys.begin_color[debugPolys.begin_vertices][2] = b;
2556 debugPolys.begin_color[debugPolys.begin_vertices][3] = a;
2557 debugPolys.begin_vertices++;
2560 void Debug_PolygonEnd(void)
2562 if (!debugPolys.begin_active)
2564 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2567 debugPolys.begin_active = false;
2568 if (debugPolys.begin_vertices >= 3)
2569 VMPolygons_Store(&debugPolys);
2571 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", debugPolys.begin_vertices);
2578 Returns false if any part of the bottom of the entity is off an edge that
2583 qboolean CL_CheckBottom (prvm_edict_t *ent)
2585 vec3_t mins, maxs, start, stop;
2590 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2591 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2593 // if all of the points under the corners are solid world, don't bother
2594 // with the tougher checks
2595 // the corners must be within 16 of the midpoint
2596 start[2] = mins[2] - 1;
2597 for (x=0 ; x<=1 ; x++)
2598 for (y=0 ; y<=1 ; y++)
2600 start[0] = x ? maxs[0] : mins[0];
2601 start[1] = y ? maxs[1] : mins[1];
2602 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2606 return true; // we got out easy
2610 // check it for real...
2614 // the midpoint must be within 16 of the bottom
2615 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2616 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2617 stop[2] = start[2] - 2*sv_stepheight.value;
2618 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2620 if (trace.fraction == 1.0)
2622 mid = bottom = trace.endpos[2];
2624 // the corners must be within 16 of the midpoint
2625 for (x=0 ; x<=1 ; x++)
2626 for (y=0 ; y<=1 ; y++)
2628 start[0] = stop[0] = x ? maxs[0] : mins[0];
2629 start[1] = stop[1] = y ? maxs[1] : mins[1];
2631 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2633 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2634 bottom = trace.endpos[2];
2635 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2646 Called by monster program code.
2647 The move will be adjusted for slopes and stairs, but if the move isn't
2648 possible, no move is done and false is returned
2651 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2654 vec3_t oldorg, neworg, end, traceendpos;
2657 prvm_edict_t *enemy;
2661 VectorCopy (ent->fields.client->origin, oldorg);
2662 VectorAdd (ent->fields.client->origin, move, neworg);
2664 // flying monsters don't step up
2665 if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2667 // try one move with vertical motion, then one without
2668 for (i=0 ; i<2 ; i++)
2670 VectorAdd (ent->fields.client->origin, move, neworg);
2671 enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2672 if (i == 0 && enemy != prog->edicts)
2674 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2680 trace = CL_Move (ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->maxs, neworg, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2682 VM_SetTraceGlobals(&trace);
2684 if (trace.fraction == 1)
2686 VectorCopy(trace.endpos, traceendpos);
2687 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2688 return false; // swim monster left water
2690 VectorCopy (traceendpos, ent->fields.client->origin);
2696 if (enemy == prog->edicts)
2703 // push down from a step height above the wished position
2704 neworg[2] += sv_stepheight.value;
2705 VectorCopy (neworg, end);
2706 end[2] -= sv_stepheight.value*2;
2708 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2710 VM_SetTraceGlobals(&trace);
2712 if (trace.startsolid)
2714 neworg[2] -= sv_stepheight.value;
2715 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2717 VM_SetTraceGlobals(&trace);
2718 if (trace.startsolid)
2721 if (trace.fraction == 1)
2723 // if monster had the ground pulled out, go ahead and fall
2724 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2726 VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2729 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2733 return false; // walked off an edge
2736 // check point traces down for dangling corners
2737 VectorCopy (trace.endpos, ent->fields.client->origin);
2739 if (!CL_CheckBottom (ent))
2741 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2742 { // entity had floor mostly pulled out from underneath it
2743 // and is trying to correct
2748 VectorCopy (oldorg, ent->fields.client->origin);
2752 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2753 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2755 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2756 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2768 float(float yaw, float dist[, settrace]) walkmove
2771 static void VM_CL_walkmove (void)
2780 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2782 // assume failure if it returns early
2783 PRVM_G_FLOAT(OFS_RETURN) = 0;
2785 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2786 if (ent == prog->edicts)
2788 VM_Warning("walkmove: can not modify world entity\n");
2791 if (ent->priv.server->free)
2793 VM_Warning("walkmove: can not modify free entity\n");
2796 yaw = PRVM_G_FLOAT(OFS_PARM0);
2797 dist = PRVM_G_FLOAT(OFS_PARM1);
2798 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2800 if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2803 yaw = yaw*M_PI*2 / 360;
2805 move[0] = cos(yaw)*dist;
2806 move[1] = sin(yaw)*dist;
2809 // save program state, because CL_movestep may call other progs
2810 oldf = prog->xfunction;
2811 oldself = prog->globals.client->self;
2813 PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2816 // restore program state
2817 prog->xfunction = oldf;
2818 prog->globals.client->self = oldself;
2825 string(string key) serverkey
2828 void VM_CL_serverkey(void)
2830 char string[VM_STRINGTEMP_LENGTH];
2831 VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2832 InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2833 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2836 //============================================================================
2838 // To create a almost working builtin file from this replace:
2839 // "^NULL.*" with ""
2840 // "^{.*//.*}:Wh\(.*\)" with "\1"
2842 // "^.*//:Wh{\#:d*}:Wh{.*}" with "\2 = \1;"
2843 // "\n\n+" with "\n\n"
2845 prvm_builtin_t vm_cl_builtins[] = {
2846 NULL, // #0 NULL function (not callable) (QUAKE)
2847 VM_CL_makevectors, // #1 void(vector ang) makevectors (QUAKE)
2848 VM_CL_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
2849 VM_CL_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
2850 VM_CL_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2851 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2852 VM_break, // #6 void() break (QUAKE)
2853 VM_random, // #7 float() random (QUAKE)
2854 VM_CL_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
2855 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
2856 VM_error, // #10 void(string e) error (QUAKE)
2857 VM_objerror, // #11 void(string e) objerror (QUAKE)
2858 VM_vlen, // #12 float(vector v) vlen (QUAKE)
2859 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
2860 VM_CL_spawn, // #14 entity() spawn (QUAKE)
2861 VM_remove, // #15 void(entity e) remove (QUAKE)
2862 VM_CL_traceline, // #16 float(vector v1, vector v2, float tryents, entity ignoreentity) traceline (QUAKE)
2863 NULL, // #17 entity() checkclient (QUAKE)
2864 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
2865 VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
2866 VM_CL_precache_model, // #20 void(string s) precache_model (QUAKE)
2867 NULL, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2868 VM_CL_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
2869 NULL, // #23 void(string s, ...) bprint (QUAKE)
2870 NULL, // #24 void(entity client, string s, ...) sprint (QUAKE)
2871 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
2872 VM_ftos, // #26 string(float f) ftos (QUAKE)
2873 VM_vtos, // #27 string(vector v) vtos (QUAKE)
2874 VM_coredump, // #28 void() coredump (QUAKE)
2875 VM_traceon, // #29 void() traceon (QUAKE)
2876 VM_traceoff, // #30 void() traceoff (QUAKE)
2877 VM_eprint, // #31 void(entity e) eprint (QUAKE)
2878 VM_CL_walkmove, // #32 float(float yaw, float dist[, float settrace]) walkmove (QUAKE)
2879 NULL, // #33 (QUAKE)
2880 VM_CL_droptofloor, // #34 float() droptofloor (QUAKE)
2881 VM_CL_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
2882 VM_rint, // #36 float(float v) rint (QUAKE)
2883 VM_floor, // #37 float(float v) floor (QUAKE)
2884 VM_ceil, // #38 float(float v) ceil (QUAKE)
2885 NULL, // #39 (QUAKE)
2886 VM_CL_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
2887 VM_CL_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
2888 NULL, // #42 (QUAKE)
2889 VM_fabs, // #43 float(float f) fabs (QUAKE)
2890 NULL, // #44 vector(entity e, float speed) aim (QUAKE)
2891 VM_cvar, // #45 float(string s) cvar (QUAKE)
2892 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
2893 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
2894 VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2895 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
2896 NULL, // #50 (QUAKE)
2897 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
2898 NULL, // #52 void(float to, float f) WriteByte (QUAKE)
2899 NULL, // #53 void(float to, float f) WriteChar (QUAKE)
2900 NULL, // #54 void(float to, float f) WriteShort (QUAKE)
2901 NULL, // #55 void(float to, float f) WriteLong (QUAKE)
2902 NULL, // #56 void(float to, float f) WriteCoord (QUAKE)
2903 NULL, // #57 void(float to, float f) WriteAngle (QUAKE)
2904 NULL, // #58 void(float to, string s) WriteString (QUAKE)
2905 NULL, // #59 (QUAKE)
2906 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2907 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2908 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2909 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2910 VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2911 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2912 NULL, // #66 (QUAKE)
2913 NULL, // #67 void(float step) movetogoal (QUAKE)
2914 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
2915 VM_CL_makestatic, // #69 void(entity e) makestatic (QUAKE)
2916 NULL, // #70 void(string s) changelevel (QUAKE)
2917 NULL, // #71 (QUAKE)
2918 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
2919 NULL, // #73 void(entity client, strings) centerprint (QUAKE)
2920 VM_CL_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2921 VM_CL_precache_model, // #75 string(string s) precache_model2 (QUAKE)
2922 VM_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
2923 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
2924 NULL, // #78 void(entity e) setspawnparms (QUAKE)
2925 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
2926 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
2927 VM_stof, // #81 float(string s) stof (FRIK_FILE)
2928 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
2929 NULL, // #83 (QUAKE)
2930 NULL, // #84 (QUAKE)
2931 NULL, // #85 (QUAKE)
2932 NULL, // #86 (QUAKE)
2933 NULL, // #87 (QUAKE)
2934 NULL, // #88 (QUAKE)
2935 NULL, // #89 (QUAKE)
2936 VM_CL_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2937 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2938 VM_CL_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2939 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2940 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2941 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2942 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2943 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2944 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2945 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
2946 // FrikaC and Telejano range #100-#199
2957 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
2958 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
2959 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
2960 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2961 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
2962 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
2963 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
2964 VM_stov, // #117 vector(string) stov (FRIK_FILE)
2965 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
2966 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3047 // FTEQW range #200-#299
3066 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3069 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3070 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3071 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3072 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3073 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3074 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3075 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3076 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3077 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3078 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3080 NULL, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3148 // CSQC range #300-#399
3149 VM_CL_R_ClearScene, // #300 void() clearscene (EXT_CSQC)
3150 VM_CL_R_AddEntities, // #301 void(float mask) addentities (EXT_CSQC)
3151 VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC)
3152 VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC)
3153 VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC)
3154 VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3155 VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3156 VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3157 VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon
3158 NULL /* R_LoadWorldModel in menu VM, should stay unassigned in client*/, // #309
3159 VM_CL_unproject, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3160 VM_CL_project, // #311 vector (vector v) cs_project (EXT_CSQC)
3164 VM_drawline, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3165 VM_iscachedpic, // #316 float(string name) iscachedpic (EXT_CSQC)
3166 VM_precache_pic, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3167 VM_getimagesize, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3168 VM_freepic, // #319 void(string name) freepic (EXT_CSQC)
3169 VM_drawcharacter, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3170 VM_drawstring, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3171 VM_drawpic, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3172 VM_drawfill, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3173 VM_drawsetcliparea, // #324 void(float x, float y, float width, float height) drawsetcliparea
3174 VM_drawresetcliparea, // #325 void(void) drawresetcliparea
3175 VM_drawcolorcodedstring, // #326 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) (EXT_CSQC)
3176 NULL, // #327 // FIXME add stringwidth() here?
3177 NULL, // #328 // FIXME add drawsubpic() here?
3179 VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
3180 VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
3181 VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
3182 VM_CL_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3183 VM_CL_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3184 VM_CL_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3185 VM_CL_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3186 VM_CL_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3187 VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC)
3188 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3189 VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3190 VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3191 VM_CL_getkeybind, // #342 string(float keynum) getkeybind (EXT_CSQC)
3192 VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3193 VM_getmousepos, // #344 vector() getmousepos (EXT_CSQC)
3194 VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC)
3195 VM_CL_setsensitivityscale, // #346 void(float sens) setsensitivityscale (EXT_CSQC)
3196 VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC)
3197 VM_CL_getplayerkey, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3198 VM_CL_isdemo, // #349 float() isdemo (EXT_CSQC)
3199 VM_isserver, // #350 float() isserver (EXT_CSQC)
3200 VM_CL_setlistener, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3201 VM_CL_registercmd, // #352 void(string cmdname) registercommand (EXT_CSQC)
3202 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3203 VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3209 VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC)
3210 VM_CL_ReadChar, // #361 float() readchar (EXT_CSQC)
3211 VM_CL_ReadShort, // #362 float() readshort (EXT_CSQC)
3212 VM_CL_ReadLong, // #363 float() readlong (EXT_CSQC)
3213 VM_CL_ReadCoord, // #364 float() readcoord (EXT_CSQC)
3214 VM_CL_ReadAngle, // #365 float() readangle (EXT_CSQC)
3215 VM_CL_ReadString, // #366 string() readstring (EXT_CSQC)
3216 VM_CL_ReadFloat, // #367 float() readfloat (EXT_CSQC)
3249 // LordHavoc's range #400-#499
3250 VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3251 NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3252 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3253 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3254 VM_CL_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3255 VM_CL_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3256 VM_CL_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3257 VM_CL_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3258 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)
3259 VM_CL_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3260 VM_CL_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3261 VM_CL_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3262 VM_CL_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3263 VM_CL_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3264 VM_CL_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3265 VM_CL_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3266 VM_CL_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3267 VM_CL_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3268 VM_CL_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3269 VM_CL_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3270 VM_CL_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3271 VM_CL_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3272 VM_CL_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3273 VM_CL_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3274 VM_CL_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3275 VM_CL_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3276 VM_CL_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3277 VM_CL_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3278 VM_CL_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3279 VM_CL_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3280 VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3281 VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3282 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3283 VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3284 VM_CL_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3285 VM_CL_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3286 VM_CL_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3287 VM_CL_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3288 VM_CL_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3289 VM_CL_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3290 NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3291 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3292 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3293 VM_CL_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3294 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3295 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3296 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3297 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3298 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3299 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3300 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3301 VM_CL_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3302 VM_CL_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3303 NULL, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3304 NULL, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3305 NULL, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3306 NULL, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3307 VM_CL_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet (DP_TE_FLAMEJET)
3309 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3310 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3311 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3312 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3313 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3314 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3315 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3316 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3317 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3318 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3319 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3320 NULL, // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3321 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3322 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3323 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3324 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3325 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3326 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3327 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3328 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3329 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3330 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3331 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3332 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3333 VM_CL_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) pointsound (DP_SV_POINTSOUND)
3334 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3335 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3336 VM_CL_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute
3337 VM_gecko_create, // #487 float gecko_create( string name )
3338 VM_gecko_destroy, // #488 void gecko_destroy( string name )
3339 VM_gecko_navigate, // #489 void gecko_navigate( string name, string URI )
3340 VM_gecko_keyevent, // #490 float gecko_keyevent( string name, float key, float eventtype )
3341 VM_gecko_movemouse, // #491 void gecko_mousemove( string name, float x, float y )
3342 VM_gecko_resize, // #492 void gecko_resize( string name, float w, float h )
3343 VM_gecko_get_texture_extent, // #493 vector gecko_get_texture_extent( string name )
3344 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3352 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3354 void VM_Polygons_Reset(void)
3356 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
3358 // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3359 if(polys->initialized)
3361 Mem_FreePool(&polys->pool);
3362 polys->initialized = false;
3366 void VM_CL_Cmd_Init(void)
3369 VM_Polygons_Reset();
3372 void VM_CL_Cmd_Reset(void)
3375 VM_Polygons_Reset();