3 #include "cl_collision.h"
6 //============================================================================
8 //[515]: unsolved PROBLEMS
9 //- finish player physics code (cs_runplayerphysics)
11 //- RF_DEPTHHACK is not like it should be
12 //- add builtin that sets cl.viewangles instead of reading "input_angles" global
13 //- finish lines support for R_Polygon***
14 //- insert selecttraceline into traceline somehow
16 //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)
17 //4 feature darkplaces csqc: add builtins to clientside qc for gl calls
19 sfx_t *S_FindName(const char *name);
20 int Sbar_GetPlayer (int index);
21 void Sbar_SortFrags (void);
22 void CL_FindNonSolidLocation(const vec3_t in, vec3_t out, vec_t radius);
23 void CSQC_RelinkAllEntities (int drawmask);
24 void CSQC_RelinkCSQCEntities (void);
25 char *Key_GetBind (int key);
32 // #1 void(vector ang) makevectors
33 static void VM_CL_makevectors (void)
35 VM_SAFEPARMCOUNT(1, VM_CL_makevectors);
36 AngleVectors (PRVM_G_VECTOR(OFS_PARM0), prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up);
39 // #2 void(entity e, vector o) setorigin
40 static void VM_CL_setorigin (void)
44 VM_SAFEPARMCOUNT(2, VM_CL_setorigin);
46 e = PRVM_G_EDICT(OFS_PARM0);
47 if (e == prog->edicts)
49 VM_Warning("setorigin: can not modify world entity\n");
52 if (e->priv.required->free)
54 VM_Warning("setorigin: can not modify free entity\n");
57 org = PRVM_G_VECTOR(OFS_PARM1);
58 VectorCopy (org, e->fields.client->origin);
62 // #3 void(entity e, string m) setmodel
63 static void VM_CL_setmodel (void)
70 VM_SAFEPARMCOUNT(2, VM_CL_setmodel);
72 e = PRVM_G_EDICT(OFS_PARM0);
73 m = PRVM_G_STRING(OFS_PARM1);
74 for (i = 0;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
76 if (!strcmp(cl.csqc_model_precache[i]->name, m))
78 e->fields.client->model = PRVM_SetEngineString(cl.csqc_model_precache[i]->name);
79 e->fields.client->modelindex = -(i+1);
84 for (i = 0;i < MAX_MODELS;i++)
86 mod = cl.model_precache[i];
87 if (mod && !strcmp(mod->name, m))
89 e->fields.client->model = PRVM_SetEngineString(mod->name);
90 e->fields.client->modelindex = i;
95 e->fields.client->modelindex = 0;
96 e->fields.client->model = 0;
99 // #4 void(entity e, vector min, vector max) setsize
100 static void VM_CL_setsize (void)
104 VM_SAFEPARMCOUNT(3, VM_CL_setsize);
106 e = PRVM_G_EDICT(OFS_PARM0);
107 if (e == prog->edicts)
109 VM_Warning("setsize: can not modify world entity\n");
112 if (e->priv.server->free)
114 VM_Warning("setsize: can not modify free entity\n");
117 min = PRVM_G_VECTOR(OFS_PARM1);
118 max = PRVM_G_VECTOR(OFS_PARM2);
120 VectorCopy (min, e->fields.client->mins);
121 VectorCopy (max, e->fields.client->maxs);
122 VectorSubtract (max, min, e->fields.client->size);
127 // #8 void(entity e, float chan, string samp, float volume, float atten) sound
128 static void VM_CL_sound (void)
132 prvm_edict_t *entity;
136 VM_SAFEPARMCOUNT(5, VM_CL_sound);
138 entity = PRVM_G_EDICT(OFS_PARM0);
139 channel = (int)PRVM_G_FLOAT(OFS_PARM1);
140 sample = PRVM_G_STRING(OFS_PARM2);
141 volume = PRVM_G_FLOAT(OFS_PARM3);
142 attenuation = PRVM_G_FLOAT(OFS_PARM4);
144 if (volume < 0 || volume > 1)
146 VM_Warning("VM_CL_sound: volume must be in range 0-1\n");
150 if (attenuation < 0 || attenuation > 4)
152 VM_Warning("VM_CL_sound: attenuation must be in range 0-4\n");
156 if (channel < 0 || channel > 7)
158 VM_Warning("VM_CL_sound: channel must be in range 0-7\n");
162 S_StartSound(32768 + PRVM_NUM_FOR_EDICT(entity), channel, S_FindName(sample), entity->fields.client->origin, volume, attenuation);
165 // #14 entity() spawn
166 static void VM_CL_spawn (void)
169 ed = PRVM_ED_Alloc();
170 ed->fields.client->entnum = PRVM_NUM_FOR_EDICT(ed); //[515]: not needed any more ?
174 // #16 float(vector v1, vector v2, float movetype, entity ignore) traceline
175 static void VM_CL_traceline (void)
182 VM_SAFEPARMCOUNTRANGE(4, 8, VM_CL_traceline); // allow more parameters for future expansion
184 prog->xfunction->builtinsprofile += 30;
186 v1 = PRVM_G_VECTOR(OFS_PARM0);
187 v2 = PRVM_G_VECTOR(OFS_PARM1);
188 move = (int)PRVM_G_FLOAT(OFS_PARM2);
189 ent = PRVM_G_EDICT(OFS_PARM3);
191 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]))
192 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));
194 trace = CL_Move(v1, vec3_origin, vec3_origin, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
196 VM_SetTraceGlobals(&trace);
203 Used for use tracing and shot targeting
204 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
205 if the tryents flag is set.
207 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
210 // LordHavoc: added this for my own use, VERY useful, similar to traceline
211 static void VM_CL_tracebox (void)
213 float *v1, *v2, *m1, *m2;
218 VM_SAFEPARMCOUNTRANGE(6, 8, VM_CL_tracebox); // allow more parameters for future expansion
220 prog->xfunction->builtinsprofile += 30;
222 v1 = PRVM_G_VECTOR(OFS_PARM0);
223 m1 = PRVM_G_VECTOR(OFS_PARM1);
224 m2 = PRVM_G_VECTOR(OFS_PARM2);
225 v2 = PRVM_G_VECTOR(OFS_PARM3);
226 move = (int)PRVM_G_FLOAT(OFS_PARM4);
227 ent = PRVM_G_EDICT(OFS_PARM5);
229 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]))
230 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));
232 trace = CL_Move(v1, m1, m2, v2, move, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
234 VM_SetTraceGlobals(&trace);
237 trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
242 vec3_t original_origin;
243 vec3_t original_velocity;
244 vec3_t original_angles;
245 vec3_t original_avelocity;
249 VectorCopy(tossent->fields.client->origin , original_origin );
250 VectorCopy(tossent->fields.client->velocity , original_velocity );
251 VectorCopy(tossent->fields.client->angles , original_angles );
252 VectorCopy(tossent->fields.client->avelocity, original_avelocity);
254 val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
255 if (val != NULL && val->_float != 0)
256 gravity = val->_float;
259 gravity *= cl.movevars_gravity * 0.05;
261 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
263 tossent->fields.client->velocity[2] -= gravity;
264 VectorMA (tossent->fields.client->angles, 0.05, tossent->fields.client->avelocity, tossent->fields.client->angles);
265 VectorScale (tossent->fields.client->velocity, 0.05, move);
266 VectorAdd (tossent->fields.client->origin, move, end);
267 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);
268 VectorCopy (trace.endpos, tossent->fields.client->origin);
270 if (trace.fraction < 1)
274 VectorCopy(original_origin , tossent->fields.client->origin );
275 VectorCopy(original_velocity , tossent->fields.client->velocity );
276 VectorCopy(original_angles , tossent->fields.client->angles );
277 VectorCopy(original_avelocity, tossent->fields.client->avelocity);
282 static void VM_CL_tracetoss (void)
286 prvm_edict_t *ignore;
288 prog->xfunction->builtinsprofile += 600;
290 VM_SAFEPARMCOUNT(2, VM_CL_tracetoss);
292 ent = PRVM_G_EDICT(OFS_PARM0);
293 if (ent == prog->edicts)
295 VM_Warning("tracetoss: can not use world entity\n");
298 ignore = PRVM_G_EDICT(OFS_PARM1);
300 trace = CL_Trace_Toss (ent, ignore);
302 VM_SetTraceGlobals(&trace);
306 // #20 void(string s) precache_model
307 static void VM_CL_precache_model (void)
313 VM_SAFEPARMCOUNT(1, VM_CL_precache_model);
315 name = PRVM_G_STRING(OFS_PARM0);
316 for (i = 1;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
318 if(!strcmp(cl.csqc_model_precache[i]->name, name))
320 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
324 PRVM_G_FLOAT(OFS_RETURN) = 0;
325 m = Mod_ForName(name, false, false, false);
328 for (i = 1;i < MAX_MODELS;i++)
330 if (!cl.csqc_model_precache[i])
332 cl.csqc_model_precache[i] = (model_t*)m;
333 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
337 VM_Warning("VM_CL_precache_model: no free models\n");
340 VM_Warning("VM_CL_precache_model: model \"%s\" not found\n", name);
343 int CSQC_EntitiesInBox (vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **list)
348 ent = PRVM_NEXT_EDICT(prog->edicts);
349 for(k=0,i=1; i<prog->num_edicts ;i++, ent = PRVM_NEXT_EDICT(ent))
351 if (ent->priv.required->free)
353 if(BoxesOverlap(mins, maxs, ent->fields.client->absmin, ent->fields.client->absmax))
359 // #22 entity(vector org, float rad) findradius
360 static void VM_CL_findradius (void)
362 prvm_edict_t *ent, *chain;
363 vec_t radius, radius2;
364 vec3_t org, eorg, mins, maxs;
365 int i, numtouchedicts;
366 prvm_edict_t *touchedicts[MAX_EDICTS];
368 VM_SAFEPARMCOUNT(2, VM_CL_findradius);
370 chain = (prvm_edict_t *)prog->edicts;
372 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
373 radius = PRVM_G_FLOAT(OFS_PARM1);
374 radius2 = radius * radius;
376 mins[0] = org[0] - (radius + 1);
377 mins[1] = org[1] - (radius + 1);
378 mins[2] = org[2] - (radius + 1);
379 maxs[0] = org[0] + (radius + 1);
380 maxs[1] = org[1] + (radius + 1);
381 maxs[2] = org[2] + (radius + 1);
382 numtouchedicts = CSQC_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
383 if (numtouchedicts > MAX_EDICTS)
385 // this never happens //[515]: for what then ?
386 Con_Printf("CSQC_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
387 numtouchedicts = MAX_EDICTS;
389 for (i = 0;i < numtouchedicts;i++)
391 ent = touchedicts[i];
392 // Quake did not return non-solid entities but darkplaces does
393 // (note: this is the reason you can't blow up fallen zombies)
394 if (ent->fields.client->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
396 // LordHavoc: compare against bounding box rather than center so it
397 // doesn't miss large objects, and use DotProduct instead of Length
398 // for a major speedup
399 VectorSubtract(org, ent->fields.client->origin, eorg);
400 if (sv_gameplayfix_findradiusdistancetobox.integer)
402 eorg[0] -= bound(ent->fields.client->mins[0], eorg[0], ent->fields.client->maxs[0]);
403 eorg[1] -= bound(ent->fields.client->mins[1], eorg[1], ent->fields.client->maxs[1]);
404 eorg[2] -= bound(ent->fields.client->mins[2], eorg[2], ent->fields.client->maxs[2]);
407 VectorMAMAM(1, eorg, -0.5f, ent->fields.client->mins, -0.5f, ent->fields.client->maxs, eorg);
408 if (DotProduct(eorg, eorg) < radius2)
410 ent->fields.client->chain = PRVM_EDICT_TO_PROG(chain);
415 VM_RETURN_EDICT(chain);
418 // #34 float() droptofloor
419 static void VM_CL_droptofloor (void)
426 VM_SAFEPARMCOUNTRANGE(0, 2, VM_CL_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
428 // assume failure if it returns early
429 PRVM_G_FLOAT(OFS_RETURN) = 0;
431 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
432 if (ent == prog->edicts)
434 VM_Warning("droptofloor: can not modify world entity\n");
437 if (ent->priv.server->free)
439 VM_Warning("droptofloor: can not modify free entity\n");
443 VectorCopy (ent->fields.client->origin, end);
446 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);
448 if (trace.fraction != 1)
450 VectorCopy (trace.endpos, ent->fields.client->origin);
451 ent->fields.client->flags = (int)ent->fields.client->flags | FL_ONGROUND;
452 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
453 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
454 PRVM_G_FLOAT(OFS_RETURN) = 1;
455 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
456 // ent->priv.server->suspendedinairflag = true;
460 // #35 void(float style, string value) lightstyle
461 static void VM_CL_lightstyle (void)
466 VM_SAFEPARMCOUNT(2, VM_CL_lightstyle);
468 i = (int)PRVM_G_FLOAT(OFS_PARM0);
469 c = PRVM_G_STRING(OFS_PARM1);
470 if (i >= cl.max_lightstyle)
472 VM_Warning("VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
475 strlcpy (cl.lightstyle[i].map, MSG_ReadString(), sizeof (cl.lightstyle[i].map));
476 cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
477 cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
480 // #40 float(entity e) checkbottom
481 static void VM_CL_checkbottom (void)
483 static int cs_yes, cs_no;
485 vec3_t mins, maxs, start, stop;
490 VM_SAFEPARMCOUNT(1, VM_CL_checkbottom);
491 ent = PRVM_G_EDICT(OFS_PARM0);
492 PRVM_G_FLOAT(OFS_RETURN) = 0;
494 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
495 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
497 // if all of the points under the corners are solid world, don't bother
498 // with the tougher checks
499 // the corners must be within 16 of the midpoint
500 start[2] = mins[2] - 1;
501 for (x=0 ; x<=1 ; x++)
502 for (y=0 ; y<=1 ; y++)
504 start[0] = x ? maxs[0] : mins[0];
505 start[1] = y ? maxs[1] : mins[1];
506 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
511 PRVM_G_FLOAT(OFS_RETURN) = true;
512 return; // we got out easy
517 // check it for real...
521 // the midpoint must be within 16 of the bottom
522 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
523 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
524 stop[2] = start[2] - 2*sv_stepheight.value;
525 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
527 if (trace.fraction == 1.0)
530 mid = bottom = trace.endpos[2];
532 // the corners must be within 16 of the midpoint
533 for (x=0 ; x<=1 ; x++)
534 for (y=0 ; y<=1 ; y++)
536 start[0] = stop[0] = x ? maxs[0] : mins[0];
537 start[1] = stop[1] = y ? maxs[1] : mins[1];
539 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
541 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
542 bottom = trace.endpos[2];
543 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
548 PRVM_G_FLOAT(OFS_RETURN) = true;
551 // #41 float(vector v) pointcontents
552 static void VM_CL_pointcontents (void)
554 VM_SAFEPARMCOUNT(1, VM_CL_pointcontents);
555 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, CL_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
558 // #48 void(vector o, vector d, float color, float count) particle
559 static void VM_CL_particle (void)
564 VM_SAFEPARMCOUNT(4, VM_CL_particle);
566 org = PRVM_G_VECTOR(OFS_PARM0);
567 dir = PRVM_G_VECTOR(OFS_PARM1);
568 color = (int)PRVM_G_FLOAT(OFS_PARM2);
569 count = (int)PRVM_G_FLOAT(OFS_PARM3);
570 CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color);
573 // #74 void(vector pos, string samp, float vol, float atten) ambientsound
574 static void VM_CL_ambientsound (void)
578 VM_SAFEPARMCOUNT(4, VM_CL_ambientsound);
579 s = S_FindName(PRVM_G_STRING(OFS_PARM0));
580 f = PRVM_G_VECTOR(OFS_PARM1);
581 S_StaticSound (s, f, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3)*64);
584 // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
585 static void VM_CL_getlight (void)
587 vec3_t ambientcolor, diffusecolor, diffusenormal;
590 VM_SAFEPARMCOUNT(1, VM_CL_getlight);
592 p = PRVM_G_VECTOR(OFS_PARM0);
593 VectorClear(ambientcolor);
594 VectorClear(diffusecolor);
595 VectorClear(diffusenormal);
596 if (cl.worldmodel && cl.worldmodel->brush.LightPoint)
597 cl.worldmodel->brush.LightPoint(cl.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
598 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
602 //============================================================================
603 //[515]: SCENE MANAGER builtins
604 extern qboolean CSQC_AddRenderEdict (prvm_edict_t *ed);//csprogs.c
606 static void CSQC_R_RecalcView (void)
608 extern matrix4x4_t viewmodelmatrix;
609 Matrix4x4_CreateFromQuakeEntity(&r_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);
610 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);
613 void CL_RelinkLightFlashes(void);
614 //#300 void() clearscene (EXT_CSQC)
615 static void VM_CL_R_ClearScene (void)
617 VM_SAFEPARMCOUNT(0, VM_CL_R_ClearScene);
618 // clear renderable entity and light lists
619 r_refdef.numentities = 0;
620 r_refdef.numlights = 0;
621 // FIXME: restore these to the values from VM_CL_UpdateView
625 r_view.width = vid.width;
626 r_view.height = vid.height;
628 // FIXME: restore frustum_x/frustum_y
629 r_view.useperspective = true;
630 r_view.frustum_y = tan(scr_fov.value * M_PI / 360.0) * (3.0/4.0) * cl.viewzoom;
631 r_view.frustum_x = r_view.frustum_y * (float)r_view.width / (float)r_view.height / vid_pixelheight.value;
632 r_view.frustum_x *= r_refdef.frustumscale_x;
633 r_view.frustum_y *= r_refdef.frustumscale_y;
634 r_view.ortho_x = scr_fov.value * (3.0 / 4.0) * (float)r_view.width / (float)r_view.height / vid_pixelheight.value;
635 r_view.ortho_y = scr_fov.value * (3.0 / 4.0);
636 // FIXME: restore cl.csqc_origin
637 // FIXME: restore cl.csqc_angles
638 cl.csqc_vidvars.drawworld = true;
639 cl.csqc_vidvars.drawenginesbar = false;
640 cl.csqc_vidvars.drawcrosshair = false;
643 //#301 void(float mask) addentities (EXT_CSQC)
644 extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
645 extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
646 static void VM_CL_R_AddEntities (void)
650 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
651 drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
652 CSQC_RelinkAllEntities(drawmask);
653 CL_RelinkLightFlashes();
655 prog->globals.client->time = cl.time;
656 for(i=1;i<prog->num_edicts;i++)
658 ed = &prog->edicts[i];
659 if(ed->priv.required->free)
662 if(ed->priv.required->free)
664 // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict
666 if(ed->priv.required->free)
668 if(!((int)ed->fields.client->drawmask & drawmask))
670 CSQC_AddRenderEdict(ed);
674 //#302 void(entity ent) addentity (EXT_CSQC)
675 static void VM_CL_R_AddEntity (void)
677 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
678 CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
681 //#303 float(float property, ...) setproperty (EXT_CSQC)
682 static void VM_CL_R_SetView (void)
688 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_SetView);
690 c = (int)PRVM_G_FLOAT(OFS_PARM0);
691 f = PRVM_G_VECTOR(OFS_PARM1);
692 k = PRVM_G_FLOAT(OFS_PARM1);
696 case VF_MIN: r_view.x = (int)(f[0] * vid.width / vid_conwidth.value);
697 r_view.y = (int)(f[1] * vid.height / vid_conheight.value);
699 case VF_MIN_X: r_view.x = (int)(k * vid.width / vid_conwidth.value);
701 case VF_MIN_Y: r_view.y = (int)(k * vid.height / vid_conheight.value);
703 case VF_SIZE: r_view.width = (int)(f[0] * vid.width / vid_conwidth.value);
704 r_view.height = (int)(f[1] * vid.height / vid_conheight.value);
706 case VF_SIZE_Y: r_view.width = (int)(k * vid.width / vid_conwidth.value);
708 case VF_SIZE_X: r_view.height = (int)(k * vid.height / vid_conheight.value);
710 case VF_VIEWPORT: r_view.x = (int)(f[0] * vid.width / vid_conwidth.value);
711 r_view.y = (int)(f[1] * vid.height / vid_conheight.value);
712 f = PRVM_G_VECTOR(OFS_PARM2);
713 r_view.width = (int)(f[0] * vid.width / vid_conwidth.value);
714 r_view.height = (int)(f[1] * vid.height / vid_conheight.value);
716 case VF_FOV: r_view.frustum_x = tan(f[0] * M_PI / 360.0);r_view.ortho_x = f[0];
717 r_view.frustum_y = tan(f[1] * M_PI / 360.0);r_view.ortho_y = f[1];
719 case VF_FOVX: r_view.frustum_x = tan(k * M_PI / 360.0);r_view.ortho_x = k;
721 case VF_FOVY: r_view.frustum_y = tan(k * M_PI / 360.0);r_view.ortho_y = k;
723 case VF_ORIGIN: VectorCopy(f, cl.csqc_origin);
726 case VF_ORIGIN_X: cl.csqc_origin[0] = k;
729 case VF_ORIGIN_Y: cl.csqc_origin[1] = k;
732 case VF_ORIGIN_Z: cl.csqc_origin[2] = k;
735 case VF_ANGLES: VectorCopy(f, cl.csqc_angles);
738 case VF_ANGLES_X: cl.csqc_angles[0] = k;
741 case VF_ANGLES_Y: cl.csqc_angles[1] = k;
744 case VF_ANGLES_Z: cl.csqc_angles[2] = k;
747 case VF_DRAWWORLD: cl.csqc_vidvars.drawworld = k;
749 case VF_DRAWENGINESBAR: cl.csqc_vidvars.drawenginesbar = k;
751 case VF_DRAWCROSSHAIR: cl.csqc_vidvars.drawcrosshair = k;
754 case VF_CL_VIEWANGLES: VectorCopy(f, cl.viewangles);
756 case VF_CL_VIEWANGLES_X:cl.viewangles[0] = k;
758 case VF_CL_VIEWANGLES_Y:cl.viewangles[1] = k;
760 case VF_CL_VIEWANGLES_Z:cl.viewangles[2] = k;
763 case VF_PERSPECTIVE: r_view.useperspective = k != 0;
766 default: PRVM_G_FLOAT(OFS_RETURN) = 0;
767 VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c);
770 PRVM_G_FLOAT(OFS_RETURN) = 1;
773 //#304 void() renderscene (EXT_CSQC)
774 static void VM_CL_R_RenderScene (void)
776 VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
777 // we need to update any RENDER_VIEWMODEL entities at this point because
778 // csqc supplies its own view matrix
779 CL_UpdateViewEntities();
784 //#305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
785 static void VM_CL_R_AddDynamicLight (void)
789 VM_SAFEPARMCOUNTRANGE(3, 8, VM_CL_R_AddDynamicLight); // allow more than 3 because we may extend this in the future
791 // if we've run out of dlights, just return
792 if (r_refdef.numlights >= MAX_DLIGHTS)
795 pos = PRVM_G_VECTOR(OFS_PARM0);
796 col = PRVM_G_VECTOR(OFS_PARM2);
797 Matrix4x4_CreateFromQuakeEntity(&matrix, pos[0], pos[1], pos[2], 0, 0, 0, PRVM_G_FLOAT(OFS_PARM1));
798 R_RTLight_Update(&r_refdef.lights[r_refdef.numlights++], false, &matrix, col, -1, NULL, true, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
801 //============================================================================
803 //#310 vector (vector v) cs_unproject (EXT_CSQC)
804 static void VM_CL_unproject (void)
809 VM_SAFEPARMCOUNT(1, VM_CL_unproject);
810 f = PRVM_G_VECTOR(OFS_PARM0);
811 VectorSet(temp, f[2], f[0] * f[2] * -r_view.frustum_x * 2.0 / r_view.width, f[1] * f[2] * -r_view.frustum_y * 2.0 / r_view.height);
812 Matrix4x4_Transform(&r_view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
815 //#311 vector (vector v) cs_project (EXT_CSQC)
816 static void VM_CL_project (void)
822 VM_SAFEPARMCOUNT(1, VM_CL_project);
823 f = PRVM_G_VECTOR(OFS_PARM0);
824 Matrix4x4_Invert_Simple(&m, &r_view.matrix);
825 Matrix4x4_Transform(&m, f, v);
826 VectorSet(PRVM_G_VECTOR(OFS_RETURN), v[1]/v[0]/-r_view.frustum_x*0.5*r_view.width, v[2]/v[0]/-r_view.frustum_y*r_view.height*0.5, v[0]);
829 //#330 float(float stnum) getstatf (EXT_CSQC)
830 static void VM_CL_getstatf (void)
838 VM_SAFEPARMCOUNT(1, VM_CL_getstatf);
839 i = (int)PRVM_G_FLOAT(OFS_PARM0);
840 if(i < 0 || i >= MAX_CL_STATS)
842 VM_Warning("VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
846 PRVM_G_FLOAT(OFS_RETURN) = dat.f;
849 //#331 float(float stnum) getstati (EXT_CSQC)
850 static void VM_CL_getstati (void)
853 int firstbit, bitcount;
855 VM_SAFEPARMCOUNTRANGE(1, 3, VM_CL_getstati);
857 index = (int)PRVM_G_FLOAT(OFS_PARM0);
860 firstbit = (int)PRVM_G_FLOAT(OFS_PARM1);
862 bitcount = (int)PRVM_G_FLOAT(OFS_PARM2);
872 if(index < 0 || index >= MAX_CL_STATS)
874 VM_Warning("VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
878 if (bitcount != 32) //32 causes the mask to overflow, so there's nothing to subtract from.
879 i = (((unsigned int)i)&(((1<<bitcount)-1)<<firstbit))>>firstbit;
880 PRVM_G_FLOAT(OFS_RETURN) = i;
883 //#332 string(float firststnum) getstats (EXT_CSQC)
884 static void VM_CL_getstats (void)
888 VM_SAFEPARMCOUNT(1, VM_CL_getstats);
889 i = (int)PRVM_G_FLOAT(OFS_PARM0);
890 if(i < 0 || i > MAX_CL_STATS-4)
892 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
893 VM_Warning("VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
896 strlcpy(t, (char*)&cl.stats[i], sizeof(t));
897 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
900 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
901 static void VM_CL_setmodelindex (void)
905 struct model_s *model;
907 VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex);
909 t = PRVM_G_EDICT(OFS_PARM0);
911 i = (int)PRVM_G_FLOAT(OFS_PARM1);
913 t->fields.client->model = 0;
914 t->fields.client->modelindex = 0;
919 model = CL_GetModelByIndex(i);
922 VM_Warning("VM_CL_setmodelindex: null model\n");
925 t->fields.client->model = PRVM_SetEngineString(model->name);
926 t->fields.client->modelindex = i;
929 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
930 static void VM_CL_modelnameforindex (void)
934 VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
936 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
937 model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
938 PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(model->name) : 0;
941 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
942 static void VM_CL_particleeffectnum (void)
945 VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
946 i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
949 PRVM_G_FLOAT(OFS_RETURN) = i;
952 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
953 static void VM_CL_trailparticles (void)
958 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles);
960 t = PRVM_G_EDICT(OFS_PARM0);
961 i = (int)PRVM_G_FLOAT(OFS_PARM1);
962 start = PRVM_G_VECTOR(OFS_PARM2);
963 end = PRVM_G_VECTOR(OFS_PARM3);
965 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);
968 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
969 static void VM_CL_pointparticles (void)
973 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
974 i = (int)PRVM_G_FLOAT(OFS_PARM0);
975 f = PRVM_G_VECTOR(OFS_PARM1);
976 v = PRVM_G_VECTOR(OFS_PARM2);
977 n = (int)PRVM_G_FLOAT(OFS_PARM3);
978 CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
981 //#342 string(float keynum) getkeybind (EXT_CSQC)
982 static void VM_CL_getkeybind (void)
984 VM_SAFEPARMCOUNT(1, VM_CL_getkeybind);
985 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0)));
988 //#343 void(float usecursor) setcursormode (EXT_CSQC)
989 static void VM_CL_setcursormode (void)
991 VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
992 cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
993 cl_ignoremousemove = true;
996 //#345 float(float framenum) getinputstate (EXT_CSQC)
997 static void VM_CL_getinputstate (void)
1000 VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
1001 frame = (int)PRVM_G_FLOAT(OFS_PARM0);
1002 for (i = 0;i < cl.movement_numqueue;i++)
1003 if (cl.movement_queue[i].sequence == frame)
1005 VectorCopy(cl.movement_queue[i].viewangles, prog->globals.client->input_angles);
1006 //prog->globals.client->input_buttons = cl.movement_queue[i].//FIXME
1007 VectorCopy(cl.movement_queue[i].move, prog->globals.client->input_movevalues);
1008 prog->globals.client->input_timelength = cl.movement_queue[i].frametime;
1009 if(cl.movement_queue[i].crouch)
1011 VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
1012 VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
1016 VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
1017 VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
1022 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
1023 static void VM_CL_setsensitivityscale (void)
1025 VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
1026 cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
1029 //#347 void() runstandardplayerphysics (EXT_CSQC)
1030 static void VM_CL_runplayerphysics (void)
1034 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
1035 static void VM_CL_getplayerkey (void)
1041 VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
1043 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1044 c = PRVM_G_STRING(OFS_PARM1);
1045 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1048 i = Sbar_GetPlayer(i);
1054 if(!strcasecmp(c, "name"))
1055 strlcpy(t, cl.scores[i].name, sizeof(t));
1057 if(!strcasecmp(c, "frags"))
1058 sprintf(t, "%i", cl.scores[i].frags);
1060 if(!strcasecmp(c, "ping"))
1061 sprintf(t, "%i", cl.scores[i].qw_ping);
1063 if(!strcasecmp(c, "pl"))
1064 sprintf(t, "%i", cl.scores[i].qw_packetloss);
1066 if(!strcasecmp(c, "entertime"))
1067 sprintf(t, "%f", cl.scores[i].qw_entertime);
1069 if(!strcasecmp(c, "colors"))
1070 sprintf(t, "%i", cl.scores[i].colors);
1072 if(!strcasecmp(c, "topcolor"))
1073 sprintf(t, "%i", cl.scores[i].colors & 0xf0);
1075 if(!strcasecmp(c, "bottomcolor"))
1076 sprintf(t, "%i", (cl.scores[i].colors &15)<<4);
1078 if(!strcasecmp(c, "viewentity"))
1079 sprintf(t, "%i", i+1);
1082 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1085 //#349 float() isdemo (EXT_CSQC)
1086 static void VM_CL_isdemo (void)
1088 VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
1089 PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
1092 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
1093 static void VM_CL_setlistener (void)
1095 VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
1096 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));
1097 cl.csqc_usecsqclistener = true; //use csqc listener at this frame
1100 //#352 void(string cmdname) registercommand (EXT_CSQC)
1101 static void VM_CL_registercmd (void)
1104 VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
1105 if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0)))
1109 alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1;
1110 t = (char *)Z_Malloc(alloclen);
1111 memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen);
1112 Cmd_AddCommand(t, NULL, "console command created by QuakeC");
1115 Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
1119 //#360 float() readbyte (EXT_CSQC)
1120 static void VM_CL_ReadByte (void)
1122 VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
1123 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte();
1126 //#361 float() readchar (EXT_CSQC)
1127 static void VM_CL_ReadChar (void)
1129 VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
1130 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar();
1133 //#362 float() readshort (EXT_CSQC)
1134 static void VM_CL_ReadShort (void)
1136 VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
1137 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort();
1140 //#363 float() readlong (EXT_CSQC)
1141 static void VM_CL_ReadLong (void)
1143 VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
1144 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong();
1147 //#364 float() readcoord (EXT_CSQC)
1148 static void VM_CL_ReadCoord (void)
1150 VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
1151 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(cls.protocol);
1154 //#365 float() readangle (EXT_CSQC)
1155 static void VM_CL_ReadAngle (void)
1157 VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
1158 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(cls.protocol);
1161 //#366 string() readstring (EXT_CSQC)
1162 static void VM_CL_ReadString (void)
1164 VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
1165 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_ReadString());
1168 //#367 float() readfloat (EXT_CSQC)
1169 static void VM_CL_ReadFloat (void)
1171 VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
1172 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
1175 //////////////////////////////////////////////////////////
1177 static void VM_CL_makestatic (void)
1181 VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
1183 ent = PRVM_G_EDICT(OFS_PARM0);
1184 if (ent == prog->edicts)
1186 VM_Warning("makestatic: can not modify world entity\n");
1189 if (ent->priv.server->free)
1191 VM_Warning("makestatic: can not modify free entity\n");
1195 if (cl.num_static_entities < cl.max_static_entities)
1199 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
1201 // copy it to the current state
1202 staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
1203 staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
1204 staticent->render.framelerp = 0;
1205 // make torchs play out of sync
1206 staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
1207 staticent->render.colormap = (int)ent->fields.client->colormap; // no special coloring
1208 staticent->render.skinnum = (int)ent->fields.client->skin;
1209 staticent->render.effects = (int)ent->fields.client->effects;
1210 staticent->render.alpha = 1;
1211 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float;
1212 staticent->render.scale = 1;
1213 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
1214 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
1217 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
1218 if (renderflags & RF_USEAXIS)
1221 VectorNegate(prog->globals.client->v_right, left);
1222 Matrix4x4_FromVectors(&staticent->render.matrix, prog->globals.client->v_forward, left, prog->globals.client->v_up, ent->fields.client->origin);
1223 Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
1226 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);
1227 CL_UpdateRenderEntity(&staticent->render);
1229 // either fullbright or lit
1230 if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
1231 staticent->render.flags |= RENDER_LIGHT;
1232 // turn off shadows from transparent objects
1233 if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
1234 staticent->render.flags |= RENDER_SHADOW;
1237 Con_Printf("Too many static entities");
1239 // throw the entity away now
1243 //=================================================================//
1249 copies data from one entity to another
1251 copyentity(src, dst)
1254 static void VM_CL_copyentity (void)
1256 prvm_edict_t *in, *out;
1257 VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
1258 in = PRVM_G_EDICT(OFS_PARM0);
1259 if (in == prog->edicts)
1261 VM_Warning("copyentity: can not read world entity\n");
1264 if (in->priv.server->free)
1266 VM_Warning("copyentity: can not read free entity\n");
1269 out = PRVM_G_EDICT(OFS_PARM1);
1270 if (out == prog->edicts)
1272 VM_Warning("copyentity: can not modify world entity\n");
1275 if (out->priv.server->free)
1277 VM_Warning("copyentity: can not modify free entity\n");
1280 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1284 //=================================================================//
1286 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
1287 static void VM_CL_effect (void)
1289 VM_SAFEPARMCOUNT(5, VM_CL_effect);
1290 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));
1293 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
1294 static void VM_CL_te_blood (void)
1298 VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
1299 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1301 pos = PRVM_G_VECTOR(OFS_PARM0);
1302 CL_FindNonSolidLocation(pos, pos2, 4);
1303 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1306 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
1307 static void VM_CL_te_bloodshower (void)
1311 VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
1312 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1314 speed = PRVM_G_FLOAT(OFS_PARM2);
1321 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), vel1, vel2, NULL, 0);
1324 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
1325 static void VM_CL_te_explosionrgb (void)
1329 matrix4x4_t tempmatrix;
1330 VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
1331 pos = PRVM_G_VECTOR(OFS_PARM0);
1332 CL_FindNonSolidLocation(pos, pos2, 10);
1333 CL_ParticleExplosion(pos2);
1334 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1335 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);
1338 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
1339 static void VM_CL_te_particlecube (void)
1341 VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
1342 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));
1345 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
1346 static void VM_CL_te_particlerain (void)
1348 VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
1349 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);
1352 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
1353 static void VM_CL_te_particlesnow (void)
1355 VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
1356 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);
1359 // #411 void(vector org, vector vel, float howmany) te_spark
1360 static void VM_CL_te_spark (void)
1364 VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
1366 pos = PRVM_G_VECTOR(OFS_PARM0);
1367 CL_FindNonSolidLocation(pos, pos2, 4);
1368 CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1371 extern cvar_t cl_sound_ric_gunshot;
1372 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
1373 static void VM_CL_te_gunshotquad (void)
1378 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
1380 pos = PRVM_G_VECTOR(OFS_PARM0);
1381 CL_FindNonSolidLocation(pos, pos2, 4);
1382 CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1383 if(cl_sound_ric_gunshot.integer >= 2)
1385 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1389 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1390 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1391 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1396 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
1397 static void VM_CL_te_spikequad (void)
1402 VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
1404 pos = PRVM_G_VECTOR(OFS_PARM0);
1405 CL_FindNonSolidLocation(pos, pos2, 4);
1406 CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1407 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1411 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1412 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1413 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1417 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
1418 static void VM_CL_te_superspikequad (void)
1423 VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
1425 pos = PRVM_G_VECTOR(OFS_PARM0);
1426 CL_FindNonSolidLocation(pos, pos2, 4);
1427 CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1428 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1432 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1433 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1434 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1438 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
1439 static void VM_CL_te_explosionquad (void)
1443 VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
1445 pos = PRVM_G_VECTOR(OFS_PARM0);
1446 CL_FindNonSolidLocation(pos, pos2, 10);
1447 CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1448 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1451 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
1452 static void VM_CL_te_smallflash (void)
1456 VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
1458 pos = PRVM_G_VECTOR(OFS_PARM0);
1459 CL_FindNonSolidLocation(pos, pos2, 10);
1460 CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1463 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
1464 static void VM_CL_te_customflash (void)
1468 matrix4x4_t tempmatrix;
1469 VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
1471 pos = PRVM_G_VECTOR(OFS_PARM0);
1472 CL_FindNonSolidLocation(pos, pos2, 4);
1473 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1474 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);
1477 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
1478 static void VM_CL_te_gunshot (void)
1483 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
1485 pos = PRVM_G_VECTOR(OFS_PARM0);
1486 CL_FindNonSolidLocation(pos, pos2, 4);
1487 CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1488 if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
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);
1501 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
1502 static void VM_CL_te_spike (void)
1507 VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
1509 pos = PRVM_G_VECTOR(OFS_PARM0);
1510 CL_FindNonSolidLocation(pos, pos2, 4);
1511 CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1512 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1516 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1517 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1518 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1522 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
1523 static void VM_CL_te_superspike (void)
1528 VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
1530 pos = PRVM_G_VECTOR(OFS_PARM0);
1531 CL_FindNonSolidLocation(pos, pos2, 4);
1532 CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1533 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1537 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1538 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1539 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1543 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
1544 static void VM_CL_te_explosion (void)
1548 VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
1550 pos = PRVM_G_VECTOR(OFS_PARM0);
1551 CL_FindNonSolidLocation(pos, pos2, 10);
1552 CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1553 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1556 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
1557 static void VM_CL_te_tarexplosion (void)
1561 VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
1563 pos = PRVM_G_VECTOR(OFS_PARM0);
1564 CL_FindNonSolidLocation(pos, pos2, 10);
1565 CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1566 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1569 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
1570 static void VM_CL_te_wizspike (void)
1574 VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
1576 pos = PRVM_G_VECTOR(OFS_PARM0);
1577 CL_FindNonSolidLocation(pos, pos2, 4);
1578 CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1579 S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
1582 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
1583 static void VM_CL_te_knightspike (void)
1587 VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
1589 pos = PRVM_G_VECTOR(OFS_PARM0);
1590 CL_FindNonSolidLocation(pos, pos2, 4);
1591 CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1592 S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
1595 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
1596 static void VM_CL_te_lavasplash (void)
1598 VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
1599 CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1602 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
1603 static void VM_CL_te_teleport (void)
1605 VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
1606 CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1609 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
1610 static void VM_CL_te_explosion2 (void)
1614 matrix4x4_t tempmatrix;
1615 int colorStart, colorLength;
1616 unsigned char *tempcolor;
1617 VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
1619 pos = PRVM_G_VECTOR(OFS_PARM0);
1620 colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
1621 colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
1622 CL_FindNonSolidLocation(pos, pos2, 10);
1623 CL_ParticleExplosion2(pos2, colorStart, colorLength);
1624 tempcolor = (unsigned char *)&palette_complete[(rand()%colorLength) + colorStart];
1625 color[0] = tempcolor[0] * (2.0f / 255.0f);
1626 color[1] = tempcolor[1] * (2.0f / 255.0f);
1627 color[2] = tempcolor[2] * (2.0f / 255.0f);
1628 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1629 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);
1630 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1634 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
1635 static void VM_CL_te_lightning1 (void)
1637 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
1638 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
1641 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
1642 static void VM_CL_te_lightning2 (void)
1644 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
1645 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
1648 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
1649 static void VM_CL_te_lightning3 (void)
1651 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
1652 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
1655 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
1656 static void VM_CL_te_beam (void)
1658 VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
1659 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
1662 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
1663 static void VM_CL_te_plasmaburn (void)
1667 VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
1669 pos = PRVM_G_VECTOR(OFS_PARM0);
1670 CL_FindNonSolidLocation(pos, pos2, 4);
1671 CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1674 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
1675 static void VM_CL_te_flamejet (void)
1679 VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
1680 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1682 pos = PRVM_G_VECTOR(OFS_PARM0);
1683 CL_FindNonSolidLocation(pos, pos2, 4);
1684 CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1688 //====================================================================
1691 extern void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
1693 static msurface_t *cl_getsurface(model_t *model, int surfacenum)
1695 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1697 return model->data_surfaces + surfacenum + model->firstmodelsurface;
1700 // #434 float(entity e, float s) getsurfacenumpoints
1701 static void VM_CL_getsurfacenumpoints(void)
1704 msurface_t *surface;
1705 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
1706 // return 0 if no such surface
1707 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1709 PRVM_G_FLOAT(OFS_RETURN) = 0;
1713 // note: this (incorrectly) assumes it is a simple polygon
1714 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1717 // #435 vector(entity e, float s, float n) getsurfacepoint
1718 static void VM_CL_getsurfacepoint(void)
1722 msurface_t *surface;
1724 VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1725 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1726 ed = PRVM_G_EDICT(OFS_PARM0);
1727 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1729 // note: this (incorrectly) assumes it is a simple polygon
1730 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1731 if (pointnum < 0 || pointnum >= surface->num_vertices)
1733 // FIXME: implement rotation/scaling
1734 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1737 // #436 vector(entity e, float s) getsurfacenormal
1738 static void VM_CL_getsurfacenormal(void)
1741 msurface_t *surface;
1743 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
1744 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1745 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1747 // FIXME: implement rotation/scaling
1748 // note: this (incorrectly) assumes it is a simple polygon
1749 // note: this only returns the first triangle, so it doesn't work very
1750 // well for curved surfaces or arbitrary meshes
1751 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);
1752 VectorNormalize(normal);
1753 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1756 // #437 string(entity e, float s) getsurfacetexture
1757 static void VM_CL_getsurfacetexture(void)
1760 msurface_t *surface;
1761 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
1762 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1763 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1765 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
1768 // #438 float(entity e, vector p) getsurfacenearpoint
1769 static void VM_CL_getsurfacenearpoint(void)
1771 int surfacenum, best;
1773 vec_t dist, bestdist;
1775 model_t *model = NULL;
1776 msurface_t *surface;
1778 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
1779 PRVM_G_FLOAT(OFS_RETURN) = -1;
1780 ed = PRVM_G_EDICT(OFS_PARM0);
1781 if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces)
1784 // FIXME: implement rotation/scaling
1785 point = PRVM_G_VECTOR(OFS_PARM1);
1786 VectorSubtract(point, ed->fields.client->origin, p);
1788 bestdist = 1000000000;
1789 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1791 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1792 // first see if the nearest point on the surface's box is closer than the previous match
1793 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1794 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1795 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1796 dist = VectorLength2(clipped);
1797 if (dist < bestdist)
1799 // it is, check the nearest point on the actual geometry
1800 clippointtosurface(model, surface, p, clipped);
1801 VectorSubtract(clipped, p, clipped);
1802 dist += VectorLength2(clipped);
1803 if (dist < bestdist)
1805 // that's closer too, store it as the best match
1811 PRVM_G_FLOAT(OFS_RETURN) = best;
1814 // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint
1815 static void VM_CL_getsurfaceclippedpoint(void)
1819 msurface_t *surface;
1821 VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
1822 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1823 ed = PRVM_G_EDICT(OFS_PARM0);
1824 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1826 // FIXME: implement rotation/scaling
1827 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
1828 clippointtosurface(model, surface, p, out);
1829 // FIXME: implement rotation/scaling
1830 VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1833 // #443 void(entity e, entity tagentity, string tagname) setattachment
1834 static void VM_CL_setattachment (void)
1837 prvm_edict_t *tagentity;
1838 const char *tagname;
1842 VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
1844 e = PRVM_G_EDICT(OFS_PARM0);
1845 tagentity = PRVM_G_EDICT(OFS_PARM1);
1846 tagname = PRVM_G_STRING(OFS_PARM2);
1848 if (e == prog->edicts)
1850 VM_Warning("setattachment: can not modify world entity\n");
1853 if (e->priv.server->free)
1855 VM_Warning("setattachment: can not modify free entity\n");
1859 if (tagentity == NULL)
1860 tagentity = prog->edicts;
1862 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
1864 v->edict = PRVM_EDICT_TO_PROG(tagentity);
1866 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
1869 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
1871 modelindex = (int)tagentity->fields.client->modelindex;
1872 model = CL_GetModelByIndex(modelindex);
1875 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
1877 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);
1880 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));
1884 /////////////////////////////////////////
1885 // DP_MD3_TAGINFO extension coded by VorteX
1887 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
1889 model_t *model = CL_GetModelFromEdict(e);
1891 return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
1896 // Warnings/errors code:
1897 // 0 - normal (everything all-right)
1900 // 3 - null or non-precached model
1901 // 4 - no tags with requested index
1902 // 5 - runaway loop at attachment chain
1903 extern cvar_t cl_bob;
1904 extern cvar_t cl_bobcycle;
1905 extern cvar_t cl_bobup;
1906 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
1909 int reqframe, attachloop;
1910 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
1911 prvm_edict_t *attachent;
1914 *out = identitymatrix; // warnings and errors return identical matrix
1916 if (ent == prog->edicts)
1918 if (ent->priv.server->free)
1921 model = CL_GetModelFromEdict(ent);
1926 if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
1927 reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
1929 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
1931 // get initial tag matrix
1934 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
1939 tagmatrix = identitymatrix;
1941 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
1942 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
1946 attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
1947 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
1949 model = CL_GetModelFromEdict(attachent);
1951 if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
1952 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
1954 attachmatrix = identitymatrix;
1956 // apply transformation by child entity matrix
1957 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1958 if (val->_float == 0)
1960 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], val->_float);
1961 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1962 Matrix4x4_Copy(&tagmatrix, out);
1964 // finally transformate by matrix of tag on parent entity
1965 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
1966 Matrix4x4_Copy(&tagmatrix, out);
1970 if (attachloop > 255) // prevent runaway looping
1973 while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
1976 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
1977 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1978 if (val->_float == 0)
1980 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
1981 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], val->_float);
1982 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1984 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
1985 {// RENDER_VIEWMODEL magic
1986 Matrix4x4_Copy(&tagmatrix, out);
1988 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1989 if (val->_float == 0)
1992 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], val->_float);
1993 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1996 // Cl_bob, ported from rendering code
1997 if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
2000 // LordHavoc: this code is *weird*, but not replacable (I think it
2001 // should be done in QC on the server, but oh well, quake is quake)
2002 // LordHavoc: figured out bobup: the time at which the sin is at 180
2003 // degrees (which allows lengthening or squishing the peak or valley)
2004 cycle = cl.time/cl_bobcycle.value;
2005 cycle -= (int)cycle;
2006 if (cycle < cl_bobup.value)
2007 cycle = sin(M_PI * cycle / cl_bobup.value);
2009 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2010 // bob is proportional to velocity in the xy plane
2011 // (don't count Z, or jumping messes it up)
2012 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;
2013 bob = bob*0.3 + bob*0.7*cycle;
2014 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2021 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
2022 static void VM_CL_gettagindex (void)
2025 const char *tag_name;
2026 int modelindex, tag_index;
2028 VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
2030 ent = PRVM_G_EDICT(OFS_PARM0);
2031 tag_name = PRVM_G_STRING(OFS_PARM1);
2032 if (ent == prog->edicts)
2034 VM_Warning("gettagindex: can't affect world entity\n");
2037 if (ent->priv.server->free)
2039 VM_Warning("gettagindex: can't affect free entity\n");
2043 modelindex = (int)ent->fields.client->modelindex;
2045 modelindex = -(modelindex+1);
2047 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2048 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2051 tag_index = CL_GetTagIndex(ent, tag_name);
2053 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2055 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2058 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2059 static void VM_CL_gettaginfo (void)
2063 matrix4x4_t tag_matrix;
2066 VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2068 e = PRVM_G_EDICT(OFS_PARM0);
2069 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2070 returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2071 Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2076 VM_Warning("gettagindex: can't affect world entity\n");
2079 VM_Warning("gettagindex: can't affect free entity\n");
2082 Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2085 Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2088 Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2093 //============================================================================
2095 //====================
2096 //QC POLYGON functions
2097 //====================
2102 float data[36]; //[515]: enough for polygons
2103 unsigned char flags; //[515]: + VM_POLYGON_2D and VM_POLYGON_FL4V flags
2106 //static float vm_polygon_linewidth = 1;
2107 static mempool_t *vm_polygons_pool = NULL;
2108 static unsigned char vm_current_vertices = 0;
2109 static qboolean vm_polygons_initialized = false;
2110 static vm_polygon_t *vm_polygons = NULL;
2111 static unsigned long vm_polygons_num = 0, vm_drawpolygons_num = 0; //[515]: ok long on 64bit ?
2112 static qboolean vm_polygonbegin = false; //[515]: for "no-crap-on-the-screen" check
2113 #define VM_DEFPOLYNUM 64 //[515]: enough for default ?
2115 #define VM_POLYGON_FL3V 16 //more than 2 vertices (used only for lines)
2116 #define VM_POLYGON_FLLINES 32
2117 #define VM_POLYGON_FL2D 64
2118 #define VM_POLYGON_FL4V 128 //4 vertices
2120 static void VM_InitPolygons (void)
2122 vm_polygons_pool = Mem_AllocPool("VMPOLY", 0, NULL);
2123 vm_polygons = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2124 memset(vm_polygons, 0, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2125 vm_polygons_num = VM_DEFPOLYNUM;
2126 vm_drawpolygons_num = 0;
2127 vm_polygonbegin = false;
2128 vm_polygons_initialized = true;
2131 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2133 int surfacelistindex;
2134 // LordHavoc: FIXME: this is stupid code
2135 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2137 const vm_polygon_t *p = &vm_polygons[surfacelist[surfacelistindex]];
2138 int flags = p->flags & 0x0f;
2140 if(flags == DRAWFLAG_ADDITIVE)
2141 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2142 else if(flags == DRAWFLAG_MODULATE)
2143 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2144 else if(flags == DRAWFLAG_2XMODULATE)
2145 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2147 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2149 R_Mesh_TexBind(0, R_GetTexture(p->tex));
2152 //[515]: is speed is max ?
2153 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2155 qglLineWidth(p->data[13]);CHECKGLERROR
2156 qglBegin(GL_LINE_LOOP);
2157 qglTexCoord1f (p->data[12]);
2158 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2159 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2161 qglTexCoord1f (p->data[14]);
2162 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2163 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2165 if(p->flags & VM_POLYGON_FL3V)
2167 qglTexCoord1f (p->data[16]);
2168 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2169 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2171 if(p->flags & VM_POLYGON_FL4V)
2173 qglTexCoord1f (p->data[18]);
2174 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2175 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2183 qglBegin(GL_POLYGON);
2184 qglTexCoord2f (p->data[12], p->data[13]);
2185 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2186 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2188 qglTexCoord2f (p->data[14], p->data[15]);
2189 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2190 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2192 qglTexCoord2f (p->data[16], p->data[17]);
2193 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2194 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2196 if(p->flags & VM_POLYGON_FL4V)
2198 qglTexCoord2f (p->data[18], p->data[19]);
2199 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2200 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2208 static void VM_CL_AddPolygonTo2DScene (vm_polygon_t *p)
2210 drawqueuemesh_t mesh;
2211 static int picelements[6] = {0, 1, 2, 0, 2, 3};
2213 mesh.texture = p->tex;
2214 mesh.data_element3i = picelements;
2215 mesh.data_vertex3f = p->data;
2216 mesh.data_texcoord2f = p->data + 12;
2217 mesh.data_color4f = p->data + 20;
2218 if(p->flags & VM_POLYGON_FL4V)
2220 mesh.num_vertices = 4;
2221 mesh.num_triangles = 2;
2225 mesh.num_vertices = 3;
2226 mesh.num_triangles = 1;
2228 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2229 DrawQ_LineLoop (&mesh, (p->flags&0x0f));
2231 DrawQ_Mesh (&mesh, (p->flags&0x0f));
2234 void VM_CL_AddPolygonsToMeshQueue (void)
2237 if(!vm_drawpolygons_num)
2239 R_Mesh_Matrix(&identitymatrix);
2240 GL_CullFace(GL_NONE);
2241 for(i = 0;i < (int)vm_drawpolygons_num;i++)
2242 VM_DrawPolygonCallback(NULL, NULL, 1, &i);
2243 vm_drawpolygons_num = 0;
2246 //void(string texturename, float flag[, float 2d[, float lines]]) R_BeginPolygon
2247 static void VM_CL_R_PolygonBegin (void)
2250 const char *picname;
2251 VM_SAFEPARMCOUNTRANGE(2, 4, VM_CL_R_PolygonBegin);
2253 if(!vm_polygons_initialized)
2257 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonEnd after first\n");
2260 if(vm_drawpolygons_num >= vm_polygons_num)
2262 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2263 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2264 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2265 Mem_Free(vm_polygons);
2267 vm_polygons_num *= 2;
2269 p = &vm_polygons[vm_drawpolygons_num];
2270 picname = PRVM_G_STRING(OFS_PARM0);
2272 p->tex = Draw_CachePic(picname, true)->tex;
2274 p->tex = r_texture_white;
2275 p->flags = (unsigned char)PRVM_G_FLOAT(OFS_PARM1);
2276 vm_current_vertices = 0;
2277 vm_polygonbegin = true;
2280 if(PRVM_G_FLOAT(OFS_PARM2))
2281 p->flags |= VM_POLYGON_FL2D;
2282 if(prog->argc >= 4 && PRVM_G_FLOAT(OFS_PARM3))
2284 p->data[13] = PRVM_G_FLOAT(OFS_PARM3); //[515]: linewidth
2285 p->flags |= VM_POLYGON_FLLINES;
2290 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2291 static void VM_CL_R_PolygonVertex (void)
2293 float *coords, *tx, *rgb, alpha;
2295 VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2297 if(!vm_polygonbegin)
2299 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2302 coords = PRVM_G_VECTOR(OFS_PARM0);
2303 tx = PRVM_G_VECTOR(OFS_PARM1);
2304 rgb = PRVM_G_VECTOR(OFS_PARM2);
2305 alpha = PRVM_G_FLOAT(OFS_PARM3);
2307 p = &vm_polygons[vm_drawpolygons_num];
2308 if(vm_current_vertices > 4)
2310 VM_Warning("VM_CL_R_PolygonVertex: may have 4 vertices max\n");
2314 p->data[vm_current_vertices*3] = coords[0];
2315 p->data[1+vm_current_vertices*3] = coords[1];
2316 p->data[2+vm_current_vertices*3] = coords[2];
2318 p->data[12+vm_current_vertices*2] = tx[0];
2319 if(!(p->flags & VM_POLYGON_FLLINES))
2320 p->data[13+vm_current_vertices*2] = tx[1];
2322 p->data[20+vm_current_vertices*4] = rgb[0];
2323 p->data[21+vm_current_vertices*4] = rgb[1];
2324 p->data[22+vm_current_vertices*4] = rgb[2];
2325 p->data[23+vm_current_vertices*4] = alpha;
2327 vm_current_vertices++;
2328 if(vm_current_vertices == 4)
2329 p->flags |= VM_POLYGON_FL4V;
2331 if(vm_current_vertices == 3)
2332 p->flags |= VM_POLYGON_FL3V;
2335 //void() R_EndPolygon
2336 static void VM_CL_R_PolygonEnd (void)
2338 VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2339 if(!vm_polygonbegin)
2341 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2344 vm_polygonbegin = false;
2345 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2347 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2348 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2350 vm_drawpolygons_num++;
2353 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2356 void Debug_PolygonBegin(const char *picname, int flags, qboolean draw2d, float linewidth)
2360 if(!vm_polygons_initialized)
2364 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2367 // limit polygons to a vaguely sane amount, beyond this each one just
2368 // replaces the last one
2369 vm_drawpolygons_num = min(vm_drawpolygons_num, (1<<20)-1);
2370 if(vm_drawpolygons_num >= vm_polygons_num)
2372 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2373 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2374 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2375 Mem_Free(vm_polygons);
2377 vm_polygons_num *= 2;
2379 p = &vm_polygons[vm_drawpolygons_num];
2380 if(picname && picname[0])
2381 p->tex = Draw_CachePic(picname, true)->tex;
2383 p->tex = r_texture_white;
2385 vm_current_vertices = 0;
2386 vm_polygonbegin = true;
2388 p->flags |= VM_POLYGON_FL2D;
2391 p->data[13] = linewidth; //[515]: linewidth
2392 p->flags |= VM_POLYGON_FLLINES;
2396 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2400 if(!vm_polygonbegin)
2402 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2406 p = &vm_polygons[vm_drawpolygons_num];
2407 if(vm_current_vertices > 4)
2409 Con_Printf("Debug_PolygonVertex: may have 4 vertices max\n");
2413 p->data[vm_current_vertices*3] = x;
2414 p->data[1+vm_current_vertices*3] = y;
2415 p->data[2+vm_current_vertices*3] = z;
2417 p->data[12+vm_current_vertices*2] = s;
2418 if(!(p->flags & VM_POLYGON_FLLINES))
2419 p->data[13+vm_current_vertices*2] = t;
2421 p->data[20+vm_current_vertices*4] = r;
2422 p->data[21+vm_current_vertices*4] = g;
2423 p->data[22+vm_current_vertices*4] = b;
2424 p->data[23+vm_current_vertices*4] = a;
2426 vm_current_vertices++;
2427 if(vm_current_vertices == 4)
2428 p->flags |= VM_POLYGON_FL4V;
2430 if(vm_current_vertices == 3)
2431 p->flags |= VM_POLYGON_FL3V;
2434 void Debug_PolygonEnd(void)
2436 if(!vm_polygonbegin)
2438 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2441 vm_polygonbegin = false;
2442 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2444 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2445 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2447 vm_drawpolygons_num++;
2450 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2457 Returns false if any part of the bottom of the entity is off an edge that
2462 qboolean CL_CheckBottom (prvm_edict_t *ent)
2464 vec3_t mins, maxs, start, stop;
2469 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2470 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2472 // if all of the points under the corners are solid world, don't bother
2473 // with the tougher checks
2474 // the corners must be within 16 of the midpoint
2475 start[2] = mins[2] - 1;
2476 for (x=0 ; x<=1 ; x++)
2477 for (y=0 ; y<=1 ; y++)
2479 start[0] = x ? maxs[0] : mins[0];
2480 start[1] = y ? maxs[1] : mins[1];
2481 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2485 return true; // we got out easy
2489 // check it for real...
2493 // the midpoint must be within 16 of the bottom
2494 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2495 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2496 stop[2] = start[2] - 2*sv_stepheight.value;
2497 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2499 if (trace.fraction == 1.0)
2501 mid = bottom = trace.endpos[2];
2503 // the corners must be within 16 of the midpoint
2504 for (x=0 ; x<=1 ; x++)
2505 for (y=0 ; y<=1 ; y++)
2507 start[0] = stop[0] = x ? maxs[0] : mins[0];
2508 start[1] = stop[1] = y ? maxs[1] : mins[1];
2510 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2512 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2513 bottom = trace.endpos[2];
2514 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2525 Called by monster program code.
2526 The move will be adjusted for slopes and stairs, but if the move isn't
2527 possible, no move is done and false is returned
2530 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2533 vec3_t oldorg, neworg, end, traceendpos;
2536 prvm_edict_t *enemy;
2540 VectorCopy (ent->fields.client->origin, oldorg);
2541 VectorAdd (ent->fields.client->origin, move, neworg);
2543 // flying monsters don't step up
2544 if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2546 // try one move with vertical motion, then one without
2547 for (i=0 ; i<2 ; i++)
2549 VectorAdd (ent->fields.client->origin, move, neworg);
2550 enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2551 if (i == 0 && enemy != prog->edicts)
2553 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2559 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);
2561 VM_SetTraceGlobals(&trace);
2563 if (trace.fraction == 1)
2565 VectorCopy(trace.endpos, traceendpos);
2566 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2567 return false; // swim monster left water
2569 VectorCopy (traceendpos, ent->fields.client->origin);
2575 if (enemy == prog->edicts)
2582 // push down from a step height above the wished position
2583 neworg[2] += sv_stepheight.value;
2584 VectorCopy (neworg, end);
2585 end[2] -= sv_stepheight.value*2;
2587 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2589 VM_SetTraceGlobals(&trace);
2591 if (trace.startsolid)
2593 neworg[2] -= sv_stepheight.value;
2594 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2596 VM_SetTraceGlobals(&trace);
2597 if (trace.startsolid)
2600 if (trace.fraction == 1)
2602 // if monster had the ground pulled out, go ahead and fall
2603 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2605 VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2608 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2612 return false; // walked off an edge
2615 // check point traces down for dangling corners
2616 VectorCopy (trace.endpos, ent->fields.client->origin);
2618 if (!CL_CheckBottom (ent))
2620 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2621 { // entity had floor mostly pulled out from underneath it
2622 // and is trying to correct
2627 VectorCopy (oldorg, ent->fields.client->origin);
2631 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2632 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2634 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2635 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2647 float(float yaw, float dist[, settrace]) walkmove
2650 static void VM_CL_walkmove (void)
2659 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2661 // assume failure if it returns early
2662 PRVM_G_FLOAT(OFS_RETURN) = 0;
2664 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2665 if (ent == prog->edicts)
2667 VM_Warning("walkmove: can not modify world entity\n");
2670 if (ent->priv.server->free)
2672 VM_Warning("walkmove: can not modify free entity\n");
2675 yaw = PRVM_G_FLOAT(OFS_PARM0);
2676 dist = PRVM_G_FLOAT(OFS_PARM1);
2677 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2679 if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2682 yaw = yaw*M_PI*2 / 360;
2684 move[0] = cos(yaw)*dist;
2685 move[1] = sin(yaw)*dist;
2688 // save program state, because CL_movestep may call other progs
2689 oldf = prog->xfunction;
2690 oldself = prog->globals.client->self;
2692 PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2695 // restore program state
2696 prog->xfunction = oldf;
2697 prog->globals.client->self = oldself;
2704 string(string key) serverkey
2707 void VM_CL_serverkey(void)
2709 char string[VM_STRINGTEMP_LENGTH];
2710 VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2711 InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2712 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2715 //============================================================================
2717 prvm_builtin_t vm_cl_builtins[] = {
2718 NULL, // #0 NULL function (not callable) (QUAKE)
2719 VM_CL_makevectors, // #1 void(vector ang) makevectors (QUAKE)
2720 VM_CL_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
2721 VM_CL_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
2722 VM_CL_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2723 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2724 VM_break, // #6 void() break (QUAKE)
2725 VM_random, // #7 float() random (QUAKE)
2726 VM_CL_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
2727 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
2728 VM_error, // #10 void(string e) error (QUAKE)
2729 VM_objerror, // #11 void(string e) objerror (QUAKE)
2730 VM_vlen, // #12 float(vector v) vlen (QUAKE)
2731 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
2732 VM_CL_spawn, // #14 entity() spawn (QUAKE)
2733 VM_remove, // #15 void(entity e) remove (QUAKE)
2734 VM_CL_traceline, // #16 float(vector v1, vector v2, float tryents) traceline (QUAKE)
2735 NULL, // #17 entity() checkclient (QUAKE)
2736 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
2737 VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
2738 VM_CL_precache_model, // #20 void(string s) precache_model (QUAKE)
2739 NULL, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2740 VM_CL_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
2741 NULL, // #23 void(string s, ...) bprint (QUAKE)
2742 NULL, // #24 void(entity client, string s, ...) sprint (QUAKE)
2743 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
2744 VM_ftos, // #26 string(float f) ftos (QUAKE)
2745 VM_vtos, // #27 string(vector v) vtos (QUAKE)
2746 VM_coredump, // #28 void() coredump (QUAKE)
2747 VM_traceon, // #29 void() traceon (QUAKE)
2748 VM_traceoff, // #30 void() traceoff (QUAKE)
2749 VM_eprint, // #31 void(entity e) eprint (QUAKE)
2750 VM_CL_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
2751 NULL, // #33 (QUAKE)
2752 VM_CL_droptofloor, // #34 float() droptofloor (QUAKE)
2753 VM_CL_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
2754 VM_rint, // #36 float(float v) rint (QUAKE)
2755 VM_floor, // #37 float(float v) floor (QUAKE)
2756 VM_ceil, // #38 float(float v) ceil (QUAKE)
2757 NULL, // #39 (QUAKE)
2758 VM_CL_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
2759 VM_CL_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
2760 NULL, // #42 (QUAKE)
2761 VM_fabs, // #43 float(float f) fabs (QUAKE)
2762 NULL, // #44 vector(entity e, float speed) aim (QUAKE)
2763 VM_cvar, // #45 float(string s) cvar (QUAKE)
2764 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
2765 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
2766 VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2767 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
2768 NULL, // #50 (QUAKE)
2769 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
2770 NULL, // #52 void(float to, float f) WriteByte (QUAKE)
2771 NULL, // #53 void(float to, float f) WriteChar (QUAKE)
2772 NULL, // #54 void(float to, float f) WriteShort (QUAKE)
2773 NULL, // #55 void(float to, float f) WriteLong (QUAKE)
2774 NULL, // #56 void(float to, float f) WriteCoord (QUAKE)
2775 NULL, // #57 void(float to, float f) WriteAngle (QUAKE)
2776 NULL, // #58 void(float to, string s) WriteString (QUAKE)
2777 NULL, // #59 (QUAKE)
2778 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2779 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2780 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2781 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2782 VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2783 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2784 NULL, // #66 (QUAKE)
2785 NULL, // #67 void(float step) movetogoal (QUAKE)
2786 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
2787 VM_CL_makestatic, // #69 void(entity e) makestatic (QUAKE)
2788 NULL, // #70 void(string s) changelevel (QUAKE)
2789 NULL, // #71 (QUAKE)
2790 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
2791 NULL, // #73 void(entity client, strings) centerprint (QUAKE)
2792 VM_CL_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2793 VM_CL_precache_model, // #75 string(string s) precache_model2 (QUAKE)
2794 VM_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
2795 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
2796 NULL, // #78 void(entity e) setspawnparms (QUAKE)
2797 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
2798 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
2799 VM_stof, // #81 float(string s) stof (FRIK_FILE)
2800 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
2801 NULL, // #83 (QUAKE)
2802 NULL, // #84 (QUAKE)
2803 NULL, // #85 (QUAKE)
2804 NULL, // #86 (QUAKE)
2805 NULL, // #87 (QUAKE)
2806 NULL, // #88 (QUAKE)
2807 NULL, // #89 (QUAKE)
2808 VM_CL_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2809 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2810 VM_CL_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2811 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2812 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2813 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2814 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2815 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2816 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2817 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
2818 // FrikaC and Telejano range #100-#199
2829 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
2830 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
2831 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
2832 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2833 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
2834 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
2835 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
2836 VM_stov, // #117 vector(string) stov (FRIK_FILE)
2837 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
2838 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
2919 // FTEQW range #200-#299
2938 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
2941 VM_strstrofs, // #221 float(string str, string sub[, float startpos]) strstrofs (FTE_STRINGS)
2942 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
2943 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
2944 VM_strconv, // #224 string(float ccase, float calpha, float cnum, string s, ...) strconv (FTE_STRINGS)
2945 VM_strpad, // #225 string(float chars, string s, ...) strpad (FTE_STRINGS)
2946 VM_infoadd, // #226 string(string info, string key, string value, ...) infoadd (FTE_STRINGS)
2947 VM_infoget, // #227 string(string info, string key) infoget (FTE_STRINGS)
2948 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
2949 VM_strncasecmp, // #229 float(string s1, string s2) strcasecmp (FTE_STRINGS)
2950 VM_strncasecmp, // #230 float(string s1, string s2, float len) strncasecmp (FTE_STRINGS)
2952 NULL, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3020 // CSQC range #300-#399
3021 VM_CL_R_ClearScene, // #300 void() clearscene (EXT_CSQC)
3022 VM_CL_R_AddEntities, // #301 void(float mask) addentities (EXT_CSQC)
3023 VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC)
3024 VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC)
3025 VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC)
3026 VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
3027 VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
3028 VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3029 VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon
3031 VM_CL_unproject, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3032 VM_CL_project, // #311 vector (vector v) cs_project (EXT_CSQC)
3036 VM_drawline, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3037 VM_iscachedpic, // #316 float(string name) iscachedpic (EXT_CSQC)
3038 VM_precache_pic, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3039 VM_getimagesize, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3040 VM_freepic, // #319 void(string name) freepic (EXT_CSQC)
3041 VM_drawcharacter, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3042 VM_drawstring, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3043 VM_drawpic, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3044 VM_drawfill, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3045 VM_drawsetcliparea, // #324 void(float x, float y, float width, float height) drawsetcliparea
3046 VM_drawresetcliparea, // #325 void(void) drawresetcliparea
3051 VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
3052 VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
3053 VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
3054 VM_CL_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3055 VM_CL_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3056 VM_CL_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3057 VM_CL_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3058 VM_CL_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3059 VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC)
3060 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3061 VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3062 VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3063 VM_CL_getkeybind, // #342 string(float keynum) getkeybind (EXT_CSQC)
3064 VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3065 VM_getmousepos, // #344 vector() getmousepos (EXT_CSQC)
3066 VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC)
3067 VM_CL_setsensitivityscale, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3068 VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC)
3069 VM_CL_getplayerkey, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3070 VM_CL_isdemo, // #349 float() isdemo (EXT_CSQC)
3071 VM_isserver, // #350 float() isserver (EXT_CSQC)
3072 VM_CL_setlistener, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3073 VM_CL_registercmd, // #352 void(string cmdname) registercommand (EXT_CSQC)
3074 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3075 VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3081 VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC)
3082 VM_CL_ReadChar, // #361 float() readchar (EXT_CSQC)
3083 VM_CL_ReadShort, // #362 float() readshort (EXT_CSQC)
3084 VM_CL_ReadLong, // #363 float() readlong (EXT_CSQC)
3085 VM_CL_ReadCoord, // #364 float() readcoord (EXT_CSQC)
3086 VM_CL_ReadAngle, // #365 float() readangle (EXT_CSQC)
3087 VM_CL_ReadString, // #366 string() readstring (EXT_CSQC)
3088 VM_CL_ReadFloat, // #367 float() readfloat (EXT_CSQC)
3121 // LordHavoc's range #400-#499
3122 VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3123 NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3124 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3125 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3126 VM_CL_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3127 VM_CL_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3128 VM_CL_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3129 VM_CL_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3130 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)
3131 VM_CL_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3132 VM_CL_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3133 VM_CL_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3134 VM_CL_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3135 VM_CL_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3136 VM_CL_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3137 VM_CL_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3138 VM_CL_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3139 VM_CL_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3140 VM_CL_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3141 VM_CL_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3142 VM_CL_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3143 VM_CL_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3144 VM_CL_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3145 VM_CL_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3146 VM_CL_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3147 VM_CL_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3148 VM_CL_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3149 VM_CL_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3150 VM_CL_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3151 VM_CL_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3152 VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3153 VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3154 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3155 VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3156 VM_CL_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3157 VM_CL_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3158 VM_CL_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3159 VM_CL_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3160 VM_CL_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3161 VM_CL_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3162 NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3163 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3164 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3165 VM_CL_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3166 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_QC_FS_SEARCH)
3167 VM_search_end, // #445 void(float handle) search_end (DP_QC_FS_SEARCH)
3168 VM_search_getsize, // #446 float(float handle) search_getsize (DP_QC_FS_SEARCH)
3169 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_QC_FS_SEARCH)
3170 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3171 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3172 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3173 VM_CL_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3174 VM_CL_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3175 NULL, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3176 NULL, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3177 NULL, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3178 NULL, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3179 VM_CL_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3181 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3182 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3183 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3184 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3185 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3186 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3187 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3188 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3189 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3190 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3191 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3192 NULL, // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3193 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3194 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3195 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3196 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3197 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3198 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3199 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3200 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3201 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3202 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3203 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3204 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3224 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3226 void VM_CL_Cmd_Init(void)
3228 // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3229 if(vm_polygons_initialized)
3231 Mem_FreePool(&vm_polygons_pool);
3232 vm_polygons_initialized = false;
3236 void VM_CL_Cmd_Reset(void)
3238 if(vm_polygons_initialized)
3240 Mem_FreePool(&vm_polygons_pool);
3241 vm_polygons_initialized = false;