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 extern cvar_t cl_gravity;
238 trace_t CL_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
243 vec3_t original_origin;
244 vec3_t original_velocity;
245 vec3_t original_angles;
246 vec3_t original_avelocity;
250 VectorCopy(tossent->fields.client->origin , original_origin );
251 VectorCopy(tossent->fields.client->velocity , original_velocity );
252 VectorCopy(tossent->fields.client->angles , original_angles );
253 VectorCopy(tossent->fields.client->avelocity, original_avelocity);
255 val = PRVM_EDICTFIELDVALUE(tossent, prog->fieldoffsets.gravity);
256 if (val != NULL && val->_float != 0)
257 gravity = val->_float;
260 gravity *= cl_gravity.value * 0.05;
262 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
264 tossent->fields.client->velocity[2] -= gravity;
265 VectorMA (tossent->fields.client->angles, 0.05, tossent->fields.client->avelocity, tossent->fields.client->angles);
266 VectorScale (tossent->fields.client->velocity, 0.05, move);
267 VectorAdd (tossent->fields.client->origin, move, end);
268 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);
269 VectorCopy (trace.endpos, tossent->fields.client->origin);
271 if (trace.fraction < 1)
275 VectorCopy(original_origin , tossent->fields.client->origin );
276 VectorCopy(original_velocity , tossent->fields.client->velocity );
277 VectorCopy(original_angles , tossent->fields.client->angles );
278 VectorCopy(original_avelocity, tossent->fields.client->avelocity);
283 static void VM_CL_tracetoss (void)
287 prvm_edict_t *ignore;
289 prog->xfunction->builtinsprofile += 600;
291 VM_SAFEPARMCOUNT(2, VM_CL_tracetoss);
293 ent = PRVM_G_EDICT(OFS_PARM0);
294 if (ent == prog->edicts)
296 VM_Warning("tracetoss: can not use world entity\n");
299 ignore = PRVM_G_EDICT(OFS_PARM1);
301 trace = CL_Trace_Toss (ent, ignore);
303 VM_SetTraceGlobals(&trace);
307 // #20 void(string s) precache_model
308 static void VM_CL_precache_model (void)
314 VM_SAFEPARMCOUNT(1, VM_CL_precache_model);
316 name = PRVM_G_STRING(OFS_PARM0);
317 for (i = 1;i < MAX_MODELS && cl.csqc_model_precache[i];i++)
319 if(!strcmp(cl.csqc_model_precache[i]->name, name))
321 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
325 PRVM_G_FLOAT(OFS_RETURN) = 0;
326 m = Mod_ForName(name, false, false, false);
329 for (i = 1;i < MAX_MODELS;i++)
331 if (!cl.csqc_model_precache[i])
333 cl.csqc_model_precache[i] = (model_t*)m;
334 PRVM_G_FLOAT(OFS_RETURN) = -(i+1);
338 VM_Warning("VM_CL_precache_model: no free models\n");
341 VM_Warning("VM_CL_precache_model: model \"%s\" not found\n", name);
344 int CSQC_EntitiesInBox (vec3_t mins, vec3_t maxs, int maxlist, prvm_edict_t **list)
349 ent = PRVM_NEXT_EDICT(prog->edicts);
350 for(k=0,i=1; i<prog->num_edicts ;i++, ent = PRVM_NEXT_EDICT(ent))
352 if (ent->priv.required->free)
354 // VectorAdd(ent->fields.client->origin, ent->fields.client->mins, ent->fields.client->absmin);
355 // VectorAdd(ent->fields.client->origin, ent->fields.client->maxs, ent->fields.client->absmax);
356 if(BoxesOverlap(mins, maxs, ent->fields.client->absmin, ent->fields.client->absmax))
362 // #22 entity(vector org, float rad) findradius
363 static void VM_CL_findradius (void)
365 prvm_edict_t *ent, *chain;
366 vec_t radius, radius2;
367 vec3_t org, eorg, mins, maxs;
368 int i, numtouchedicts;
369 prvm_edict_t *touchedicts[MAX_EDICTS];
371 VM_SAFEPARMCOUNT(2, VM_CL_findradius);
373 chain = (prvm_edict_t *)prog->edicts;
375 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
376 radius = PRVM_G_FLOAT(OFS_PARM1);
377 radius2 = radius * radius;
379 mins[0] = org[0] - (radius + 1);
380 mins[1] = org[1] - (radius + 1);
381 mins[2] = org[2] - (radius + 1);
382 maxs[0] = org[0] + (radius + 1);
383 maxs[1] = org[1] + (radius + 1);
384 maxs[2] = org[2] + (radius + 1);
385 numtouchedicts = CSQC_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
386 if (numtouchedicts > MAX_EDICTS)
388 // this never happens //[515]: for what then ?
389 Con_Printf("CSQC_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
390 numtouchedicts = MAX_EDICTS;
392 for (i = 0;i < numtouchedicts;i++)
394 ent = touchedicts[i];
395 // Quake did not return non-solid entities but darkplaces does
396 // (note: this is the reason you can't blow up fallen zombies)
397 if (ent->fields.client->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
399 // LordHavoc: compare against bounding box rather than center so it
400 // doesn't miss large objects, and use DotProduct instead of Length
401 // for a major speedup
402 VectorSubtract(org, ent->fields.client->origin, eorg);
403 if (sv_gameplayfix_findradiusdistancetobox.integer)
405 eorg[0] -= bound(ent->fields.client->mins[0], eorg[0], ent->fields.client->maxs[0]);
406 eorg[1] -= bound(ent->fields.client->mins[1], eorg[1], ent->fields.client->maxs[1]);
407 eorg[2] -= bound(ent->fields.client->mins[2], eorg[2], ent->fields.client->maxs[2]);
410 VectorMAMAM(1, eorg, 0.5f, ent->fields.client->mins, 0.5f, ent->fields.client->maxs, eorg);
411 if (DotProduct(eorg, eorg) < radius2)
413 ent->fields.client->chain = PRVM_EDICT_TO_PROG(chain);
418 VM_RETURN_EDICT(chain);
421 // #34 float() droptofloor
422 static void VM_CL_droptofloor (void)
429 VM_SAFEPARMCOUNTRANGE(0, 2, VM_CL_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
431 // assume failure if it returns early
432 PRVM_G_FLOAT(OFS_RETURN) = 0;
434 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
435 if (ent == prog->edicts)
437 VM_Warning("droptofloor: can not modify world entity\n");
440 if (ent->priv.server->free)
442 VM_Warning("droptofloor: can not modify free entity\n");
446 VectorCopy (ent->fields.client->origin, end);
449 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);
451 if (trace.fraction != 1)
453 VectorCopy (trace.endpos, ent->fields.client->origin);
454 ent->fields.client->flags = (int)ent->fields.client->flags | FL_ONGROUND;
455 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
456 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
457 PRVM_G_FLOAT(OFS_RETURN) = 1;
458 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
459 // ent->priv.server->suspendedinairflag = true;
463 // #35 void(float style, string value) lightstyle
464 static void VM_CL_lightstyle (void)
469 VM_SAFEPARMCOUNT(2, VM_CL_lightstyle);
471 i = (int)PRVM_G_FLOAT(OFS_PARM0);
472 c = PRVM_G_STRING(OFS_PARM1);
473 if (i >= cl.max_lightstyle)
475 VM_Warning("VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
478 strlcpy (cl.lightstyle[i].map, MSG_ReadString(), sizeof (cl.lightstyle[i].map));
479 cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
480 cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
483 // #40 float(entity e) checkbottom
484 static void VM_CL_checkbottom (void)
486 static int cs_yes, cs_no;
488 vec3_t mins, maxs, start, stop;
493 VM_SAFEPARMCOUNT(1, VM_CL_checkbottom);
494 ent = PRVM_G_EDICT(OFS_PARM0);
495 PRVM_G_FLOAT(OFS_RETURN) = 0;
497 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
498 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
500 // if all of the points under the corners are solid world, don't bother
501 // with the tougher checks
502 // the corners must be within 16 of the midpoint
503 start[2] = mins[2] - 1;
504 for (x=0 ; x<=1 ; x++)
505 for (y=0 ; y<=1 ; y++)
507 start[0] = x ? maxs[0] : mins[0];
508 start[1] = y ? maxs[1] : mins[1];
509 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
514 PRVM_G_FLOAT(OFS_RETURN) = true;
515 return; // we got out easy
520 // check it for real...
524 // the midpoint must be within 16 of the bottom
525 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
526 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
527 stop[2] = start[2] - 2*sv_stepheight.value;
528 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
530 if (trace.fraction == 1.0)
533 mid = bottom = trace.endpos[2];
535 // the corners must be within 16 of the midpoint
536 for (x=0 ; x<=1 ; x++)
537 for (y=0 ; y<=1 ; y++)
539 start[0] = stop[0] = x ? maxs[0] : mins[0];
540 start[1] = stop[1] = y ? maxs[1] : mins[1];
542 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
544 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
545 bottom = trace.endpos[2];
546 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
551 PRVM_G_FLOAT(OFS_RETURN) = true;
554 // #41 float(vector v) pointcontents
555 static void VM_CL_pointcontents (void)
557 VM_SAFEPARMCOUNT(1, VM_CL_pointcontents);
558 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, CL_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
561 // #48 void(vector o, vector d, float color, float count) particle
562 static void VM_CL_particle (void)
567 VM_SAFEPARMCOUNT(4, VM_CL_particle);
569 org = PRVM_G_VECTOR(OFS_PARM0);
570 dir = PRVM_G_VECTOR(OFS_PARM1);
571 color = (int)PRVM_G_FLOAT(OFS_PARM2);
572 count = (int)PRVM_G_FLOAT(OFS_PARM3);
573 CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color);
576 // #74 void(vector pos, string samp, float vol, float atten) ambientsound
577 static void VM_CL_ambientsound (void)
581 VM_SAFEPARMCOUNT(4, VM_CL_ambientsound);
582 s = S_FindName(PRVM_G_STRING(OFS_PARM0));
583 f = PRVM_G_VECTOR(OFS_PARM1);
584 S_StaticSound (s, f, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3)*64);
587 // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
588 static void VM_CL_getlight (void)
590 vec3_t ambientcolor, diffusecolor, diffusenormal;
593 VM_SAFEPARMCOUNT(1, VM_CL_getlight);
595 p = PRVM_G_VECTOR(OFS_PARM0);
596 VectorClear(ambientcolor);
597 VectorClear(diffusecolor);
598 VectorClear(diffusenormal);
599 if (cl.worldmodel && cl.worldmodel->brush.LightPoint)
600 cl.worldmodel->brush.LightPoint(cl.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
601 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
605 //============================================================================
606 //[515]: SCENE MANAGER builtins
607 extern qboolean CSQC_AddRenderEdict (prvm_edict_t *ed);//csprogs.c
609 matrix4x4_t csqc_listenermatrix;
610 qboolean csqc_usecsqclistener = false;//[515]: per-frame
612 static void CSQC_R_RecalcView (void)
614 extern matrix4x4_t viewmodelmatrix;
615 Matrix4x4_CreateFromQuakeEntity(&r_view.matrix, csqc_origin[0], csqc_origin[1], csqc_origin[2], csqc_angles[0], csqc_angles[1], csqc_angles[2], 1);
616 Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix, csqc_origin[0], csqc_origin[1], csqc_origin[2], csqc_angles[0], csqc_angles[1], csqc_angles[2], cl_viewmodel_scale.value);
619 void CL_RelinkLightFlashes(void);
620 //#300 void() clearscene (EXT_CSQC)
621 static void VM_CL_R_ClearScene (void)
623 VM_SAFEPARMCOUNT(0, VM_CL_R_ClearScene);
624 // clear renderable entity and light lists
625 r_refdef.numentities = 0;
626 r_refdef.numlights = 0;
629 //#301 void(float mask) addentities (EXT_CSQC)
630 extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
631 extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
632 static void VM_CL_R_AddEntities (void)
636 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
637 drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
638 CSQC_RelinkAllEntities(drawmask);
639 CL_RelinkLightFlashes();
641 prog->globals.client->time = cl.time;
642 for(i=1;i<prog->num_edicts;i++)
644 ed = &prog->edicts[i];
645 if(ed->priv.required->free)
647 VectorAdd(ed->fields.client->origin, ed->fields.client->mins, ed->fields.client->absmin);
648 VectorAdd(ed->fields.client->origin, ed->fields.client->maxs, ed->fields.client->absmax);
650 if(ed->priv.required->free)
652 // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict
654 if(ed->priv.required->free)
656 if(!((int)ed->fields.client->drawmask & drawmask))
658 CSQC_AddRenderEdict(ed);
662 //#302 void(entity ent) addentity (EXT_CSQC)
663 static void VM_CL_R_AddEntity (void)
665 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
666 CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
669 //#303 float(float property, ...) setproperty (EXT_CSQC)
670 static void VM_CL_R_SetView (void)
676 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_SetView);
678 c = (int)PRVM_G_FLOAT(OFS_PARM0);
679 f = PRVM_G_VECTOR(OFS_PARM1);
680 k = PRVM_G_FLOAT(OFS_PARM1);
684 case VF_MIN: r_view.x = (int)f[0];
685 r_view.y = (int)f[1];
687 case VF_MIN_X: r_view.x = (int)k;
689 case VF_MIN_Y: r_view.y = (int)k;
691 case VF_SIZE: r_view.width = (int)f[0];
692 r_view.height = (int)f[1];
694 case VF_SIZE_Y: r_view.width = (int)k;
696 case VF_SIZE_X: r_view.height = (int)k;
698 case VF_VIEWPORT: r_view.x = (int)f[0];
699 r_view.y = (int)f[1];
701 // TODO: make sure that view_z and view_depth are set properly even if csqc does not set them!
702 f = PRVM_G_VECTOR(OFS_PARM2);
703 r_view.width = (int)f[0];
704 r_view.height = (int)f[1];
707 case VF_FOV: //r_refdef.fov_x = f[0]; // FIXME!
708 //r_refdef.fov_y = f[1]; // FIXME!
710 case VF_FOVX: //r_refdef.fov_x = k; // FIXME!
712 case VF_FOVY: //r_refdef.fov_y = k; // FIXME!
714 case VF_ORIGIN: VectorCopy(f, csqc_origin);
717 case VF_ORIGIN_X: csqc_origin[0] = k;
720 case VF_ORIGIN_Y: csqc_origin[1] = k;
723 case VF_ORIGIN_Z: csqc_origin[2] = k;
726 case VF_ANGLES: VectorCopy(f, csqc_angles);
729 case VF_ANGLES_X: csqc_angles[0] = k;
732 case VF_ANGLES_Y: csqc_angles[1] = k;
735 case VF_ANGLES_Z: csqc_angles[2] = k;
738 case VF_DRAWWORLD: cl.csqc_vidvars.drawworld = k;
740 case VF_DRAWENGINESBAR: cl.csqc_vidvars.drawenginesbar = k;
742 case VF_DRAWCROSSHAIR: cl.csqc_vidvars.drawcrosshair = k;
745 case VF_CL_VIEWANGLES: VectorCopy(f, cl.viewangles);
747 case VF_CL_VIEWANGLES_X:cl.viewangles[0] = k;
749 case VF_CL_VIEWANGLES_Y:cl.viewangles[1] = k;
751 case VF_CL_VIEWANGLES_Z:cl.viewangles[2] = k;
754 default: PRVM_G_FLOAT(OFS_RETURN) = 0;
755 VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c);
758 PRVM_G_FLOAT(OFS_RETURN) = 1;
761 extern void CL_UpdateNetworkEntity(entity_t *e, int recursionlimit);
762 //#304 void() renderscene (EXT_CSQC)
763 static void VM_CL_R_RenderScene (void)
766 VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
767 // we need to update any RENDER_VIEWMODEL entities at this point because
768 // csqc supplies its own view matrix
769 for (i = 1;i < cl.num_entities;i++)
771 if (cl.entities_active[i])
773 entity_t *ent = cl.entities + i;
774 if ((ent->render.flags & RENDER_VIEWMODEL) || ent->state_current.tagentity)
775 CL_UpdateNetworkEntity(ent, 32);
778 // and of course the engine viewmodel needs updating as well
779 CL_UpdateNetworkEntity(&cl.viewent, 32);
784 //#305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
785 static void VM_CL_R_AddDynamicLight (void)
789 VM_SAFEPARMCOUNTRANGE(3, 8, VM_CL_R_AddDynamicLight); // allow more than 3 because we may extend this in the future
791 // if we've run out of dlights, just return
792 if (r_refdef.numlights >= MAX_DLIGHTS)
795 pos = PRVM_G_VECTOR(OFS_PARM0);
796 col = PRVM_G_VECTOR(OFS_PARM2);
797 Matrix4x4_CreateFromQuakeEntity(&matrix, pos[0], pos[1], pos[2], 0, 0, 0, PRVM_G_FLOAT(OFS_PARM1));
798 R_RTLight_Update(&r_refdef.lights[r_refdef.numlights++], false, &matrix, col, -1, NULL, true, 1, 0.25, 0, 1, 1, LIGHTFLAG_NORMALMODE | LIGHTFLAG_REALTIMEMODE);
801 //============================================================================
803 //#310 vector (vector v) cs_unproject (EXT_CSQC)
804 static void VM_CL_unproject (void)
809 VM_SAFEPARMCOUNT(1, VM_CL_unproject);
810 f = PRVM_G_VECTOR(OFS_PARM0);
811 VectorSet(temp, f[2], f[0] * f[2] * -r_view.frustum_x * 2.0 / r_view.width, f[1] * f[2] * -r_view.frustum_y * 2.0 / r_view.height);
812 Matrix4x4_Transform(&r_view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
815 //#311 vector (vector v) cs_project (EXT_CSQC)
816 static void VM_CL_project (void)
822 VM_SAFEPARMCOUNT(1, VM_CL_project);
823 f = PRVM_G_VECTOR(OFS_PARM0);
824 Matrix4x4_Invert_Simple(&m, &r_view.matrix);
825 Matrix4x4_Transform(&m, f, v);
826 VectorSet(PRVM_G_VECTOR(OFS_RETURN), v[1]/v[0]/-r_view.frustum_x*0.5*r_view.width, v[2]/v[0]/-r_view.frustum_y*r_view.height*0.5, v[0]);
829 //#330 float(float stnum) getstatf (EXT_CSQC)
830 static void VM_CL_getstatf (void)
838 VM_SAFEPARMCOUNT(1, VM_CL_getstatf);
839 i = (int)PRVM_G_FLOAT(OFS_PARM0);
840 if(i < 0 || i >= MAX_CL_STATS)
842 VM_Warning("VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
846 PRVM_G_FLOAT(OFS_RETURN) = dat.f;
849 //#331 float(float stnum) getstati (EXT_CSQC)
850 static void VM_CL_getstati (void)
853 VM_SAFEPARMCOUNT(1, VM_CL_getstati);
854 index = (int)PRVM_G_FLOAT(OFS_PARM0);
856 if(index < 0 || index >= MAX_CL_STATS)
858 VM_Warning("VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
862 PRVM_G_FLOAT(OFS_RETURN) = i;
865 //#332 string(float firststnum) getstats (EXT_CSQC)
866 static void VM_CL_getstats (void)
870 VM_SAFEPARMCOUNT(1, VM_CL_getstats);
871 i = (int)PRVM_G_FLOAT(OFS_PARM0);
872 if(i < 0 || i > MAX_CL_STATS-4)
874 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
875 VM_Warning("VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
878 strlcpy(t, (char*)&cl.stats[i], sizeof(t));
879 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
882 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
883 static void VM_CL_setmodelindex (void)
887 struct model_s *model;
889 VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex);
891 t = PRVM_G_EDICT(OFS_PARM0);
893 i = (int)PRVM_G_FLOAT(OFS_PARM1);
895 t->fields.client->model = 0;
896 t->fields.client->modelindex = 0;
901 model = CL_GetModelByIndex(i);
904 VM_Warning("VM_CL_setmodelindex: null model\n");
907 t->fields.client->model = PRVM_SetEngineString(model->name);
908 t->fields.client->modelindex = i;
911 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
912 static void VM_CL_modelnameforindex (void)
916 VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
918 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
919 model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
920 PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(model->name) : 0;
923 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
924 static void VM_CL_particleeffectnum (void)
927 VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
928 i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
931 PRVM_G_FLOAT(OFS_RETURN) = i;
934 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
935 static void VM_CL_trailparticles (void)
940 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles);
942 t = PRVM_G_EDICT(OFS_PARM0);
943 i = (int)PRVM_G_FLOAT(OFS_PARM1);
944 start = PRVM_G_VECTOR(OFS_PARM2);
945 end = PRVM_G_VECTOR(OFS_PARM3);
947 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);
950 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
951 static void VM_CL_pointparticles (void)
955 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
956 i = (int)PRVM_G_FLOAT(OFS_PARM0);
957 f = PRVM_G_VECTOR(OFS_PARM1);
958 v = PRVM_G_VECTOR(OFS_PARM2);
959 n = (int)PRVM_G_FLOAT(OFS_PARM3);
960 CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
963 //#342 string(float keynum) getkeybind (EXT_CSQC)
964 static void VM_CL_getkeybind (void)
966 VM_SAFEPARMCOUNT(1, VM_CL_getkeybind);
967 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0)));
970 //#343 void(float usecursor) setcursormode (EXT_CSQC)
971 static void VM_CL_setcursormode (void)
973 VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
974 cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
975 cl_ignoremousemove = true;
978 //#345 float(float framenum) getinputstate (EXT_CSQC)
979 static void VM_CL_getinputstate (void)
982 VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
983 frame = (int)PRVM_G_FLOAT(OFS_PARM0);
984 for (i = 0;i < cl.movement_numqueue;i++)
985 if (cl.movement_queue[i].sequence == frame)
987 VectorCopy(cl.movement_queue[i].viewangles, prog->globals.client->input_angles);
988 //prog->globals.client->input_buttons = cl.movement_queue[i].//FIXME
989 VectorCopy(cl.movement_queue[i].move, prog->globals.client->input_movevalues);
990 prog->globals.client->input_timelength = cl.movement_queue[i].frametime;
991 if(cl.movement_queue[i].crouch)
993 VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
994 VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
998 VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
999 VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
1004 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
1005 static void VM_CL_setsensitivityscale (void)
1007 VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
1008 cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
1011 //#347 void() runstandardplayerphysics (EXT_CSQC)
1012 static void VM_CL_runplayerphysics (void)
1016 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
1017 static void VM_CL_getplayerkey (void)
1023 VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
1025 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1026 c = PRVM_G_STRING(OFS_PARM1);
1027 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1030 i = Sbar_GetPlayer(i);
1036 if(!strcasecmp(c, "name"))
1037 strlcpy(t, cl.scores[i].name, sizeof(t));
1039 if(!strcasecmp(c, "frags"))
1040 sprintf(t, "%i", cl.scores[i].frags);
1042 if(!strcasecmp(c, "ping"))
1043 sprintf(t, "%i", cl.scores[i].qw_ping);
1045 if(!strcasecmp(c, "entertime"))
1046 sprintf(t, "%f", cl.scores[i].qw_entertime);
1048 if(!strcasecmp(c, "colors"))
1049 sprintf(t, "%i", cl.scores[i].colors);
1051 if(!strcasecmp(c, "topcolor"))
1052 sprintf(t, "%i", cl.scores[i].colors & 0xf0);
1054 if(!strcasecmp(c, "bottomcolor"))
1055 sprintf(t, "%i", (cl.scores[i].colors &15)<<4);
1057 if(!strcasecmp(c, "viewentity"))
1058 sprintf(t, "%i", i+1);
1061 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1064 //#349 float() isdemo (EXT_CSQC)
1065 static void VM_CL_isdemo (void)
1067 VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
1068 PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
1071 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
1072 static void VM_CL_setlistener (void)
1074 VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
1075 Matrix4x4_FromVectors(&csqc_listenermatrix, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), PRVM_G_VECTOR(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0));
1076 csqc_usecsqclistener = true; //use csqc listener at this frame
1079 //#352 void(string cmdname) registercommand (EXT_CSQC)
1080 static void VM_CL_registercmd (void)
1083 VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
1084 if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0)))
1088 alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1;
1089 t = (char *)Z_Malloc(alloclen);
1090 memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen);
1091 Cmd_AddCommand(t, NULL, "console command created by QuakeC");
1094 Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
1098 //#360 float() readbyte (EXT_CSQC)
1099 static void VM_CL_ReadByte (void)
1101 VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
1102 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte();
1105 //#361 float() readchar (EXT_CSQC)
1106 static void VM_CL_ReadChar (void)
1108 VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
1109 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar();
1112 //#362 float() readshort (EXT_CSQC)
1113 static void VM_CL_ReadShort (void)
1115 VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
1116 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort();
1119 //#363 float() readlong (EXT_CSQC)
1120 static void VM_CL_ReadLong (void)
1122 VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
1123 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong();
1126 //#364 float() readcoord (EXT_CSQC)
1127 static void VM_CL_ReadCoord (void)
1129 VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
1130 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(cls.protocol);
1133 //#365 float() readangle (EXT_CSQC)
1134 static void VM_CL_ReadAngle (void)
1136 VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
1137 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(cls.protocol);
1140 //#366 string() readstring (EXT_CSQC)
1141 static void VM_CL_ReadString (void)
1143 VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
1144 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_ReadString());
1147 //#367 float() readfloat (EXT_CSQC)
1148 static void VM_CL_ReadFloat (void)
1150 VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
1151 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
1154 //////////////////////////////////////////////////////////
1156 static void VM_CL_makestatic (void)
1160 VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
1162 ent = PRVM_G_EDICT(OFS_PARM0);
1163 if (ent == prog->edicts)
1165 VM_Warning("makestatic: can not modify world entity\n");
1168 if (ent->priv.server->free)
1170 VM_Warning("makestatic: can not modify free entity\n");
1174 if (cl.num_static_entities < cl.max_static_entities)
1178 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
1180 // copy it to the current state
1181 staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
1182 staticent->render.frame = staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
1183 staticent->render.framelerp = 0;
1184 // make torchs play out of sync
1185 staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
1186 staticent->render.colormap = (int)ent->fields.client->colormap; // no special coloring
1187 staticent->render.skinnum = (int)ent->fields.client->skin;
1188 staticent->render.effects = (int)ent->fields.client->effects;
1189 staticent->render.alpha = 1;
1190 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float;
1191 staticent->render.scale = 1;
1192 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
1193 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
1196 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
1197 if (renderflags & RF_USEAXIS)
1200 VectorNegate(prog->globals.client->v_right, left);
1201 Matrix4x4_FromVectors(&staticent->render.matrix, prog->globals.client->v_forward, left, prog->globals.client->v_up, ent->fields.client->origin);
1202 Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
1205 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);
1206 CL_UpdateRenderEntity(&staticent->render);
1208 // transparent stuff can't be lit during the opaque stage
1209 if (staticent->render.effects & (EF_ADDITIVE | EF_NODEPTHTEST) || staticent->render.alpha < 1)
1210 staticent->render.flags |= RENDER_TRANSPARENT;
1211 // double sided rendering mode causes backfaces to be visible
1212 // (mostly useful on transparent stuff)
1213 if (staticent->render.effects & EF_DOUBLESIDED)
1214 staticent->render.flags |= RENDER_NOCULLFACE;
1215 // either fullbright or lit
1216 if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
1217 staticent->render.flags |= RENDER_LIGHT;
1218 // turn off shadows from transparent objects
1219 if (!(staticent->render.effects & EF_NOSHADOW)
1220 && !(staticent->render.flags & RENDER_TRANSPARENT))
1221 staticent->render.flags |= RENDER_SHADOW;
1224 Con_Printf("Too many static entities");
1226 // throw the entity away now
1230 //=================================================================//
1236 copies data from one entity to another
1238 copyentity(src, dst)
1241 static void VM_CL_copyentity (void)
1243 prvm_edict_t *in, *out;
1244 VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
1245 in = PRVM_G_EDICT(OFS_PARM0);
1246 if (in == prog->edicts)
1248 VM_Warning("copyentity: can not read world entity\n");
1251 if (in->priv.server->free)
1253 VM_Warning("copyentity: can not read free entity\n");
1256 out = PRVM_G_EDICT(OFS_PARM1);
1257 if (out == prog->edicts)
1259 VM_Warning("copyentity: can not modify world entity\n");
1262 if (out->priv.server->free)
1264 VM_Warning("copyentity: can not modify free entity\n");
1267 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1271 //=================================================================//
1273 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
1274 static void VM_CL_effect (void)
1276 VM_SAFEPARMCOUNT(5, VM_CL_effect);
1277 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));
1280 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
1281 static void VM_CL_te_blood (void)
1285 VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
1286 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1288 pos = PRVM_G_VECTOR(OFS_PARM0);
1289 CL_FindNonSolidLocation(pos, pos2, 4);
1290 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1293 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
1294 static void VM_CL_te_bloodshower (void)
1298 VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
1299 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1301 speed = PRVM_G_FLOAT(OFS_PARM2);
1308 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), vel1, vel2, NULL, 0);
1311 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
1312 static void VM_CL_te_explosionrgb (void)
1316 matrix4x4_t tempmatrix;
1317 VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
1318 pos = PRVM_G_VECTOR(OFS_PARM0);
1319 CL_FindNonSolidLocation(pos, pos2, 10);
1320 CL_ParticleExplosion(pos2);
1321 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1322 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);
1325 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
1326 static void VM_CL_te_particlecube (void)
1328 VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
1329 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));
1332 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
1333 static void VM_CL_te_particlerain (void)
1335 VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
1336 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);
1339 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
1340 static void VM_CL_te_particlesnow (void)
1342 VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
1343 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);
1346 // #411 void(vector org, vector vel, float howmany) te_spark
1347 static void VM_CL_te_spark (void)
1351 VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
1353 pos = PRVM_G_VECTOR(OFS_PARM0);
1354 CL_FindNonSolidLocation(pos, pos2, 4);
1355 CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1358 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
1359 static void VM_CL_te_gunshotquad (void)
1363 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
1365 pos = PRVM_G_VECTOR(OFS_PARM0);
1366 CL_FindNonSolidLocation(pos, pos2, 4);
1367 CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1370 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
1371 static void VM_CL_te_spikequad (void)
1376 VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
1378 pos = PRVM_G_VECTOR(OFS_PARM0);
1379 CL_FindNonSolidLocation(pos, pos2, 4);
1380 CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1381 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1385 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1386 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1387 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1391 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
1392 static void VM_CL_te_superspikequad (void)
1397 VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
1399 pos = PRVM_G_VECTOR(OFS_PARM0);
1400 CL_FindNonSolidLocation(pos, pos2, 4);
1401 CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1402 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1406 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1407 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1408 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1412 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
1413 static void VM_CL_te_explosionquad (void)
1417 VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
1419 pos = PRVM_G_VECTOR(OFS_PARM0);
1420 CL_FindNonSolidLocation(pos, pos2, 10);
1421 CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1422 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1425 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
1426 static void VM_CL_te_smallflash (void)
1430 VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
1432 pos = PRVM_G_VECTOR(OFS_PARM0);
1433 CL_FindNonSolidLocation(pos, pos2, 10);
1434 CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1437 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
1438 static void VM_CL_te_customflash (void)
1442 matrix4x4_t tempmatrix;
1443 VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
1445 pos = PRVM_G_VECTOR(OFS_PARM0);
1446 CL_FindNonSolidLocation(pos, pos2, 4);
1447 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1448 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);
1451 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
1452 static void VM_CL_te_gunshot (void)
1456 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
1458 pos = PRVM_G_VECTOR(OFS_PARM0);
1459 CL_FindNonSolidLocation(pos, pos2, 4);
1460 CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1463 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
1464 static void VM_CL_te_spike (void)
1469 VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
1471 pos = PRVM_G_VECTOR(OFS_PARM0);
1472 CL_FindNonSolidLocation(pos, pos2, 4);
1473 CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1474 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1478 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1479 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1480 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1484 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
1485 static void VM_CL_te_superspike (void)
1490 VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
1492 pos = PRVM_G_VECTOR(OFS_PARM0);
1493 CL_FindNonSolidLocation(pos, pos2, 4);
1494 CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1495 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1499 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1500 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1501 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1505 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
1506 static void VM_CL_te_explosion (void)
1510 VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
1512 pos = PRVM_G_VECTOR(OFS_PARM0);
1513 CL_FindNonSolidLocation(pos, pos2, 10);
1514 CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1515 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1518 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
1519 static void VM_CL_te_tarexplosion (void)
1523 VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
1525 pos = PRVM_G_VECTOR(OFS_PARM0);
1526 CL_FindNonSolidLocation(pos, pos2, 10);
1527 CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1528 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1531 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
1532 static void VM_CL_te_wizspike (void)
1536 VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
1538 pos = PRVM_G_VECTOR(OFS_PARM0);
1539 CL_FindNonSolidLocation(pos, pos2, 4);
1540 CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1541 S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
1544 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
1545 static void VM_CL_te_knightspike (void)
1549 VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
1551 pos = PRVM_G_VECTOR(OFS_PARM0);
1552 CL_FindNonSolidLocation(pos, pos2, 4);
1553 CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1554 S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
1557 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
1558 static void VM_CL_te_lavasplash (void)
1560 VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
1561 CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1564 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
1565 static void VM_CL_te_teleport (void)
1567 VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
1568 CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1571 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
1572 static void VM_CL_te_explosion2 (void)
1576 matrix4x4_t tempmatrix;
1577 int colorStart, colorLength;
1578 unsigned char *tempcolor;
1579 VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
1581 pos = PRVM_G_VECTOR(OFS_PARM0);
1582 colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
1583 colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
1584 CL_FindNonSolidLocation(pos, pos2, 10);
1585 CL_ParticleExplosion2(pos2, colorStart, colorLength);
1586 tempcolor = (unsigned char *)&palette_complete[(rand()%colorLength) + colorStart];
1587 color[0] = tempcolor[0] * (2.0f / 255.0f);
1588 color[1] = tempcolor[1] * (2.0f / 255.0f);
1589 color[2] = tempcolor[2] * (2.0f / 255.0f);
1590 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1591 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);
1592 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1596 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
1597 static void VM_CL_te_lightning1 (void)
1599 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
1600 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
1603 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
1604 static void VM_CL_te_lightning2 (void)
1606 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
1607 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
1610 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
1611 static void VM_CL_te_lightning3 (void)
1613 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
1614 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
1617 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
1618 static void VM_CL_te_beam (void)
1620 VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
1621 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
1624 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
1625 static void VM_CL_te_plasmaburn (void)
1629 VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
1631 pos = PRVM_G_VECTOR(OFS_PARM0);
1632 CL_FindNonSolidLocation(pos, pos2, 4);
1633 CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1636 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
1637 static void VM_CL_te_flamejet (void)
1641 VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
1642 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1644 pos = PRVM_G_VECTOR(OFS_PARM0);
1645 CL_FindNonSolidLocation(pos, pos2, 4);
1646 CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1650 //====================================================================
1653 extern void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
1655 static msurface_t *cl_getsurface(model_t *model, int surfacenum)
1657 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1659 return model->data_surfaces + surfacenum + model->firstmodelsurface;
1662 // #434 float(entity e, float s) getsurfacenumpoints
1663 static void VM_CL_getsurfacenumpoints(void)
1666 msurface_t *surface;
1667 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
1668 // return 0 if no such surface
1669 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1671 PRVM_G_FLOAT(OFS_RETURN) = 0;
1675 // note: this (incorrectly) assumes it is a simple polygon
1676 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1679 // #435 vector(entity e, float s, float n) getsurfacepoint
1680 static void VM_CL_getsurfacepoint(void)
1684 msurface_t *surface;
1686 VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1687 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1688 ed = PRVM_G_EDICT(OFS_PARM0);
1689 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1691 // note: this (incorrectly) assumes it is a simple polygon
1692 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1693 if (pointnum < 0 || pointnum >= surface->num_vertices)
1695 // FIXME: implement rotation/scaling
1696 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1699 // #436 vector(entity e, float s) getsurfacenormal
1700 static void VM_CL_getsurfacenormal(void)
1703 msurface_t *surface;
1705 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
1706 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1707 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1709 // FIXME: implement rotation/scaling
1710 // note: this (incorrectly) assumes it is a simple polygon
1711 // note: this only returns the first triangle, so it doesn't work very
1712 // well for curved surfaces or arbitrary meshes
1713 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);
1714 VectorNormalize(normal);
1715 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1718 // #437 string(entity e, float s) getsurfacetexture
1719 static void VM_CL_getsurfacetexture(void)
1722 msurface_t *surface;
1723 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
1724 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1725 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1727 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
1730 // #438 float(entity e, vector p) getsurfacenearpoint
1731 static void VM_CL_getsurfacenearpoint(void)
1733 int surfacenum, best;
1735 vec_t dist, bestdist;
1737 model_t *model = NULL;
1738 msurface_t *surface;
1740 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
1741 PRVM_G_FLOAT(OFS_RETURN) = -1;
1742 ed = PRVM_G_EDICT(OFS_PARM0);
1743 if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces)
1746 // FIXME: implement rotation/scaling
1747 point = PRVM_G_VECTOR(OFS_PARM1);
1748 VectorSubtract(point, ed->fields.client->origin, p);
1750 bestdist = 1000000000;
1751 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1753 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1754 // first see if the nearest point on the surface's box is closer than the previous match
1755 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1756 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1757 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1758 dist = VectorLength2(clipped);
1759 if (dist < bestdist)
1761 // it is, check the nearest point on the actual geometry
1762 clippointtosurface(model, surface, p, clipped);
1763 VectorSubtract(clipped, p, clipped);
1764 dist += VectorLength2(clipped);
1765 if (dist < bestdist)
1767 // that's closer too, store it as the best match
1773 PRVM_G_FLOAT(OFS_RETURN) = best;
1776 // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint
1777 static void VM_CL_getsurfaceclippedpoint(void)
1781 msurface_t *surface;
1783 VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
1784 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1785 ed = PRVM_G_EDICT(OFS_PARM0);
1786 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1788 // FIXME: implement rotation/scaling
1789 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
1790 clippointtosurface(model, surface, p, out);
1791 // FIXME: implement rotation/scaling
1792 VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1795 // #443 void(entity e, entity tagentity, string tagname) setattachment
1796 static void VM_CL_setattachment (void)
1799 prvm_edict_t *tagentity;
1800 const char *tagname;
1804 VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
1806 e = PRVM_G_EDICT(OFS_PARM0);
1807 tagentity = PRVM_G_EDICT(OFS_PARM1);
1808 tagname = PRVM_G_STRING(OFS_PARM2);
1810 if (e == prog->edicts)
1812 VM_Warning("setattachment: can not modify world entity\n");
1815 if (e->priv.server->free)
1817 VM_Warning("setattachment: can not modify free entity\n");
1821 if (tagentity == NULL)
1822 tagentity = prog->edicts;
1824 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
1826 v->edict = PRVM_EDICT_TO_PROG(tagentity);
1828 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
1831 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
1833 modelindex = (int)tagentity->fields.client->modelindex;
1834 model = CL_GetModelByIndex(modelindex);
1837 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
1839 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);
1842 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));
1846 /////////////////////////////////////////
1847 // DP_MD3_TAGINFO extension coded by VorteX
1849 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
1851 model_t *model = CL_GetModelFromEdict(e);
1853 return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
1858 // Warnings/errors code:
1859 // 0 - normal (everything all-right)
1862 // 3 - null or non-precached model
1863 // 4 - no tags with requested index
1864 // 5 - runaway loop at attachment chain
1865 extern cvar_t cl_bob;
1866 extern cvar_t cl_bobcycle;
1867 extern cvar_t cl_bobup;
1868 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
1871 int reqframe, attachloop;
1872 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
1873 prvm_edict_t *attachent;
1876 *out = identitymatrix; // warnings and errors return identical matrix
1878 if (ent == prog->edicts)
1880 if (ent->priv.server->free)
1883 model = CL_GetModelFromEdict(ent);
1888 if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
1889 reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
1891 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
1893 // get initial tag matrix
1896 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
1901 tagmatrix = identitymatrix;
1903 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
1904 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
1908 attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
1909 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
1911 model = CL_GetModelFromEdict(attachent);
1913 if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
1914 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
1916 attachmatrix = identitymatrix;
1918 // apply transformation by child entity matrix
1919 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1920 if (val->_float == 0)
1922 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);
1923 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1924 Matrix4x4_Copy(&tagmatrix, out);
1926 // finally transformate by matrix of tag on parent entity
1927 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
1928 Matrix4x4_Copy(&tagmatrix, out);
1932 if (attachloop > 255) // prevent runaway looping
1935 while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
1938 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
1939 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1940 if (val->_float == 0)
1942 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
1943 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);
1944 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1946 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
1947 {// RENDER_VIEWMODEL magic
1948 Matrix4x4_Copy(&tagmatrix, out);
1950 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1951 if (val->_float == 0)
1954 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, csqc_origin[0], csqc_origin[1], csqc_origin[2], csqc_angles[0], csqc_angles[1], csqc_angles[2], val->_float);
1955 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1958 // Cl_bob, ported from rendering code
1959 if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
1962 // LordHavoc: this code is *weird*, but not replacable (I think it
1963 // should be done in QC on the server, but oh well, quake is quake)
1964 // LordHavoc: figured out bobup: the time at which the sin is at 180
1965 // degrees (which allows lengthening or squishing the peak or valley)
1966 cycle = sv.time/cl_bobcycle.value;
1967 cycle -= (int)cycle;
1968 if (cycle < cl_bobup.value)
1969 cycle = sin(M_PI * cycle / cl_bobup.value);
1971 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
1972 // bob is proportional to velocity in the xy plane
1973 // (don't count Z, or jumping messes it up)
1974 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;
1975 bob = bob*0.3 + bob*0.7*cycle;
1976 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
1983 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
1984 static void VM_CL_gettagindex (void)
1987 const char *tag_name;
1988 int modelindex, tag_index;
1990 VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
1992 ent = PRVM_G_EDICT(OFS_PARM0);
1993 tag_name = PRVM_G_STRING(OFS_PARM1);
1994 if (ent == prog->edicts)
1996 VM_Warning("gettagindex: can't affect world entity\n");
1999 if (ent->priv.server->free)
2001 VM_Warning("gettagindex: can't affect free entity\n");
2005 modelindex = (int)ent->fields.client->modelindex;
2007 modelindex = -(modelindex+1);
2009 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2010 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2013 tag_index = CL_GetTagIndex(ent, tag_name);
2015 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2017 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2020 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2021 static void VM_CL_gettaginfo (void)
2025 matrix4x4_t tag_matrix;
2028 VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2030 e = PRVM_G_EDICT(OFS_PARM0);
2031 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2032 returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2033 Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2038 VM_Warning("gettagindex: can't affect world entity\n");
2041 VM_Warning("gettagindex: can't affect free entity\n");
2044 Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2047 Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2050 Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2055 //============================================================================
2057 //====================
2058 //QC POLYGON functions
2059 //====================
2064 float data[36]; //[515]: enough for polygons
2065 unsigned char flags; //[515]: + VM_POLYGON_2D and VM_POLYGON_FL4V flags
2068 //static float vm_polygon_linewidth = 1;
2069 static mempool_t *vm_polygons_pool = NULL;
2070 static unsigned char vm_current_vertices = 0;
2071 static qboolean vm_polygons_initialized = false;
2072 static vm_polygon_t *vm_polygons = NULL;
2073 static unsigned long vm_polygons_num = 0, vm_drawpolygons_num = 0; //[515]: ok long on 64bit ?
2074 static qboolean vm_polygonbegin = false; //[515]: for "no-crap-on-the-screen" check
2075 #define VM_DEFPOLYNUM 64 //[515]: enough for default ?
2077 #define VM_POLYGON_FL3V 16 //more than 2 vertices (used only for lines)
2078 #define VM_POLYGON_FLLINES 32
2079 #define VM_POLYGON_FL2D 64
2080 #define VM_POLYGON_FL4V 128 //4 vertices
2082 static void VM_InitPolygons (void)
2084 vm_polygons_pool = Mem_AllocPool("VMPOLY", 0, NULL);
2085 vm_polygons = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2086 memset(vm_polygons, 0, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2087 vm_polygons_num = VM_DEFPOLYNUM;
2088 vm_drawpolygons_num = 0;
2089 vm_polygonbegin = false;
2090 vm_polygons_initialized = true;
2093 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2095 int surfacelistindex;
2096 // LordHavoc: FIXME: this is stupid code
2097 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2099 const vm_polygon_t *p = &vm_polygons[surfacelist[surfacelistindex]];
2100 int flags = p->flags & 0x0f;
2102 if(flags == DRAWFLAG_ADDITIVE)
2103 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2104 else if(flags == DRAWFLAG_MODULATE)
2105 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2106 else if(flags == DRAWFLAG_2XMODULATE)
2107 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2109 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2111 R_Mesh_TexBind(0, R_GetTexture(p->tex));
2114 //[515]: is speed is max ?
2115 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2117 qglLineWidth(p->data[13]);CHECKGLERROR
2118 qglBegin(GL_LINE_LOOP);
2119 qglTexCoord1f (p->data[12]);
2120 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2121 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2123 qglTexCoord1f (p->data[14]);
2124 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2125 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2127 if(p->flags & VM_POLYGON_FL3V)
2129 qglTexCoord1f (p->data[16]);
2130 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2131 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2133 if(p->flags & VM_POLYGON_FL4V)
2135 qglTexCoord1f (p->data[18]);
2136 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2137 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2145 qglBegin(GL_POLYGON);
2146 qglTexCoord2f (p->data[12], p->data[13]);
2147 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2148 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2150 qglTexCoord2f (p->data[14], p->data[15]);
2151 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2152 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2154 qglTexCoord2f (p->data[16], p->data[17]);
2155 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2156 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2158 if(p->flags & VM_POLYGON_FL4V)
2160 qglTexCoord2f (p->data[18], p->data[19]);
2161 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2162 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2170 static void VM_CL_AddPolygonTo2DScene (vm_polygon_t *p)
2172 drawqueuemesh_t mesh;
2173 static int picelements[6] = {0, 1, 2, 0, 2, 3};
2175 mesh.texture = p->tex;
2176 mesh.data_element3i = picelements;
2177 mesh.data_vertex3f = p->data;
2178 mesh.data_texcoord2f = p->data + 12;
2179 mesh.data_color4f = p->data + 20;
2180 if(p->flags & VM_POLYGON_FL4V)
2182 mesh.num_vertices = 4;
2183 mesh.num_triangles = 2;
2187 mesh.num_vertices = 3;
2188 mesh.num_triangles = 1;
2190 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2191 DrawQ_LineLoop (&mesh, (p->flags&0x0f));
2193 DrawQ_Mesh (&mesh, (p->flags&0x0f));
2196 void VM_CL_AddPolygonsToMeshQueue (void)
2199 if(!vm_drawpolygons_num)
2201 R_Mesh_Matrix(&identitymatrix);
2202 GL_CullFace(GL_NONE);
2203 for(i = 0;i < (int)vm_drawpolygons_num;i++)
2204 VM_DrawPolygonCallback(NULL, NULL, 1, &i);
2205 vm_drawpolygons_num = 0;
2208 //void(string texturename, float flag[, float 2d[, float lines]]) R_BeginPolygon
2209 static void VM_CL_R_PolygonBegin (void)
2212 const char *picname;
2213 VM_SAFEPARMCOUNTRANGE(2, 4, VM_CL_R_PolygonBegin);
2215 if(!vm_polygons_initialized)
2219 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonEnd after first\n");
2222 if(vm_drawpolygons_num >= vm_polygons_num)
2224 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2225 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2226 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2227 Mem_Free(vm_polygons);
2229 vm_polygons_num *= 2;
2231 p = &vm_polygons[vm_drawpolygons_num];
2232 picname = PRVM_G_STRING(OFS_PARM0);
2234 p->tex = Draw_CachePic(picname, true)->tex;
2236 p->tex = r_texture_white;
2237 p->flags = (unsigned char)PRVM_G_FLOAT(OFS_PARM1);
2238 vm_current_vertices = 0;
2239 vm_polygonbegin = true;
2242 if(PRVM_G_FLOAT(OFS_PARM2))
2243 p->flags |= VM_POLYGON_FL2D;
2244 if(prog->argc >= 4 && PRVM_G_FLOAT(OFS_PARM3))
2246 p->data[13] = PRVM_G_FLOAT(OFS_PARM3); //[515]: linewidth
2247 p->flags |= VM_POLYGON_FLLINES;
2252 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2253 static void VM_CL_R_PolygonVertex (void)
2255 float *coords, *tx, *rgb, alpha;
2257 VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2259 if(!vm_polygonbegin)
2261 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2264 coords = PRVM_G_VECTOR(OFS_PARM0);
2265 tx = PRVM_G_VECTOR(OFS_PARM1);
2266 rgb = PRVM_G_VECTOR(OFS_PARM2);
2267 alpha = PRVM_G_FLOAT(OFS_PARM3);
2269 p = &vm_polygons[vm_drawpolygons_num];
2270 if(vm_current_vertices > 4)
2272 VM_Warning("VM_CL_R_PolygonVertex: may have 4 vertices max\n");
2276 p->data[vm_current_vertices*3] = coords[0];
2277 p->data[1+vm_current_vertices*3] = coords[1];
2278 p->data[2+vm_current_vertices*3] = coords[2];
2280 p->data[12+vm_current_vertices*2] = tx[0];
2281 if(!(p->flags & VM_POLYGON_FLLINES))
2282 p->data[13+vm_current_vertices*2] = tx[1];
2284 p->data[20+vm_current_vertices*4] = rgb[0];
2285 p->data[21+vm_current_vertices*4] = rgb[1];
2286 p->data[22+vm_current_vertices*4] = rgb[2];
2287 p->data[23+vm_current_vertices*4] = alpha;
2289 vm_current_vertices++;
2290 if(vm_current_vertices == 4)
2291 p->flags |= VM_POLYGON_FL4V;
2293 if(vm_current_vertices == 3)
2294 p->flags |= VM_POLYGON_FL3V;
2297 //void() R_EndPolygon
2298 static void VM_CL_R_PolygonEnd (void)
2300 VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2301 if(!vm_polygonbegin)
2303 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2306 vm_polygonbegin = false;
2307 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2309 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2310 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2312 vm_drawpolygons_num++;
2315 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2318 void Debug_PolygonBegin(const char *picname, int flags, qboolean draw2d, float linewidth)
2322 if(!vm_polygons_initialized)
2326 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2329 // limit polygons to a vaguely sane amount, beyond this each one just
2330 // replaces the last one
2331 vm_drawpolygons_num = min(vm_drawpolygons_num, (1<<20)-1);
2332 if(vm_drawpolygons_num >= vm_polygons_num)
2334 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2335 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2336 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2337 Mem_Free(vm_polygons);
2339 vm_polygons_num *= 2;
2341 p = &vm_polygons[vm_drawpolygons_num];
2342 if(picname && picname[0])
2343 p->tex = Draw_CachePic(picname, true)->tex;
2345 p->tex = r_texture_white;
2347 vm_current_vertices = 0;
2348 vm_polygonbegin = true;
2350 p->flags |= VM_POLYGON_FL2D;
2353 p->data[13] = linewidth; //[515]: linewidth
2354 p->flags |= VM_POLYGON_FLLINES;
2358 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2362 if(!vm_polygonbegin)
2364 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2368 p = &vm_polygons[vm_drawpolygons_num];
2369 if(vm_current_vertices > 4)
2371 Con_Printf("Debug_PolygonVertex: may have 4 vertices max\n");
2375 p->data[vm_current_vertices*3] = x;
2376 p->data[1+vm_current_vertices*3] = y;
2377 p->data[2+vm_current_vertices*3] = z;
2379 p->data[12+vm_current_vertices*2] = s;
2380 if(!(p->flags & VM_POLYGON_FLLINES))
2381 p->data[13+vm_current_vertices*2] = t;
2383 p->data[20+vm_current_vertices*4] = r;
2384 p->data[21+vm_current_vertices*4] = g;
2385 p->data[22+vm_current_vertices*4] = b;
2386 p->data[23+vm_current_vertices*4] = a;
2388 vm_current_vertices++;
2389 if(vm_current_vertices == 4)
2390 p->flags |= VM_POLYGON_FL4V;
2392 if(vm_current_vertices == 3)
2393 p->flags |= VM_POLYGON_FL3V;
2396 void Debug_PolygonEnd(void)
2398 if(!vm_polygonbegin)
2400 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2403 vm_polygonbegin = false;
2404 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2406 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2407 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2409 vm_drawpolygons_num++;
2412 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2419 Returns false if any part of the bottom of the entity is off an edge that
2424 qboolean CL_CheckBottom (prvm_edict_t *ent)
2426 vec3_t mins, maxs, start, stop;
2431 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2432 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2434 // if all of the points under the corners are solid world, don't bother
2435 // with the tougher checks
2436 // the corners must be within 16 of the midpoint
2437 start[2] = mins[2] - 1;
2438 for (x=0 ; x<=1 ; x++)
2439 for (y=0 ; y<=1 ; y++)
2441 start[0] = x ? maxs[0] : mins[0];
2442 start[1] = y ? maxs[1] : mins[1];
2443 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2447 return true; // we got out easy
2451 // check it for real...
2455 // the midpoint must be within 16 of the bottom
2456 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2457 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2458 stop[2] = start[2] - 2*sv_stepheight.value;
2459 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2461 if (trace.fraction == 1.0)
2463 mid = bottom = trace.endpos[2];
2465 // the corners must be within 16 of the midpoint
2466 for (x=0 ; x<=1 ; x++)
2467 for (y=0 ; y<=1 ; y++)
2469 start[0] = stop[0] = x ? maxs[0] : mins[0];
2470 start[1] = stop[1] = y ? maxs[1] : mins[1];
2472 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2474 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2475 bottom = trace.endpos[2];
2476 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2487 Called by monster program code.
2488 The move will be adjusted for slopes and stairs, but if the move isn't
2489 possible, no move is done and false is returned
2492 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2495 vec3_t oldorg, neworg, end, traceendpos;
2498 prvm_edict_t *enemy;
2502 VectorCopy (ent->fields.client->origin, oldorg);
2503 VectorAdd (ent->fields.client->origin, move, neworg);
2505 // flying monsters don't step up
2506 if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2508 // try one move with vertical motion, then one without
2509 for (i=0 ; i<2 ; i++)
2511 VectorAdd (ent->fields.client->origin, move, neworg);
2512 enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2513 if (i == 0 && enemy != prog->edicts)
2515 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2521 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);
2523 VM_SetTraceGlobals(&trace);
2525 if (trace.fraction == 1)
2527 VectorCopy(trace.endpos, traceendpos);
2528 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2529 return false; // swim monster left water
2531 VectorCopy (traceendpos, ent->fields.client->origin);
2537 if (enemy == prog->edicts)
2544 // push down from a step height above the wished position
2545 neworg[2] += sv_stepheight.value;
2546 VectorCopy (neworg, end);
2547 end[2] -= sv_stepheight.value*2;
2549 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2551 VM_SetTraceGlobals(&trace);
2553 if (trace.startsolid)
2555 neworg[2] -= sv_stepheight.value;
2556 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2558 VM_SetTraceGlobals(&trace);
2559 if (trace.startsolid)
2562 if (trace.fraction == 1)
2564 // if monster had the ground pulled out, go ahead and fall
2565 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2567 VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2570 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2574 return false; // walked off an edge
2577 // check point traces down for dangling corners
2578 VectorCopy (trace.endpos, ent->fields.client->origin);
2580 if (!CL_CheckBottom (ent))
2582 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2583 { // entity had floor mostly pulled out from underneath it
2584 // and is trying to correct
2589 VectorCopy (oldorg, ent->fields.client->origin);
2593 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2594 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2596 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2597 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2609 float(float yaw, float dist[, settrace]) walkmove
2612 static void VM_CL_walkmove (void)
2621 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2623 // assume failure if it returns early
2624 PRVM_G_FLOAT(OFS_RETURN) = 0;
2626 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2627 if (ent == prog->edicts)
2629 VM_Warning("walkmove: can not modify world entity\n");
2632 if (ent->priv.server->free)
2634 VM_Warning("walkmove: can not modify free entity\n");
2637 yaw = PRVM_G_FLOAT(OFS_PARM0);
2638 dist = PRVM_G_FLOAT(OFS_PARM1);
2639 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2641 if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2644 yaw = yaw*M_PI*2 / 360;
2646 move[0] = cos(yaw)*dist;
2647 move[1] = sin(yaw)*dist;
2650 // save program state, because CL_movestep may call other progs
2651 oldf = prog->xfunction;
2652 oldself = prog->globals.client->self;
2654 PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2657 // restore program state
2658 prog->xfunction = oldf;
2659 prog->globals.client->self = oldself;
2666 string(string key) serverkey
2669 void VM_CL_serverkey(void)
2671 char string[VM_STRINGTEMP_LENGTH];
2672 VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2673 InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2674 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2677 //============================================================================
2679 prvm_builtin_t vm_cl_builtins[] = {
2680 NULL, // #0 NULL function (not callable) (QUAKE)
2681 VM_CL_makevectors, // #1 void(vector ang) makevectors (QUAKE)
2682 VM_CL_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
2683 VM_CL_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
2684 VM_CL_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2685 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2686 VM_break, // #6 void() break (QUAKE)
2687 VM_random, // #7 float() random (QUAKE)
2688 VM_CL_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
2689 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
2690 VM_error, // #10 void(string e) error (QUAKE)
2691 VM_objerror, // #11 void(string e) objerror (QUAKE)
2692 VM_vlen, // #12 float(vector v) vlen (QUAKE)
2693 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
2694 VM_CL_spawn, // #14 entity() spawn (QUAKE)
2695 VM_remove, // #15 void(entity e) remove (QUAKE)
2696 VM_CL_traceline, // #16 float(vector v1, vector v2, float tryents) traceline (QUAKE)
2697 NULL, // #17 entity() checkclient (QUAKE)
2698 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
2699 VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
2700 VM_CL_precache_model, // #20 void(string s) precache_model (QUAKE)
2701 NULL, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2702 VM_CL_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
2703 NULL, // #23 void(string s, ...) bprint (QUAKE)
2704 NULL, // #24 void(entity client, string s, ...) sprint (QUAKE)
2705 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
2706 VM_ftos, // #26 string(float f) ftos (QUAKE)
2707 VM_vtos, // #27 string(vector v) vtos (QUAKE)
2708 VM_coredump, // #28 void() coredump (QUAKE)
2709 VM_traceon, // #29 void() traceon (QUAKE)
2710 VM_traceoff, // #30 void() traceoff (QUAKE)
2711 VM_eprint, // #31 void(entity e) eprint (QUAKE)
2712 VM_CL_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
2713 NULL, // #33 (QUAKE)
2714 VM_CL_droptofloor, // #34 float() droptofloor (QUAKE)
2715 VM_CL_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
2716 VM_rint, // #36 float(float v) rint (QUAKE)
2717 VM_floor, // #37 float(float v) floor (QUAKE)
2718 VM_ceil, // #38 float(float v) ceil (QUAKE)
2719 NULL, // #39 (QUAKE)
2720 VM_CL_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
2721 VM_CL_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
2722 NULL, // #42 (QUAKE)
2723 VM_fabs, // #43 float(float f) fabs (QUAKE)
2724 NULL, // #44 vector(entity e, float speed) aim (QUAKE)
2725 VM_cvar, // #45 float(string s) cvar (QUAKE)
2726 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
2727 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
2728 VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2729 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
2730 NULL, // #50 (QUAKE)
2731 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
2732 NULL, // #52 void(float to, float f) WriteByte (QUAKE)
2733 NULL, // #53 void(float to, float f) WriteChar (QUAKE)
2734 NULL, // #54 void(float to, float f) WriteShort (QUAKE)
2735 NULL, // #55 void(float to, float f) WriteLong (QUAKE)
2736 NULL, // #56 void(float to, float f) WriteCoord (QUAKE)
2737 NULL, // #57 void(float to, float f) WriteAngle (QUAKE)
2738 NULL, // #58 void(float to, string s) WriteString (QUAKE)
2739 NULL, // #59 (QUAKE)
2740 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2741 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2742 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2743 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2744 VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2745 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2746 NULL, // #66 (QUAKE)
2747 NULL, // #67 void(float step) movetogoal (QUAKE)
2748 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
2749 VM_CL_makestatic, // #69 void(entity e) makestatic (QUAKE)
2750 NULL, // #70 void(string s) changelevel (QUAKE)
2751 NULL, // #71 (QUAKE)
2752 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
2753 NULL, // #73 void(entity client, strings) centerprint (QUAKE)
2754 VM_CL_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2755 VM_CL_precache_model, // #75 string(string s) precache_model2 (QUAKE)
2756 VM_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
2757 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
2758 NULL, // #78 void(entity e) setspawnparms (QUAKE)
2759 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
2760 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
2761 VM_stof, // #81 float(string s) stof (FRIK_FILE)
2762 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
2763 NULL, // #83 (QUAKE)
2764 NULL, // #84 (QUAKE)
2765 NULL, // #85 (QUAKE)
2766 NULL, // #86 (QUAKE)
2767 NULL, // #87 (QUAKE)
2768 NULL, // #88 (QUAKE)
2769 NULL, // #89 (QUAKE)
2770 VM_CL_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2771 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2772 VM_CL_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2773 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2774 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2775 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2776 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2777 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2778 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2779 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
2780 // FrikaC and Telejano range #100-#199
2791 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
2792 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
2793 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
2794 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2795 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
2796 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
2797 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
2798 VM_stov, // #117 vector(string) stov (FRIK_FILE)
2799 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
2800 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
2881 // FTEQW range #200-#299
2900 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
2904 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
2905 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
2910 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
2914 NULL, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
2982 // CSQC range #300-#399
2983 VM_CL_R_ClearScene, // #300 void() clearscene (EXT_CSQC)
2984 VM_CL_R_AddEntities, // #301 void(float mask) addentities (EXT_CSQC)
2985 VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC)
2986 VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC)
2987 VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC)
2988 VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
2989 VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
2990 VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2991 VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon
2993 VM_CL_unproject, // #310 vector (vector v) cs_unproject (EXT_CSQC)
2994 VM_CL_project, // #311 vector (vector v) cs_project (EXT_CSQC)
2998 VM_drawline, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
2999 VM_iscachedpic, // #316 float(string name) iscachedpic (EXT_CSQC)
3000 VM_precache_pic, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3001 VM_getimagesize, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3002 VM_freepic, // #319 void(string name) freepic (EXT_CSQC)
3003 VM_drawcharacter, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3004 VM_drawstring, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3005 VM_drawpic, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3006 VM_drawfill, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3007 VM_drawsetcliparea, // #324 void(float x, float y, float width, float height) drawsetcliparea
3008 VM_drawresetcliparea, // #325 void(void) drawresetcliparea
3013 VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
3014 VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
3015 VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
3016 VM_CL_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3017 VM_CL_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3018 VM_CL_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3019 VM_CL_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3020 VM_CL_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3021 VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC)
3022 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3023 VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3024 VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3025 VM_CL_getkeybind, // #342 string(float keynum) getkeybind (EXT_CSQC)
3026 VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3027 VM_getmousepos, // #344 vector() getmousepos (EXT_CSQC)
3028 VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC)
3029 VM_CL_setsensitivityscale, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3030 VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC)
3031 VM_CL_getplayerkey, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3032 VM_CL_isdemo, // #349 float() isdemo (EXT_CSQC)
3033 VM_isserver, // #350 float() isserver (EXT_CSQC)
3034 VM_CL_setlistener, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3035 VM_CL_registercmd, // #352 void(string cmdname) registercommand (EXT_CSQC)
3036 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3037 VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3043 VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC)
3044 VM_CL_ReadChar, // #361 float() readchar (EXT_CSQC)
3045 VM_CL_ReadShort, // #362 float() readshort (EXT_CSQC)
3046 VM_CL_ReadLong, // #363 float() readlong (EXT_CSQC)
3047 VM_CL_ReadCoord, // #364 float() readcoord (EXT_CSQC)
3048 VM_CL_ReadAngle, // #365 float() readangle (EXT_CSQC)
3049 VM_CL_ReadString, // #366 string() readstring (EXT_CSQC)
3050 VM_CL_ReadFloat, // #367 float() readfloat (EXT_CSQC)
3083 // LordHavoc's range #400-#499
3084 VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3085 NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3086 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3087 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3088 VM_CL_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3089 VM_CL_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3090 VM_CL_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3091 VM_CL_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3092 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)
3093 VM_CL_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3094 VM_CL_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3095 VM_CL_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3096 VM_CL_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3097 VM_CL_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3098 VM_CL_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3099 VM_CL_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3100 VM_CL_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3101 VM_CL_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3102 VM_CL_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3103 VM_CL_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3104 VM_CL_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3105 VM_CL_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3106 VM_CL_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3107 VM_CL_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3108 VM_CL_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3109 VM_CL_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3110 VM_CL_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3111 VM_CL_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3112 VM_CL_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3113 VM_CL_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3114 VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3115 VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3116 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3117 VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3118 VM_CL_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3119 VM_CL_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3120 VM_CL_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3121 VM_CL_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3122 VM_CL_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3123 VM_CL_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3124 NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3125 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3126 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3127 VM_CL_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3128 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3129 VM_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3130 VM_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3131 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3132 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3133 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3134 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3135 VM_CL_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3136 VM_CL_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3137 NULL, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3138 NULL, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3139 NULL, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3140 NULL, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3141 VM_CL_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3143 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3144 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3145 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3146 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3147 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3148 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3149 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3150 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3151 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3152 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3153 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3154 NULL, // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3155 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3156 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3157 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3158 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3159 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3160 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3161 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3162 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3186 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3188 void VM_CL_Cmd_Init(void)
3190 // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3191 if(vm_polygons_initialized)
3193 Mem_FreePool(&vm_polygons_pool);
3194 vm_polygons_initialized = false;
3198 void VM_CL_Cmd_Reset(void)
3200 if(vm_polygons_initialized)
3202 Mem_FreePool(&vm_polygons_pool);
3203 vm_polygons_initialized = false;