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 = (int)(PRVM_G_FLOAT(OFS_PARM3)*255.0f);
142 attenuation = PRVM_G_FLOAT(OFS_PARM4);
144 if (volume < 0 || volume > 255)
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 cl.csqc_origin
629 // FIXME: restore cl.csqc_angles
630 cl.csqc_vidvars.drawworld = true;
631 cl.csqc_vidvars.drawenginesbar = true;
632 cl.csqc_vidvars.drawcrosshair = true;
635 //#301 void(float mask) addentities (EXT_CSQC)
636 extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
637 extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
638 static void VM_CL_R_AddEntities (void)
642 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
643 drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
644 CSQC_RelinkAllEntities(drawmask);
645 CL_RelinkLightFlashes();
647 prog->globals.client->time = cl.time;
648 for(i=1;i<prog->num_edicts;i++)
650 ed = &prog->edicts[i];
651 if(ed->priv.required->free)
654 if(ed->priv.required->free)
656 // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict
658 if(ed->priv.required->free)
660 if(!((int)ed->fields.client->drawmask & drawmask))
662 CSQC_AddRenderEdict(ed);
666 //#302 void(entity ent) addentity (EXT_CSQC)
667 static void VM_CL_R_AddEntity (void)
669 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
670 CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
673 //#303 float(float property, ...) setproperty (EXT_CSQC)
674 static void VM_CL_R_SetView (void)
680 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_SetView);
682 c = (int)PRVM_G_FLOAT(OFS_PARM0);
683 f = PRVM_G_VECTOR(OFS_PARM1);
684 k = PRVM_G_FLOAT(OFS_PARM1);
688 case VF_MIN: r_view.x = (int)(f[0] * vid.width / vid_conwidth.value);
689 r_view.y = (int)(f[1] * vid.height / vid_conheight.value);
691 case VF_MIN_X: r_view.x = (int)(k * vid.width / vid_conwidth.value);
693 case VF_MIN_Y: r_view.y = (int)(k * vid.height / vid_conheight.value);
695 case VF_SIZE: r_view.width = (int)(f[0] * vid.width / vid_conwidth.value);
696 r_view.height = (int)(f[1] * vid.height / vid_conheight.value);
698 case VF_SIZE_Y: r_view.width = (int)(k * vid.width / vid_conwidth.value);
700 case VF_SIZE_X: r_view.height = (int)(k * vid.height / vid_conheight.value);
702 case VF_VIEWPORT: r_view.x = (int)(f[0] * vid.width / vid_conwidth.value);
703 r_view.y = (int)(f[1] * vid.height / vid_conheight.value);
704 f = PRVM_G_VECTOR(OFS_PARM2);
705 r_view.width = (int)(f[0] * vid.width / vid_conwidth.value);
706 r_view.height = (int)(f[1] * vid.height / vid_conheight.value);
708 case VF_FOV: r_view.frustum_x = tan(f[0] * M_PI / 360.0);
709 r_view.frustum_y = tan(f[1] * M_PI / 360.0);
711 case VF_FOVX: r_view.frustum_x = tan(k * M_PI / 360.0);
713 case VF_FOVY: r_view.frustum_y = tan(k * M_PI / 360.0);
715 case VF_ORIGIN: VectorCopy(f, cl.csqc_origin);
718 case VF_ORIGIN_X: cl.csqc_origin[0] = k;
721 case VF_ORIGIN_Y: cl.csqc_origin[1] = k;
724 case VF_ORIGIN_Z: cl.csqc_origin[2] = k;
727 case VF_ANGLES: VectorCopy(f, cl.csqc_angles);
730 case VF_ANGLES_X: cl.csqc_angles[0] = k;
733 case VF_ANGLES_Y: cl.csqc_angles[1] = k;
736 case VF_ANGLES_Z: cl.csqc_angles[2] = k;
739 case VF_DRAWWORLD: cl.csqc_vidvars.drawworld = k;
741 case VF_DRAWENGINESBAR: cl.csqc_vidvars.drawenginesbar = k;
743 case VF_DRAWCROSSHAIR: cl.csqc_vidvars.drawcrosshair = k;
746 case VF_CL_VIEWANGLES: VectorCopy(f, cl.viewangles);
748 case VF_CL_VIEWANGLES_X:cl.viewangles[0] = k;
750 case VF_CL_VIEWANGLES_Y:cl.viewangles[1] = k;
752 case VF_CL_VIEWANGLES_Z:cl.viewangles[2] = k;
755 case VF_PERSPECTIVE: r_view.useperspective = k != 0;
758 default: PRVM_G_FLOAT(OFS_RETURN) = 0;
759 VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c);
762 PRVM_G_FLOAT(OFS_RETURN) = 1;
765 //#304 void() renderscene (EXT_CSQC)
766 static void VM_CL_R_RenderScene (void)
768 VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
769 // we need to update any RENDER_VIEWMODEL entities at this point because
770 // csqc supplies its own view matrix
771 CL_UpdateViewEntities();
776 //#305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
777 static void VM_CL_R_AddDynamicLight (void)
781 VM_SAFEPARMCOUNTRANGE(3, 8, VM_CL_R_AddDynamicLight); // allow more than 3 because we may extend this in the future
783 // if we've run out of dlights, just return
784 if (r_refdef.numlights >= MAX_DLIGHTS)
787 pos = PRVM_G_VECTOR(OFS_PARM0);
788 col = PRVM_G_VECTOR(OFS_PARM2);
789 Matrix4x4_CreateFromQuakeEntity(&matrix, pos[0], pos[1], pos[2], 0, 0, 0, PRVM_G_FLOAT(OFS_PARM1));
790 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);
793 //============================================================================
795 //#310 vector (vector v) cs_unproject (EXT_CSQC)
796 static void VM_CL_unproject (void)
801 VM_SAFEPARMCOUNT(1, VM_CL_unproject);
802 f = PRVM_G_VECTOR(OFS_PARM0);
803 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);
804 Matrix4x4_Transform(&r_view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
807 //#311 vector (vector v) cs_project (EXT_CSQC)
808 static void VM_CL_project (void)
814 VM_SAFEPARMCOUNT(1, VM_CL_project);
815 f = PRVM_G_VECTOR(OFS_PARM0);
816 Matrix4x4_Invert_Simple(&m, &r_view.matrix);
817 Matrix4x4_Transform(&m, f, v);
818 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]);
821 //#330 float(float stnum) getstatf (EXT_CSQC)
822 static void VM_CL_getstatf (void)
830 VM_SAFEPARMCOUNT(1, VM_CL_getstatf);
831 i = (int)PRVM_G_FLOAT(OFS_PARM0);
832 if(i < 0 || i >= MAX_CL_STATS)
834 VM_Warning("VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
838 PRVM_G_FLOAT(OFS_RETURN) = dat.f;
841 //#331 float(float stnum) getstati (EXT_CSQC)
842 static void VM_CL_getstati (void)
845 VM_SAFEPARMCOUNT(1, VM_CL_getstati);
846 index = (int)PRVM_G_FLOAT(OFS_PARM0);
848 if(index < 0 || index >= MAX_CL_STATS)
850 VM_Warning("VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
854 PRVM_G_FLOAT(OFS_RETURN) = i;
857 //#332 string(float firststnum) getstats (EXT_CSQC)
858 static void VM_CL_getstats (void)
862 VM_SAFEPARMCOUNT(1, VM_CL_getstats);
863 i = (int)PRVM_G_FLOAT(OFS_PARM0);
864 if(i < 0 || i > MAX_CL_STATS-4)
866 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
867 VM_Warning("VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
870 strlcpy(t, (char*)&cl.stats[i], sizeof(t));
871 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
874 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
875 static void VM_CL_setmodelindex (void)
879 struct model_s *model;
881 VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex);
883 t = PRVM_G_EDICT(OFS_PARM0);
885 i = (int)PRVM_G_FLOAT(OFS_PARM1);
887 t->fields.client->model = 0;
888 t->fields.client->modelindex = 0;
893 model = CL_GetModelByIndex(i);
896 VM_Warning("VM_CL_setmodelindex: null model\n");
899 t->fields.client->model = PRVM_SetEngineString(model->name);
900 t->fields.client->modelindex = i;
903 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
904 static void VM_CL_modelnameforindex (void)
908 VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
910 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
911 model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
912 PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(model->name) : 0;
915 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
916 static void VM_CL_particleeffectnum (void)
919 VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
920 i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
923 PRVM_G_FLOAT(OFS_RETURN) = i;
926 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
927 static void VM_CL_trailparticles (void)
932 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles);
934 t = PRVM_G_EDICT(OFS_PARM0);
935 i = (int)PRVM_G_FLOAT(OFS_PARM1);
936 start = PRVM_G_VECTOR(OFS_PARM2);
937 end = PRVM_G_VECTOR(OFS_PARM3);
939 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);
942 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
943 static void VM_CL_pointparticles (void)
947 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
948 i = (int)PRVM_G_FLOAT(OFS_PARM0);
949 f = PRVM_G_VECTOR(OFS_PARM1);
950 v = PRVM_G_VECTOR(OFS_PARM2);
951 n = (int)PRVM_G_FLOAT(OFS_PARM3);
952 CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
955 //#342 string(float keynum) getkeybind (EXT_CSQC)
956 static void VM_CL_getkeybind (void)
958 VM_SAFEPARMCOUNT(1, VM_CL_getkeybind);
959 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0)));
962 //#343 void(float usecursor) setcursormode (EXT_CSQC)
963 static void VM_CL_setcursormode (void)
965 VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
966 cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
967 cl_ignoremousemove = true;
970 //#345 float(float framenum) getinputstate (EXT_CSQC)
971 static void VM_CL_getinputstate (void)
974 VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
975 frame = (int)PRVM_G_FLOAT(OFS_PARM0);
976 for (i = 0;i < cl.movement_numqueue;i++)
977 if (cl.movement_queue[i].sequence == frame)
979 VectorCopy(cl.movement_queue[i].viewangles, prog->globals.client->input_angles);
980 //prog->globals.client->input_buttons = cl.movement_queue[i].//FIXME
981 VectorCopy(cl.movement_queue[i].move, prog->globals.client->input_movevalues);
982 prog->globals.client->input_timelength = cl.movement_queue[i].frametime;
983 if(cl.movement_queue[i].crouch)
985 VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
986 VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
990 VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
991 VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
996 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
997 static void VM_CL_setsensitivityscale (void)
999 VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
1000 cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
1003 //#347 void() runstandardplayerphysics (EXT_CSQC)
1004 static void VM_CL_runplayerphysics (void)
1008 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
1009 static void VM_CL_getplayerkey (void)
1015 VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
1017 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1018 c = PRVM_G_STRING(OFS_PARM1);
1019 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1022 i = Sbar_GetPlayer(i);
1028 if(!strcasecmp(c, "name"))
1029 strlcpy(t, cl.scores[i].name, sizeof(t));
1031 if(!strcasecmp(c, "frags"))
1032 sprintf(t, "%i", cl.scores[i].frags);
1034 if(!strcasecmp(c, "ping"))
1035 sprintf(t, "%i", cl.scores[i].qw_ping);
1037 if(!strcasecmp(c, "entertime"))
1038 sprintf(t, "%f", cl.scores[i].qw_entertime);
1040 if(!strcasecmp(c, "colors"))
1041 sprintf(t, "%i", cl.scores[i].colors);
1043 if(!strcasecmp(c, "topcolor"))
1044 sprintf(t, "%i", cl.scores[i].colors & 0xf0);
1046 if(!strcasecmp(c, "bottomcolor"))
1047 sprintf(t, "%i", (cl.scores[i].colors &15)<<4);
1049 if(!strcasecmp(c, "viewentity"))
1050 sprintf(t, "%i", i+1);
1053 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1056 //#349 float() isdemo (EXT_CSQC)
1057 static void VM_CL_isdemo (void)
1059 VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
1060 PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
1063 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
1064 static void VM_CL_setlistener (void)
1066 VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
1067 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));
1068 cl.csqc_usecsqclistener = true; //use csqc listener at this frame
1071 //#352 void(string cmdname) registercommand (EXT_CSQC)
1072 static void VM_CL_registercmd (void)
1075 VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
1076 if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0)))
1080 alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1;
1081 t = (char *)Z_Malloc(alloclen);
1082 memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen);
1083 Cmd_AddCommand(t, NULL, "console command created by QuakeC");
1086 Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
1090 //#360 float() readbyte (EXT_CSQC)
1091 static void VM_CL_ReadByte (void)
1093 VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
1094 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte();
1097 //#361 float() readchar (EXT_CSQC)
1098 static void VM_CL_ReadChar (void)
1100 VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
1101 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar();
1104 //#362 float() readshort (EXT_CSQC)
1105 static void VM_CL_ReadShort (void)
1107 VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
1108 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort();
1111 //#363 float() readlong (EXT_CSQC)
1112 static void VM_CL_ReadLong (void)
1114 VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
1115 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong();
1118 //#364 float() readcoord (EXT_CSQC)
1119 static void VM_CL_ReadCoord (void)
1121 VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
1122 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(cls.protocol);
1125 //#365 float() readangle (EXT_CSQC)
1126 static void VM_CL_ReadAngle (void)
1128 VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
1129 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(cls.protocol);
1132 //#366 string() readstring (EXT_CSQC)
1133 static void VM_CL_ReadString (void)
1135 VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
1136 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_ReadString());
1139 //#367 float() readfloat (EXT_CSQC)
1140 static void VM_CL_ReadFloat (void)
1142 VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
1143 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
1146 //////////////////////////////////////////////////////////
1148 static void VM_CL_makestatic (void)
1152 VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
1154 ent = PRVM_G_EDICT(OFS_PARM0);
1155 if (ent == prog->edicts)
1157 VM_Warning("makestatic: can not modify world entity\n");
1160 if (ent->priv.server->free)
1162 VM_Warning("makestatic: can not modify free entity\n");
1166 if (cl.num_static_entities < cl.max_static_entities)
1170 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
1172 // copy it to the current state
1173 staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
1174 staticent->render.frame = staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
1175 staticent->render.framelerp = 0;
1176 // make torchs play out of sync
1177 staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
1178 staticent->render.colormap = (int)ent->fields.client->colormap; // no special coloring
1179 staticent->render.skinnum = (int)ent->fields.client->skin;
1180 staticent->render.effects = (int)ent->fields.client->effects;
1181 staticent->render.alpha = 1;
1182 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float;
1183 staticent->render.scale = 1;
1184 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
1185 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
1188 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
1189 if (renderflags & RF_USEAXIS)
1192 VectorNegate(prog->globals.client->v_right, left);
1193 Matrix4x4_FromVectors(&staticent->render.matrix, prog->globals.client->v_forward, left, prog->globals.client->v_up, ent->fields.client->origin);
1194 Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
1197 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);
1198 CL_UpdateRenderEntity(&staticent->render);
1200 // either fullbright or lit
1201 if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
1202 staticent->render.flags |= RENDER_LIGHT;
1203 // turn off shadows from transparent objects
1204 if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
1205 staticent->render.flags |= RENDER_SHADOW;
1208 Con_Printf("Too many static entities");
1210 // throw the entity away now
1214 //=================================================================//
1220 copies data from one entity to another
1222 copyentity(src, dst)
1225 static void VM_CL_copyentity (void)
1227 prvm_edict_t *in, *out;
1228 VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
1229 in = PRVM_G_EDICT(OFS_PARM0);
1230 if (in == prog->edicts)
1232 VM_Warning("copyentity: can not read world entity\n");
1235 if (in->priv.server->free)
1237 VM_Warning("copyentity: can not read free entity\n");
1240 out = PRVM_G_EDICT(OFS_PARM1);
1241 if (out == prog->edicts)
1243 VM_Warning("copyentity: can not modify world entity\n");
1246 if (out->priv.server->free)
1248 VM_Warning("copyentity: can not modify free entity\n");
1251 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1255 //=================================================================//
1257 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
1258 static void VM_CL_effect (void)
1260 VM_SAFEPARMCOUNT(5, VM_CL_effect);
1261 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));
1264 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
1265 static void VM_CL_te_blood (void)
1269 VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
1270 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1272 pos = PRVM_G_VECTOR(OFS_PARM0);
1273 CL_FindNonSolidLocation(pos, pos2, 4);
1274 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1277 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
1278 static void VM_CL_te_bloodshower (void)
1282 VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
1283 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1285 speed = PRVM_G_FLOAT(OFS_PARM2);
1292 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), vel1, vel2, NULL, 0);
1295 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
1296 static void VM_CL_te_explosionrgb (void)
1300 matrix4x4_t tempmatrix;
1301 VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
1302 pos = PRVM_G_VECTOR(OFS_PARM0);
1303 CL_FindNonSolidLocation(pos, pos2, 10);
1304 CL_ParticleExplosion(pos2);
1305 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1306 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);
1309 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
1310 static void VM_CL_te_particlecube (void)
1312 VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
1313 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));
1316 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
1317 static void VM_CL_te_particlerain (void)
1319 VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
1320 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);
1323 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
1324 static void VM_CL_te_particlesnow (void)
1326 VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
1327 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);
1330 // #411 void(vector org, vector vel, float howmany) te_spark
1331 static void VM_CL_te_spark (void)
1335 VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
1337 pos = PRVM_G_VECTOR(OFS_PARM0);
1338 CL_FindNonSolidLocation(pos, pos2, 4);
1339 CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1342 extern cvar_t cl_sound_ric_gunshot;
1343 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
1344 static void VM_CL_te_gunshotquad (void)
1349 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
1351 pos = PRVM_G_VECTOR(OFS_PARM0);
1352 CL_FindNonSolidLocation(pos, pos2, 4);
1353 CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1354 if(cl_sound_ric_gunshot.integer >= 2)
1356 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1360 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1361 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1362 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1367 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
1368 static void VM_CL_te_spikequad (void)
1373 VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
1375 pos = PRVM_G_VECTOR(OFS_PARM0);
1376 CL_FindNonSolidLocation(pos, pos2, 4);
1377 CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1378 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1382 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1383 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1384 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1388 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
1389 static void VM_CL_te_superspikequad (void)
1394 VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
1396 pos = PRVM_G_VECTOR(OFS_PARM0);
1397 CL_FindNonSolidLocation(pos, pos2, 4);
1398 CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1399 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1403 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1404 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1405 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1409 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
1410 static void VM_CL_te_explosionquad (void)
1414 VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
1416 pos = PRVM_G_VECTOR(OFS_PARM0);
1417 CL_FindNonSolidLocation(pos, pos2, 10);
1418 CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1419 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1422 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
1423 static void VM_CL_te_smallflash (void)
1427 VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
1429 pos = PRVM_G_VECTOR(OFS_PARM0);
1430 CL_FindNonSolidLocation(pos, pos2, 10);
1431 CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1434 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
1435 static void VM_CL_te_customflash (void)
1439 matrix4x4_t tempmatrix;
1440 VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
1442 pos = PRVM_G_VECTOR(OFS_PARM0);
1443 CL_FindNonSolidLocation(pos, pos2, 4);
1444 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1445 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);
1448 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
1449 static void VM_CL_te_gunshot (void)
1454 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
1456 pos = PRVM_G_VECTOR(OFS_PARM0);
1457 CL_FindNonSolidLocation(pos, pos2, 4);
1458 CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1459 if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
1461 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1465 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1466 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1467 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1472 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
1473 static void VM_CL_te_spike (void)
1478 VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
1480 pos = PRVM_G_VECTOR(OFS_PARM0);
1481 CL_FindNonSolidLocation(pos, pos2, 4);
1482 CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1483 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1487 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1488 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1489 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1493 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
1494 static void VM_CL_te_superspike (void)
1499 VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
1501 pos = PRVM_G_VECTOR(OFS_PARM0);
1502 CL_FindNonSolidLocation(pos, pos2, 4);
1503 CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1504 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1508 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1509 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1510 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1514 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
1515 static void VM_CL_te_explosion (void)
1519 VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
1521 pos = PRVM_G_VECTOR(OFS_PARM0);
1522 CL_FindNonSolidLocation(pos, pos2, 10);
1523 CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1524 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1527 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
1528 static void VM_CL_te_tarexplosion (void)
1532 VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
1534 pos = PRVM_G_VECTOR(OFS_PARM0);
1535 CL_FindNonSolidLocation(pos, pos2, 10);
1536 CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1537 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1540 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
1541 static void VM_CL_te_wizspike (void)
1545 VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
1547 pos = PRVM_G_VECTOR(OFS_PARM0);
1548 CL_FindNonSolidLocation(pos, pos2, 4);
1549 CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1550 S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
1553 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
1554 static void VM_CL_te_knightspike (void)
1558 VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
1560 pos = PRVM_G_VECTOR(OFS_PARM0);
1561 CL_FindNonSolidLocation(pos, pos2, 4);
1562 CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1563 S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
1566 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
1567 static void VM_CL_te_lavasplash (void)
1569 VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
1570 CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1573 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
1574 static void VM_CL_te_teleport (void)
1576 VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
1577 CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1580 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
1581 static void VM_CL_te_explosion2 (void)
1585 matrix4x4_t tempmatrix;
1586 int colorStart, colorLength;
1587 unsigned char *tempcolor;
1588 VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
1590 pos = PRVM_G_VECTOR(OFS_PARM0);
1591 colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
1592 colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
1593 CL_FindNonSolidLocation(pos, pos2, 10);
1594 CL_ParticleExplosion2(pos2, colorStart, colorLength);
1595 tempcolor = (unsigned char *)&palette_complete[(rand()%colorLength) + colorStart];
1596 color[0] = tempcolor[0] * (2.0f / 255.0f);
1597 color[1] = tempcolor[1] * (2.0f / 255.0f);
1598 color[2] = tempcolor[2] * (2.0f / 255.0f);
1599 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1600 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);
1601 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1605 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
1606 static void VM_CL_te_lightning1 (void)
1608 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
1609 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
1612 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
1613 static void VM_CL_te_lightning2 (void)
1615 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
1616 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
1619 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
1620 static void VM_CL_te_lightning3 (void)
1622 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
1623 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
1626 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
1627 static void VM_CL_te_beam (void)
1629 VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
1630 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
1633 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
1634 static void VM_CL_te_plasmaburn (void)
1638 VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
1640 pos = PRVM_G_VECTOR(OFS_PARM0);
1641 CL_FindNonSolidLocation(pos, pos2, 4);
1642 CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1645 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
1646 static void VM_CL_te_flamejet (void)
1650 VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
1651 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1653 pos = PRVM_G_VECTOR(OFS_PARM0);
1654 CL_FindNonSolidLocation(pos, pos2, 4);
1655 CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1659 //====================================================================
1662 extern void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
1664 static msurface_t *cl_getsurface(model_t *model, int surfacenum)
1666 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1668 return model->data_surfaces + surfacenum + model->firstmodelsurface;
1671 // #434 float(entity e, float s) getsurfacenumpoints
1672 static void VM_CL_getsurfacenumpoints(void)
1675 msurface_t *surface;
1676 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
1677 // return 0 if no such surface
1678 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1680 PRVM_G_FLOAT(OFS_RETURN) = 0;
1684 // note: this (incorrectly) assumes it is a simple polygon
1685 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1688 // #435 vector(entity e, float s, float n) getsurfacepoint
1689 static void VM_CL_getsurfacepoint(void)
1693 msurface_t *surface;
1695 VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1696 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1697 ed = PRVM_G_EDICT(OFS_PARM0);
1698 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1700 // note: this (incorrectly) assumes it is a simple polygon
1701 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1702 if (pointnum < 0 || pointnum >= surface->num_vertices)
1704 // FIXME: implement rotation/scaling
1705 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1708 // #436 vector(entity e, float s) getsurfacenormal
1709 static void VM_CL_getsurfacenormal(void)
1712 msurface_t *surface;
1714 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
1715 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1716 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1718 // FIXME: implement rotation/scaling
1719 // note: this (incorrectly) assumes it is a simple polygon
1720 // note: this only returns the first triangle, so it doesn't work very
1721 // well for curved surfaces or arbitrary meshes
1722 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);
1723 VectorNormalize(normal);
1724 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1727 // #437 string(entity e, float s) getsurfacetexture
1728 static void VM_CL_getsurfacetexture(void)
1731 msurface_t *surface;
1732 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
1733 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1734 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1736 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
1739 // #438 float(entity e, vector p) getsurfacenearpoint
1740 static void VM_CL_getsurfacenearpoint(void)
1742 int surfacenum, best;
1744 vec_t dist, bestdist;
1746 model_t *model = NULL;
1747 msurface_t *surface;
1749 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
1750 PRVM_G_FLOAT(OFS_RETURN) = -1;
1751 ed = PRVM_G_EDICT(OFS_PARM0);
1752 if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces)
1755 // FIXME: implement rotation/scaling
1756 point = PRVM_G_VECTOR(OFS_PARM1);
1757 VectorSubtract(point, ed->fields.client->origin, p);
1759 bestdist = 1000000000;
1760 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1762 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1763 // first see if the nearest point on the surface's box is closer than the previous match
1764 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1765 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1766 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1767 dist = VectorLength2(clipped);
1768 if (dist < bestdist)
1770 // it is, check the nearest point on the actual geometry
1771 clippointtosurface(model, surface, p, clipped);
1772 VectorSubtract(clipped, p, clipped);
1773 dist += VectorLength2(clipped);
1774 if (dist < bestdist)
1776 // that's closer too, store it as the best match
1782 PRVM_G_FLOAT(OFS_RETURN) = best;
1785 // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint
1786 static void VM_CL_getsurfaceclippedpoint(void)
1790 msurface_t *surface;
1792 VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
1793 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1794 ed = PRVM_G_EDICT(OFS_PARM0);
1795 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1797 // FIXME: implement rotation/scaling
1798 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
1799 clippointtosurface(model, surface, p, out);
1800 // FIXME: implement rotation/scaling
1801 VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1804 // #443 void(entity e, entity tagentity, string tagname) setattachment
1805 static void VM_CL_setattachment (void)
1808 prvm_edict_t *tagentity;
1809 const char *tagname;
1813 VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
1815 e = PRVM_G_EDICT(OFS_PARM0);
1816 tagentity = PRVM_G_EDICT(OFS_PARM1);
1817 tagname = PRVM_G_STRING(OFS_PARM2);
1819 if (e == prog->edicts)
1821 VM_Warning("setattachment: can not modify world entity\n");
1824 if (e->priv.server->free)
1826 VM_Warning("setattachment: can not modify free entity\n");
1830 if (tagentity == NULL)
1831 tagentity = prog->edicts;
1833 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
1835 v->edict = PRVM_EDICT_TO_PROG(tagentity);
1837 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
1840 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
1842 modelindex = (int)tagentity->fields.client->modelindex;
1843 model = CL_GetModelByIndex(modelindex);
1846 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
1848 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);
1851 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));
1855 /////////////////////////////////////////
1856 // DP_MD3_TAGINFO extension coded by VorteX
1858 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
1860 model_t *model = CL_GetModelFromEdict(e);
1862 return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
1867 // Warnings/errors code:
1868 // 0 - normal (everything all-right)
1871 // 3 - null or non-precached model
1872 // 4 - no tags with requested index
1873 // 5 - runaway loop at attachment chain
1874 extern cvar_t cl_bob;
1875 extern cvar_t cl_bobcycle;
1876 extern cvar_t cl_bobup;
1877 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
1880 int reqframe, attachloop;
1881 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
1882 prvm_edict_t *attachent;
1885 *out = identitymatrix; // warnings and errors return identical matrix
1887 if (ent == prog->edicts)
1889 if (ent->priv.server->free)
1892 model = CL_GetModelFromEdict(ent);
1897 if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
1898 reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
1900 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
1902 // get initial tag matrix
1905 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
1910 tagmatrix = identitymatrix;
1912 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
1913 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
1917 attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
1918 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
1920 model = CL_GetModelFromEdict(attachent);
1922 if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
1923 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
1925 attachmatrix = identitymatrix;
1927 // apply transformation by child entity matrix
1928 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1929 if (val->_float == 0)
1931 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);
1932 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1933 Matrix4x4_Copy(&tagmatrix, out);
1935 // finally transformate by matrix of tag on parent entity
1936 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
1937 Matrix4x4_Copy(&tagmatrix, out);
1941 if (attachloop > 255) // prevent runaway looping
1944 while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
1947 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
1948 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1949 if (val->_float == 0)
1951 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
1952 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);
1953 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1955 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
1956 {// RENDER_VIEWMODEL magic
1957 Matrix4x4_Copy(&tagmatrix, out);
1959 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1960 if (val->_float == 0)
1963 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);
1964 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1967 // Cl_bob, ported from rendering code
1968 if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
1971 // LordHavoc: this code is *weird*, but not replacable (I think it
1972 // should be done in QC on the server, but oh well, quake is quake)
1973 // LordHavoc: figured out bobup: the time at which the sin is at 180
1974 // degrees (which allows lengthening or squishing the peak or valley)
1975 cycle = cl.time/cl_bobcycle.value;
1976 cycle -= (int)cycle;
1977 if (cycle < cl_bobup.value)
1978 cycle = sin(M_PI * cycle / cl_bobup.value);
1980 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
1981 // bob is proportional to velocity in the xy plane
1982 // (don't count Z, or jumping messes it up)
1983 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;
1984 bob = bob*0.3 + bob*0.7*cycle;
1985 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
1992 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
1993 static void VM_CL_gettagindex (void)
1996 const char *tag_name;
1997 int modelindex, tag_index;
1999 VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
2001 ent = PRVM_G_EDICT(OFS_PARM0);
2002 tag_name = PRVM_G_STRING(OFS_PARM1);
2003 if (ent == prog->edicts)
2005 VM_Warning("gettagindex: can't affect world entity\n");
2008 if (ent->priv.server->free)
2010 VM_Warning("gettagindex: can't affect free entity\n");
2014 modelindex = (int)ent->fields.client->modelindex;
2016 modelindex = -(modelindex+1);
2018 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2019 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2022 tag_index = CL_GetTagIndex(ent, tag_name);
2024 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2026 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2029 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2030 static void VM_CL_gettaginfo (void)
2034 matrix4x4_t tag_matrix;
2037 VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2039 e = PRVM_G_EDICT(OFS_PARM0);
2040 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2041 returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2042 Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2047 VM_Warning("gettagindex: can't affect world entity\n");
2050 VM_Warning("gettagindex: can't affect free entity\n");
2053 Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2056 Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2059 Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2064 //============================================================================
2066 //====================
2067 //QC POLYGON functions
2068 //====================
2073 float data[36]; //[515]: enough for polygons
2074 unsigned char flags; //[515]: + VM_POLYGON_2D and VM_POLYGON_FL4V flags
2077 //static float vm_polygon_linewidth = 1;
2078 static mempool_t *vm_polygons_pool = NULL;
2079 static unsigned char vm_current_vertices = 0;
2080 static qboolean vm_polygons_initialized = false;
2081 static vm_polygon_t *vm_polygons = NULL;
2082 static unsigned long vm_polygons_num = 0, vm_drawpolygons_num = 0; //[515]: ok long on 64bit ?
2083 static qboolean vm_polygonbegin = false; //[515]: for "no-crap-on-the-screen" check
2084 #define VM_DEFPOLYNUM 64 //[515]: enough for default ?
2086 #define VM_POLYGON_FL3V 16 //more than 2 vertices (used only for lines)
2087 #define VM_POLYGON_FLLINES 32
2088 #define VM_POLYGON_FL2D 64
2089 #define VM_POLYGON_FL4V 128 //4 vertices
2091 static void VM_InitPolygons (void)
2093 vm_polygons_pool = Mem_AllocPool("VMPOLY", 0, NULL);
2094 vm_polygons = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2095 memset(vm_polygons, 0, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2096 vm_polygons_num = VM_DEFPOLYNUM;
2097 vm_drawpolygons_num = 0;
2098 vm_polygonbegin = false;
2099 vm_polygons_initialized = true;
2102 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2104 int surfacelistindex;
2105 // LordHavoc: FIXME: this is stupid code
2106 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2108 const vm_polygon_t *p = &vm_polygons[surfacelist[surfacelistindex]];
2109 int flags = p->flags & 0x0f;
2111 if(flags == DRAWFLAG_ADDITIVE)
2112 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2113 else if(flags == DRAWFLAG_MODULATE)
2114 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2115 else if(flags == DRAWFLAG_2XMODULATE)
2116 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2118 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2120 R_Mesh_TexBind(0, R_GetTexture(p->tex));
2123 //[515]: is speed is max ?
2124 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2126 qglLineWidth(p->data[13]);CHECKGLERROR
2127 qglBegin(GL_LINE_LOOP);
2128 qglTexCoord1f (p->data[12]);
2129 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2130 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2132 qglTexCoord1f (p->data[14]);
2133 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2134 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2136 if(p->flags & VM_POLYGON_FL3V)
2138 qglTexCoord1f (p->data[16]);
2139 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2140 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2142 if(p->flags & VM_POLYGON_FL4V)
2144 qglTexCoord1f (p->data[18]);
2145 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2146 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2154 qglBegin(GL_POLYGON);
2155 qglTexCoord2f (p->data[12], p->data[13]);
2156 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2157 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2159 qglTexCoord2f (p->data[14], p->data[15]);
2160 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2161 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2163 qglTexCoord2f (p->data[16], p->data[17]);
2164 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2165 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2167 if(p->flags & VM_POLYGON_FL4V)
2169 qglTexCoord2f (p->data[18], p->data[19]);
2170 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2171 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2179 static void VM_CL_AddPolygonTo2DScene (vm_polygon_t *p)
2181 drawqueuemesh_t mesh;
2182 static int picelements[6] = {0, 1, 2, 0, 2, 3};
2184 mesh.texture = p->tex;
2185 mesh.data_element3i = picelements;
2186 mesh.data_vertex3f = p->data;
2187 mesh.data_texcoord2f = p->data + 12;
2188 mesh.data_color4f = p->data + 20;
2189 if(p->flags & VM_POLYGON_FL4V)
2191 mesh.num_vertices = 4;
2192 mesh.num_triangles = 2;
2196 mesh.num_vertices = 3;
2197 mesh.num_triangles = 1;
2199 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2200 DrawQ_LineLoop (&mesh, (p->flags&0x0f));
2202 DrawQ_Mesh (&mesh, (p->flags&0x0f));
2205 void VM_CL_AddPolygonsToMeshQueue (void)
2208 if(!vm_drawpolygons_num)
2210 R_Mesh_Matrix(&identitymatrix);
2211 GL_CullFace(GL_NONE);
2212 for(i = 0;i < (int)vm_drawpolygons_num;i++)
2213 VM_DrawPolygonCallback(NULL, NULL, 1, &i);
2214 vm_drawpolygons_num = 0;
2217 //void(string texturename, float flag[, float 2d[, float lines]]) R_BeginPolygon
2218 static void VM_CL_R_PolygonBegin (void)
2221 const char *picname;
2222 VM_SAFEPARMCOUNTRANGE(2, 4, VM_CL_R_PolygonBegin);
2224 if(!vm_polygons_initialized)
2228 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonEnd after first\n");
2231 if(vm_drawpolygons_num >= vm_polygons_num)
2233 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2234 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2235 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2236 Mem_Free(vm_polygons);
2238 vm_polygons_num *= 2;
2240 p = &vm_polygons[vm_drawpolygons_num];
2241 picname = PRVM_G_STRING(OFS_PARM0);
2243 p->tex = Draw_CachePic(picname, true)->tex;
2245 p->tex = r_texture_white;
2246 p->flags = (unsigned char)PRVM_G_FLOAT(OFS_PARM1);
2247 vm_current_vertices = 0;
2248 vm_polygonbegin = true;
2251 if(PRVM_G_FLOAT(OFS_PARM2))
2252 p->flags |= VM_POLYGON_FL2D;
2253 if(prog->argc >= 4 && PRVM_G_FLOAT(OFS_PARM3))
2255 p->data[13] = PRVM_G_FLOAT(OFS_PARM3); //[515]: linewidth
2256 p->flags |= VM_POLYGON_FLLINES;
2261 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2262 static void VM_CL_R_PolygonVertex (void)
2264 float *coords, *tx, *rgb, alpha;
2266 VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2268 if(!vm_polygonbegin)
2270 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2273 coords = PRVM_G_VECTOR(OFS_PARM0);
2274 tx = PRVM_G_VECTOR(OFS_PARM1);
2275 rgb = PRVM_G_VECTOR(OFS_PARM2);
2276 alpha = PRVM_G_FLOAT(OFS_PARM3);
2278 p = &vm_polygons[vm_drawpolygons_num];
2279 if(vm_current_vertices > 4)
2281 VM_Warning("VM_CL_R_PolygonVertex: may have 4 vertices max\n");
2285 p->data[vm_current_vertices*3] = coords[0];
2286 p->data[1+vm_current_vertices*3] = coords[1];
2287 p->data[2+vm_current_vertices*3] = coords[2];
2289 p->data[12+vm_current_vertices*2] = tx[0];
2290 if(!(p->flags & VM_POLYGON_FLLINES))
2291 p->data[13+vm_current_vertices*2] = tx[1];
2293 p->data[20+vm_current_vertices*4] = rgb[0];
2294 p->data[21+vm_current_vertices*4] = rgb[1];
2295 p->data[22+vm_current_vertices*4] = rgb[2];
2296 p->data[23+vm_current_vertices*4] = alpha;
2298 vm_current_vertices++;
2299 if(vm_current_vertices == 4)
2300 p->flags |= VM_POLYGON_FL4V;
2302 if(vm_current_vertices == 3)
2303 p->flags |= VM_POLYGON_FL3V;
2306 //void() R_EndPolygon
2307 static void VM_CL_R_PolygonEnd (void)
2309 VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2310 if(!vm_polygonbegin)
2312 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2315 vm_polygonbegin = false;
2316 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2318 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2319 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2321 vm_drawpolygons_num++;
2324 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2327 void Debug_PolygonBegin(const char *picname, int flags, qboolean draw2d, float linewidth)
2331 if(!vm_polygons_initialized)
2335 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2338 // limit polygons to a vaguely sane amount, beyond this each one just
2339 // replaces the last one
2340 vm_drawpolygons_num = min(vm_drawpolygons_num, (1<<20)-1);
2341 if(vm_drawpolygons_num >= vm_polygons_num)
2343 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2344 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2345 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2346 Mem_Free(vm_polygons);
2348 vm_polygons_num *= 2;
2350 p = &vm_polygons[vm_drawpolygons_num];
2351 if(picname && picname[0])
2352 p->tex = Draw_CachePic(picname, true)->tex;
2354 p->tex = r_texture_white;
2356 vm_current_vertices = 0;
2357 vm_polygonbegin = true;
2359 p->flags |= VM_POLYGON_FL2D;
2362 p->data[13] = linewidth; //[515]: linewidth
2363 p->flags |= VM_POLYGON_FLLINES;
2367 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2371 if(!vm_polygonbegin)
2373 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2377 p = &vm_polygons[vm_drawpolygons_num];
2378 if(vm_current_vertices > 4)
2380 Con_Printf("Debug_PolygonVertex: may have 4 vertices max\n");
2384 p->data[vm_current_vertices*3] = x;
2385 p->data[1+vm_current_vertices*3] = y;
2386 p->data[2+vm_current_vertices*3] = z;
2388 p->data[12+vm_current_vertices*2] = s;
2389 if(!(p->flags & VM_POLYGON_FLLINES))
2390 p->data[13+vm_current_vertices*2] = t;
2392 p->data[20+vm_current_vertices*4] = r;
2393 p->data[21+vm_current_vertices*4] = g;
2394 p->data[22+vm_current_vertices*4] = b;
2395 p->data[23+vm_current_vertices*4] = a;
2397 vm_current_vertices++;
2398 if(vm_current_vertices == 4)
2399 p->flags |= VM_POLYGON_FL4V;
2401 if(vm_current_vertices == 3)
2402 p->flags |= VM_POLYGON_FL3V;
2405 void Debug_PolygonEnd(void)
2407 if(!vm_polygonbegin)
2409 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2412 vm_polygonbegin = false;
2413 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2415 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2416 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2418 vm_drawpolygons_num++;
2421 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2428 Returns false if any part of the bottom of the entity is off an edge that
2433 qboolean CL_CheckBottom (prvm_edict_t *ent)
2435 vec3_t mins, maxs, start, stop;
2440 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2441 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2443 // if all of the points under the corners are solid world, don't bother
2444 // with the tougher checks
2445 // the corners must be within 16 of the midpoint
2446 start[2] = mins[2] - 1;
2447 for (x=0 ; x<=1 ; x++)
2448 for (y=0 ; y<=1 ; y++)
2450 start[0] = x ? maxs[0] : mins[0];
2451 start[1] = y ? maxs[1] : mins[1];
2452 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2456 return true; // we got out easy
2460 // check it for real...
2464 // the midpoint must be within 16 of the bottom
2465 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2466 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2467 stop[2] = start[2] - 2*sv_stepheight.value;
2468 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2470 if (trace.fraction == 1.0)
2472 mid = bottom = trace.endpos[2];
2474 // the corners must be within 16 of the midpoint
2475 for (x=0 ; x<=1 ; x++)
2476 for (y=0 ; y<=1 ; y++)
2478 start[0] = stop[0] = x ? maxs[0] : mins[0];
2479 start[1] = stop[1] = y ? maxs[1] : mins[1];
2481 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2483 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2484 bottom = trace.endpos[2];
2485 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2496 Called by monster program code.
2497 The move will be adjusted for slopes and stairs, but if the move isn't
2498 possible, no move is done and false is returned
2501 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2504 vec3_t oldorg, neworg, end, traceendpos;
2507 prvm_edict_t *enemy;
2511 VectorCopy (ent->fields.client->origin, oldorg);
2512 VectorAdd (ent->fields.client->origin, move, neworg);
2514 // flying monsters don't step up
2515 if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2517 // try one move with vertical motion, then one without
2518 for (i=0 ; i<2 ; i++)
2520 VectorAdd (ent->fields.client->origin, move, neworg);
2521 enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2522 if (i == 0 && enemy != prog->edicts)
2524 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2530 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);
2532 VM_SetTraceGlobals(&trace);
2534 if (trace.fraction == 1)
2536 VectorCopy(trace.endpos, traceendpos);
2537 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2538 return false; // swim monster left water
2540 VectorCopy (traceendpos, ent->fields.client->origin);
2546 if (enemy == prog->edicts)
2553 // push down from a step height above the wished position
2554 neworg[2] += sv_stepheight.value;
2555 VectorCopy (neworg, end);
2556 end[2] -= sv_stepheight.value*2;
2558 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2560 VM_SetTraceGlobals(&trace);
2562 if (trace.startsolid)
2564 neworg[2] -= sv_stepheight.value;
2565 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2567 VM_SetTraceGlobals(&trace);
2568 if (trace.startsolid)
2571 if (trace.fraction == 1)
2573 // if monster had the ground pulled out, go ahead and fall
2574 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2576 VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2579 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2583 return false; // walked off an edge
2586 // check point traces down for dangling corners
2587 VectorCopy (trace.endpos, ent->fields.client->origin);
2589 if (!CL_CheckBottom (ent))
2591 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2592 { // entity had floor mostly pulled out from underneath it
2593 // and is trying to correct
2598 VectorCopy (oldorg, ent->fields.client->origin);
2602 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2603 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2605 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2606 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2618 float(float yaw, float dist[, settrace]) walkmove
2621 static void VM_CL_walkmove (void)
2630 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2632 // assume failure if it returns early
2633 PRVM_G_FLOAT(OFS_RETURN) = 0;
2635 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2636 if (ent == prog->edicts)
2638 VM_Warning("walkmove: can not modify world entity\n");
2641 if (ent->priv.server->free)
2643 VM_Warning("walkmove: can not modify free entity\n");
2646 yaw = PRVM_G_FLOAT(OFS_PARM0);
2647 dist = PRVM_G_FLOAT(OFS_PARM1);
2648 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2650 if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2653 yaw = yaw*M_PI*2 / 360;
2655 move[0] = cos(yaw)*dist;
2656 move[1] = sin(yaw)*dist;
2659 // save program state, because CL_movestep may call other progs
2660 oldf = prog->xfunction;
2661 oldself = prog->globals.client->self;
2663 PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2666 // restore program state
2667 prog->xfunction = oldf;
2668 prog->globals.client->self = oldself;
2675 string(string key) serverkey
2678 void VM_CL_serverkey(void)
2680 char string[VM_STRINGTEMP_LENGTH];
2681 VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2682 InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2683 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2686 //============================================================================
2688 prvm_builtin_t vm_cl_builtins[] = {
2689 NULL, // #0 NULL function (not callable) (QUAKE)
2690 VM_CL_makevectors, // #1 void(vector ang) makevectors (QUAKE)
2691 VM_CL_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
2692 VM_CL_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
2693 VM_CL_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2694 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2695 VM_break, // #6 void() break (QUAKE)
2696 VM_random, // #7 float() random (QUAKE)
2697 VM_CL_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
2698 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
2699 VM_error, // #10 void(string e) error (QUAKE)
2700 VM_objerror, // #11 void(string e) objerror (QUAKE)
2701 VM_vlen, // #12 float(vector v) vlen (QUAKE)
2702 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
2703 VM_CL_spawn, // #14 entity() spawn (QUAKE)
2704 VM_remove, // #15 void(entity e) remove (QUAKE)
2705 VM_CL_traceline, // #16 float(vector v1, vector v2, float tryents) traceline (QUAKE)
2706 NULL, // #17 entity() checkclient (QUAKE)
2707 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
2708 VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
2709 VM_CL_precache_model, // #20 void(string s) precache_model (QUAKE)
2710 NULL, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2711 VM_CL_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
2712 NULL, // #23 void(string s, ...) bprint (QUAKE)
2713 NULL, // #24 void(entity client, string s, ...) sprint (QUAKE)
2714 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
2715 VM_ftos, // #26 string(float f) ftos (QUAKE)
2716 VM_vtos, // #27 string(vector v) vtos (QUAKE)
2717 VM_coredump, // #28 void() coredump (QUAKE)
2718 VM_traceon, // #29 void() traceon (QUAKE)
2719 VM_traceoff, // #30 void() traceoff (QUAKE)
2720 VM_eprint, // #31 void(entity e) eprint (QUAKE)
2721 VM_CL_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
2722 NULL, // #33 (QUAKE)
2723 VM_CL_droptofloor, // #34 float() droptofloor (QUAKE)
2724 VM_CL_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
2725 VM_rint, // #36 float(float v) rint (QUAKE)
2726 VM_floor, // #37 float(float v) floor (QUAKE)
2727 VM_ceil, // #38 float(float v) ceil (QUAKE)
2728 NULL, // #39 (QUAKE)
2729 VM_CL_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
2730 VM_CL_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
2731 NULL, // #42 (QUAKE)
2732 VM_fabs, // #43 float(float f) fabs (QUAKE)
2733 NULL, // #44 vector(entity e, float speed) aim (QUAKE)
2734 VM_cvar, // #45 float(string s) cvar (QUAKE)
2735 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
2736 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
2737 VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2738 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
2739 NULL, // #50 (QUAKE)
2740 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
2741 NULL, // #52 void(float to, float f) WriteByte (QUAKE)
2742 NULL, // #53 void(float to, float f) WriteChar (QUAKE)
2743 NULL, // #54 void(float to, float f) WriteShort (QUAKE)
2744 NULL, // #55 void(float to, float f) WriteLong (QUAKE)
2745 NULL, // #56 void(float to, float f) WriteCoord (QUAKE)
2746 NULL, // #57 void(float to, float f) WriteAngle (QUAKE)
2747 NULL, // #58 void(float to, string s) WriteString (QUAKE)
2748 NULL, // #59 (QUAKE)
2749 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2750 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2751 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2752 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2753 VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2754 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2755 NULL, // #66 (QUAKE)
2756 NULL, // #67 void(float step) movetogoal (QUAKE)
2757 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
2758 VM_CL_makestatic, // #69 void(entity e) makestatic (QUAKE)
2759 NULL, // #70 void(string s) changelevel (QUAKE)
2760 NULL, // #71 (QUAKE)
2761 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
2762 NULL, // #73 void(entity client, strings) centerprint (QUAKE)
2763 VM_CL_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2764 VM_CL_precache_model, // #75 string(string s) precache_model2 (QUAKE)
2765 VM_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
2766 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
2767 NULL, // #78 void(entity e) setspawnparms (QUAKE)
2768 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
2769 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
2770 VM_stof, // #81 float(string s) stof (FRIK_FILE)
2771 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
2772 NULL, // #83 (QUAKE)
2773 NULL, // #84 (QUAKE)
2774 NULL, // #85 (QUAKE)
2775 NULL, // #86 (QUAKE)
2776 NULL, // #87 (QUAKE)
2777 NULL, // #88 (QUAKE)
2778 NULL, // #89 (QUAKE)
2779 VM_CL_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2780 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2781 VM_CL_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2782 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2783 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2784 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2785 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2786 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2787 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2788 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
2789 // FrikaC and Telejano range #100-#199
2800 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
2801 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
2802 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
2803 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2804 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
2805 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
2806 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
2807 VM_stov, // #117 vector(string) stov (FRIK_FILE)
2808 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
2809 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
2890 // FTEQW range #200-#299
2909 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
2913 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
2914 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
2919 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
2923 NULL, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
2991 // CSQC range #300-#399
2992 VM_CL_R_ClearScene, // #300 void() clearscene (EXT_CSQC)
2993 VM_CL_R_AddEntities, // #301 void(float mask) addentities (EXT_CSQC)
2994 VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC)
2995 VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC)
2996 VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC)
2997 VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
2998 VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
2999 VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
3000 VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon
3002 VM_CL_unproject, // #310 vector (vector v) cs_unproject (EXT_CSQC)
3003 VM_CL_project, // #311 vector (vector v) cs_project (EXT_CSQC)
3007 VM_drawline, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3008 VM_iscachedpic, // #316 float(string name) iscachedpic (EXT_CSQC)
3009 VM_precache_pic, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3010 VM_getimagesize, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3011 VM_freepic, // #319 void(string name) freepic (EXT_CSQC)
3012 VM_drawcharacter, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3013 VM_drawstring, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3014 VM_drawpic, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3015 VM_drawfill, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3016 VM_drawsetcliparea, // #324 void(float x, float y, float width, float height) drawsetcliparea
3017 VM_drawresetcliparea, // #325 void(void) drawresetcliparea
3022 VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
3023 VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
3024 VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
3025 VM_CL_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3026 VM_CL_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3027 VM_CL_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3028 VM_CL_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3029 VM_CL_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3030 VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC)
3031 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3032 VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3033 VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3034 VM_CL_getkeybind, // #342 string(float keynum) getkeybind (EXT_CSQC)
3035 VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3036 VM_getmousepos, // #344 vector() getmousepos (EXT_CSQC)
3037 VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC)
3038 VM_CL_setsensitivityscale, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3039 VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC)
3040 VM_CL_getplayerkey, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3041 VM_CL_isdemo, // #349 float() isdemo (EXT_CSQC)
3042 VM_isserver, // #350 float() isserver (EXT_CSQC)
3043 VM_CL_setlistener, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3044 VM_CL_registercmd, // #352 void(string cmdname) registercommand (EXT_CSQC)
3045 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3046 VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3052 VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC)
3053 VM_CL_ReadChar, // #361 float() readchar (EXT_CSQC)
3054 VM_CL_ReadShort, // #362 float() readshort (EXT_CSQC)
3055 VM_CL_ReadLong, // #363 float() readlong (EXT_CSQC)
3056 VM_CL_ReadCoord, // #364 float() readcoord (EXT_CSQC)
3057 VM_CL_ReadAngle, // #365 float() readangle (EXT_CSQC)
3058 VM_CL_ReadString, // #366 string() readstring (EXT_CSQC)
3059 VM_CL_ReadFloat, // #367 float() readfloat (EXT_CSQC)
3092 // LordHavoc's range #400-#499
3093 VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3094 NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3095 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3096 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3097 VM_CL_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3098 VM_CL_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3099 VM_CL_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3100 VM_CL_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3101 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)
3102 VM_CL_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3103 VM_CL_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3104 VM_CL_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3105 VM_CL_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3106 VM_CL_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3107 VM_CL_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3108 VM_CL_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3109 VM_CL_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3110 VM_CL_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3111 VM_CL_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3112 VM_CL_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3113 VM_CL_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3114 VM_CL_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3115 VM_CL_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3116 VM_CL_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3117 VM_CL_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3118 VM_CL_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3119 VM_CL_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3120 VM_CL_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3121 VM_CL_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3122 VM_CL_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3123 VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3124 VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3125 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3126 VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3127 VM_CL_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3128 VM_CL_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3129 VM_CL_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3130 VM_CL_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3131 VM_CL_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3132 VM_CL_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3133 NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3134 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3135 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3136 VM_CL_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3137 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3138 VM_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3139 VM_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3140 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3141 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3142 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3143 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3144 VM_CL_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3145 VM_CL_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3146 NULL, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3147 NULL, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3148 NULL, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3149 NULL, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3150 VM_CL_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3152 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3153 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3154 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3155 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3156 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3157 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3158 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3159 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3160 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3161 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3162 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3163 NULL, // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3164 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3165 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3166 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3167 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3168 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3169 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3170 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3171 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3172 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3173 VM_strtolower, // #480 string(string s) VM_strtolower (DP_QC_STRING_CASE_FUNCTIONS)
3174 VM_strtoupper, // #481 string(string s) VM_strtoupper (DP_QC_STRING_CASE_FUNCTIONS)
3175 VM_cvar_defstring, // #482 string(string s) cvar_defstring (DP_QC_CVAR_DEFSTRING)
3195 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3197 void VM_CL_Cmd_Init(void)
3199 // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3200 if(vm_polygons_initialized)
3202 Mem_FreePool(&vm_polygons_pool);
3203 vm_polygons_initialized = false;
3207 void VM_CL_Cmd_Reset(void)
3209 if(vm_polygons_initialized)
3211 Mem_FreePool(&vm_polygons_pool);
3212 vm_polygons_initialized = false;