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 // FIXME: restore cl.csqc_origin
687 // FIXME: restore cl.csqc_angles
688 cl.csqc_vidvars.drawworld = true;
689 cl.csqc_vidvars.drawenginesbar = false;
690 cl.csqc_vidvars.drawcrosshair = false;
693 //#301 void(float mask) addentities (EXT_CSQC)
694 extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
695 extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
696 void VM_CL_R_AddEntities (void)
700 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
701 drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
702 CSQC_RelinkAllEntities(drawmask);
703 CL_RelinkLightFlashes();
705 prog->globals.client->time = cl.time;
706 for(i=1;i<prog->num_edicts;i++)
708 ed = &prog->edicts[i];
709 if(ed->priv.required->free)
712 if(ed->priv.required->free)
714 // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict
716 if(ed->priv.required->free)
718 if(!((int)ed->fields.client->drawmask & drawmask))
720 CSQC_AddRenderEdict(ed);
724 //#302 void(entity ent) addentity (EXT_CSQC)
725 void VM_CL_R_AddEntity (void)
727 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
728 CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
731 //#303 float(float property, ...) setproperty (EXT_CSQC)
732 void VM_CL_R_SetView (void)
738 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_SetView);
740 c = (int)PRVM_G_FLOAT(OFS_PARM0);
741 f = PRVM_G_VECTOR(OFS_PARM1);
742 k = PRVM_G_FLOAT(OFS_PARM1);
747 r_refdef.view.x = (int)(f[0] * vid.width / vid_conwidth.value);
748 r_refdef.view.y = (int)(f[1] * vid.height / vid_conheight.value);
751 r_refdef.view.x = (int)(k * vid.width / vid_conwidth.value);
754 r_refdef.view.y = (int)(k * vid.height / vid_conheight.value);
757 r_refdef.view.width = (int)(f[0] * vid.width / vid_conwidth.value);
758 r_refdef.view.height = (int)(f[1] * vid.height / vid_conheight.value);
761 r_refdef.view.width = (int)(k * vid.width / vid_conwidth.value);
764 r_refdef.view.height = (int)(k * vid.height / vid_conheight.value);
767 r_refdef.view.x = (int)(f[0] * vid.width / vid_conwidth.value);
768 r_refdef.view.y = (int)(f[1] * vid.height / vid_conheight.value);
769 f = PRVM_G_VECTOR(OFS_PARM2);
770 r_refdef.view.width = (int)(f[0] * vid.width / vid_conwidth.value);
771 r_refdef.view.height = (int)(f[1] * vid.height / vid_conheight.value);
774 r_refdef.view.frustum_x = tan(f[0] * M_PI / 360.0);r_refdef.view.ortho_x = f[0];
775 r_refdef.view.frustum_y = tan(f[1] * M_PI / 360.0);r_refdef.view.ortho_y = f[1];
778 r_refdef.view.frustum_x = tan(k * M_PI / 360.0);r_refdef.view.ortho_x = k;
781 r_refdef.view.frustum_y = tan(k * M_PI / 360.0);r_refdef.view.ortho_y = k;
784 VectorCopy(f, cl.csqc_origin);
788 cl.csqc_origin[0] = k;
792 cl.csqc_origin[1] = k;
796 cl.csqc_origin[2] = k;
800 VectorCopy(f, cl.csqc_angles);
804 cl.csqc_angles[0] = k;
808 cl.csqc_angles[1] = k;
812 cl.csqc_angles[2] = k;
816 cl.csqc_vidvars.drawworld = k;
818 case VF_DRAWENGINESBAR:
819 cl.csqc_vidvars.drawenginesbar = k;
821 case VF_DRAWCROSSHAIR:
822 cl.csqc_vidvars.drawcrosshair = k;
824 case VF_CL_VIEWANGLES:
825 VectorCopy(f, cl.viewangles);
827 case VF_CL_VIEWANGLES_X:
828 cl.viewangles[0] = k;
830 case VF_CL_VIEWANGLES_Y:
831 cl.viewangles[1] = k;
833 case VF_CL_VIEWANGLES_Z:
834 cl.viewangles[2] = k;
837 r_refdef.view.useperspective = k != 0;
840 PRVM_G_FLOAT(OFS_RETURN) = 0;
841 VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c);
844 PRVM_G_FLOAT(OFS_RETURN) = 1;
847 //#304 void() renderscene (EXT_CSQC)
848 void VM_CL_R_RenderScene (void)
850 VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
851 // we need to update any RENDER_VIEWMODEL entities at this point because
852 // csqc supplies its own view matrix
853 CL_UpdateViewEntities();
858 //#305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
859 void VM_CL_R_AddDynamicLight (void)
863 VM_SAFEPARMCOUNTRANGE(3, 3, VM_CL_R_AddDynamicLight);
865 // if we've run out of dlights, just return
866 if (r_refdef.scene.numlights >= MAX_DLIGHTS)
869 pos = PRVM_G_VECTOR(OFS_PARM0);
870 col = PRVM_G_VECTOR(OFS_PARM2);
871 Matrix4x4_CreateFromQuakeEntity(&matrix, pos[0], pos[1], pos[2], 0, 0, 0, PRVM_G_FLOAT(OFS_PARM1));
872 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);
875 //============================================================================
877 //#310 vector (vector v) cs_unproject (EXT_CSQC)
878 static void VM_CL_unproject (void)
883 VM_SAFEPARMCOUNT(1, VM_CL_unproject);
884 f = PRVM_G_VECTOR(OFS_PARM0);
885 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);
886 Matrix4x4_Transform(&r_refdef.view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
889 //#311 vector (vector v) cs_project (EXT_CSQC)
890 static void VM_CL_project (void)
896 VM_SAFEPARMCOUNT(1, VM_CL_project);
897 f = PRVM_G_VECTOR(OFS_PARM0);
898 Matrix4x4_Invert_Simple(&m, &r_refdef.view.matrix);
899 Matrix4x4_Transform(&m, f, v);
900 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]);
903 //#330 float(float stnum) getstatf (EXT_CSQC)
904 static void VM_CL_getstatf (void)
912 VM_SAFEPARMCOUNT(1, VM_CL_getstatf);
913 i = (int)PRVM_G_FLOAT(OFS_PARM0);
914 if(i < 0 || i >= MAX_CL_STATS)
916 VM_Warning("VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
920 PRVM_G_FLOAT(OFS_RETURN) = dat.f;
923 //#331 float(float stnum) getstati (EXT_CSQC)
924 static void VM_CL_getstati (void)
927 int firstbit, bitcount;
929 VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getstati);
931 index = (int)PRVM_G_FLOAT(OFS_PARM0);
934 firstbit = (int)PRVM_G_FLOAT(OFS_PARM1);
936 bitcount = (int)PRVM_G_FLOAT(OFS_PARM2);
946 if(index < 0 || index >= MAX_CL_STATS)
948 VM_Warning("VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
952 if (bitcount != 32) //32 causes the mask to overflow, so there's nothing to subtract from.
953 i = (((unsigned int)i)&(((1<<bitcount)-1)<<firstbit))>>firstbit;
954 PRVM_G_FLOAT(OFS_RETURN) = i;
957 //#332 string(float firststnum) getstats (EXT_CSQC)
958 static void VM_CL_getstats (void)
962 VM_SAFEPARMCOUNT(1, VM_CL_getstats);
963 i = (int)PRVM_G_FLOAT(OFS_PARM0);
964 if(i < 0 || i > MAX_CL_STATS-4)
966 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
967 VM_Warning("VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
970 strlcpy(t, (char*)&cl.stats[i], sizeof(t));
971 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
974 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
975 static void VM_CL_setmodelindex (void)
979 struct model_s *model;
981 VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex);
983 t = PRVM_G_EDICT(OFS_PARM0);
985 i = (int)PRVM_G_FLOAT(OFS_PARM1);
987 t->fields.client->model = 0;
988 t->fields.client->modelindex = 0;
993 model = CL_GetModelByIndex(i);
996 VM_Warning("VM_CL_setmodelindex: null model\n");
999 t->fields.client->model = PRVM_SetEngineString(model->name);
1000 t->fields.client->modelindex = i;
1002 // TODO: check if this breaks needed consistency and maybe add a cvar for it too?? [1/10/2008 Black]
1005 SetMinMaxSize (t, model->normalmins, model->normalmaxs);
1008 SetMinMaxSize (t, vec3_origin, vec3_origin);
1011 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
1012 static void VM_CL_modelnameforindex (void)
1016 VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
1018 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1019 model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
1020 PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(model->name) : 0;
1023 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
1024 static void VM_CL_particleeffectnum (void)
1027 VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
1028 i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
1031 PRVM_G_FLOAT(OFS_RETURN) = i;
1034 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
1035 static void VM_CL_trailparticles (void)
1040 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles);
1042 t = PRVM_G_EDICT(OFS_PARM0);
1043 i = (int)PRVM_G_FLOAT(OFS_PARM1);
1044 start = PRVM_G_VECTOR(OFS_PARM2);
1045 end = PRVM_G_VECTOR(OFS_PARM3);
1047 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);
1050 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
1051 static void VM_CL_pointparticles (void)
1055 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
1056 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1057 f = PRVM_G_VECTOR(OFS_PARM1);
1058 v = PRVM_G_VECTOR(OFS_PARM2);
1059 n = (int)PRVM_G_FLOAT(OFS_PARM3);
1060 CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
1063 //#342 string(float keynum) getkeybind (EXT_CSQC)
1064 static void VM_CL_getkeybind (void)
1066 VM_SAFEPARMCOUNT(1, VM_CL_getkeybind);
1067 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0)));
1070 //#343 void(float usecursor) setcursormode (EXT_CSQC)
1071 static void VM_CL_setcursormode (void)
1073 VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
1074 cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
1075 cl_ignoremousemoves = 2;
1078 //#345 float(float framenum) getinputstate (EXT_CSQC)
1079 static void VM_CL_getinputstate (void)
1082 VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
1083 frame = (int)PRVM_G_FLOAT(OFS_PARM0);
1084 for (i = 0;i < cl.movement_numqueue;i++)
1085 if (cl.movement_queue[i].sequence == frame)
1087 VectorCopy(cl.movement_queue[i].viewangles, prog->globals.client->input_angles);
1088 //prog->globals.client->input_buttons = cl.movement_queue[i].//FIXME
1089 VectorCopy(cl.movement_queue[i].move, prog->globals.client->input_movevalues);
1090 prog->globals.client->input_timelength = cl.movement_queue[i].frametime;
1091 if(cl.movement_queue[i].crouch)
1093 VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
1094 VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
1098 VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
1099 VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
1104 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
1105 static void VM_CL_setsensitivityscale (void)
1107 VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
1108 cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
1111 //#347 void() runstandardplayerphysics (EXT_CSQC)
1112 static void VM_CL_runplayerphysics (void)
1116 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
1117 static void VM_CL_getplayerkey (void)
1123 VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
1125 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1126 c = PRVM_G_STRING(OFS_PARM1);
1127 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1130 i = Sbar_GetPlayer(i);
1136 if(!strcasecmp(c, "name"))
1137 strlcpy(t, cl.scores[i].name, sizeof(t));
1139 if(!strcasecmp(c, "frags"))
1140 sprintf(t, "%i", cl.scores[i].frags);
1142 if(!strcasecmp(c, "ping"))
1143 sprintf(t, "%i", cl.scores[i].qw_ping);
1145 if(!strcasecmp(c, "pl"))
1146 sprintf(t, "%i", cl.scores[i].qw_packetloss);
1148 if(!strcasecmp(c, "entertime"))
1149 sprintf(t, "%f", cl.scores[i].qw_entertime);
1151 if(!strcasecmp(c, "colors"))
1152 sprintf(t, "%i", cl.scores[i].colors);
1154 if(!strcasecmp(c, "topcolor"))
1155 sprintf(t, "%i", cl.scores[i].colors & 0xf0);
1157 if(!strcasecmp(c, "bottomcolor"))
1158 sprintf(t, "%i", (cl.scores[i].colors &15)<<4);
1160 if(!strcasecmp(c, "viewentity"))
1161 sprintf(t, "%i", i+1);
1164 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1167 //#349 float() isdemo (EXT_CSQC)
1168 static void VM_CL_isdemo (void)
1170 VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
1171 PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
1174 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
1175 static void VM_CL_setlistener (void)
1177 VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
1178 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));
1179 cl.csqc_usecsqclistener = true; //use csqc listener at this frame
1182 //#352 void(string cmdname) registercommand (EXT_CSQC)
1183 static void VM_CL_registercmd (void)
1186 VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
1187 if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0)))
1191 alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1;
1192 t = (char *)Z_Malloc(alloclen);
1193 memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen);
1194 Cmd_AddCommand(t, NULL, "console command created by QuakeC");
1197 Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
1201 //#360 float() readbyte (EXT_CSQC)
1202 static void VM_CL_ReadByte (void)
1204 VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
1205 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte();
1208 //#361 float() readchar (EXT_CSQC)
1209 static void VM_CL_ReadChar (void)
1211 VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
1212 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar();
1215 //#362 float() readshort (EXT_CSQC)
1216 static void VM_CL_ReadShort (void)
1218 VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
1219 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort();
1222 //#363 float() readlong (EXT_CSQC)
1223 static void VM_CL_ReadLong (void)
1225 VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
1226 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong();
1229 //#364 float() readcoord (EXT_CSQC)
1230 static void VM_CL_ReadCoord (void)
1232 VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
1233 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(cls.protocol);
1236 //#365 float() readangle (EXT_CSQC)
1237 static void VM_CL_ReadAngle (void)
1239 VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
1240 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(cls.protocol);
1243 //#366 string() readstring (EXT_CSQC)
1244 static void VM_CL_ReadString (void)
1246 VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
1247 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_ReadString());
1250 //#367 float() readfloat (EXT_CSQC)
1251 static void VM_CL_ReadFloat (void)
1253 VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
1254 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
1257 //////////////////////////////////////////////////////////
1259 static void VM_CL_makestatic (void)
1263 VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
1265 ent = PRVM_G_EDICT(OFS_PARM0);
1266 if (ent == prog->edicts)
1268 VM_Warning("makestatic: can not modify world entity\n");
1271 if (ent->priv.server->free)
1273 VM_Warning("makestatic: can not modify free entity\n");
1277 if (cl.num_static_entities < cl.max_static_entities)
1281 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
1283 // copy it to the current state
1284 memset(staticent, 0, sizeof(*staticent));
1285 staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
1286 staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
1287 staticent->render.framelerp = 0;
1288 // make torchs play out of sync
1289 staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
1290 staticent->render.skinnum = (int)ent->fields.client->skin;
1291 staticent->render.effects = (int)ent->fields.client->effects;
1292 staticent->render.alpha = 1;
1293 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float;
1294 staticent->render.scale = 1;
1295 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
1296 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
1299 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
1300 if (renderflags & RF_USEAXIS)
1303 VectorNegate(prog->globals.client->v_right, left);
1304 Matrix4x4_FromVectors(&staticent->render.matrix, prog->globals.client->v_forward, left, prog->globals.client->v_up, ent->fields.client->origin);
1305 Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
1308 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);
1310 // either fullbright or lit
1311 if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
1312 staticent->render.flags |= RENDER_LIGHT;
1313 // turn off shadows from transparent objects
1314 if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
1315 staticent->render.flags |= RENDER_SHADOW;
1317 CL_UpdateRenderEntity(&staticent->render);
1320 Con_Printf("Too many static entities");
1322 // throw the entity away now
1326 //=================================================================//
1332 copies data from one entity to another
1334 copyentity(src, dst)
1337 static void VM_CL_copyentity (void)
1339 prvm_edict_t *in, *out;
1340 VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
1341 in = PRVM_G_EDICT(OFS_PARM0);
1342 if (in == prog->edicts)
1344 VM_Warning("copyentity: can not read world entity\n");
1347 if (in->priv.server->free)
1349 VM_Warning("copyentity: can not read free entity\n");
1352 out = PRVM_G_EDICT(OFS_PARM1);
1353 if (out == prog->edicts)
1355 VM_Warning("copyentity: can not modify world entity\n");
1358 if (out->priv.server->free)
1360 VM_Warning("copyentity: can not modify free entity\n");
1363 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1367 //=================================================================//
1369 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
1370 static void VM_CL_effect (void)
1372 VM_SAFEPARMCOUNT(5, VM_CL_effect);
1373 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));
1376 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
1377 static void VM_CL_te_blood (void)
1381 VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
1382 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1384 pos = PRVM_G_VECTOR(OFS_PARM0);
1385 CL_FindNonSolidLocation(pos, pos2, 4);
1386 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1389 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
1390 static void VM_CL_te_bloodshower (void)
1394 VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
1395 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1397 speed = PRVM_G_FLOAT(OFS_PARM2);
1404 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), vel1, vel2, NULL, 0);
1407 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
1408 static void VM_CL_te_explosionrgb (void)
1412 matrix4x4_t tempmatrix;
1413 VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
1414 pos = PRVM_G_VECTOR(OFS_PARM0);
1415 CL_FindNonSolidLocation(pos, pos2, 10);
1416 CL_ParticleExplosion(pos2);
1417 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1418 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);
1421 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
1422 static void VM_CL_te_particlecube (void)
1424 VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
1425 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));
1428 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
1429 static void VM_CL_te_particlerain (void)
1431 VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
1432 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);
1435 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
1436 static void VM_CL_te_particlesnow (void)
1438 VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
1439 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);
1442 // #411 void(vector org, vector vel, float howmany) te_spark
1443 static void VM_CL_te_spark (void)
1447 VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
1449 pos = PRVM_G_VECTOR(OFS_PARM0);
1450 CL_FindNonSolidLocation(pos, pos2, 4);
1451 CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1454 extern cvar_t cl_sound_ric_gunshot;
1455 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
1456 static void VM_CL_te_gunshotquad (void)
1461 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
1463 pos = PRVM_G_VECTOR(OFS_PARM0);
1464 CL_FindNonSolidLocation(pos, pos2, 4);
1465 CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1466 if(cl_sound_ric_gunshot.integer >= 2)
1468 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1472 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1473 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1474 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1479 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
1480 static void VM_CL_te_spikequad (void)
1485 VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
1487 pos = PRVM_G_VECTOR(OFS_PARM0);
1488 CL_FindNonSolidLocation(pos, pos2, 4);
1489 CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1490 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1494 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1495 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1496 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1500 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
1501 static void VM_CL_te_superspikequad (void)
1506 VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
1508 pos = PRVM_G_VECTOR(OFS_PARM0);
1509 CL_FindNonSolidLocation(pos, pos2, 4);
1510 CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1511 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1515 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1516 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1517 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1521 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
1522 static void VM_CL_te_explosionquad (void)
1526 VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
1528 pos = PRVM_G_VECTOR(OFS_PARM0);
1529 CL_FindNonSolidLocation(pos, pos2, 10);
1530 CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1531 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1534 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
1535 static void VM_CL_te_smallflash (void)
1539 VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
1541 pos = PRVM_G_VECTOR(OFS_PARM0);
1542 CL_FindNonSolidLocation(pos, pos2, 10);
1543 CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1546 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
1547 static void VM_CL_te_customflash (void)
1551 matrix4x4_t tempmatrix;
1552 VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
1554 pos = PRVM_G_VECTOR(OFS_PARM0);
1555 CL_FindNonSolidLocation(pos, pos2, 4);
1556 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1557 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);
1560 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
1561 static void VM_CL_te_gunshot (void)
1566 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
1568 pos = PRVM_G_VECTOR(OFS_PARM0);
1569 CL_FindNonSolidLocation(pos, pos2, 4);
1570 CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1571 if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
1573 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1577 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1578 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1579 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1584 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
1585 static void VM_CL_te_spike (void)
1590 VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
1592 pos = PRVM_G_VECTOR(OFS_PARM0);
1593 CL_FindNonSolidLocation(pos, pos2, 4);
1594 CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1595 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1599 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1600 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1601 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1605 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
1606 static void VM_CL_te_superspike (void)
1611 VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
1613 pos = PRVM_G_VECTOR(OFS_PARM0);
1614 CL_FindNonSolidLocation(pos, pos2, 4);
1615 CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1616 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1620 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1621 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1622 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1626 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
1627 static void VM_CL_te_explosion (void)
1631 VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
1633 pos = PRVM_G_VECTOR(OFS_PARM0);
1634 CL_FindNonSolidLocation(pos, pos2, 10);
1635 CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1636 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1639 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
1640 static void VM_CL_te_tarexplosion (void)
1644 VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
1646 pos = PRVM_G_VECTOR(OFS_PARM0);
1647 CL_FindNonSolidLocation(pos, pos2, 10);
1648 CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1649 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1652 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
1653 static void VM_CL_te_wizspike (void)
1657 VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
1659 pos = PRVM_G_VECTOR(OFS_PARM0);
1660 CL_FindNonSolidLocation(pos, pos2, 4);
1661 CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1662 S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
1665 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
1666 static void VM_CL_te_knightspike (void)
1670 VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
1672 pos = PRVM_G_VECTOR(OFS_PARM0);
1673 CL_FindNonSolidLocation(pos, pos2, 4);
1674 CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1675 S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
1678 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
1679 static void VM_CL_te_lavasplash (void)
1681 VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
1682 CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1685 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
1686 static void VM_CL_te_teleport (void)
1688 VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
1689 CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1692 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
1693 static void VM_CL_te_explosion2 (void)
1697 matrix4x4_t tempmatrix;
1698 int colorStart, colorLength;
1699 unsigned char *tempcolor;
1700 VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
1702 pos = PRVM_G_VECTOR(OFS_PARM0);
1703 colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
1704 colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
1705 CL_FindNonSolidLocation(pos, pos2, 10);
1706 CL_ParticleExplosion2(pos2, colorStart, colorLength);
1707 tempcolor = palette_rgb[(rand()%colorLength) + colorStart];
1708 color[0] = tempcolor[0] * (2.0f / 255.0f);
1709 color[1] = tempcolor[1] * (2.0f / 255.0f);
1710 color[2] = tempcolor[2] * (2.0f / 255.0f);
1711 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1712 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);
1713 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1717 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
1718 static void VM_CL_te_lightning1 (void)
1720 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
1721 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
1724 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
1725 static void VM_CL_te_lightning2 (void)
1727 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
1728 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
1731 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
1732 static void VM_CL_te_lightning3 (void)
1734 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
1735 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
1738 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
1739 static void VM_CL_te_beam (void)
1741 VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
1742 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
1745 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
1746 static void VM_CL_te_plasmaburn (void)
1750 VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
1752 pos = PRVM_G_VECTOR(OFS_PARM0);
1753 CL_FindNonSolidLocation(pos, pos2, 4);
1754 CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1757 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
1758 static void VM_CL_te_flamejet (void)
1762 VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
1763 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1765 pos = PRVM_G_VECTOR(OFS_PARM0);
1766 CL_FindNonSolidLocation(pos, pos2, 4);
1767 CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1771 //====================================================================
1774 extern void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
1776 static msurface_t *cl_getsurface(model_t *model, int surfacenum)
1778 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1780 return model->data_surfaces + surfacenum + model->firstmodelsurface;
1783 // #434 float(entity e, float s) getsurfacenumpoints
1784 static void VM_CL_getsurfacenumpoints(void)
1787 msurface_t *surface;
1788 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
1789 // return 0 if no such surface
1790 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1792 PRVM_G_FLOAT(OFS_RETURN) = 0;
1796 // note: this (incorrectly) assumes it is a simple polygon
1797 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1800 // #435 vector(entity e, float s, float n) getsurfacepoint
1801 static void VM_CL_getsurfacepoint(void)
1805 msurface_t *surface;
1807 VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1808 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1809 ed = PRVM_G_EDICT(OFS_PARM0);
1810 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1812 // note: this (incorrectly) assumes it is a simple polygon
1813 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1814 if (pointnum < 0 || pointnum >= surface->num_vertices)
1816 // FIXME: implement rotation/scaling
1817 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1819 //PF_getsurfacepointattribute, // #486 vector(entity e, float s, float n, float a) getsurfacepointattribute = #486;
1820 // float SPA_POSITION = 0;
1821 // float SPA_S_AXIS = 1;
1822 // float SPA_T_AXIS = 2;
1823 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
1824 // float SPA_TEXCOORDS0 = 4;
1825 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
1826 // float SPA_LIGHTMAP0_COLOR = 6;
1827 // TODO: add some wrapper code and merge VM_CL/SV_getsurface* [12/16/2007 Black]
1828 static void VM_CL_getsurfacepointattribute(void)
1832 msurface_t *surface;
1836 VM_SAFEPARMCOUNT(4, VM_CL_getsurfacenumpoints);
1837 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1838 ed = PRVM_G_EDICT(OFS_PARM0);
1839 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1841 // note: this (incorrectly) assumes it is a simple polygon
1842 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1843 if (pointnum < 0 || pointnum >= surface->num_vertices)
1846 // FIXME: implement rotation/scaling
1847 attributetype = (int) PRVM_G_FLOAT(OFS_PARM3);
1849 switch( attributetype ) {
1850 // float SPA_POSITION = 0;
1852 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
1854 // float SPA_S_AXIS = 1;
1856 VectorCopy(&(model->surfmesh.data_svector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1858 // float SPA_T_AXIS = 2;
1860 VectorCopy(&(model->surfmesh.data_tvector3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1862 // float SPA_R_AXIS = 3; // same as SPA_NORMAL
1864 VectorCopy(&(model->surfmesh.data_normal3f + 3 * surface->num_firstvertex)[pointnum * 3], PRVM_G_VECTOR(OFS_RETURN));
1866 // float SPA_TEXCOORDS0 = 4;
1868 float *ret = PRVM_G_VECTOR(OFS_RETURN);
1869 float *texcoord = &(model->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[pointnum * 2];
1870 ret[0] = texcoord[0];
1871 ret[1] = texcoord[1];
1875 // float SPA_LIGHTMAP0_TEXCOORDS = 5;
1877 float *ret = PRVM_G_VECTOR(OFS_RETURN);
1878 float *texcoord = &(model->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[pointnum * 2];
1879 ret[0] = texcoord[0];
1880 ret[1] = texcoord[1];
1884 // float SPA_LIGHTMAP0_COLOR = 6;
1886 // ignore alpha for now..
1887 VectorCopy( &(model->surfmesh.data_lightmapcolor4f + 4 * surface->num_firstvertex)[pointnum * 4], PRVM_G_VECTOR(OFS_RETURN));
1890 VectorSet( PRVM_G_VECTOR(OFS_RETURN), 0.0f, 0.0f, 0.0f );
1894 // #436 vector(entity e, float s) getsurfacenormal
1895 static void VM_CL_getsurfacenormal(void)
1898 msurface_t *surface;
1900 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
1901 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1902 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1904 // FIXME: implement rotation/scaling
1905 // note: this (incorrectly) assumes it is a simple polygon
1906 // note: this only returns the first triangle, so it doesn't work very
1907 // well for curved surfaces or arbitrary meshes
1908 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);
1909 VectorNormalize(normal);
1910 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1913 // #437 string(entity e, float s) getsurfacetexture
1914 static void VM_CL_getsurfacetexture(void)
1917 msurface_t *surface;
1918 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
1919 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1920 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1922 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
1925 // #438 float(entity e, vector p) getsurfacenearpoint
1926 static void VM_CL_getsurfacenearpoint(void)
1928 int surfacenum, best;
1930 vec_t dist, bestdist;
1932 model_t *model = NULL;
1933 msurface_t *surface;
1935 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
1936 PRVM_G_FLOAT(OFS_RETURN) = -1;
1937 ed = PRVM_G_EDICT(OFS_PARM0);
1938 if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces)
1941 // FIXME: implement rotation/scaling
1942 point = PRVM_G_VECTOR(OFS_PARM1);
1943 VectorSubtract(point, ed->fields.client->origin, p);
1945 bestdist = 1000000000;
1946 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1948 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1949 // first see if the nearest point on the surface's box is closer than the previous match
1950 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1951 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1952 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1953 dist = VectorLength2(clipped);
1954 if (dist < bestdist)
1956 // it is, check the nearest point on the actual geometry
1957 clippointtosurface(model, surface, p, clipped);
1958 VectorSubtract(clipped, p, clipped);
1959 dist += VectorLength2(clipped);
1960 if (dist < bestdist)
1962 // that's closer too, store it as the best match
1968 PRVM_G_FLOAT(OFS_RETURN) = best;
1971 // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint
1972 static void VM_CL_getsurfaceclippedpoint(void)
1976 msurface_t *surface;
1978 VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
1979 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1980 ed = PRVM_G_EDICT(OFS_PARM0);
1981 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1983 // FIXME: implement rotation/scaling
1984 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
1985 clippointtosurface(model, surface, p, out);
1986 // FIXME: implement rotation/scaling
1987 VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1990 // #443 void(entity e, entity tagentity, string tagname) setattachment
1991 static void VM_CL_setattachment (void)
1994 prvm_edict_t *tagentity;
1995 const char *tagname;
1999 VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
2001 e = PRVM_G_EDICT(OFS_PARM0);
2002 tagentity = PRVM_G_EDICT(OFS_PARM1);
2003 tagname = PRVM_G_STRING(OFS_PARM2);
2005 if (e == prog->edicts)
2007 VM_Warning("setattachment: can not modify world entity\n");
2010 if (e->priv.server->free)
2012 VM_Warning("setattachment: can not modify free entity\n");
2016 if (tagentity == NULL)
2017 tagentity = prog->edicts;
2019 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
2021 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2023 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
2026 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2028 modelindex = (int)tagentity->fields.client->modelindex;
2029 model = CL_GetModelByIndex(modelindex);
2032 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
2034 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);
2037 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));
2041 /////////////////////////////////////////
2042 // DP_MD3_TAGINFO extension coded by VorteX
2044 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
2046 model_t *model = CL_GetModelFromEdict(e);
2048 return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
2053 // Warnings/errors code:
2054 // 0 - normal (everything all-right)
2057 // 3 - null or non-precached model
2058 // 4 - no tags with requested index
2059 // 5 - runaway loop at attachment chain
2060 extern cvar_t cl_bob;
2061 extern cvar_t cl_bobcycle;
2062 extern cvar_t cl_bobup;
2063 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2066 int reqframe, attachloop;
2067 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2068 prvm_edict_t *attachent;
2072 *out = identitymatrix; // warnings and errors return identical matrix
2074 if (ent == prog->edicts)
2076 if (ent->priv.server->free)
2079 model = CL_GetModelFromEdict(ent);
2084 if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
2085 reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
2087 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
2089 // get initial tag matrix
2092 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
2097 tagmatrix = identitymatrix;
2099 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
2100 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2104 attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
2105 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
2107 model = CL_GetModelFromEdict(attachent);
2109 if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
2110 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
2112 attachmatrix = identitymatrix;
2114 // apply transformation by child entity matrix
2116 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2117 if (val && val->_float != 0)
2118 scale = val->_float;
2119 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);
2120 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2121 Matrix4x4_Copy(&tagmatrix, out);
2123 // finally transformate by matrix of tag on parent entity
2124 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
2125 Matrix4x4_Copy(&tagmatrix, out);
2129 if (attachloop > 255) // prevent runaway looping
2132 while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
2135 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
2137 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2138 if (val && val->_float != 0)
2139 scale = val->_float;
2140 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
2141 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);
2142 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2144 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
2145 {// RENDER_VIEWMODEL magic
2146 Matrix4x4_Copy(&tagmatrix, out);
2149 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
2150 if (val && val->_float != 0)
2151 scale = val->_float;
2153 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);
2154 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2157 // Cl_bob, ported from rendering code
2158 if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
2161 // LordHavoc: this code is *weird*, but not replacable (I think it
2162 // should be done in QC on the server, but oh well, quake is quake)
2163 // LordHavoc: figured out bobup: the time at which the sin is at 180
2164 // degrees (which allows lengthening or squishing the peak or valley)
2165 cycle = cl.time/cl_bobcycle.value;
2166 cycle -= (int)cycle;
2167 if (cycle < cl_bobup.value)
2168 cycle = sin(M_PI * cycle / cl_bobup.value);
2170 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2171 // bob is proportional to velocity in the xy plane
2172 // (don't count Z, or jumping messes it up)
2173 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;
2174 bob = bob*0.3 + bob*0.7*cycle;
2175 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2182 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
2183 static void VM_CL_gettagindex (void)
2186 const char *tag_name;
2187 int modelindex, tag_index;
2189 VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
2191 ent = PRVM_G_EDICT(OFS_PARM0);
2192 tag_name = PRVM_G_STRING(OFS_PARM1);
2193 if (ent == prog->edicts)
2195 VM_Warning("gettagindex: can't affect world entity\n");
2198 if (ent->priv.server->free)
2200 VM_Warning("gettagindex: can't affect free entity\n");
2204 modelindex = (int)ent->fields.client->modelindex;
2206 if (modelindex >= MAX_MODELS || (modelindex <= -MAX_MODELS /* client models */))
2207 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2210 tag_index = CL_GetTagIndex(ent, tag_name);
2212 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2214 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2217 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2218 static void VM_CL_gettaginfo (void)
2222 matrix4x4_t tag_matrix;
2225 VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2227 e = PRVM_G_EDICT(OFS_PARM0);
2228 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2229 returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2230 Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2235 VM_Warning("gettagindex: can't affect world entity\n");
2238 VM_Warning("gettagindex: can't affect free entity\n");
2241 Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2244 Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2247 Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2252 //============================================================================
2254 //====================
2255 //QC POLYGON functions
2256 //====================
2258 #define VMPOLYGONS_MAXPOINTS 64
2260 typedef struct vmpolygons_triangle_s
2262 rtexture_t *texture;
2265 }vmpolygons_triangle_t;
2267 typedef struct vmpolygons_s
2270 qboolean initialized;
2274 float *data_vertex3f;
2275 float *data_color4f;
2276 float *data_texcoord2f;
2280 vmpolygons_triangle_t *data_triangles;
2281 int *data_sortedelement3i;
2283 qboolean begin_active;
2284 rtexture_t *begin_texture;
2287 float begin_vertex[VMPOLYGONS_MAXPOINTS][3];
2288 float begin_color[VMPOLYGONS_MAXPOINTS][4];
2289 float begin_texcoord[VMPOLYGONS_MAXPOINTS][2];
2292 // FIXME: make VM_CL_R_Polygon functions use Debug_Polygon functions?
2293 vmpolygons_t vmpolygons[PRVM_MAXPROGS];
2295 static void VM_ResizePolygons(vmpolygons_t *polys)
2297 float *oldvertex3f = polys->data_vertex3f;
2298 float *oldcolor4f = polys->data_color4f;
2299 float *oldtexcoord2f = polys->data_texcoord2f;
2300 vmpolygons_triangle_t *oldtriangles = polys->data_triangles;
2301 int *oldsortedelement3i = polys->data_sortedelement3i;
2302 polys->max_vertices = polys->max_triangles*3;
2303 polys->data_vertex3f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[3]));
2304 polys->data_color4f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[4]));
2305 polys->data_texcoord2f = (float *)Mem_Alloc(polys->pool, polys->max_vertices*sizeof(float[2]));
2306 polys->data_triangles = (vmpolygons_triangle_t *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(vmpolygons_triangle_t));
2307 polys->data_sortedelement3i = (int *)Mem_Alloc(polys->pool, polys->max_triangles*sizeof(int[3]));
2308 if (polys->num_vertices)
2310 memcpy(polys->data_vertex3f, oldvertex3f, polys->num_vertices*sizeof(float[3]));
2311 memcpy(polys->data_color4f, oldcolor4f, polys->num_vertices*sizeof(float[4]));
2312 memcpy(polys->data_texcoord2f, oldtexcoord2f, polys->num_vertices*sizeof(float[2]));
2314 if (polys->num_triangles)
2316 memcpy(polys->data_triangles, oldtriangles, polys->num_triangles*sizeof(vmpolygons_triangle_t));
2317 memcpy(polys->data_sortedelement3i, oldsortedelement3i, polys->num_triangles*sizeof(int[3]));
2320 Mem_Free(oldvertex3f);
2322 Mem_Free(oldcolor4f);
2324 Mem_Free(oldtexcoord2f);
2326 Mem_Free(oldtriangles);
2327 if (oldsortedelement3i)
2328 Mem_Free(oldsortedelement3i);
2331 static void VM_InitPolygons (vmpolygons_t* polys)
2333 memset(polys, 0, sizeof(*polys));
2334 polys->pool = Mem_AllocPool("VMPOLY", 0, NULL);
2335 polys->max_triangles = 1024;
2336 VM_ResizePolygons(polys);
2337 polys->initialized = true;
2340 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2342 int surfacelistindex;
2343 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2344 R_Mesh_Matrix(&identitymatrix);
2345 GL_CullFace(GL_NONE);
2346 R_Mesh_VertexPointer(polys->data_vertex3f, 0, 0);
2347 R_Mesh_ColorPointer(polys->data_color4f, 0, 0);
2348 R_Mesh_TexCoordPointer(0, 2, polys->data_texcoord2f, 0, 0);
2349 for (surfacelistindex = 0;surfacelistindex < numsurfaces;)
2351 int numtriangles = 0;
2352 rtexture_t *tex = polys->data_triangles[surfacelist[surfacelistindex]].texture;
2353 int drawflag = polys->data_triangles[surfacelist[surfacelistindex]].drawflag;
2354 if(drawflag == DRAWFLAG_ADDITIVE)
2355 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2356 else if(drawflag == DRAWFLAG_MODULATE)
2357 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2358 else if(drawflag == DRAWFLAG_2XMODULATE)
2359 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2361 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2362 R_Mesh_TexBind(0, R_GetTexture(tex));
2364 for (;surfacelistindex < numsurfaces;surfacelistindex++)
2366 if (polys->data_triangles[surfacelist[surfacelistindex]].texture != tex || polys->data_triangles[surfacelist[surfacelistindex]].drawflag != drawflag)
2368 VectorCopy(polys->data_triangles[surfacelist[surfacelistindex]].element3i, polys->data_sortedelement3i + 3*numtriangles);
2371 R_Mesh_Draw(0, polys->num_vertices, numtriangles, polys->data_sortedelement3i, 0, 0);
2375 void VMPolygons_Store(vmpolygons_t *polys)
2377 if (r_refdef.draw2dstage)
2379 // draw the polygon as 2D immediately
2380 drawqueuemesh_t mesh;
2381 mesh.texture = polys->begin_texture;
2382 mesh.num_vertices = polys->begin_vertices;
2383 mesh.num_triangles = polys->begin_vertices-2;
2384 mesh.data_element3i = polygonelements;
2385 mesh.data_vertex3f = polys->begin_vertex[0];
2386 mesh.data_color4f = polys->begin_color[0];
2387 mesh.data_texcoord2f = polys->begin_texcoord[0];
2388 DrawQ_Mesh(&mesh, polys->begin_drawflag);
2392 // queue the polygon as 3D for sorted transparent rendering later
2394 if (polys->max_triangles < polys->num_triangles + polys->begin_vertices-2)
2396 polys->max_triangles *= 2;
2397 VM_ResizePolygons(polys);
2399 memcpy(polys->data_vertex3f + polys->num_vertices * 3, polys->begin_vertex[0], polys->num_vertices * sizeof(float[3]));
2400 memcpy(polys->data_color4f + polys->num_vertices * 4, polys->begin_color[0], polys->num_vertices * sizeof(float[4]));
2401 memcpy(polys->data_texcoord2f + polys->num_vertices * 2, polys->begin_texcoord[0], polys->num_vertices * sizeof(float[2]));
2402 for (i = 0;i < polys->begin_vertices-2;i++)
2404 polys->data_triangles[polys->num_triangles].texture = polys->begin_texture;
2405 polys->data_triangles[polys->num_triangles].drawflag = polys->begin_drawflag;
2406 polys->data_triangles[polys->num_triangles].element3i[0] = polys->num_vertices;
2407 polys->data_triangles[polys->num_triangles].element3i[1] = polys->num_vertices + i+1;
2408 polys->data_triangles[polys->num_triangles].element3i[2] = polys->num_vertices + i+2;
2409 polys->num_triangles++;
2411 polys->num_vertices += polys->begin_vertices;
2413 polys->begin_active = false;
2416 // TODO: move this into the client code and clean-up everything else, too! [1/6/2008 Black]
2417 // LordHavoc: agreed, this is a mess
2418 void VM_CL_AddPolygonsToMeshQueue (void)
2421 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2424 // only add polygons of the currently active prog to the queue - if there is none, we're done
2428 if (!polys->num_triangles)
2431 for (i = 0;i < polys->num_triangles;i++)
2433 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);
2434 R_MeshQueue_AddTransparent(center, VM_DrawPolygonCallback, NULL, i, NULL);
2437 polys->num_triangles = 0;
2438 polys->num_vertices = 0;
2441 //void(string texturename, float flag) R_BeginPolygon
2442 void VM_CL_R_PolygonBegin (void)
2444 const char *picname;
2445 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2447 VM_SAFEPARMCOUNT(2, VM_CL_R_PolygonBegin);
2449 if (!polys->initialized)
2450 VM_InitPolygons(polys);
2451 if (polys->begin_active)
2453 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonEnd after first\n");
2456 picname = PRVM_G_STRING(OFS_PARM0);
2457 polys->begin_texture = picname[0] ? Draw_CachePic(picname, true)->tex : r_texture_white;
2458 polys->begin_drawflag = (int)PRVM_G_FLOAT(OFS_PARM1);
2459 polys->begin_vertices = 0;
2460 polys->begin_active = true;
2463 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2464 void VM_CL_R_PolygonVertex (void)
2466 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2468 VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2470 if (!polys->begin_active)
2472 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2476 if (polys->begin_vertices >= VMPOLYGONS_MAXPOINTS)
2478 VM_Warning("VM_CL_R_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
2482 polys->begin_vertex[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM0)[0];
2483 polys->begin_vertex[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM0)[1];
2484 polys->begin_vertex[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM0)[2];
2485 polys->begin_texcoord[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM1)[0];
2486 polys->begin_texcoord[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM1)[1];
2487 polys->begin_color[polys->begin_vertices][0] = PRVM_G_VECTOR(OFS_PARM2)[0];
2488 polys->begin_color[polys->begin_vertices][1] = PRVM_G_VECTOR(OFS_PARM2)[1];
2489 polys->begin_color[polys->begin_vertices][2] = PRVM_G_VECTOR(OFS_PARM2)[2];
2490 polys->begin_color[polys->begin_vertices][3] = PRVM_G_FLOAT(OFS_PARM3);
2491 polys->begin_vertices++;
2494 //void() R_EndPolygon
2495 void VM_CL_R_PolygonEnd (void)
2497 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
2499 VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2500 if (!polys->begin_active)
2502 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2505 polys->begin_active = false;
2506 if (polys->begin_vertices >= 3)
2507 VMPolygons_Store(polys);
2509 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", polys->begin_vertices);
2512 static vmpolygons_t debugPolys;
2514 void Debug_PolygonBegin(const char *picname, int drawflag)
2516 if(!debugPolys.initialized)
2517 VM_InitPolygons(&debugPolys);
2518 if(debugPolys.begin_active)
2520 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2523 debugPolys.begin_texture = picname[0] ? Draw_CachePic(picname, true)->tex : r_texture_white;
2524 debugPolys.begin_drawflag = drawflag;
2525 debugPolys.begin_vertices = 0;
2526 debugPolys.begin_active = true;
2529 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2531 if(!debugPolys.begin_active)
2533 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2537 if(debugPolys.begin_vertices > VMPOLYGONS_MAXPOINTS)
2539 Con_Printf("Debug_PolygonVertex: may have %i vertices max\n", VMPOLYGONS_MAXPOINTS);
2543 debugPolys.begin_vertex[debugPolys.begin_vertices][0] = x;
2544 debugPolys.begin_vertex[debugPolys.begin_vertices][1] = y;
2545 debugPolys.begin_vertex[debugPolys.begin_vertices][2] = z;
2546 debugPolys.begin_texcoord[debugPolys.begin_vertices][0] = s;
2547 debugPolys.begin_texcoord[debugPolys.begin_vertices][1] = t;
2548 debugPolys.begin_color[debugPolys.begin_vertices][0] = r;
2549 debugPolys.begin_color[debugPolys.begin_vertices][1] = g;
2550 debugPolys.begin_color[debugPolys.begin_vertices][2] = b;
2551 debugPolys.begin_color[debugPolys.begin_vertices][3] = a;
2552 debugPolys.begin_vertices++;
2555 void Debug_PolygonEnd(void)
2557 if (!debugPolys.begin_active)
2559 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2562 debugPolys.begin_active = false;
2563 if (debugPolys.begin_vertices >= 3)
2564 VMPolygons_Store(&debugPolys);
2566 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", debugPolys.begin_vertices);
2573 Returns false if any part of the bottom of the entity is off an edge that
2578 qboolean CL_CheckBottom (prvm_edict_t *ent)
2580 vec3_t mins, maxs, start, stop;
2585 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2586 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2588 // if all of the points under the corners are solid world, don't bother
2589 // with the tougher checks
2590 // the corners must be within 16 of the midpoint
2591 start[2] = mins[2] - 1;
2592 for (x=0 ; x<=1 ; x++)
2593 for (y=0 ; y<=1 ; y++)
2595 start[0] = x ? maxs[0] : mins[0];
2596 start[1] = y ? maxs[1] : mins[1];
2597 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2601 return true; // we got out easy
2605 // check it for real...
2609 // the midpoint must be within 16 of the bottom
2610 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2611 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2612 stop[2] = start[2] - 2*sv_stepheight.value;
2613 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2615 if (trace.fraction == 1.0)
2617 mid = bottom = trace.endpos[2];
2619 // the corners must be within 16 of the midpoint
2620 for (x=0 ; x<=1 ; x++)
2621 for (y=0 ; y<=1 ; y++)
2623 start[0] = stop[0] = x ? maxs[0] : mins[0];
2624 start[1] = stop[1] = y ? maxs[1] : mins[1];
2626 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2628 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2629 bottom = trace.endpos[2];
2630 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2641 Called by monster program code.
2642 The move will be adjusted for slopes and stairs, but if the move isn't
2643 possible, no move is done and false is returned
2646 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2649 vec3_t oldorg, neworg, end, traceendpos;
2652 prvm_edict_t *enemy;
2656 VectorCopy (ent->fields.client->origin, oldorg);
2657 VectorAdd (ent->fields.client->origin, move, neworg);
2659 // flying monsters don't step up
2660 if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2662 // try one move with vertical motion, then one without
2663 for (i=0 ; i<2 ; i++)
2665 VectorAdd (ent->fields.client->origin, move, neworg);
2666 enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2667 if (i == 0 && enemy != prog->edicts)
2669 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2675 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);
2677 VM_SetTraceGlobals(&trace);
2679 if (trace.fraction == 1)
2681 VectorCopy(trace.endpos, traceendpos);
2682 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2683 return false; // swim monster left water
2685 VectorCopy (traceendpos, ent->fields.client->origin);
2691 if (enemy == prog->edicts)
2698 // push down from a step height above the wished position
2699 neworg[2] += sv_stepheight.value;
2700 VectorCopy (neworg, end);
2701 end[2] -= sv_stepheight.value*2;
2703 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2705 VM_SetTraceGlobals(&trace);
2707 if (trace.startsolid)
2709 neworg[2] -= sv_stepheight.value;
2710 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2712 VM_SetTraceGlobals(&trace);
2713 if (trace.startsolid)
2716 if (trace.fraction == 1)
2718 // if monster had the ground pulled out, go ahead and fall
2719 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2721 VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2724 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2728 return false; // walked off an edge
2731 // check point traces down for dangling corners
2732 VectorCopy (trace.endpos, ent->fields.client->origin);
2734 if (!CL_CheckBottom (ent))
2736 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2737 { // entity had floor mostly pulled out from underneath it
2738 // and is trying to correct
2743 VectorCopy (oldorg, ent->fields.client->origin);
2747 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2748 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2750 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2751 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2763 float(float yaw, float dist[, settrace]) walkmove
2766 static void VM_CL_walkmove (void)
2775 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2777 // assume failure if it returns early
2778 PRVM_G_FLOAT(OFS_RETURN) = 0;
2780 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2781 if (ent == prog->edicts)
2783 VM_Warning("walkmove: can not modify world entity\n");
2786 if (ent->priv.server->free)
2788 VM_Warning("walkmove: can not modify free entity\n");
2791 yaw = PRVM_G_FLOAT(OFS_PARM0);
2792 dist = PRVM_G_FLOAT(OFS_PARM1);
2793 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2795 if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2798 yaw = yaw*M_PI*2 / 360;
2800 move[0] = cos(yaw)*dist;
2801 move[1] = sin(yaw)*dist;
2804 // save program state, because CL_movestep may call other progs
2805 oldf = prog->xfunction;
2806 oldself = prog->globals.client->self;
2808 PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2811 // restore program state
2812 prog->xfunction = oldf;
2813 prog->globals.client->self = oldself;
2820 string(string key) serverkey
2823 void VM_CL_serverkey(void)
2825 char string[VM_STRINGTEMP_LENGTH];
2826 VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2827 InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2828 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2831 //============================================================================
2833 // To create a almost working builtin file from this replace:
2834 // "^NULL.*" with ""
2835 // "^{.*//.*}:Wh\(.*\)" with "\1"
2837 // "^.*//:Wh{\#:d*}:Wh{.*}" with "\2 = \1;"
2838 // "\n\n+" with "\n\n"
2840 prvm_builtin_t vm_cl_builtins[] = {
2841 NULL, // #0 NULL function (not callable) (QUAKE)
2842 VM_CL_makevectors, // #1 void(vector ang) makevectors (QUAKE)
2843 VM_CL_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
2844 VM_CL_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
2845 VM_CL_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2846 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2847 VM_break, // #6 void() break (QUAKE)
2848 VM_random, // #7 float() random (QUAKE)
2849 VM_CL_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
2850 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
2851 VM_error, // #10 void(string e) error (QUAKE)
2852 VM_objerror, // #11 void(string e) objerror (QUAKE)
2853 VM_vlen, // #12 float(vector v) vlen (QUAKE)
2854 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
2855 VM_CL_spawn, // #14 entity() spawn (QUAKE)
2856 VM_remove, // #15 void(entity e) remove (QUAKE)
2857 VM_CL_traceline, // #16 float(vector v1, vector v2, float tryents, entity ignoreentity) traceline (QUAKE)
2858 NULL, // #17 entity() checkclient (QUAKE)
2859 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
2860 VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
2861 VM_CL_precache_model, // #20 void(string s) precache_model (QUAKE)
2862 NULL, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2863 VM_CL_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
2864 NULL, // #23 void(string s, ...) bprint (QUAKE)
2865 NULL, // #24 void(entity client, string s, ...) sprint (QUAKE)
2866 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
2867 VM_ftos, // #26 string(float f) ftos (QUAKE)
2868 VM_vtos, // #27 string(vector v) vtos (QUAKE)
2869 VM_coredump, // #28 void() coredump (QUAKE)
2870 VM_traceon, // #29 void() traceon (QUAKE)
2871 VM_traceoff, // #30 void() traceoff (QUAKE)
2872 VM_eprint, // #31 void(entity e) eprint (QUAKE)
2873 VM_CL_walkmove, // #32 float(float yaw, float dist[, float settrace]) walkmove (QUAKE)
2874 NULL, // #33 (QUAKE)
2875 VM_CL_droptofloor, // #34 float() droptofloor (QUAKE)
2876 VM_CL_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
2877 VM_rint, // #36 float(float v) rint (QUAKE)
2878 VM_floor, // #37 float(float v) floor (QUAKE)
2879 VM_ceil, // #38 float(float v) ceil (QUAKE)
2880 NULL, // #39 (QUAKE)
2881 VM_CL_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
2882 VM_CL_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
2883 NULL, // #42 (QUAKE)
2884 VM_fabs, // #43 float(float f) fabs (QUAKE)
2885 NULL, // #44 vector(entity e, float speed) aim (QUAKE)
2886 VM_cvar, // #45 float(string s) cvar (QUAKE)
2887 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
2888 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
2889 VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2890 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
2891 NULL, // #50 (QUAKE)
2892 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
2893 NULL, // #52 void(float to, float f) WriteByte (QUAKE)
2894 NULL, // #53 void(float to, float f) WriteChar (QUAKE)
2895 NULL, // #54 void(float to, float f) WriteShort (QUAKE)
2896 NULL, // #55 void(float to, float f) WriteLong (QUAKE)
2897 NULL, // #56 void(float to, float f) WriteCoord (QUAKE)
2898 NULL, // #57 void(float to, float f) WriteAngle (QUAKE)
2899 NULL, // #58 void(float to, string s) WriteString (QUAKE)
2900 NULL, // #59 (QUAKE)
2901 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2902 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2903 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2904 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2905 VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2906 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2907 NULL, // #66 (QUAKE)
2908 NULL, // #67 void(float step) movetogoal (QUAKE)
2909 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
2910 VM_CL_makestatic, // #69 void(entity e) makestatic (QUAKE)
2911 NULL, // #70 void(string s) changelevel (QUAKE)
2912 NULL, // #71 (QUAKE)
2913 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
2914 NULL, // #73 void(entity client, strings) centerprint (QUAKE)
2915 VM_CL_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2916 VM_CL_precache_model, // #75 string(string s) precache_model2 (QUAKE)
2917 VM_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
2918 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
2919 NULL, // #78 void(entity e) setspawnparms (QUAKE)
2920 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
2921 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
2922 VM_stof, // #81 float(string s) stof (FRIK_FILE)
2923 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
2924 NULL, // #83 (QUAKE)
2925 NULL, // #84 (QUAKE)
2926 NULL, // #85 (QUAKE)
2927 NULL, // #86 (QUAKE)
2928 NULL, // #87 (QUAKE)
2929 NULL, // #88 (QUAKE)
2930 NULL, // #89 (QUAKE)
2931 VM_CL_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2932 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2933 VM_CL_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2934 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2935 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2936 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2937 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2938 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2939 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2940 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
2941 // FrikaC and Telejano range #100-#199
2952 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
2953 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
2954 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
2955 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2956 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
2957 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
2958 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
2959 VM_stov, // #117 vector(string) stov (FRIK_FILE)
2960 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
2961 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
3042 // FTEQW range #200-#299
3061 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
3064 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
3065 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
3066 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
3067 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
3068 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
3069 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
3070 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
3071 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
3072 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
3073 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
3075 NULL, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3143 // CSQC range #300-#399
3144 VM_CL_R_ClearScene, // #300 void() clearscene (EXT_CSQC)
3145 VM_CL_R_AddEntities, // #301 void(float mask) addentities (EXT_CSQC)
3146 VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC)
3147 VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC)
3148 VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC)
3149 VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3150 VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3151 VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3152 VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon
3153 NULL /* R_LoadWorldModel in menu VM, should stay unassigned in client*/, // #309
3154 VM_CL_unproject, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3155 VM_CL_project, // #311 vector (vector v) cs_project (EXT_CSQC)
3159 VM_drawline, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3160 VM_iscachedpic, // #316 float(string name) iscachedpic (EXT_CSQC)
3161 VM_precache_pic, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3162 VM_getimagesize, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3163 VM_freepic, // #319 void(string name) freepic (EXT_CSQC)
3164 VM_drawcharacter, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3165 VM_drawstring, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3166 VM_drawpic, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3167 VM_drawfill, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3168 VM_drawsetcliparea, // #324 void(float x, float y, float width, float height) drawsetcliparea
3169 VM_drawresetcliparea, // #325 void(void) drawresetcliparea
3170 VM_drawcolorcodedstring, // #326 float drawcolorcodedstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) (EXT_CSQC)
3171 NULL, // #327 // FIXME add stringwidth() here?
3172 NULL, // #328 // FIXME add drawsubpic() here?
3174 VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
3175 VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
3176 VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
3177 VM_CL_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3178 VM_CL_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3179 VM_CL_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3180 VM_CL_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3181 VM_CL_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3182 VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC)
3183 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3184 VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3185 VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3186 VM_CL_getkeybind, // #342 string(float keynum) getkeybind (EXT_CSQC)
3187 VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3188 VM_getmousepos, // #344 vector() getmousepos (EXT_CSQC)
3189 VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC)
3190 VM_CL_setsensitivityscale, // #346 void(float sens) setsensitivityscale (EXT_CSQC)
3191 VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC)
3192 VM_CL_getplayerkey, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3193 VM_CL_isdemo, // #349 float() isdemo (EXT_CSQC)
3194 VM_isserver, // #350 float() isserver (EXT_CSQC)
3195 VM_CL_setlistener, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3196 VM_CL_registercmd, // #352 void(string cmdname) registercommand (EXT_CSQC)
3197 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3198 VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3204 VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC)
3205 VM_CL_ReadChar, // #361 float() readchar (EXT_CSQC)
3206 VM_CL_ReadShort, // #362 float() readshort (EXT_CSQC)
3207 VM_CL_ReadLong, // #363 float() readlong (EXT_CSQC)
3208 VM_CL_ReadCoord, // #364 float() readcoord (EXT_CSQC)
3209 VM_CL_ReadAngle, // #365 float() readangle (EXT_CSQC)
3210 VM_CL_ReadString, // #366 string() readstring (EXT_CSQC)
3211 VM_CL_ReadFloat, // #367 float() readfloat (EXT_CSQC)
3244 // LordHavoc's range #400-#499
3245 VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3246 NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3247 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3248 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3249 VM_CL_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3250 VM_CL_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3251 VM_CL_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3252 VM_CL_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3253 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)
3254 VM_CL_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3255 VM_CL_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3256 VM_CL_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3257 VM_CL_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3258 VM_CL_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3259 VM_CL_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3260 VM_CL_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3261 VM_CL_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3262 VM_CL_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3263 VM_CL_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3264 VM_CL_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3265 VM_CL_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3266 VM_CL_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3267 VM_CL_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3268 VM_CL_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3269 VM_CL_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3270 VM_CL_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3271 VM_CL_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3272 VM_CL_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3273 VM_CL_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3274 VM_CL_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3275 VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3276 VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3277 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3278 VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3279 VM_CL_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3280 VM_CL_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3281 VM_CL_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3282 VM_CL_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3283 VM_CL_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3284 VM_CL_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3285 NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3286 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3287 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3288 VM_CL_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3289 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3290 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3291 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3292 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3293 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3294 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3295 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3296 VM_CL_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3297 VM_CL_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3298 NULL, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3299 NULL, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3300 NULL, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3301 NULL, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3302 VM_CL_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet (DP_TE_FLAMEJET)
3304 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3305 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3306 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3307 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3308 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3309 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3310 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3311 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3312 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3313 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3314 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3315 NULL, // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3316 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3317 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3318 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3319 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3320 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3321 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3322 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3323 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3324 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3325 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3326 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3327 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3328 VM_CL_pointsound, // #483 void(vector origin, string sample, float volume, float attenuation) pointsound (DP_SV_POINTSOUND)
3329 VM_strreplace, // #484 string(string search, string replace, string subject) strreplace (DP_QC_STRREPLACE)
3330 VM_strireplace, // #485 string(string search, string replace, string subject) strireplace (DP_QC_STRREPLACE)
3331 VM_CL_getsurfacepointattribute,// #486 vector(entity e, float s, float n, float a) getsurfacepointattribute
3332 VM_gecko_create, // #487 float gecko_create( string name )
3333 VM_gecko_destroy, // #488 void gecko_destroy( string name )
3334 VM_gecko_navigate, // #489 void gecko_navigate( string name, string URI )
3335 VM_gecko_keyevent, // #490 float gecko_keyevent( string name, float key, float eventtype )
3336 VM_gecko_movemouse, // #491 void gecko_mousemove( string name, float x, float y )
3337 VM_gecko_resize, // #492 void gecko_resize( string name, float w, float h )
3338 VM_gecko_get_texture_extent, // #493 vector gecko_get_texture_extent( string name )
3339 VM_crc16, // #494 float(float caseinsensitive, string s, ...) crc16 = #494 (DP_QC_CRC16)
3347 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3349 void VM_Polygons_Reset(void)
3351 vmpolygons_t* polys = vmpolygons + PRVM_GetProgNr();
3353 // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3354 if(polys->initialized)
3356 Mem_FreePool(&polys->pool);
3357 polys->initialized = false;
3361 void VM_CL_Cmd_Init(void)
3364 VM_Polygons_Reset();
3367 void VM_CL_Cmd_Reset(void)
3370 VM_Polygons_Reset();