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 if(BoxesOverlap(mins, maxs, ent->fields.client->absmin, ent->fields.client->absmax))
360 // #22 entity(vector org, float rad) findradius
361 static void VM_CL_findradius (void)
363 prvm_edict_t *ent, *chain;
364 vec_t radius, radius2;
365 vec3_t org, eorg, mins, maxs;
366 int i, numtouchedicts;
367 prvm_edict_t *touchedicts[MAX_EDICTS];
369 VM_SAFEPARMCOUNT(2, VM_CL_findradius);
371 chain = (prvm_edict_t *)prog->edicts;
373 VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
374 radius = PRVM_G_FLOAT(OFS_PARM1);
375 radius2 = radius * radius;
377 mins[0] = org[0] - (radius + 1);
378 mins[1] = org[1] - (radius + 1);
379 mins[2] = org[2] - (radius + 1);
380 maxs[0] = org[0] + (radius + 1);
381 maxs[1] = org[1] + (radius + 1);
382 maxs[2] = org[2] + (radius + 1);
383 numtouchedicts = CSQC_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
384 if (numtouchedicts > MAX_EDICTS)
386 // this never happens //[515]: for what then ?
387 Con_Printf("CSQC_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
388 numtouchedicts = MAX_EDICTS;
390 for (i = 0;i < numtouchedicts;i++)
392 ent = touchedicts[i];
393 // Quake did not return non-solid entities but darkplaces does
394 // (note: this is the reason you can't blow up fallen zombies)
395 if (ent->fields.client->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
397 // LordHavoc: compare against bounding box rather than center so it
398 // doesn't miss large objects, and use DotProduct instead of Length
399 // for a major speedup
400 VectorSubtract(org, ent->fields.client->origin, eorg);
401 if (sv_gameplayfix_findradiusdistancetobox.integer)
403 eorg[0] -= bound(ent->fields.client->mins[0], eorg[0], ent->fields.client->maxs[0]);
404 eorg[1] -= bound(ent->fields.client->mins[1], eorg[1], ent->fields.client->maxs[1]);
405 eorg[2] -= bound(ent->fields.client->mins[2], eorg[2], ent->fields.client->maxs[2]);
408 VectorMAMAM(1, eorg, 0.5f, ent->fields.client->mins, 0.5f, ent->fields.client->maxs, eorg);
409 if (DotProduct(eorg, eorg) < radius2)
411 ent->fields.client->chain = PRVM_EDICT_TO_PROG(chain);
416 VM_RETURN_EDICT(chain);
419 // #34 float() droptofloor
420 static void VM_CL_droptofloor (void)
427 VM_SAFEPARMCOUNTRANGE(0, 2, VM_CL_droptofloor); // allow 2 parameters because the id1 defs.qc had an incorrect prototype
429 // assume failure if it returns early
430 PRVM_G_FLOAT(OFS_RETURN) = 0;
432 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
433 if (ent == prog->edicts)
435 VM_Warning("droptofloor: can not modify world entity\n");
438 if (ent->priv.server->free)
440 VM_Warning("droptofloor: can not modify free entity\n");
444 VectorCopy (ent->fields.client->origin, end);
447 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);
449 if (trace.fraction != 1)
451 VectorCopy (trace.endpos, ent->fields.client->origin);
452 ent->fields.client->flags = (int)ent->fields.client->flags | FL_ONGROUND;
453 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
454 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
455 PRVM_G_FLOAT(OFS_RETURN) = 1;
456 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
457 // ent->priv.server->suspendedinairflag = true;
461 // #35 void(float style, string value) lightstyle
462 static void VM_CL_lightstyle (void)
467 VM_SAFEPARMCOUNT(2, VM_CL_lightstyle);
469 i = (int)PRVM_G_FLOAT(OFS_PARM0);
470 c = PRVM_G_STRING(OFS_PARM1);
471 if (i >= cl.max_lightstyle)
473 VM_Warning("VM_CL_lightstyle >= MAX_LIGHTSTYLES\n");
476 strlcpy (cl.lightstyle[i].map, MSG_ReadString(), sizeof (cl.lightstyle[i].map));
477 cl.lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
478 cl.lightstyle[i].length = (int)strlen(cl.lightstyle[i].map);
481 // #40 float(entity e) checkbottom
482 static void VM_CL_checkbottom (void)
484 static int cs_yes, cs_no;
486 vec3_t mins, maxs, start, stop;
491 VM_SAFEPARMCOUNT(1, VM_CL_checkbottom);
492 ent = PRVM_G_EDICT(OFS_PARM0);
493 PRVM_G_FLOAT(OFS_RETURN) = 0;
495 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
496 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
498 // if all of the points under the corners are solid world, don't bother
499 // with the tougher checks
500 // the corners must be within 16 of the midpoint
501 start[2] = mins[2] - 1;
502 for (x=0 ; x<=1 ; x++)
503 for (y=0 ; y<=1 ; y++)
505 start[0] = x ? maxs[0] : mins[0];
506 start[1] = y ? maxs[1] : mins[1];
507 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
512 PRVM_G_FLOAT(OFS_RETURN) = true;
513 return; // we got out easy
518 // check it for real...
522 // the midpoint must be within 16 of the bottom
523 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
524 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
525 stop[2] = start[2] - 2*sv_stepheight.value;
526 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
528 if (trace.fraction == 1.0)
531 mid = bottom = trace.endpos[2];
533 // the corners must be within 16 of the midpoint
534 for (x=0 ; x<=1 ; x++)
535 for (y=0 ; y<=1 ; y++)
537 start[0] = stop[0] = x ? maxs[0] : mins[0];
538 start[1] = stop[1] = y ? maxs[1] : mins[1];
540 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
542 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
543 bottom = trace.endpos[2];
544 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
549 PRVM_G_FLOAT(OFS_RETURN) = true;
552 // #41 float(vector v) pointcontents
553 static void VM_CL_pointcontents (void)
555 VM_SAFEPARMCOUNT(1, VM_CL_pointcontents);
556 PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, CL_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
559 // #48 void(vector o, vector d, float color, float count) particle
560 static void VM_CL_particle (void)
565 VM_SAFEPARMCOUNT(4, VM_CL_particle);
567 org = PRVM_G_VECTOR(OFS_PARM0);
568 dir = PRVM_G_VECTOR(OFS_PARM1);
569 color = (int)PRVM_G_FLOAT(OFS_PARM2);
570 count = (int)PRVM_G_FLOAT(OFS_PARM3);
571 CL_ParticleEffect(EFFECT_SVC_PARTICLE, count, org, org, dir, dir, NULL, color);
574 // #74 void(vector pos, string samp, float vol, float atten) ambientsound
575 static void VM_CL_ambientsound (void)
579 VM_SAFEPARMCOUNT(4, VM_CL_ambientsound);
580 s = S_FindName(PRVM_G_STRING(OFS_PARM0));
581 f = PRVM_G_VECTOR(OFS_PARM1);
582 S_StaticSound (s, f, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3)*64);
585 // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
586 static void VM_CL_getlight (void)
588 vec3_t ambientcolor, diffusecolor, diffusenormal;
591 VM_SAFEPARMCOUNT(1, VM_CL_getlight);
593 p = PRVM_G_VECTOR(OFS_PARM0);
594 VectorClear(ambientcolor);
595 VectorClear(diffusecolor);
596 VectorClear(diffusenormal);
597 if (cl.worldmodel && cl.worldmodel->brush.LightPoint)
598 cl.worldmodel->brush.LightPoint(cl.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
599 VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
603 //============================================================================
604 //[515]: SCENE MANAGER builtins
605 extern qboolean CSQC_AddRenderEdict (prvm_edict_t *ed);//csprogs.c
607 static void CSQC_R_RecalcView (void)
609 extern matrix4x4_t viewmodelmatrix;
610 Matrix4x4_CreateFromQuakeEntity(&r_view.matrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], 1);
611 Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], cl_viewmodel_scale.value);
614 void CL_RelinkLightFlashes(void);
615 //#300 void() clearscene (EXT_CSQC)
616 static void VM_CL_R_ClearScene (void)
618 VM_SAFEPARMCOUNT(0, VM_CL_R_ClearScene);
619 // clear renderable entity and light lists
620 r_refdef.numentities = 0;
621 r_refdef.numlights = 0;
624 //#301 void(float mask) addentities (EXT_CSQC)
625 extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
626 extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
627 static void VM_CL_R_AddEntities (void)
631 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
632 drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
633 CSQC_RelinkAllEntities(drawmask);
634 CL_RelinkLightFlashes();
636 prog->globals.client->time = cl.time;
637 for(i=1;i<prog->num_edicts;i++)
639 ed = &prog->edicts[i];
640 if(ed->priv.required->free)
643 if(ed->priv.required->free)
645 // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict
647 if(ed->priv.required->free)
649 if(!((int)ed->fields.client->drawmask & drawmask))
651 CSQC_AddRenderEdict(ed);
655 //#302 void(entity ent) addentity (EXT_CSQC)
656 static void VM_CL_R_AddEntity (void)
658 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
659 CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
662 //#303 float(float property, ...) setproperty (EXT_CSQC)
663 static void VM_CL_R_SetView (void)
669 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_SetView);
671 c = (int)PRVM_G_FLOAT(OFS_PARM0);
672 f = PRVM_G_VECTOR(OFS_PARM1);
673 k = PRVM_G_FLOAT(OFS_PARM1);
677 case VF_MIN: r_view.x = (int)f[0];
678 r_view.y = (int)f[1];
680 case VF_MIN_X: r_view.x = (int)k;
682 case VF_MIN_Y: r_view.y = (int)k;
684 case VF_SIZE: r_view.width = (int)f[0];
685 r_view.height = (int)f[1];
687 case VF_SIZE_Y: r_view.width = (int)k;
689 case VF_SIZE_X: r_view.height = (int)k;
691 case VF_VIEWPORT: r_view.x = (int)f[0];
692 r_view.y = (int)f[1];
694 // TODO: make sure that view_z and view_depth are set properly even if csqc does not set them!
695 f = PRVM_G_VECTOR(OFS_PARM2);
696 r_view.width = (int)f[0];
697 r_view.height = (int)f[1];
700 case VF_FOV: //r_refdef.fov_x = f[0]; // FIXME!
701 //r_refdef.fov_y = f[1]; // FIXME!
703 case VF_FOVX: //r_refdef.fov_x = k; // FIXME!
705 case VF_FOVY: //r_refdef.fov_y = k; // FIXME!
707 case VF_ORIGIN: VectorCopy(f, cl.csqc_origin);
710 case VF_ORIGIN_X: cl.csqc_origin[0] = k;
713 case VF_ORIGIN_Y: cl.csqc_origin[1] = k;
716 case VF_ORIGIN_Z: cl.csqc_origin[2] = k;
719 case VF_ANGLES: VectorCopy(f, cl.csqc_angles);
722 case VF_ANGLES_X: cl.csqc_angles[0] = k;
725 case VF_ANGLES_Y: cl.csqc_angles[1] = k;
728 case VF_ANGLES_Z: cl.csqc_angles[2] = k;
731 case VF_DRAWWORLD: cl.csqc_vidvars.drawworld = k;
733 case VF_DRAWENGINESBAR: cl.csqc_vidvars.drawenginesbar = k;
735 case VF_DRAWCROSSHAIR: cl.csqc_vidvars.drawcrosshair = k;
738 case VF_CL_VIEWANGLES: VectorCopy(f, cl.viewangles);
740 case VF_CL_VIEWANGLES_X:cl.viewangles[0] = k;
742 case VF_CL_VIEWANGLES_Y:cl.viewangles[1] = k;
744 case VF_CL_VIEWANGLES_Z:cl.viewangles[2] = k;
747 default: PRVM_G_FLOAT(OFS_RETURN) = 0;
748 VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c);
751 PRVM_G_FLOAT(OFS_RETURN) = 1;
754 //#304 void() renderscene (EXT_CSQC)
755 static void VM_CL_R_RenderScene (void)
757 VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
758 // we need to update any RENDER_VIEWMODEL entities at this point because
759 // csqc supplies its own view matrix
760 CL_UpdateViewEntities();
765 //#305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
766 static void VM_CL_R_AddDynamicLight (void)
770 VM_SAFEPARMCOUNTRANGE(3, 8, VM_CL_R_AddDynamicLight); // allow more than 3 because we may extend this in the future
772 // if we've run out of dlights, just return
773 if (r_refdef.numlights >= MAX_DLIGHTS)
776 pos = PRVM_G_VECTOR(OFS_PARM0);
777 col = PRVM_G_VECTOR(OFS_PARM2);
778 Matrix4x4_CreateFromQuakeEntity(&matrix, pos[0], pos[1], pos[2], 0, 0, 0, PRVM_G_FLOAT(OFS_PARM1));
779 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);
782 //============================================================================
784 //#310 vector (vector v) cs_unproject (EXT_CSQC)
785 static void VM_CL_unproject (void)
790 VM_SAFEPARMCOUNT(1, VM_CL_unproject);
791 f = PRVM_G_VECTOR(OFS_PARM0);
792 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);
793 Matrix4x4_Transform(&r_view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
796 //#311 vector (vector v) cs_project (EXT_CSQC)
797 static void VM_CL_project (void)
803 VM_SAFEPARMCOUNT(1, VM_CL_project);
804 f = PRVM_G_VECTOR(OFS_PARM0);
805 Matrix4x4_Invert_Simple(&m, &r_view.matrix);
806 Matrix4x4_Transform(&m, f, v);
807 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]);
810 //#330 float(float stnum) getstatf (EXT_CSQC)
811 static void VM_CL_getstatf (void)
819 VM_SAFEPARMCOUNT(1, VM_CL_getstatf);
820 i = (int)PRVM_G_FLOAT(OFS_PARM0);
821 if(i < 0 || i >= MAX_CL_STATS)
823 VM_Warning("VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
827 PRVM_G_FLOAT(OFS_RETURN) = dat.f;
830 //#331 float(float stnum) getstati (EXT_CSQC)
831 static void VM_CL_getstati (void)
834 VM_SAFEPARMCOUNT(1, VM_CL_getstati);
835 index = (int)PRVM_G_FLOAT(OFS_PARM0);
837 if(index < 0 || index >= MAX_CL_STATS)
839 VM_Warning("VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
843 PRVM_G_FLOAT(OFS_RETURN) = i;
846 //#332 string(float firststnum) getstats (EXT_CSQC)
847 static void VM_CL_getstats (void)
851 VM_SAFEPARMCOUNT(1, VM_CL_getstats);
852 i = (int)PRVM_G_FLOAT(OFS_PARM0);
853 if(i < 0 || i > MAX_CL_STATS-4)
855 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
856 VM_Warning("VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
859 strlcpy(t, (char*)&cl.stats[i], sizeof(t));
860 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
863 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
864 static void VM_CL_setmodelindex (void)
868 struct model_s *model;
870 VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex);
872 t = PRVM_G_EDICT(OFS_PARM0);
874 i = (int)PRVM_G_FLOAT(OFS_PARM1);
876 t->fields.client->model = 0;
877 t->fields.client->modelindex = 0;
882 model = CL_GetModelByIndex(i);
885 VM_Warning("VM_CL_setmodelindex: null model\n");
888 t->fields.client->model = PRVM_SetEngineString(model->name);
889 t->fields.client->modelindex = i;
892 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
893 static void VM_CL_modelnameforindex (void)
897 VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
899 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
900 model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
901 PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(model->name) : 0;
904 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
905 static void VM_CL_particleeffectnum (void)
908 VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
909 i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
912 PRVM_G_FLOAT(OFS_RETURN) = i;
915 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
916 static void VM_CL_trailparticles (void)
921 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles);
923 t = PRVM_G_EDICT(OFS_PARM0);
924 i = (int)PRVM_G_FLOAT(OFS_PARM1);
925 start = PRVM_G_VECTOR(OFS_PARM2);
926 end = PRVM_G_VECTOR(OFS_PARM3);
928 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);
931 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
932 static void VM_CL_pointparticles (void)
936 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
937 i = (int)PRVM_G_FLOAT(OFS_PARM0);
938 f = PRVM_G_VECTOR(OFS_PARM1);
939 v = PRVM_G_VECTOR(OFS_PARM2);
940 n = (int)PRVM_G_FLOAT(OFS_PARM3);
941 CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
944 //#342 string(float keynum) getkeybind (EXT_CSQC)
945 static void VM_CL_getkeybind (void)
947 VM_SAFEPARMCOUNT(1, VM_CL_getkeybind);
948 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0)));
951 //#343 void(float usecursor) setcursormode (EXT_CSQC)
952 static void VM_CL_setcursormode (void)
954 VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
955 cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
956 cl_ignoremousemove = true;
959 //#345 float(float framenum) getinputstate (EXT_CSQC)
960 static void VM_CL_getinputstate (void)
963 VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
964 frame = (int)PRVM_G_FLOAT(OFS_PARM0);
965 for (i = 0;i < cl.movement_numqueue;i++)
966 if (cl.movement_queue[i].sequence == frame)
968 VectorCopy(cl.movement_queue[i].viewangles, prog->globals.client->input_angles);
969 //prog->globals.client->input_buttons = cl.movement_queue[i].//FIXME
970 VectorCopy(cl.movement_queue[i].move, prog->globals.client->input_movevalues);
971 prog->globals.client->input_timelength = cl.movement_queue[i].frametime;
972 if(cl.movement_queue[i].crouch)
974 VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
975 VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
979 VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
980 VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
985 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
986 static void VM_CL_setsensitivityscale (void)
988 VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
989 cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
992 //#347 void() runstandardplayerphysics (EXT_CSQC)
993 static void VM_CL_runplayerphysics (void)
997 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
998 static void VM_CL_getplayerkey (void)
1004 VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
1006 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1007 c = PRVM_G_STRING(OFS_PARM1);
1008 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1011 i = Sbar_GetPlayer(i);
1017 if(!strcasecmp(c, "name"))
1018 strlcpy(t, cl.scores[i].name, sizeof(t));
1020 if(!strcasecmp(c, "frags"))
1021 sprintf(t, "%i", cl.scores[i].frags);
1023 if(!strcasecmp(c, "ping"))
1024 sprintf(t, "%i", cl.scores[i].qw_ping);
1026 if(!strcasecmp(c, "entertime"))
1027 sprintf(t, "%f", cl.scores[i].qw_entertime);
1029 if(!strcasecmp(c, "colors"))
1030 sprintf(t, "%i", cl.scores[i].colors);
1032 if(!strcasecmp(c, "topcolor"))
1033 sprintf(t, "%i", cl.scores[i].colors & 0xf0);
1035 if(!strcasecmp(c, "bottomcolor"))
1036 sprintf(t, "%i", (cl.scores[i].colors &15)<<4);
1038 if(!strcasecmp(c, "viewentity"))
1039 sprintf(t, "%i", i+1);
1042 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1045 //#349 float() isdemo (EXT_CSQC)
1046 static void VM_CL_isdemo (void)
1048 VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
1049 PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
1052 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
1053 static void VM_CL_setlistener (void)
1055 VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
1056 Matrix4x4_FromVectors(&cl.csqc_listenermatrix, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), PRVM_G_VECTOR(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0));
1057 cl.csqc_usecsqclistener = true; //use csqc listener at this frame
1060 //#352 void(string cmdname) registercommand (EXT_CSQC)
1061 static void VM_CL_registercmd (void)
1064 VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
1065 if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0)))
1069 alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1;
1070 t = (char *)Z_Malloc(alloclen);
1071 memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen);
1072 Cmd_AddCommand(t, NULL, "console command created by QuakeC");
1075 Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
1079 //#360 float() readbyte (EXT_CSQC)
1080 static void VM_CL_ReadByte (void)
1082 VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
1083 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte();
1086 //#361 float() readchar (EXT_CSQC)
1087 static void VM_CL_ReadChar (void)
1089 VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
1090 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar();
1093 //#362 float() readshort (EXT_CSQC)
1094 static void VM_CL_ReadShort (void)
1096 VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
1097 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort();
1100 //#363 float() readlong (EXT_CSQC)
1101 static void VM_CL_ReadLong (void)
1103 VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
1104 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong();
1107 //#364 float() readcoord (EXT_CSQC)
1108 static void VM_CL_ReadCoord (void)
1110 VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
1111 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(cls.protocol);
1114 //#365 float() readangle (EXT_CSQC)
1115 static void VM_CL_ReadAngle (void)
1117 VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
1118 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(cls.protocol);
1121 //#366 string() readstring (EXT_CSQC)
1122 static void VM_CL_ReadString (void)
1124 VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
1125 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_ReadString());
1128 //#367 float() readfloat (EXT_CSQC)
1129 static void VM_CL_ReadFloat (void)
1131 VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
1132 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
1135 //////////////////////////////////////////////////////////
1137 static void VM_CL_makestatic (void)
1141 VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
1143 ent = PRVM_G_EDICT(OFS_PARM0);
1144 if (ent == prog->edicts)
1146 VM_Warning("makestatic: can not modify world entity\n");
1149 if (ent->priv.server->free)
1151 VM_Warning("makestatic: can not modify free entity\n");
1155 if (cl.num_static_entities < cl.max_static_entities)
1159 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
1161 // copy it to the current state
1162 staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
1163 staticent->render.frame = staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
1164 staticent->render.framelerp = 0;
1165 // make torchs play out of sync
1166 staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
1167 staticent->render.colormap = (int)ent->fields.client->colormap; // no special coloring
1168 staticent->render.skinnum = (int)ent->fields.client->skin;
1169 staticent->render.effects = (int)ent->fields.client->effects;
1170 staticent->render.alpha = 1;
1171 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float;
1172 staticent->render.scale = 1;
1173 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
1174 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
1177 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
1178 if (renderflags & RF_USEAXIS)
1181 VectorNegate(prog->globals.client->v_right, left);
1182 Matrix4x4_FromVectors(&staticent->render.matrix, prog->globals.client->v_forward, left, prog->globals.client->v_up, ent->fields.client->origin);
1183 Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
1186 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);
1187 CL_UpdateRenderEntity(&staticent->render);
1189 // either fullbright or lit
1190 if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
1191 staticent->render.flags |= RENDER_LIGHT;
1192 // turn off shadows from transparent objects
1193 if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
1194 staticent->render.flags |= RENDER_SHADOW;
1197 Con_Printf("Too many static entities");
1199 // throw the entity away now
1203 //=================================================================//
1209 copies data from one entity to another
1211 copyentity(src, dst)
1214 static void VM_CL_copyentity (void)
1216 prvm_edict_t *in, *out;
1217 VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
1218 in = PRVM_G_EDICT(OFS_PARM0);
1219 if (in == prog->edicts)
1221 VM_Warning("copyentity: can not read world entity\n");
1224 if (in->priv.server->free)
1226 VM_Warning("copyentity: can not read free entity\n");
1229 out = PRVM_G_EDICT(OFS_PARM1);
1230 if (out == prog->edicts)
1232 VM_Warning("copyentity: can not modify world entity\n");
1235 if (out->priv.server->free)
1237 VM_Warning("copyentity: can not modify free entity\n");
1240 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1244 //=================================================================//
1246 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
1247 static void VM_CL_effect (void)
1249 VM_SAFEPARMCOUNT(5, VM_CL_effect);
1250 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));
1253 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
1254 static void VM_CL_te_blood (void)
1258 VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
1259 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1261 pos = PRVM_G_VECTOR(OFS_PARM0);
1262 CL_FindNonSolidLocation(pos, pos2, 4);
1263 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1266 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
1267 static void VM_CL_te_bloodshower (void)
1271 VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
1272 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1274 speed = PRVM_G_FLOAT(OFS_PARM2);
1281 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), vel1, vel2, NULL, 0);
1284 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
1285 static void VM_CL_te_explosionrgb (void)
1289 matrix4x4_t tempmatrix;
1290 VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
1291 pos = PRVM_G_VECTOR(OFS_PARM0);
1292 CL_FindNonSolidLocation(pos, pos2, 10);
1293 CL_ParticleExplosion(pos2);
1294 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1295 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);
1298 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
1299 static void VM_CL_te_particlecube (void)
1301 VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
1302 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));
1305 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
1306 static void VM_CL_te_particlerain (void)
1308 VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
1309 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);
1312 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
1313 static void VM_CL_te_particlesnow (void)
1315 VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
1316 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);
1319 // #411 void(vector org, vector vel, float howmany) te_spark
1320 static void VM_CL_te_spark (void)
1324 VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
1326 pos = PRVM_G_VECTOR(OFS_PARM0);
1327 CL_FindNonSolidLocation(pos, pos2, 4);
1328 CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1331 extern cvar_t cl_sound_ric_gunshot;
1332 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
1333 static void VM_CL_te_gunshotquad (void)
1338 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
1340 pos = PRVM_G_VECTOR(OFS_PARM0);
1341 CL_FindNonSolidLocation(pos, pos2, 4);
1342 CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1343 if(cl_sound_ric_gunshot.integer >= 2)
1345 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1349 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1350 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1351 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1356 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
1357 static void VM_CL_te_spikequad (void)
1362 VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
1364 pos = PRVM_G_VECTOR(OFS_PARM0);
1365 CL_FindNonSolidLocation(pos, pos2, 4);
1366 CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1367 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1371 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1372 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1373 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1377 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
1378 static void VM_CL_te_superspikequad (void)
1383 VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
1385 pos = PRVM_G_VECTOR(OFS_PARM0);
1386 CL_FindNonSolidLocation(pos, pos2, 4);
1387 CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1388 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1392 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1393 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1394 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1398 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
1399 static void VM_CL_te_explosionquad (void)
1403 VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
1405 pos = PRVM_G_VECTOR(OFS_PARM0);
1406 CL_FindNonSolidLocation(pos, pos2, 10);
1407 CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1408 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1411 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
1412 static void VM_CL_te_smallflash (void)
1416 VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
1418 pos = PRVM_G_VECTOR(OFS_PARM0);
1419 CL_FindNonSolidLocation(pos, pos2, 10);
1420 CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1423 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
1424 static void VM_CL_te_customflash (void)
1428 matrix4x4_t tempmatrix;
1429 VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
1431 pos = PRVM_G_VECTOR(OFS_PARM0);
1432 CL_FindNonSolidLocation(pos, pos2, 4);
1433 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1434 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);
1437 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
1438 static void VM_CL_te_gunshot (void)
1443 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
1445 pos = PRVM_G_VECTOR(OFS_PARM0);
1446 CL_FindNonSolidLocation(pos, pos2, 4);
1447 CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1448 if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
1450 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1454 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1455 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1456 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1461 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
1462 static void VM_CL_te_spike (void)
1467 VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
1469 pos = PRVM_G_VECTOR(OFS_PARM0);
1470 CL_FindNonSolidLocation(pos, pos2, 4);
1471 CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1472 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1476 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1477 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1478 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1482 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
1483 static void VM_CL_te_superspike (void)
1488 VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
1490 pos = PRVM_G_VECTOR(OFS_PARM0);
1491 CL_FindNonSolidLocation(pos, pos2, 4);
1492 CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1493 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1497 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1498 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1499 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1503 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
1504 static void VM_CL_te_explosion (void)
1508 VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
1510 pos = PRVM_G_VECTOR(OFS_PARM0);
1511 CL_FindNonSolidLocation(pos, pos2, 10);
1512 CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1513 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1516 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
1517 static void VM_CL_te_tarexplosion (void)
1521 VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
1523 pos = PRVM_G_VECTOR(OFS_PARM0);
1524 CL_FindNonSolidLocation(pos, pos2, 10);
1525 CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1526 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1529 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
1530 static void VM_CL_te_wizspike (void)
1534 VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
1536 pos = PRVM_G_VECTOR(OFS_PARM0);
1537 CL_FindNonSolidLocation(pos, pos2, 4);
1538 CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1539 S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
1542 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
1543 static void VM_CL_te_knightspike (void)
1547 VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
1549 pos = PRVM_G_VECTOR(OFS_PARM0);
1550 CL_FindNonSolidLocation(pos, pos2, 4);
1551 CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1552 S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
1555 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
1556 static void VM_CL_te_lavasplash (void)
1558 VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
1559 CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1562 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
1563 static void VM_CL_te_teleport (void)
1565 VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
1566 CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1569 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
1570 static void VM_CL_te_explosion2 (void)
1574 matrix4x4_t tempmatrix;
1575 int colorStart, colorLength;
1576 unsigned char *tempcolor;
1577 VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
1579 pos = PRVM_G_VECTOR(OFS_PARM0);
1580 colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
1581 colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
1582 CL_FindNonSolidLocation(pos, pos2, 10);
1583 CL_ParticleExplosion2(pos2, colorStart, colorLength);
1584 tempcolor = (unsigned char *)&palette_complete[(rand()%colorLength) + colorStart];
1585 color[0] = tempcolor[0] * (2.0f / 255.0f);
1586 color[1] = tempcolor[1] * (2.0f / 255.0f);
1587 color[2] = tempcolor[2] * (2.0f / 255.0f);
1588 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1589 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);
1590 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1594 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
1595 static void VM_CL_te_lightning1 (void)
1597 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
1598 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
1601 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
1602 static void VM_CL_te_lightning2 (void)
1604 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
1605 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
1608 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
1609 static void VM_CL_te_lightning3 (void)
1611 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
1612 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
1615 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
1616 static void VM_CL_te_beam (void)
1618 VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
1619 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
1622 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
1623 static void VM_CL_te_plasmaburn (void)
1627 VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
1629 pos = PRVM_G_VECTOR(OFS_PARM0);
1630 CL_FindNonSolidLocation(pos, pos2, 4);
1631 CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1634 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
1635 static void VM_CL_te_flamejet (void)
1639 VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
1640 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1642 pos = PRVM_G_VECTOR(OFS_PARM0);
1643 CL_FindNonSolidLocation(pos, pos2, 4);
1644 CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1648 //====================================================================
1651 extern void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
1653 static msurface_t *cl_getsurface(model_t *model, int surfacenum)
1655 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1657 return model->data_surfaces + surfacenum + model->firstmodelsurface;
1660 // #434 float(entity e, float s) getsurfacenumpoints
1661 static void VM_CL_getsurfacenumpoints(void)
1664 msurface_t *surface;
1665 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
1666 // return 0 if no such surface
1667 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1669 PRVM_G_FLOAT(OFS_RETURN) = 0;
1673 // note: this (incorrectly) assumes it is a simple polygon
1674 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1677 // #435 vector(entity e, float s, float n) getsurfacepoint
1678 static void VM_CL_getsurfacepoint(void)
1682 msurface_t *surface;
1684 VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1685 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1686 ed = PRVM_G_EDICT(OFS_PARM0);
1687 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1689 // note: this (incorrectly) assumes it is a simple polygon
1690 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1691 if (pointnum < 0 || pointnum >= surface->num_vertices)
1693 // FIXME: implement rotation/scaling
1694 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1697 // #436 vector(entity e, float s) getsurfacenormal
1698 static void VM_CL_getsurfacenormal(void)
1701 msurface_t *surface;
1703 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
1704 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1705 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1707 // FIXME: implement rotation/scaling
1708 // note: this (incorrectly) assumes it is a simple polygon
1709 // note: this only returns the first triangle, so it doesn't work very
1710 // well for curved surfaces or arbitrary meshes
1711 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);
1712 VectorNormalize(normal);
1713 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1716 // #437 string(entity e, float s) getsurfacetexture
1717 static void VM_CL_getsurfacetexture(void)
1720 msurface_t *surface;
1721 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
1722 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1723 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1725 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
1728 // #438 float(entity e, vector p) getsurfacenearpoint
1729 static void VM_CL_getsurfacenearpoint(void)
1731 int surfacenum, best;
1733 vec_t dist, bestdist;
1735 model_t *model = NULL;
1736 msurface_t *surface;
1738 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
1739 PRVM_G_FLOAT(OFS_RETURN) = -1;
1740 ed = PRVM_G_EDICT(OFS_PARM0);
1741 if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces)
1744 // FIXME: implement rotation/scaling
1745 point = PRVM_G_VECTOR(OFS_PARM1);
1746 VectorSubtract(point, ed->fields.client->origin, p);
1748 bestdist = 1000000000;
1749 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1751 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1752 // first see if the nearest point on the surface's box is closer than the previous match
1753 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1754 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1755 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1756 dist = VectorLength2(clipped);
1757 if (dist < bestdist)
1759 // it is, check the nearest point on the actual geometry
1760 clippointtosurface(model, surface, p, clipped);
1761 VectorSubtract(clipped, p, clipped);
1762 dist += VectorLength2(clipped);
1763 if (dist < bestdist)
1765 // that's closer too, store it as the best match
1771 PRVM_G_FLOAT(OFS_RETURN) = best;
1774 // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint
1775 static void VM_CL_getsurfaceclippedpoint(void)
1779 msurface_t *surface;
1781 VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
1782 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1783 ed = PRVM_G_EDICT(OFS_PARM0);
1784 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1786 // FIXME: implement rotation/scaling
1787 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
1788 clippointtosurface(model, surface, p, out);
1789 // FIXME: implement rotation/scaling
1790 VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1793 // #443 void(entity e, entity tagentity, string tagname) setattachment
1794 static void VM_CL_setattachment (void)
1797 prvm_edict_t *tagentity;
1798 const char *tagname;
1802 VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
1804 e = PRVM_G_EDICT(OFS_PARM0);
1805 tagentity = PRVM_G_EDICT(OFS_PARM1);
1806 tagname = PRVM_G_STRING(OFS_PARM2);
1808 if (e == prog->edicts)
1810 VM_Warning("setattachment: can not modify world entity\n");
1813 if (e->priv.server->free)
1815 VM_Warning("setattachment: can not modify free entity\n");
1819 if (tagentity == NULL)
1820 tagentity = prog->edicts;
1822 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
1824 v->edict = PRVM_EDICT_TO_PROG(tagentity);
1826 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
1829 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
1831 modelindex = (int)tagentity->fields.client->modelindex;
1832 model = CL_GetModelByIndex(modelindex);
1835 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
1837 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);
1840 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));
1844 /////////////////////////////////////////
1845 // DP_MD3_TAGINFO extension coded by VorteX
1847 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
1849 model_t *model = CL_GetModelFromEdict(e);
1851 return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
1856 // Warnings/errors code:
1857 // 0 - normal (everything all-right)
1860 // 3 - null or non-precached model
1861 // 4 - no tags with requested index
1862 // 5 - runaway loop at attachment chain
1863 extern cvar_t cl_bob;
1864 extern cvar_t cl_bobcycle;
1865 extern cvar_t cl_bobup;
1866 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
1869 int reqframe, attachloop;
1870 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
1871 prvm_edict_t *attachent;
1874 *out = identitymatrix; // warnings and errors return identical matrix
1876 if (ent == prog->edicts)
1878 if (ent->priv.server->free)
1881 model = CL_GetModelFromEdict(ent);
1886 if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
1887 reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
1889 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
1891 // get initial tag matrix
1894 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
1899 tagmatrix = identitymatrix;
1901 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
1902 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
1906 attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
1907 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
1909 model = CL_GetModelFromEdict(attachent);
1911 if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
1912 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
1914 attachmatrix = identitymatrix;
1916 // apply transformation by child entity matrix
1917 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1918 if (val->_float == 0)
1920 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);
1921 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1922 Matrix4x4_Copy(&tagmatrix, out);
1924 // finally transformate by matrix of tag on parent entity
1925 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
1926 Matrix4x4_Copy(&tagmatrix, out);
1930 if (attachloop > 255) // prevent runaway looping
1933 while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
1936 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
1937 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1938 if (val->_float == 0)
1940 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
1941 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);
1942 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1944 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
1945 {// RENDER_VIEWMODEL magic
1946 Matrix4x4_Copy(&tagmatrix, out);
1948 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1949 if (val->_float == 0)
1952 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, cl.csqc_origin[0], cl.csqc_origin[1], cl.csqc_origin[2], cl.csqc_angles[0], cl.csqc_angles[1], cl.csqc_angles[2], val->_float);
1953 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1956 // Cl_bob, ported from rendering code
1957 if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
1960 // LordHavoc: this code is *weird*, but not replacable (I think it
1961 // should be done in QC on the server, but oh well, quake is quake)
1962 // LordHavoc: figured out bobup: the time at which the sin is at 180
1963 // degrees (which allows lengthening or squishing the peak or valley)
1964 cycle = cl.time/cl_bobcycle.value;
1965 cycle -= (int)cycle;
1966 if (cycle < cl_bobup.value)
1967 cycle = sin(M_PI * cycle / cl_bobup.value);
1969 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
1970 // bob is proportional to velocity in the xy plane
1971 // (don't count Z, or jumping messes it up)
1972 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;
1973 bob = bob*0.3 + bob*0.7*cycle;
1974 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
1981 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
1982 static void VM_CL_gettagindex (void)
1985 const char *tag_name;
1986 int modelindex, tag_index;
1988 VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
1990 ent = PRVM_G_EDICT(OFS_PARM0);
1991 tag_name = PRVM_G_STRING(OFS_PARM1);
1992 if (ent == prog->edicts)
1994 VM_Warning("gettagindex: can't affect world entity\n");
1997 if (ent->priv.server->free)
1999 VM_Warning("gettagindex: can't affect free entity\n");
2003 modelindex = (int)ent->fields.client->modelindex;
2005 modelindex = -(modelindex+1);
2007 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2008 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2011 tag_index = CL_GetTagIndex(ent, tag_name);
2013 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2015 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2018 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2019 static void VM_CL_gettaginfo (void)
2023 matrix4x4_t tag_matrix;
2026 VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2028 e = PRVM_G_EDICT(OFS_PARM0);
2029 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2030 returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2031 Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2036 VM_Warning("gettagindex: can't affect world entity\n");
2039 VM_Warning("gettagindex: can't affect free entity\n");
2042 Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2045 Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2048 Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2053 //============================================================================
2055 //====================
2056 //QC POLYGON functions
2057 //====================
2062 float data[36]; //[515]: enough for polygons
2063 unsigned char flags; //[515]: + VM_POLYGON_2D and VM_POLYGON_FL4V flags
2066 //static float vm_polygon_linewidth = 1;
2067 static mempool_t *vm_polygons_pool = NULL;
2068 static unsigned char vm_current_vertices = 0;
2069 static qboolean vm_polygons_initialized = false;
2070 static vm_polygon_t *vm_polygons = NULL;
2071 static unsigned long vm_polygons_num = 0, vm_drawpolygons_num = 0; //[515]: ok long on 64bit ?
2072 static qboolean vm_polygonbegin = false; //[515]: for "no-crap-on-the-screen" check
2073 #define VM_DEFPOLYNUM 64 //[515]: enough for default ?
2075 #define VM_POLYGON_FL3V 16 //more than 2 vertices (used only for lines)
2076 #define VM_POLYGON_FLLINES 32
2077 #define VM_POLYGON_FL2D 64
2078 #define VM_POLYGON_FL4V 128 //4 vertices
2080 static void VM_InitPolygons (void)
2082 vm_polygons_pool = Mem_AllocPool("VMPOLY", 0, NULL);
2083 vm_polygons = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2084 memset(vm_polygons, 0, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2085 vm_polygons_num = VM_DEFPOLYNUM;
2086 vm_drawpolygons_num = 0;
2087 vm_polygonbegin = false;
2088 vm_polygons_initialized = true;
2091 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2093 int surfacelistindex;
2094 // LordHavoc: FIXME: this is stupid code
2095 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2097 const vm_polygon_t *p = &vm_polygons[surfacelist[surfacelistindex]];
2098 int flags = p->flags & 0x0f;
2100 if(flags == DRAWFLAG_ADDITIVE)
2101 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2102 else if(flags == DRAWFLAG_MODULATE)
2103 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2104 else if(flags == DRAWFLAG_2XMODULATE)
2105 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2107 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2109 R_Mesh_TexBind(0, R_GetTexture(p->tex));
2112 //[515]: is speed is max ?
2113 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2115 qglLineWidth(p->data[13]);CHECKGLERROR
2116 qglBegin(GL_LINE_LOOP);
2117 qglTexCoord1f (p->data[12]);
2118 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2119 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2121 qglTexCoord1f (p->data[14]);
2122 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2123 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2125 if(p->flags & VM_POLYGON_FL3V)
2127 qglTexCoord1f (p->data[16]);
2128 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2129 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2131 if(p->flags & VM_POLYGON_FL4V)
2133 qglTexCoord1f (p->data[18]);
2134 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2135 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2143 qglBegin(GL_POLYGON);
2144 qglTexCoord2f (p->data[12], p->data[13]);
2145 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2146 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2148 qglTexCoord2f (p->data[14], p->data[15]);
2149 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2150 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2152 qglTexCoord2f (p->data[16], p->data[17]);
2153 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2154 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2156 if(p->flags & VM_POLYGON_FL4V)
2158 qglTexCoord2f (p->data[18], p->data[19]);
2159 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2160 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2168 static void VM_CL_AddPolygonTo2DScene (vm_polygon_t *p)
2170 drawqueuemesh_t mesh;
2171 static int picelements[6] = {0, 1, 2, 0, 2, 3};
2173 mesh.texture = p->tex;
2174 mesh.data_element3i = picelements;
2175 mesh.data_vertex3f = p->data;
2176 mesh.data_texcoord2f = p->data + 12;
2177 mesh.data_color4f = p->data + 20;
2178 if(p->flags & VM_POLYGON_FL4V)
2180 mesh.num_vertices = 4;
2181 mesh.num_triangles = 2;
2185 mesh.num_vertices = 3;
2186 mesh.num_triangles = 1;
2188 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2189 DrawQ_LineLoop (&mesh, (p->flags&0x0f));
2191 DrawQ_Mesh (&mesh, (p->flags&0x0f));
2194 void VM_CL_AddPolygonsToMeshQueue (void)
2197 if(!vm_drawpolygons_num)
2199 R_Mesh_Matrix(&identitymatrix);
2200 GL_CullFace(GL_NONE);
2201 for(i = 0;i < (int)vm_drawpolygons_num;i++)
2202 VM_DrawPolygonCallback(NULL, NULL, 1, &i);
2203 vm_drawpolygons_num = 0;
2206 //void(string texturename, float flag[, float 2d[, float lines]]) R_BeginPolygon
2207 static void VM_CL_R_PolygonBegin (void)
2210 const char *picname;
2211 VM_SAFEPARMCOUNTRANGE(2, 4, VM_CL_R_PolygonBegin);
2213 if(!vm_polygons_initialized)
2217 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonEnd after first\n");
2220 if(vm_drawpolygons_num >= vm_polygons_num)
2222 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2223 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2224 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2225 Mem_Free(vm_polygons);
2227 vm_polygons_num *= 2;
2229 p = &vm_polygons[vm_drawpolygons_num];
2230 picname = PRVM_G_STRING(OFS_PARM0);
2232 p->tex = Draw_CachePic(picname, true)->tex;
2234 p->tex = r_texture_white;
2235 p->flags = (unsigned char)PRVM_G_FLOAT(OFS_PARM1);
2236 vm_current_vertices = 0;
2237 vm_polygonbegin = true;
2240 if(PRVM_G_FLOAT(OFS_PARM2))
2241 p->flags |= VM_POLYGON_FL2D;
2242 if(prog->argc >= 4 && PRVM_G_FLOAT(OFS_PARM3))
2244 p->data[13] = PRVM_G_FLOAT(OFS_PARM3); //[515]: linewidth
2245 p->flags |= VM_POLYGON_FLLINES;
2250 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2251 static void VM_CL_R_PolygonVertex (void)
2253 float *coords, *tx, *rgb, alpha;
2255 VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2257 if(!vm_polygonbegin)
2259 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2262 coords = PRVM_G_VECTOR(OFS_PARM0);
2263 tx = PRVM_G_VECTOR(OFS_PARM1);
2264 rgb = PRVM_G_VECTOR(OFS_PARM2);
2265 alpha = PRVM_G_FLOAT(OFS_PARM3);
2267 p = &vm_polygons[vm_drawpolygons_num];
2268 if(vm_current_vertices > 4)
2270 VM_Warning("VM_CL_R_PolygonVertex: may have 4 vertices max\n");
2274 p->data[vm_current_vertices*3] = coords[0];
2275 p->data[1+vm_current_vertices*3] = coords[1];
2276 p->data[2+vm_current_vertices*3] = coords[2];
2278 p->data[12+vm_current_vertices*2] = tx[0];
2279 if(!(p->flags & VM_POLYGON_FLLINES))
2280 p->data[13+vm_current_vertices*2] = tx[1];
2282 p->data[20+vm_current_vertices*4] = rgb[0];
2283 p->data[21+vm_current_vertices*4] = rgb[1];
2284 p->data[22+vm_current_vertices*4] = rgb[2];
2285 p->data[23+vm_current_vertices*4] = alpha;
2287 vm_current_vertices++;
2288 if(vm_current_vertices == 4)
2289 p->flags |= VM_POLYGON_FL4V;
2291 if(vm_current_vertices == 3)
2292 p->flags |= VM_POLYGON_FL3V;
2295 //void() R_EndPolygon
2296 static void VM_CL_R_PolygonEnd (void)
2298 VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2299 if(!vm_polygonbegin)
2301 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2304 vm_polygonbegin = false;
2305 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2307 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2308 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2310 vm_drawpolygons_num++;
2313 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2316 void Debug_PolygonBegin(const char *picname, int flags, qboolean draw2d, float linewidth)
2320 if(!vm_polygons_initialized)
2324 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2327 // limit polygons to a vaguely sane amount, beyond this each one just
2328 // replaces the last one
2329 vm_drawpolygons_num = min(vm_drawpolygons_num, (1<<20)-1);
2330 if(vm_drawpolygons_num >= vm_polygons_num)
2332 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2333 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2334 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2335 Mem_Free(vm_polygons);
2337 vm_polygons_num *= 2;
2339 p = &vm_polygons[vm_drawpolygons_num];
2340 if(picname && picname[0])
2341 p->tex = Draw_CachePic(picname, true)->tex;
2343 p->tex = r_texture_white;
2345 vm_current_vertices = 0;
2346 vm_polygonbegin = true;
2348 p->flags |= VM_POLYGON_FL2D;
2351 p->data[13] = linewidth; //[515]: linewidth
2352 p->flags |= VM_POLYGON_FLLINES;
2356 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2360 if(!vm_polygonbegin)
2362 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2366 p = &vm_polygons[vm_drawpolygons_num];
2367 if(vm_current_vertices > 4)
2369 Con_Printf("Debug_PolygonVertex: may have 4 vertices max\n");
2373 p->data[vm_current_vertices*3] = x;
2374 p->data[1+vm_current_vertices*3] = y;
2375 p->data[2+vm_current_vertices*3] = z;
2377 p->data[12+vm_current_vertices*2] = s;
2378 if(!(p->flags & VM_POLYGON_FLLINES))
2379 p->data[13+vm_current_vertices*2] = t;
2381 p->data[20+vm_current_vertices*4] = r;
2382 p->data[21+vm_current_vertices*4] = g;
2383 p->data[22+vm_current_vertices*4] = b;
2384 p->data[23+vm_current_vertices*4] = a;
2386 vm_current_vertices++;
2387 if(vm_current_vertices == 4)
2388 p->flags |= VM_POLYGON_FL4V;
2390 if(vm_current_vertices == 3)
2391 p->flags |= VM_POLYGON_FL3V;
2394 void Debug_PolygonEnd(void)
2396 if(!vm_polygonbegin)
2398 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2401 vm_polygonbegin = false;
2402 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2404 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2405 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2407 vm_drawpolygons_num++;
2410 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2417 Returns false if any part of the bottom of the entity is off an edge that
2422 qboolean CL_CheckBottom (prvm_edict_t *ent)
2424 vec3_t mins, maxs, start, stop;
2429 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2430 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2432 // if all of the points under the corners are solid world, don't bother
2433 // with the tougher checks
2434 // the corners must be within 16 of the midpoint
2435 start[2] = mins[2] - 1;
2436 for (x=0 ; x<=1 ; x++)
2437 for (y=0 ; y<=1 ; y++)
2439 start[0] = x ? maxs[0] : mins[0];
2440 start[1] = y ? maxs[1] : mins[1];
2441 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2445 return true; // we got out easy
2449 // check it for real...
2453 // the midpoint must be within 16 of the bottom
2454 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2455 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2456 stop[2] = start[2] - 2*sv_stepheight.value;
2457 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2459 if (trace.fraction == 1.0)
2461 mid = bottom = trace.endpos[2];
2463 // the corners must be within 16 of the midpoint
2464 for (x=0 ; x<=1 ; x++)
2465 for (y=0 ; y<=1 ; y++)
2467 start[0] = stop[0] = x ? maxs[0] : mins[0];
2468 start[1] = stop[1] = y ? maxs[1] : mins[1];
2470 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2472 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2473 bottom = trace.endpos[2];
2474 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2485 Called by monster program code.
2486 The move will be adjusted for slopes and stairs, but if the move isn't
2487 possible, no move is done and false is returned
2490 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2493 vec3_t oldorg, neworg, end, traceendpos;
2496 prvm_edict_t *enemy;
2500 VectorCopy (ent->fields.client->origin, oldorg);
2501 VectorAdd (ent->fields.client->origin, move, neworg);
2503 // flying monsters don't step up
2504 if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2506 // try one move with vertical motion, then one without
2507 for (i=0 ; i<2 ; i++)
2509 VectorAdd (ent->fields.client->origin, move, neworg);
2510 enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2511 if (i == 0 && enemy != prog->edicts)
2513 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2519 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);
2521 VM_SetTraceGlobals(&trace);
2523 if (trace.fraction == 1)
2525 VectorCopy(trace.endpos, traceendpos);
2526 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2527 return false; // swim monster left water
2529 VectorCopy (traceendpos, ent->fields.client->origin);
2535 if (enemy == prog->edicts)
2542 // push down from a step height above the wished position
2543 neworg[2] += sv_stepheight.value;
2544 VectorCopy (neworg, end);
2545 end[2] -= sv_stepheight.value*2;
2547 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2549 VM_SetTraceGlobals(&trace);
2551 if (trace.startsolid)
2553 neworg[2] -= sv_stepheight.value;
2554 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2556 VM_SetTraceGlobals(&trace);
2557 if (trace.startsolid)
2560 if (trace.fraction == 1)
2562 // if monster had the ground pulled out, go ahead and fall
2563 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2565 VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2568 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2572 return false; // walked off an edge
2575 // check point traces down for dangling corners
2576 VectorCopy (trace.endpos, ent->fields.client->origin);
2578 if (!CL_CheckBottom (ent))
2580 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2581 { // entity had floor mostly pulled out from underneath it
2582 // and is trying to correct
2587 VectorCopy (oldorg, ent->fields.client->origin);
2591 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2592 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2594 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2595 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2607 float(float yaw, float dist[, settrace]) walkmove
2610 static void VM_CL_walkmove (void)
2619 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2621 // assume failure if it returns early
2622 PRVM_G_FLOAT(OFS_RETURN) = 0;
2624 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2625 if (ent == prog->edicts)
2627 VM_Warning("walkmove: can not modify world entity\n");
2630 if (ent->priv.server->free)
2632 VM_Warning("walkmove: can not modify free entity\n");
2635 yaw = PRVM_G_FLOAT(OFS_PARM0);
2636 dist = PRVM_G_FLOAT(OFS_PARM1);
2637 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2639 if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2642 yaw = yaw*M_PI*2 / 360;
2644 move[0] = cos(yaw)*dist;
2645 move[1] = sin(yaw)*dist;
2648 // save program state, because CL_movestep may call other progs
2649 oldf = prog->xfunction;
2650 oldself = prog->globals.client->self;
2652 PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2655 // restore program state
2656 prog->xfunction = oldf;
2657 prog->globals.client->self = oldself;
2664 string(string key) serverkey
2667 void VM_CL_serverkey(void)
2669 char string[VM_STRINGTEMP_LENGTH];
2670 VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2671 InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2672 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2675 //============================================================================
2677 prvm_builtin_t vm_cl_builtins[] = {
2678 NULL, // #0 NULL function (not callable) (QUAKE)
2679 VM_CL_makevectors, // #1 void(vector ang) makevectors (QUAKE)
2680 VM_CL_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
2681 VM_CL_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
2682 VM_CL_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2683 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2684 VM_break, // #6 void() break (QUAKE)
2685 VM_random, // #7 float() random (QUAKE)
2686 VM_CL_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
2687 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
2688 VM_error, // #10 void(string e) error (QUAKE)
2689 VM_objerror, // #11 void(string e) objerror (QUAKE)
2690 VM_vlen, // #12 float(vector v) vlen (QUAKE)
2691 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
2692 VM_CL_spawn, // #14 entity() spawn (QUAKE)
2693 VM_remove, // #15 void(entity e) remove (QUAKE)
2694 VM_CL_traceline, // #16 float(vector v1, vector v2, float tryents) traceline (QUAKE)
2695 NULL, // #17 entity() checkclient (QUAKE)
2696 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
2697 VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
2698 VM_CL_precache_model, // #20 void(string s) precache_model (QUAKE)
2699 NULL, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2700 VM_CL_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
2701 NULL, // #23 void(string s, ...) bprint (QUAKE)
2702 NULL, // #24 void(entity client, string s, ...) sprint (QUAKE)
2703 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
2704 VM_ftos, // #26 string(float f) ftos (QUAKE)
2705 VM_vtos, // #27 string(vector v) vtos (QUAKE)
2706 VM_coredump, // #28 void() coredump (QUAKE)
2707 VM_traceon, // #29 void() traceon (QUAKE)
2708 VM_traceoff, // #30 void() traceoff (QUAKE)
2709 VM_eprint, // #31 void(entity e) eprint (QUAKE)
2710 VM_CL_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
2711 NULL, // #33 (QUAKE)
2712 VM_CL_droptofloor, // #34 float() droptofloor (QUAKE)
2713 VM_CL_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
2714 VM_rint, // #36 float(float v) rint (QUAKE)
2715 VM_floor, // #37 float(float v) floor (QUAKE)
2716 VM_ceil, // #38 float(float v) ceil (QUAKE)
2717 NULL, // #39 (QUAKE)
2718 VM_CL_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
2719 VM_CL_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
2720 NULL, // #42 (QUAKE)
2721 VM_fabs, // #43 float(float f) fabs (QUAKE)
2722 NULL, // #44 vector(entity e, float speed) aim (QUAKE)
2723 VM_cvar, // #45 float(string s) cvar (QUAKE)
2724 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
2725 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
2726 VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2727 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
2728 NULL, // #50 (QUAKE)
2729 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
2730 NULL, // #52 void(float to, float f) WriteByte (QUAKE)
2731 NULL, // #53 void(float to, float f) WriteChar (QUAKE)
2732 NULL, // #54 void(float to, float f) WriteShort (QUAKE)
2733 NULL, // #55 void(float to, float f) WriteLong (QUAKE)
2734 NULL, // #56 void(float to, float f) WriteCoord (QUAKE)
2735 NULL, // #57 void(float to, float f) WriteAngle (QUAKE)
2736 NULL, // #58 void(float to, string s) WriteString (QUAKE)
2737 NULL, // #59 (QUAKE)
2738 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2739 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2740 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2741 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2742 VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2743 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2744 NULL, // #66 (QUAKE)
2745 NULL, // #67 void(float step) movetogoal (QUAKE)
2746 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
2747 VM_CL_makestatic, // #69 void(entity e) makestatic (QUAKE)
2748 NULL, // #70 void(string s) changelevel (QUAKE)
2749 NULL, // #71 (QUAKE)
2750 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
2751 NULL, // #73 void(entity client, strings) centerprint (QUAKE)
2752 VM_CL_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2753 VM_CL_precache_model, // #75 string(string s) precache_model2 (QUAKE)
2754 VM_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
2755 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
2756 NULL, // #78 void(entity e) setspawnparms (QUAKE)
2757 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
2758 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
2759 VM_stof, // #81 float(string s) stof (FRIK_FILE)
2760 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
2761 NULL, // #83 (QUAKE)
2762 NULL, // #84 (QUAKE)
2763 NULL, // #85 (QUAKE)
2764 NULL, // #86 (QUAKE)
2765 NULL, // #87 (QUAKE)
2766 NULL, // #88 (QUAKE)
2767 NULL, // #89 (QUAKE)
2768 VM_CL_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2769 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2770 VM_CL_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2771 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2772 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2773 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2774 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2775 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2776 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2777 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
2778 // FrikaC and Telejano range #100-#199
2789 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
2790 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
2791 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
2792 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2793 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
2794 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
2795 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
2796 VM_stov, // #117 vector(string) stov (FRIK_FILE)
2797 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
2798 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
2879 // FTEQW range #200-#299
2898 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
2902 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
2903 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
2908 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
2912 NULL, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
2980 // CSQC range #300-#399
2981 VM_CL_R_ClearScene, // #300 void() clearscene (EXT_CSQC)
2982 VM_CL_R_AddEntities, // #301 void(float mask) addentities (EXT_CSQC)
2983 VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC)
2984 VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC)
2985 VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC)
2986 VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
2987 VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
2988 VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2989 VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon
2991 VM_CL_unproject, // #310 vector (vector v) cs_unproject (EXT_CSQC)
2992 VM_CL_project, // #311 vector (vector v) cs_project (EXT_CSQC)
2996 VM_drawline, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
2997 VM_iscachedpic, // #316 float(string name) iscachedpic (EXT_CSQC)
2998 VM_precache_pic, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
2999 VM_getimagesize, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3000 VM_freepic, // #319 void(string name) freepic (EXT_CSQC)
3001 VM_drawcharacter, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3002 VM_drawstring, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3003 VM_drawpic, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3004 VM_drawfill, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3005 VM_drawsetcliparea, // #324 void(float x, float y, float width, float height) drawsetcliparea
3006 VM_drawresetcliparea, // #325 void(void) drawresetcliparea
3011 VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
3012 VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
3013 VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
3014 VM_CL_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3015 VM_CL_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3016 VM_CL_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3017 VM_CL_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3018 VM_CL_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3019 VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC)
3020 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3021 VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3022 VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3023 VM_CL_getkeybind, // #342 string(float keynum) getkeybind (EXT_CSQC)
3024 VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3025 VM_getmousepos, // #344 vector() getmousepos (EXT_CSQC)
3026 VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC)
3027 VM_CL_setsensitivityscale, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3028 VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC)
3029 VM_CL_getplayerkey, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3030 VM_CL_isdemo, // #349 float() isdemo (EXT_CSQC)
3031 VM_isserver, // #350 float() isserver (EXT_CSQC)
3032 VM_CL_setlistener, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3033 VM_CL_registercmd, // #352 void(string cmdname) registercommand (EXT_CSQC)
3034 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3035 VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3041 VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC)
3042 VM_CL_ReadChar, // #361 float() readchar (EXT_CSQC)
3043 VM_CL_ReadShort, // #362 float() readshort (EXT_CSQC)
3044 VM_CL_ReadLong, // #363 float() readlong (EXT_CSQC)
3045 VM_CL_ReadCoord, // #364 float() readcoord (EXT_CSQC)
3046 VM_CL_ReadAngle, // #365 float() readangle (EXT_CSQC)
3047 VM_CL_ReadString, // #366 string() readstring (EXT_CSQC)
3048 VM_CL_ReadFloat, // #367 float() readfloat (EXT_CSQC)
3081 // LordHavoc's range #400-#499
3082 VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3083 NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3084 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3085 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3086 VM_CL_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3087 VM_CL_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3088 VM_CL_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3089 VM_CL_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3090 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)
3091 VM_CL_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3092 VM_CL_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3093 VM_CL_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3094 VM_CL_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3095 VM_CL_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3096 VM_CL_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3097 VM_CL_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3098 VM_CL_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3099 VM_CL_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3100 VM_CL_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3101 VM_CL_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3102 VM_CL_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3103 VM_CL_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3104 VM_CL_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3105 VM_CL_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3106 VM_CL_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3107 VM_CL_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3108 VM_CL_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3109 VM_CL_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3110 VM_CL_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3111 VM_CL_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3112 VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3113 VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3114 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3115 VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3116 VM_CL_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3117 VM_CL_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3118 VM_CL_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3119 VM_CL_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3120 VM_CL_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3121 VM_CL_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3122 NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3123 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3124 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3125 VM_CL_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3126 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3127 VM_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3128 VM_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3129 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3130 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3131 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3132 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3133 VM_CL_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3134 VM_CL_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3135 NULL, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3136 NULL, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3137 NULL, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3138 NULL, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3139 VM_CL_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3141 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3142 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3143 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3144 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3145 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3146 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3147 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3148 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3149 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3150 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3151 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3152 NULL, // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3153 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3154 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3155 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3156 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3157 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3158 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3159 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3160 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3161 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3162 VM_strtolower, // #480 string(string s) VM_strtolower : DRESK - Return string as lowercase
3163 VM_strtoupper, // #481 string(string s) VM_strtoupper : DRESK - Return string as uppercase
3184 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3186 void VM_CL_Cmd_Init(void)
3188 // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3189 if(vm_polygons_initialized)
3191 Mem_FreePool(&vm_polygons_pool);
3192 vm_polygons_initialized = false;
3196 void VM_CL_Cmd_Reset(void)
3198 if(vm_polygons_initialized)
3200 Mem_FreePool(&vm_polygons_pool);
3201 vm_polygons_initialized = false;