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 matrix4x4_t csqc_listenermatrix;
608 qboolean csqc_usecsqclistener = false;//[515]: per-frame
610 static void CSQC_R_RecalcView (void)
612 extern matrix4x4_t viewmodelmatrix;
613 Matrix4x4_CreateFromQuakeEntity(&r_view.matrix, csqc_origin[0], csqc_origin[1], csqc_origin[2], csqc_angles[0], csqc_angles[1], csqc_angles[2], 1);
614 Matrix4x4_CreateFromQuakeEntity(&viewmodelmatrix, csqc_origin[0], csqc_origin[1], csqc_origin[2], csqc_angles[0], csqc_angles[1], csqc_angles[2], cl_viewmodel_scale.value);
617 void CL_RelinkLightFlashes(void);
618 //#300 void() clearscene (EXT_CSQC)
619 static void VM_CL_R_ClearScene (void)
621 VM_SAFEPARMCOUNT(0, VM_CL_R_ClearScene);
622 // clear renderable entity and light lists
623 r_refdef.numentities = 0;
624 r_refdef.numlights = 0;
627 //#301 void(float mask) addentities (EXT_CSQC)
628 extern void CSQC_Predraw (prvm_edict_t *ed);//csprogs.c
629 extern void CSQC_Think (prvm_edict_t *ed);//csprogs.c
630 static void VM_CL_R_AddEntities (void)
634 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntities);
635 drawmask = (int)PRVM_G_FLOAT(OFS_PARM0);
636 CSQC_RelinkAllEntities(drawmask);
637 CL_RelinkLightFlashes();
639 prog->globals.client->time = cl.time;
640 for(i=1;i<prog->num_edicts;i++)
642 ed = &prog->edicts[i];
643 if(ed->priv.required->free)
646 if(ed->priv.required->free)
648 // note that for RF_USEAXIS entities, Predraw sets v_forward/v_right/v_up globals that are read by CSQC_AddRenderEdict
650 if(ed->priv.required->free)
652 if(!((int)ed->fields.client->drawmask & drawmask))
654 CSQC_AddRenderEdict(ed);
658 //#302 void(entity ent) addentity (EXT_CSQC)
659 static void VM_CL_R_AddEntity (void)
661 VM_SAFEPARMCOUNT(1, VM_CL_R_AddEntity);
662 CSQC_AddRenderEdict(PRVM_G_EDICT(OFS_PARM0));
665 //#303 float(float property, ...) setproperty (EXT_CSQC)
666 static void VM_CL_R_SetView (void)
672 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_R_SetView);
674 c = (int)PRVM_G_FLOAT(OFS_PARM0);
675 f = PRVM_G_VECTOR(OFS_PARM1);
676 k = PRVM_G_FLOAT(OFS_PARM1);
680 case VF_MIN: r_view.x = (int)f[0];
681 r_view.y = (int)f[1];
683 case VF_MIN_X: r_view.x = (int)k;
685 case VF_MIN_Y: r_view.y = (int)k;
687 case VF_SIZE: r_view.width = (int)f[0];
688 r_view.height = (int)f[1];
690 case VF_SIZE_Y: r_view.width = (int)k;
692 case VF_SIZE_X: r_view.height = (int)k;
694 case VF_VIEWPORT: r_view.x = (int)f[0];
695 r_view.y = (int)f[1];
697 // TODO: make sure that view_z and view_depth are set properly even if csqc does not set them!
698 f = PRVM_G_VECTOR(OFS_PARM2);
699 r_view.width = (int)f[0];
700 r_view.height = (int)f[1];
703 case VF_FOV: //r_refdef.fov_x = f[0]; // FIXME!
704 //r_refdef.fov_y = f[1]; // FIXME!
706 case VF_FOVX: //r_refdef.fov_x = k; // FIXME!
708 case VF_FOVY: //r_refdef.fov_y = k; // FIXME!
710 case VF_ORIGIN: VectorCopy(f, csqc_origin);
713 case VF_ORIGIN_X: csqc_origin[0] = k;
716 case VF_ORIGIN_Y: csqc_origin[1] = k;
719 case VF_ORIGIN_Z: csqc_origin[2] = k;
722 case VF_ANGLES: VectorCopy(f, csqc_angles);
725 case VF_ANGLES_X: csqc_angles[0] = k;
728 case VF_ANGLES_Y: csqc_angles[1] = k;
731 case VF_ANGLES_Z: csqc_angles[2] = k;
734 case VF_DRAWWORLD: cl.csqc_vidvars.drawworld = k;
736 case VF_DRAWENGINESBAR: cl.csqc_vidvars.drawenginesbar = k;
738 case VF_DRAWCROSSHAIR: cl.csqc_vidvars.drawcrosshair = k;
741 case VF_CL_VIEWANGLES: VectorCopy(f, cl.viewangles);
743 case VF_CL_VIEWANGLES_X:cl.viewangles[0] = k;
745 case VF_CL_VIEWANGLES_Y:cl.viewangles[1] = k;
747 case VF_CL_VIEWANGLES_Z:cl.viewangles[2] = k;
750 default: PRVM_G_FLOAT(OFS_RETURN) = 0;
751 VM_Warning("VM_CL_R_SetView : unknown parm %i\n", c);
754 PRVM_G_FLOAT(OFS_RETURN) = 1;
757 //#304 void() renderscene (EXT_CSQC)
758 static void VM_CL_R_RenderScene (void)
760 VM_SAFEPARMCOUNT(0, VM_CL_R_RenderScene);
761 // we need to update any RENDER_VIEWMODEL entities at this point because
762 // csqc supplies its own view matrix
763 CL_UpdateViewEntities();
768 //#305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
769 static void VM_CL_R_AddDynamicLight (void)
773 VM_SAFEPARMCOUNTRANGE(3, 8, VM_CL_R_AddDynamicLight); // allow more than 3 because we may extend this in the future
775 // if we've run out of dlights, just return
776 if (r_refdef.numlights >= MAX_DLIGHTS)
779 pos = PRVM_G_VECTOR(OFS_PARM0);
780 col = PRVM_G_VECTOR(OFS_PARM2);
781 Matrix4x4_CreateFromQuakeEntity(&matrix, pos[0], pos[1], pos[2], 0, 0, 0, PRVM_G_FLOAT(OFS_PARM1));
782 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);
785 //============================================================================
787 //#310 vector (vector v) cs_unproject (EXT_CSQC)
788 static void VM_CL_unproject (void)
793 VM_SAFEPARMCOUNT(1, VM_CL_unproject);
794 f = PRVM_G_VECTOR(OFS_PARM0);
795 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);
796 Matrix4x4_Transform(&r_view.matrix, temp, PRVM_G_VECTOR(OFS_RETURN));
799 //#311 vector (vector v) cs_project (EXT_CSQC)
800 static void VM_CL_project (void)
806 VM_SAFEPARMCOUNT(1, VM_CL_project);
807 f = PRVM_G_VECTOR(OFS_PARM0);
808 Matrix4x4_Invert_Simple(&m, &r_view.matrix);
809 Matrix4x4_Transform(&m, f, v);
810 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]);
813 //#330 float(float stnum) getstatf (EXT_CSQC)
814 static void VM_CL_getstatf (void)
822 VM_SAFEPARMCOUNT(1, VM_CL_getstatf);
823 i = (int)PRVM_G_FLOAT(OFS_PARM0);
824 if(i < 0 || i >= MAX_CL_STATS)
826 VM_Warning("VM_CL_getstatf: index>=MAX_CL_STATS or index<0\n");
830 PRVM_G_FLOAT(OFS_RETURN) = dat.f;
833 //#331 float(float stnum) getstati (EXT_CSQC)
834 static void VM_CL_getstati (void)
837 VM_SAFEPARMCOUNT(1, VM_CL_getstati);
838 index = (int)PRVM_G_FLOAT(OFS_PARM0);
840 if(index < 0 || index >= MAX_CL_STATS)
842 VM_Warning("VM_CL_getstati: index>=MAX_CL_STATS or index<0\n");
846 PRVM_G_FLOAT(OFS_RETURN) = i;
849 //#332 string(float firststnum) getstats (EXT_CSQC)
850 static void VM_CL_getstats (void)
854 VM_SAFEPARMCOUNT(1, VM_CL_getstats);
855 i = (int)PRVM_G_FLOAT(OFS_PARM0);
856 if(i < 0 || i > MAX_CL_STATS-4)
858 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
859 VM_Warning("VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
862 strlcpy(t, (char*)&cl.stats[i], sizeof(t));
863 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
866 //#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
867 static void VM_CL_setmodelindex (void)
871 struct model_s *model;
873 VM_SAFEPARMCOUNT(2, VM_CL_setmodelindex);
875 t = PRVM_G_EDICT(OFS_PARM0);
877 i = (int)PRVM_G_FLOAT(OFS_PARM1);
879 t->fields.client->model = 0;
880 t->fields.client->modelindex = 0;
885 model = CL_GetModelByIndex(i);
888 VM_Warning("VM_CL_setmodelindex: null model\n");
891 t->fields.client->model = PRVM_SetEngineString(model->name);
892 t->fields.client->modelindex = i;
895 //#334 string(float mdlindex) modelnameforindex (EXT_CSQC)
896 static void VM_CL_modelnameforindex (void)
900 VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
902 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
903 model = CL_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
904 PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(model->name) : 0;
907 //#335 float(string effectname) particleeffectnum (EXT_CSQC)
908 static void VM_CL_particleeffectnum (void)
911 VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
912 i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
915 PRVM_G_FLOAT(OFS_RETURN) = i;
918 // #336 void(entity ent, float effectnum, vector start, vector end[, float color]) trailparticles (EXT_CSQC)
919 static void VM_CL_trailparticles (void)
924 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_trailparticles);
926 t = PRVM_G_EDICT(OFS_PARM0);
927 i = (int)PRVM_G_FLOAT(OFS_PARM1);
928 start = PRVM_G_VECTOR(OFS_PARM2);
929 end = PRVM_G_VECTOR(OFS_PARM3);
931 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);
934 //#337 void(float effectnum, vector origin, vector dir, float count[, float color]) pointparticles (EXT_CSQC)
935 static void VM_CL_pointparticles (void)
939 VM_SAFEPARMCOUNTRANGE(4, 5, VM_CL_pointparticles);
940 i = (int)PRVM_G_FLOAT(OFS_PARM0);
941 f = PRVM_G_VECTOR(OFS_PARM1);
942 v = PRVM_G_VECTOR(OFS_PARM2);
943 n = (int)PRVM_G_FLOAT(OFS_PARM3);
944 CL_ParticleEffect(i, n, f, f, v, v, NULL, prog->argc >= 5 ? (int)PRVM_G_FLOAT(OFS_PARM4) : 0);
947 //#342 string(float keynum) getkeybind (EXT_CSQC)
948 static void VM_CL_getkeybind (void)
950 VM_SAFEPARMCOUNT(1, VM_CL_getkeybind);
951 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0)));
954 //#343 void(float usecursor) setcursormode (EXT_CSQC)
955 static void VM_CL_setcursormode (void)
957 VM_SAFEPARMCOUNT(1, VM_CL_setcursormode);
958 cl.csqc_wantsmousemove = PRVM_G_FLOAT(OFS_PARM0);
959 cl_ignoremousemove = true;
962 //#345 float(float framenum) getinputstate (EXT_CSQC)
963 static void VM_CL_getinputstate (void)
966 VM_SAFEPARMCOUNT(1, VM_CL_getinputstate);
967 frame = (int)PRVM_G_FLOAT(OFS_PARM0);
968 for (i = 0;i < cl.movement_numqueue;i++)
969 if (cl.movement_queue[i].sequence == frame)
971 VectorCopy(cl.movement_queue[i].viewangles, prog->globals.client->input_angles);
972 //prog->globals.client->input_buttons = cl.movement_queue[i].//FIXME
973 VectorCopy(cl.movement_queue[i].move, prog->globals.client->input_movevalues);
974 prog->globals.client->input_timelength = cl.movement_queue[i].frametime;
975 if(cl.movement_queue[i].crouch)
977 VectorCopy(cl.playercrouchmins, prog->globals.client->pmove_mins);
978 VectorCopy(cl.playercrouchmaxs, prog->globals.client->pmove_maxs);
982 VectorCopy(cl.playerstandmins, prog->globals.client->pmove_mins);
983 VectorCopy(cl.playerstandmaxs, prog->globals.client->pmove_maxs);
988 //#346 void(float sens) setsensitivityscaler (EXT_CSQC)
989 static void VM_CL_setsensitivityscale (void)
991 VM_SAFEPARMCOUNT(1, VM_CL_setsensitivityscale);
992 cl.sensitivityscale = PRVM_G_FLOAT(OFS_PARM0);
995 //#347 void() runstandardplayerphysics (EXT_CSQC)
996 static void VM_CL_runplayerphysics (void)
1000 //#348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
1001 static void VM_CL_getplayerkey (void)
1007 VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
1009 i = (int)PRVM_G_FLOAT(OFS_PARM0);
1010 c = PRVM_G_STRING(OFS_PARM1);
1011 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1014 i = Sbar_GetPlayer(i);
1020 if(!strcasecmp(c, "name"))
1021 strlcpy(t, cl.scores[i].name, sizeof(t));
1023 if(!strcasecmp(c, "frags"))
1024 sprintf(t, "%i", cl.scores[i].frags);
1026 if(!strcasecmp(c, "ping"))
1027 sprintf(t, "%i", cl.scores[i].qw_ping);
1029 if(!strcasecmp(c, "entertime"))
1030 sprintf(t, "%f", cl.scores[i].qw_entertime);
1032 if(!strcasecmp(c, "colors"))
1033 sprintf(t, "%i", cl.scores[i].colors);
1035 if(!strcasecmp(c, "topcolor"))
1036 sprintf(t, "%i", cl.scores[i].colors & 0xf0);
1038 if(!strcasecmp(c, "bottomcolor"))
1039 sprintf(t, "%i", (cl.scores[i].colors &15)<<4);
1041 if(!strcasecmp(c, "viewentity"))
1042 sprintf(t, "%i", i+1);
1045 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
1048 //#349 float() isdemo (EXT_CSQC)
1049 static void VM_CL_isdemo (void)
1051 VM_SAFEPARMCOUNT(0, VM_CL_isdemo);
1052 PRVM_G_FLOAT(OFS_RETURN) = cls.demoplayback;
1055 //#351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
1056 static void VM_CL_setlistener (void)
1058 VM_SAFEPARMCOUNT(4, VM_CL_setlistener);
1059 Matrix4x4_FromVectors(&csqc_listenermatrix, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), PRVM_G_VECTOR(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0));
1060 csqc_usecsqclistener = true; //use csqc listener at this frame
1063 //#352 void(string cmdname) registercommand (EXT_CSQC)
1064 static void VM_CL_registercmd (void)
1067 VM_SAFEPARMCOUNT(1, VM_CL_registercmd);
1068 if(!Cmd_Exists(PRVM_G_STRING(OFS_PARM0)))
1072 alloclen = strlen(PRVM_G_STRING(OFS_PARM0)) + 1;
1073 t = (char *)Z_Malloc(alloclen);
1074 memcpy(t, PRVM_G_STRING(OFS_PARM0), alloclen);
1075 Cmd_AddCommand(t, NULL, "console command created by QuakeC");
1078 Cmd_AddCommand(PRVM_G_STRING(OFS_PARM0), NULL, "console command created by QuakeC");
1082 //#360 float() readbyte (EXT_CSQC)
1083 static void VM_CL_ReadByte (void)
1085 VM_SAFEPARMCOUNT(0, VM_CL_ReadByte);
1086 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadByte();
1089 //#361 float() readchar (EXT_CSQC)
1090 static void VM_CL_ReadChar (void)
1092 VM_SAFEPARMCOUNT(0, VM_CL_ReadChar);
1093 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadChar();
1096 //#362 float() readshort (EXT_CSQC)
1097 static void VM_CL_ReadShort (void)
1099 VM_SAFEPARMCOUNT(0, VM_CL_ReadShort);
1100 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadShort();
1103 //#363 float() readlong (EXT_CSQC)
1104 static void VM_CL_ReadLong (void)
1106 VM_SAFEPARMCOUNT(0, VM_CL_ReadLong);
1107 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadLong();
1110 //#364 float() readcoord (EXT_CSQC)
1111 static void VM_CL_ReadCoord (void)
1113 VM_SAFEPARMCOUNT(0, VM_CL_ReadCoord);
1114 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadCoord(cls.protocol);
1117 //#365 float() readangle (EXT_CSQC)
1118 static void VM_CL_ReadAngle (void)
1120 VM_SAFEPARMCOUNT(0, VM_CL_ReadAngle);
1121 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadAngle(cls.protocol);
1124 //#366 string() readstring (EXT_CSQC)
1125 static void VM_CL_ReadString (void)
1127 VM_SAFEPARMCOUNT(0, VM_CL_ReadString);
1128 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_ReadString());
1131 //#367 float() readfloat (EXT_CSQC)
1132 static void VM_CL_ReadFloat (void)
1134 VM_SAFEPARMCOUNT(0, VM_CL_ReadFloat);
1135 PRVM_G_FLOAT(OFS_RETURN) = MSG_ReadFloat();
1138 //////////////////////////////////////////////////////////
1140 static void VM_CL_makestatic (void)
1144 VM_SAFEPARMCOUNT(1, VM_CL_makestatic);
1146 ent = PRVM_G_EDICT(OFS_PARM0);
1147 if (ent == prog->edicts)
1149 VM_Warning("makestatic: can not modify world entity\n");
1152 if (ent->priv.server->free)
1154 VM_Warning("makestatic: can not modify free entity\n");
1158 if (cl.num_static_entities < cl.max_static_entities)
1162 entity_t *staticent = &cl.static_entities[cl.num_static_entities++];
1164 // copy it to the current state
1165 staticent->render.model = CL_GetModelByIndex((int)ent->fields.client->modelindex);
1166 staticent->render.frame = staticent->render.frame1 = staticent->render.frame2 = (int)ent->fields.client->frame;
1167 staticent->render.framelerp = 0;
1168 // make torchs play out of sync
1169 staticent->render.frame1time = staticent->render.frame2time = lhrandom(-10, -1);
1170 staticent->render.colormap = (int)ent->fields.client->colormap; // no special coloring
1171 staticent->render.skinnum = (int)ent->fields.client->skin;
1172 staticent->render.effects = (int)ent->fields.client->effects;
1173 staticent->render.alpha = 1;
1174 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)) && val->_float) staticent->render.alpha = val->_float;
1175 staticent->render.scale = 1;
1176 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)) && val->_float) staticent->render.scale = val->_float;
1177 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod)) && VectorLength2(val->vector)) VectorCopy(val->vector, staticent->render.colormod);
1180 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && val->_float) renderflags = (int)val->_float;
1181 if (renderflags & RF_USEAXIS)
1184 VectorNegate(prog->globals.client->v_right, left);
1185 Matrix4x4_FromVectors(&staticent->render.matrix, prog->globals.client->v_forward, left, prog->globals.client->v_up, ent->fields.client->origin);
1186 Matrix4x4_Scale(&staticent->render.matrix, staticent->render.scale, 1);
1189 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);
1190 CL_UpdateRenderEntity(&staticent->render);
1192 // either fullbright or lit
1193 if (!(staticent->render.effects & EF_FULLBRIGHT) && !r_fullbright.integer)
1194 staticent->render.flags |= RENDER_LIGHT;
1195 // turn off shadows from transparent objects
1196 if (!(staticent->render.effects & (EF_NOSHADOW | EF_ADDITIVE | EF_NODEPTHTEST)) && (staticent->render.alpha >= 1))
1197 staticent->render.flags |= RENDER_SHADOW;
1200 Con_Printf("Too many static entities");
1202 // throw the entity away now
1206 //=================================================================//
1212 copies data from one entity to another
1214 copyentity(src, dst)
1217 static void VM_CL_copyentity (void)
1219 prvm_edict_t *in, *out;
1220 VM_SAFEPARMCOUNT(2, VM_CL_copyentity);
1221 in = PRVM_G_EDICT(OFS_PARM0);
1222 if (in == prog->edicts)
1224 VM_Warning("copyentity: can not read world entity\n");
1227 if (in->priv.server->free)
1229 VM_Warning("copyentity: can not read free entity\n");
1232 out = PRVM_G_EDICT(OFS_PARM1);
1233 if (out == prog->edicts)
1235 VM_Warning("copyentity: can not modify world entity\n");
1238 if (out->priv.server->free)
1240 VM_Warning("copyentity: can not modify free entity\n");
1243 memcpy(out->fields.vp, in->fields.vp, prog->progs->entityfields * 4);
1247 //=================================================================//
1249 // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
1250 static void VM_CL_effect (void)
1252 VM_SAFEPARMCOUNT(5, VM_CL_effect);
1253 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));
1256 // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
1257 static void VM_CL_te_blood (void)
1261 VM_SAFEPARMCOUNT(3, VM_CL_te_blood);
1262 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1264 pos = PRVM_G_VECTOR(OFS_PARM0);
1265 CL_FindNonSolidLocation(pos, pos2, 4);
1266 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1269 // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
1270 static void VM_CL_te_bloodshower (void)
1274 VM_SAFEPARMCOUNT(4, VM_CL_te_bloodshower);
1275 if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1277 speed = PRVM_G_FLOAT(OFS_PARM2);
1284 CL_ParticleEffect(EFFECT_TE_BLOOD, PRVM_G_FLOAT(OFS_PARM3), PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), vel1, vel2, NULL, 0);
1287 // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
1288 static void VM_CL_te_explosionrgb (void)
1292 matrix4x4_t tempmatrix;
1293 VM_SAFEPARMCOUNT(2, VM_CL_te_explosionrgb);
1294 pos = PRVM_G_VECTOR(OFS_PARM0);
1295 CL_FindNonSolidLocation(pos, pos2, 10);
1296 CL_ParticleExplosion(pos2);
1297 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1298 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);
1301 // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
1302 static void VM_CL_te_particlecube (void)
1304 VM_SAFEPARMCOUNT(7, VM_CL_te_particlecube);
1305 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));
1308 // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
1309 static void VM_CL_te_particlerain (void)
1311 VM_SAFEPARMCOUNT(5, VM_CL_te_particlerain);
1312 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);
1315 // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
1316 static void VM_CL_te_particlesnow (void)
1318 VM_SAFEPARMCOUNT(5, VM_CL_te_particlesnow);
1319 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);
1322 // #411 void(vector org, vector vel, float howmany) te_spark
1323 static void VM_CL_te_spark (void)
1327 VM_SAFEPARMCOUNT(3, VM_CL_te_spark);
1329 pos = PRVM_G_VECTOR(OFS_PARM0);
1330 CL_FindNonSolidLocation(pos, pos2, 4);
1331 CL_ParticleEffect(EFFECT_TE_SPARK, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1334 extern cvar_t cl_sound_ric_gunshot;
1335 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
1336 static void VM_CL_te_gunshotquad (void)
1341 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
1343 pos = PRVM_G_VECTOR(OFS_PARM0);
1344 CL_FindNonSolidLocation(pos, pos2, 4);
1345 CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1346 if(cl_sound_ric_gunshot.integer >= 2)
1348 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1352 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1353 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1354 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1359 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
1360 static void VM_CL_te_spikequad (void)
1365 VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
1367 pos = PRVM_G_VECTOR(OFS_PARM0);
1368 CL_FindNonSolidLocation(pos, pos2, 4);
1369 CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1370 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1374 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1375 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1376 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1380 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
1381 static void VM_CL_te_superspikequad (void)
1386 VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
1388 pos = PRVM_G_VECTOR(OFS_PARM0);
1389 CL_FindNonSolidLocation(pos, pos2, 4);
1390 CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1391 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1395 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1396 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1397 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1401 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
1402 static void VM_CL_te_explosionquad (void)
1406 VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
1408 pos = PRVM_G_VECTOR(OFS_PARM0);
1409 CL_FindNonSolidLocation(pos, pos2, 10);
1410 CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1411 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1414 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
1415 static void VM_CL_te_smallflash (void)
1419 VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
1421 pos = PRVM_G_VECTOR(OFS_PARM0);
1422 CL_FindNonSolidLocation(pos, pos2, 10);
1423 CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1426 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
1427 static void VM_CL_te_customflash (void)
1431 matrix4x4_t tempmatrix;
1432 VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
1434 pos = PRVM_G_VECTOR(OFS_PARM0);
1435 CL_FindNonSolidLocation(pos, pos2, 4);
1436 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1437 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);
1440 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
1441 static void VM_CL_te_gunshot (void)
1446 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
1448 pos = PRVM_G_VECTOR(OFS_PARM0);
1449 CL_FindNonSolidLocation(pos, pos2, 4);
1450 CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1451 if(cl_sound_ric_gunshot.integer == 1 || cl_sound_ric_gunshot.integer == 3)
1453 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1457 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1458 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1459 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1464 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
1465 static void VM_CL_te_spike (void)
1470 VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
1472 pos = PRVM_G_VECTOR(OFS_PARM0);
1473 CL_FindNonSolidLocation(pos, pos2, 4);
1474 CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1475 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1479 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1480 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1481 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1485 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
1486 static void VM_CL_te_superspike (void)
1491 VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
1493 pos = PRVM_G_VECTOR(OFS_PARM0);
1494 CL_FindNonSolidLocation(pos, pos2, 4);
1495 CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1496 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1500 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1501 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1502 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1506 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
1507 static void VM_CL_te_explosion (void)
1511 VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
1513 pos = PRVM_G_VECTOR(OFS_PARM0);
1514 CL_FindNonSolidLocation(pos, pos2, 10);
1515 CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1516 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1519 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
1520 static void VM_CL_te_tarexplosion (void)
1524 VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
1526 pos = PRVM_G_VECTOR(OFS_PARM0);
1527 CL_FindNonSolidLocation(pos, pos2, 10);
1528 CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1529 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1532 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
1533 static void VM_CL_te_wizspike (void)
1537 VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
1539 pos = PRVM_G_VECTOR(OFS_PARM0);
1540 CL_FindNonSolidLocation(pos, pos2, 4);
1541 CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1542 S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
1545 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
1546 static void VM_CL_te_knightspike (void)
1550 VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
1552 pos = PRVM_G_VECTOR(OFS_PARM0);
1553 CL_FindNonSolidLocation(pos, pos2, 4);
1554 CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1555 S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
1558 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
1559 static void VM_CL_te_lavasplash (void)
1561 VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
1562 CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1565 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
1566 static void VM_CL_te_teleport (void)
1568 VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
1569 CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1572 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
1573 static void VM_CL_te_explosion2 (void)
1577 matrix4x4_t tempmatrix;
1578 int colorStart, colorLength;
1579 unsigned char *tempcolor;
1580 VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
1582 pos = PRVM_G_VECTOR(OFS_PARM0);
1583 colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
1584 colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
1585 CL_FindNonSolidLocation(pos, pos2, 10);
1586 CL_ParticleExplosion2(pos2, colorStart, colorLength);
1587 tempcolor = (unsigned char *)&palette_complete[(rand()%colorLength) + colorStart];
1588 color[0] = tempcolor[0] * (2.0f / 255.0f);
1589 color[1] = tempcolor[1] * (2.0f / 255.0f);
1590 color[2] = tempcolor[2] * (2.0f / 255.0f);
1591 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1592 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);
1593 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1597 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
1598 static void VM_CL_te_lightning1 (void)
1600 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
1601 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
1604 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
1605 static void VM_CL_te_lightning2 (void)
1607 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
1608 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
1611 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
1612 static void VM_CL_te_lightning3 (void)
1614 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
1615 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
1618 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
1619 static void VM_CL_te_beam (void)
1621 VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
1622 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
1625 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
1626 static void VM_CL_te_plasmaburn (void)
1630 VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
1632 pos = PRVM_G_VECTOR(OFS_PARM0);
1633 CL_FindNonSolidLocation(pos, pos2, 4);
1634 CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1637 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
1638 static void VM_CL_te_flamejet (void)
1642 VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
1643 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1645 pos = PRVM_G_VECTOR(OFS_PARM0);
1646 CL_FindNonSolidLocation(pos, pos2, 4);
1647 CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1651 //====================================================================
1654 extern void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
1656 static msurface_t *cl_getsurface(model_t *model, int surfacenum)
1658 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1660 return model->data_surfaces + surfacenum + model->firstmodelsurface;
1663 // #434 float(entity e, float s) getsurfacenumpoints
1664 static void VM_CL_getsurfacenumpoints(void)
1667 msurface_t *surface;
1668 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
1669 // return 0 if no such surface
1670 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1672 PRVM_G_FLOAT(OFS_RETURN) = 0;
1676 // note: this (incorrectly) assumes it is a simple polygon
1677 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1680 // #435 vector(entity e, float s, float n) getsurfacepoint
1681 static void VM_CL_getsurfacepoint(void)
1685 msurface_t *surface;
1687 VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1688 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1689 ed = PRVM_G_EDICT(OFS_PARM0);
1690 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1692 // note: this (incorrectly) assumes it is a simple polygon
1693 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1694 if (pointnum < 0 || pointnum >= surface->num_vertices)
1696 // FIXME: implement rotation/scaling
1697 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1700 // #436 vector(entity e, float s) getsurfacenormal
1701 static void VM_CL_getsurfacenormal(void)
1704 msurface_t *surface;
1706 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
1707 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1708 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1710 // FIXME: implement rotation/scaling
1711 // note: this (incorrectly) assumes it is a simple polygon
1712 // note: this only returns the first triangle, so it doesn't work very
1713 // well for curved surfaces or arbitrary meshes
1714 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);
1715 VectorNormalize(normal);
1716 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1719 // #437 string(entity e, float s) getsurfacetexture
1720 static void VM_CL_getsurfacetexture(void)
1723 msurface_t *surface;
1724 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
1725 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1726 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1728 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
1731 // #438 float(entity e, vector p) getsurfacenearpoint
1732 static void VM_CL_getsurfacenearpoint(void)
1734 int surfacenum, best;
1736 vec_t dist, bestdist;
1738 model_t *model = NULL;
1739 msurface_t *surface;
1741 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
1742 PRVM_G_FLOAT(OFS_RETURN) = -1;
1743 ed = PRVM_G_EDICT(OFS_PARM0);
1744 if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces)
1747 // FIXME: implement rotation/scaling
1748 point = PRVM_G_VECTOR(OFS_PARM1);
1749 VectorSubtract(point, ed->fields.client->origin, p);
1751 bestdist = 1000000000;
1752 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1754 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1755 // first see if the nearest point on the surface's box is closer than the previous match
1756 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1757 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1758 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1759 dist = VectorLength2(clipped);
1760 if (dist < bestdist)
1762 // it is, check the nearest point on the actual geometry
1763 clippointtosurface(model, surface, p, clipped);
1764 VectorSubtract(clipped, p, clipped);
1765 dist += VectorLength2(clipped);
1766 if (dist < bestdist)
1768 // that's closer too, store it as the best match
1774 PRVM_G_FLOAT(OFS_RETURN) = best;
1777 // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint
1778 static void VM_CL_getsurfaceclippedpoint(void)
1782 msurface_t *surface;
1784 VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
1785 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1786 ed = PRVM_G_EDICT(OFS_PARM0);
1787 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1789 // FIXME: implement rotation/scaling
1790 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
1791 clippointtosurface(model, surface, p, out);
1792 // FIXME: implement rotation/scaling
1793 VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1796 // #443 void(entity e, entity tagentity, string tagname) setattachment
1797 static void VM_CL_setattachment (void)
1800 prvm_edict_t *tagentity;
1801 const char *tagname;
1805 VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
1807 e = PRVM_G_EDICT(OFS_PARM0);
1808 tagentity = PRVM_G_EDICT(OFS_PARM1);
1809 tagname = PRVM_G_STRING(OFS_PARM2);
1811 if (e == prog->edicts)
1813 VM_Warning("setattachment: can not modify world entity\n");
1816 if (e->priv.server->free)
1818 VM_Warning("setattachment: can not modify free entity\n");
1822 if (tagentity == NULL)
1823 tagentity = prog->edicts;
1825 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
1827 v->edict = PRVM_EDICT_TO_PROG(tagentity);
1829 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
1832 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
1834 modelindex = (int)tagentity->fields.client->modelindex;
1835 model = CL_GetModelByIndex(modelindex);
1838 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
1840 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);
1843 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));
1847 /////////////////////////////////////////
1848 // DP_MD3_TAGINFO extension coded by VorteX
1850 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
1852 model_t *model = CL_GetModelFromEdict(e);
1854 return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
1859 // Warnings/errors code:
1860 // 0 - normal (everything all-right)
1863 // 3 - null or non-precached model
1864 // 4 - no tags with requested index
1865 // 5 - runaway loop at attachment chain
1866 extern cvar_t cl_bob;
1867 extern cvar_t cl_bobcycle;
1868 extern cvar_t cl_bobup;
1869 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
1872 int reqframe, attachloop;
1873 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
1874 prvm_edict_t *attachent;
1877 *out = identitymatrix; // warnings and errors return identical matrix
1879 if (ent == prog->edicts)
1881 if (ent->priv.server->free)
1884 model = CL_GetModelFromEdict(ent);
1889 if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
1890 reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
1892 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
1894 // get initial tag matrix
1897 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
1902 tagmatrix = identitymatrix;
1904 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
1905 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
1909 attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
1910 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
1912 model = CL_GetModelFromEdict(attachent);
1914 if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
1915 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
1917 attachmatrix = identitymatrix;
1919 // apply transformation by child entity matrix
1920 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1921 if (val->_float == 0)
1923 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);
1924 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1925 Matrix4x4_Copy(&tagmatrix, out);
1927 // finally transformate by matrix of tag on parent entity
1928 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
1929 Matrix4x4_Copy(&tagmatrix, out);
1933 if (attachloop > 255) // prevent runaway looping
1936 while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
1939 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
1940 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1941 if (val->_float == 0)
1943 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
1944 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);
1945 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1947 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
1948 {// RENDER_VIEWMODEL magic
1949 Matrix4x4_Copy(&tagmatrix, out);
1951 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1952 if (val->_float == 0)
1955 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, csqc_origin[0], csqc_origin[1], csqc_origin[2], csqc_angles[0], csqc_angles[1], csqc_angles[2], val->_float);
1956 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1959 // Cl_bob, ported from rendering code
1960 if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
1963 // LordHavoc: this code is *weird*, but not replacable (I think it
1964 // should be done in QC on the server, but oh well, quake is quake)
1965 // LordHavoc: figured out bobup: the time at which the sin is at 180
1966 // degrees (which allows lengthening or squishing the peak or valley)
1967 cycle = sv.time/cl_bobcycle.value;
1968 cycle -= (int)cycle;
1969 if (cycle < cl_bobup.value)
1970 cycle = sin(M_PI * cycle / cl_bobup.value);
1972 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
1973 // bob is proportional to velocity in the xy plane
1974 // (don't count Z, or jumping messes it up)
1975 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;
1976 bob = bob*0.3 + bob*0.7*cycle;
1977 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
1984 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
1985 static void VM_CL_gettagindex (void)
1988 const char *tag_name;
1989 int modelindex, tag_index;
1991 VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
1993 ent = PRVM_G_EDICT(OFS_PARM0);
1994 tag_name = PRVM_G_STRING(OFS_PARM1);
1995 if (ent == prog->edicts)
1997 VM_Warning("gettagindex: can't affect world entity\n");
2000 if (ent->priv.server->free)
2002 VM_Warning("gettagindex: can't affect free entity\n");
2006 modelindex = (int)ent->fields.client->modelindex;
2008 modelindex = -(modelindex+1);
2010 if (modelindex <= 0 || modelindex >= MAX_MODELS)
2011 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2014 tag_index = CL_GetTagIndex(ent, tag_name);
2016 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2018 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2021 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2022 static void VM_CL_gettaginfo (void)
2026 matrix4x4_t tag_matrix;
2029 VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2031 e = PRVM_G_EDICT(OFS_PARM0);
2032 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2033 returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2034 Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2039 VM_Warning("gettagindex: can't affect world entity\n");
2042 VM_Warning("gettagindex: can't affect free entity\n");
2045 Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2048 Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2051 Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2056 //============================================================================
2058 //====================
2059 //QC POLYGON functions
2060 //====================
2065 float data[36]; //[515]: enough for polygons
2066 unsigned char flags; //[515]: + VM_POLYGON_2D and VM_POLYGON_FL4V flags
2069 //static float vm_polygon_linewidth = 1;
2070 static mempool_t *vm_polygons_pool = NULL;
2071 static unsigned char vm_current_vertices = 0;
2072 static qboolean vm_polygons_initialized = false;
2073 static vm_polygon_t *vm_polygons = NULL;
2074 static unsigned long vm_polygons_num = 0, vm_drawpolygons_num = 0; //[515]: ok long on 64bit ?
2075 static qboolean vm_polygonbegin = false; //[515]: for "no-crap-on-the-screen" check
2076 #define VM_DEFPOLYNUM 64 //[515]: enough for default ?
2078 #define VM_POLYGON_FL3V 16 //more than 2 vertices (used only for lines)
2079 #define VM_POLYGON_FLLINES 32
2080 #define VM_POLYGON_FL2D 64
2081 #define VM_POLYGON_FL4V 128 //4 vertices
2083 static void VM_InitPolygons (void)
2085 vm_polygons_pool = Mem_AllocPool("VMPOLY", 0, NULL);
2086 vm_polygons = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2087 memset(vm_polygons, 0, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2088 vm_polygons_num = VM_DEFPOLYNUM;
2089 vm_drawpolygons_num = 0;
2090 vm_polygonbegin = false;
2091 vm_polygons_initialized = true;
2094 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2096 int surfacelistindex;
2097 // LordHavoc: FIXME: this is stupid code
2098 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2100 const vm_polygon_t *p = &vm_polygons[surfacelist[surfacelistindex]];
2101 int flags = p->flags & 0x0f;
2103 if(flags == DRAWFLAG_ADDITIVE)
2104 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2105 else if(flags == DRAWFLAG_MODULATE)
2106 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2107 else if(flags == DRAWFLAG_2XMODULATE)
2108 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2110 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2112 R_Mesh_TexBind(0, R_GetTexture(p->tex));
2115 //[515]: is speed is max ?
2116 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2118 qglLineWidth(p->data[13]);CHECKGLERROR
2119 qglBegin(GL_LINE_LOOP);
2120 qglTexCoord1f (p->data[12]);
2121 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2122 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2124 qglTexCoord1f (p->data[14]);
2125 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2126 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2128 if(p->flags & VM_POLYGON_FL3V)
2130 qglTexCoord1f (p->data[16]);
2131 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2132 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2134 if(p->flags & VM_POLYGON_FL4V)
2136 qglTexCoord1f (p->data[18]);
2137 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2138 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2146 qglBegin(GL_POLYGON);
2147 qglTexCoord2f (p->data[12], p->data[13]);
2148 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2149 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2151 qglTexCoord2f (p->data[14], p->data[15]);
2152 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2153 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2155 qglTexCoord2f (p->data[16], p->data[17]);
2156 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2157 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2159 if(p->flags & VM_POLYGON_FL4V)
2161 qglTexCoord2f (p->data[18], p->data[19]);
2162 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2163 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2171 static void VM_CL_AddPolygonTo2DScene (vm_polygon_t *p)
2173 drawqueuemesh_t mesh;
2174 static int picelements[6] = {0, 1, 2, 0, 2, 3};
2176 mesh.texture = p->tex;
2177 mesh.data_element3i = picelements;
2178 mesh.data_vertex3f = p->data;
2179 mesh.data_texcoord2f = p->data + 12;
2180 mesh.data_color4f = p->data + 20;
2181 if(p->flags & VM_POLYGON_FL4V)
2183 mesh.num_vertices = 4;
2184 mesh.num_triangles = 2;
2188 mesh.num_vertices = 3;
2189 mesh.num_triangles = 1;
2191 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2192 DrawQ_LineLoop (&mesh, (p->flags&0x0f));
2194 DrawQ_Mesh (&mesh, (p->flags&0x0f));
2197 void VM_CL_AddPolygonsToMeshQueue (void)
2200 if(!vm_drawpolygons_num)
2202 R_Mesh_Matrix(&identitymatrix);
2203 GL_CullFace(GL_NONE);
2204 for(i = 0;i < (int)vm_drawpolygons_num;i++)
2205 VM_DrawPolygonCallback(NULL, NULL, 1, &i);
2206 vm_drawpolygons_num = 0;
2209 //void(string texturename, float flag[, float 2d[, float lines]]) R_BeginPolygon
2210 static void VM_CL_R_PolygonBegin (void)
2213 const char *picname;
2214 VM_SAFEPARMCOUNTRANGE(2, 4, VM_CL_R_PolygonBegin);
2216 if(!vm_polygons_initialized)
2220 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonEnd after first\n");
2223 if(vm_drawpolygons_num >= vm_polygons_num)
2225 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2226 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2227 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2228 Mem_Free(vm_polygons);
2230 vm_polygons_num *= 2;
2232 p = &vm_polygons[vm_drawpolygons_num];
2233 picname = PRVM_G_STRING(OFS_PARM0);
2235 p->tex = Draw_CachePic(picname, true)->tex;
2237 p->tex = r_texture_white;
2238 p->flags = (unsigned char)PRVM_G_FLOAT(OFS_PARM1);
2239 vm_current_vertices = 0;
2240 vm_polygonbegin = true;
2243 if(PRVM_G_FLOAT(OFS_PARM2))
2244 p->flags |= VM_POLYGON_FL2D;
2245 if(prog->argc >= 4 && PRVM_G_FLOAT(OFS_PARM3))
2247 p->data[13] = PRVM_G_FLOAT(OFS_PARM3); //[515]: linewidth
2248 p->flags |= VM_POLYGON_FLLINES;
2253 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2254 static void VM_CL_R_PolygonVertex (void)
2256 float *coords, *tx, *rgb, alpha;
2258 VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2260 if(!vm_polygonbegin)
2262 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2265 coords = PRVM_G_VECTOR(OFS_PARM0);
2266 tx = PRVM_G_VECTOR(OFS_PARM1);
2267 rgb = PRVM_G_VECTOR(OFS_PARM2);
2268 alpha = PRVM_G_FLOAT(OFS_PARM3);
2270 p = &vm_polygons[vm_drawpolygons_num];
2271 if(vm_current_vertices > 4)
2273 VM_Warning("VM_CL_R_PolygonVertex: may have 4 vertices max\n");
2277 p->data[vm_current_vertices*3] = coords[0];
2278 p->data[1+vm_current_vertices*3] = coords[1];
2279 p->data[2+vm_current_vertices*3] = coords[2];
2281 p->data[12+vm_current_vertices*2] = tx[0];
2282 if(!(p->flags & VM_POLYGON_FLLINES))
2283 p->data[13+vm_current_vertices*2] = tx[1];
2285 p->data[20+vm_current_vertices*4] = rgb[0];
2286 p->data[21+vm_current_vertices*4] = rgb[1];
2287 p->data[22+vm_current_vertices*4] = rgb[2];
2288 p->data[23+vm_current_vertices*4] = alpha;
2290 vm_current_vertices++;
2291 if(vm_current_vertices == 4)
2292 p->flags |= VM_POLYGON_FL4V;
2294 if(vm_current_vertices == 3)
2295 p->flags |= VM_POLYGON_FL3V;
2298 //void() R_EndPolygon
2299 static void VM_CL_R_PolygonEnd (void)
2301 VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2302 if(!vm_polygonbegin)
2304 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2307 vm_polygonbegin = false;
2308 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2310 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2311 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2313 vm_drawpolygons_num++;
2316 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2319 void Debug_PolygonBegin(const char *picname, int flags, qboolean draw2d, float linewidth)
2323 if(!vm_polygons_initialized)
2327 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2330 // limit polygons to a vaguely sane amount, beyond this each one just
2331 // replaces the last one
2332 vm_drawpolygons_num = min(vm_drawpolygons_num, (1<<20)-1);
2333 if(vm_drawpolygons_num >= vm_polygons_num)
2335 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2336 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2337 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2338 Mem_Free(vm_polygons);
2340 vm_polygons_num *= 2;
2342 p = &vm_polygons[vm_drawpolygons_num];
2343 if(picname && picname[0])
2344 p->tex = Draw_CachePic(picname, true)->tex;
2346 p->tex = r_texture_white;
2348 vm_current_vertices = 0;
2349 vm_polygonbegin = true;
2351 p->flags |= VM_POLYGON_FL2D;
2354 p->data[13] = linewidth; //[515]: linewidth
2355 p->flags |= VM_POLYGON_FLLINES;
2359 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2363 if(!vm_polygonbegin)
2365 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2369 p = &vm_polygons[vm_drawpolygons_num];
2370 if(vm_current_vertices > 4)
2372 Con_Printf("Debug_PolygonVertex: may have 4 vertices max\n");
2376 p->data[vm_current_vertices*3] = x;
2377 p->data[1+vm_current_vertices*3] = y;
2378 p->data[2+vm_current_vertices*3] = z;
2380 p->data[12+vm_current_vertices*2] = s;
2381 if(!(p->flags & VM_POLYGON_FLLINES))
2382 p->data[13+vm_current_vertices*2] = t;
2384 p->data[20+vm_current_vertices*4] = r;
2385 p->data[21+vm_current_vertices*4] = g;
2386 p->data[22+vm_current_vertices*4] = b;
2387 p->data[23+vm_current_vertices*4] = a;
2389 vm_current_vertices++;
2390 if(vm_current_vertices == 4)
2391 p->flags |= VM_POLYGON_FL4V;
2393 if(vm_current_vertices == 3)
2394 p->flags |= VM_POLYGON_FL3V;
2397 void Debug_PolygonEnd(void)
2399 if(!vm_polygonbegin)
2401 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2404 vm_polygonbegin = false;
2405 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2407 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2408 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2410 vm_drawpolygons_num++;
2413 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2420 Returns false if any part of the bottom of the entity is off an edge that
2425 qboolean CL_CheckBottom (prvm_edict_t *ent)
2427 vec3_t mins, maxs, start, stop;
2432 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2433 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2435 // if all of the points under the corners are solid world, don't bother
2436 // with the tougher checks
2437 // the corners must be within 16 of the midpoint
2438 start[2] = mins[2] - 1;
2439 for (x=0 ; x<=1 ; x++)
2440 for (y=0 ; y<=1 ; y++)
2442 start[0] = x ? maxs[0] : mins[0];
2443 start[1] = y ? maxs[1] : mins[1];
2444 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2448 return true; // we got out easy
2452 // check it for real...
2456 // the midpoint must be within 16 of the bottom
2457 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2458 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2459 stop[2] = start[2] - 2*sv_stepheight.value;
2460 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2462 if (trace.fraction == 1.0)
2464 mid = bottom = trace.endpos[2];
2466 // the corners must be within 16 of the midpoint
2467 for (x=0 ; x<=1 ; x++)
2468 for (y=0 ; y<=1 ; y++)
2470 start[0] = stop[0] = x ? maxs[0] : mins[0];
2471 start[1] = stop[1] = y ? maxs[1] : mins[1];
2473 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2475 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2476 bottom = trace.endpos[2];
2477 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2488 Called by monster program code.
2489 The move will be adjusted for slopes and stairs, but if the move isn't
2490 possible, no move is done and false is returned
2493 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2496 vec3_t oldorg, neworg, end, traceendpos;
2499 prvm_edict_t *enemy;
2503 VectorCopy (ent->fields.client->origin, oldorg);
2504 VectorAdd (ent->fields.client->origin, move, neworg);
2506 // flying monsters don't step up
2507 if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2509 // try one move with vertical motion, then one without
2510 for (i=0 ; i<2 ; i++)
2512 VectorAdd (ent->fields.client->origin, move, neworg);
2513 enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2514 if (i == 0 && enemy != prog->edicts)
2516 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2522 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);
2524 VM_SetTraceGlobals(&trace);
2526 if (trace.fraction == 1)
2528 VectorCopy(trace.endpos, traceendpos);
2529 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2530 return false; // swim monster left water
2532 VectorCopy (traceendpos, ent->fields.client->origin);
2538 if (enemy == prog->edicts)
2545 // push down from a step height above the wished position
2546 neworg[2] += sv_stepheight.value;
2547 VectorCopy (neworg, end);
2548 end[2] -= sv_stepheight.value*2;
2550 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2552 VM_SetTraceGlobals(&trace);
2554 if (trace.startsolid)
2556 neworg[2] -= sv_stepheight.value;
2557 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2559 VM_SetTraceGlobals(&trace);
2560 if (trace.startsolid)
2563 if (trace.fraction == 1)
2565 // if monster had the ground pulled out, go ahead and fall
2566 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2568 VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2571 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2575 return false; // walked off an edge
2578 // check point traces down for dangling corners
2579 VectorCopy (trace.endpos, ent->fields.client->origin);
2581 if (!CL_CheckBottom (ent))
2583 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2584 { // entity had floor mostly pulled out from underneath it
2585 // and is trying to correct
2590 VectorCopy (oldorg, ent->fields.client->origin);
2594 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2595 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2597 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2598 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2610 float(float yaw, float dist[, settrace]) walkmove
2613 static void VM_CL_walkmove (void)
2622 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2624 // assume failure if it returns early
2625 PRVM_G_FLOAT(OFS_RETURN) = 0;
2627 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2628 if (ent == prog->edicts)
2630 VM_Warning("walkmove: can not modify world entity\n");
2633 if (ent->priv.server->free)
2635 VM_Warning("walkmove: can not modify free entity\n");
2638 yaw = PRVM_G_FLOAT(OFS_PARM0);
2639 dist = PRVM_G_FLOAT(OFS_PARM1);
2640 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2642 if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2645 yaw = yaw*M_PI*2 / 360;
2647 move[0] = cos(yaw)*dist;
2648 move[1] = sin(yaw)*dist;
2651 // save program state, because CL_movestep may call other progs
2652 oldf = prog->xfunction;
2653 oldself = prog->globals.client->self;
2655 PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2658 // restore program state
2659 prog->xfunction = oldf;
2660 prog->globals.client->self = oldself;
2667 string(string key) serverkey
2670 void VM_CL_serverkey(void)
2672 char string[VM_STRINGTEMP_LENGTH];
2673 VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2674 InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2675 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2678 //============================================================================
2680 prvm_builtin_t vm_cl_builtins[] = {
2681 NULL, // #0 NULL function (not callable) (QUAKE)
2682 VM_CL_makevectors, // #1 void(vector ang) makevectors (QUAKE)
2683 VM_CL_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
2684 VM_CL_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
2685 VM_CL_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2686 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2687 VM_break, // #6 void() break (QUAKE)
2688 VM_random, // #7 float() random (QUAKE)
2689 VM_CL_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
2690 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
2691 VM_error, // #10 void(string e) error (QUAKE)
2692 VM_objerror, // #11 void(string e) objerror (QUAKE)
2693 VM_vlen, // #12 float(vector v) vlen (QUAKE)
2694 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
2695 VM_CL_spawn, // #14 entity() spawn (QUAKE)
2696 VM_remove, // #15 void(entity e) remove (QUAKE)
2697 VM_CL_traceline, // #16 float(vector v1, vector v2, float tryents) traceline (QUAKE)
2698 NULL, // #17 entity() checkclient (QUAKE)
2699 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
2700 VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
2701 VM_CL_precache_model, // #20 void(string s) precache_model (QUAKE)
2702 NULL, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2703 VM_CL_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
2704 NULL, // #23 void(string s, ...) bprint (QUAKE)
2705 NULL, // #24 void(entity client, string s, ...) sprint (QUAKE)
2706 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
2707 VM_ftos, // #26 string(float f) ftos (QUAKE)
2708 VM_vtos, // #27 string(vector v) vtos (QUAKE)
2709 VM_coredump, // #28 void() coredump (QUAKE)
2710 VM_traceon, // #29 void() traceon (QUAKE)
2711 VM_traceoff, // #30 void() traceoff (QUAKE)
2712 VM_eprint, // #31 void(entity e) eprint (QUAKE)
2713 VM_CL_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
2714 NULL, // #33 (QUAKE)
2715 VM_CL_droptofloor, // #34 float() droptofloor (QUAKE)
2716 VM_CL_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
2717 VM_rint, // #36 float(float v) rint (QUAKE)
2718 VM_floor, // #37 float(float v) floor (QUAKE)
2719 VM_ceil, // #38 float(float v) ceil (QUAKE)
2720 NULL, // #39 (QUAKE)
2721 VM_CL_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
2722 VM_CL_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
2723 NULL, // #42 (QUAKE)
2724 VM_fabs, // #43 float(float f) fabs (QUAKE)
2725 NULL, // #44 vector(entity e, float speed) aim (QUAKE)
2726 VM_cvar, // #45 float(string s) cvar (QUAKE)
2727 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
2728 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
2729 VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2730 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
2731 NULL, // #50 (QUAKE)
2732 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
2733 NULL, // #52 void(float to, float f) WriteByte (QUAKE)
2734 NULL, // #53 void(float to, float f) WriteChar (QUAKE)
2735 NULL, // #54 void(float to, float f) WriteShort (QUAKE)
2736 NULL, // #55 void(float to, float f) WriteLong (QUAKE)
2737 NULL, // #56 void(float to, float f) WriteCoord (QUAKE)
2738 NULL, // #57 void(float to, float f) WriteAngle (QUAKE)
2739 NULL, // #58 void(float to, string s) WriteString (QUAKE)
2740 NULL, // #59 (QUAKE)
2741 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2742 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2743 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2744 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2745 VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2746 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2747 NULL, // #66 (QUAKE)
2748 NULL, // #67 void(float step) movetogoal (QUAKE)
2749 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
2750 VM_CL_makestatic, // #69 void(entity e) makestatic (QUAKE)
2751 NULL, // #70 void(string s) changelevel (QUAKE)
2752 NULL, // #71 (QUAKE)
2753 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
2754 NULL, // #73 void(entity client, strings) centerprint (QUAKE)
2755 VM_CL_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2756 VM_CL_precache_model, // #75 string(string s) precache_model2 (QUAKE)
2757 VM_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
2758 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
2759 NULL, // #78 void(entity e) setspawnparms (QUAKE)
2760 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
2761 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
2762 VM_stof, // #81 float(string s) stof (FRIK_FILE)
2763 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
2764 NULL, // #83 (QUAKE)
2765 NULL, // #84 (QUAKE)
2766 NULL, // #85 (QUAKE)
2767 NULL, // #86 (QUAKE)
2768 NULL, // #87 (QUAKE)
2769 NULL, // #88 (QUAKE)
2770 NULL, // #89 (QUAKE)
2771 VM_CL_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2772 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2773 VM_CL_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2774 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2775 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2776 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2777 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2778 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2779 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2780 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
2781 // FrikaC and Telejano range #100-#199
2792 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
2793 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
2794 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
2795 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2796 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
2797 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
2798 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
2799 VM_stov, // #117 vector(string) stov (FRIK_FILE)
2800 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
2801 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
2882 // FTEQW range #200-#299
2901 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
2905 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
2906 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
2911 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
2915 NULL, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
2983 // CSQC range #300-#399
2984 VM_CL_R_ClearScene, // #300 void() clearscene (EXT_CSQC)
2985 VM_CL_R_AddEntities, // #301 void(float mask) addentities (EXT_CSQC)
2986 VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC)
2987 VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC)
2988 VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC)
2989 VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
2990 VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
2991 VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2992 VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon
2994 VM_CL_unproject, // #310 vector (vector v) cs_unproject (EXT_CSQC)
2995 VM_CL_project, // #311 vector (vector v) cs_project (EXT_CSQC)
2999 VM_drawline, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
3000 VM_iscachedpic, // #316 float(string name) iscachedpic (EXT_CSQC)
3001 VM_precache_pic, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
3002 VM_getimagesize, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
3003 VM_freepic, // #319 void(string name) freepic (EXT_CSQC)
3004 VM_drawcharacter, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
3005 VM_drawstring, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
3006 VM_drawpic, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
3007 VM_drawfill, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
3008 VM_drawsetcliparea, // #324 void(float x, float y, float width, float height) drawsetcliparea
3009 VM_drawresetcliparea, // #325 void(void) drawresetcliparea
3014 VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
3015 VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
3016 VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
3017 VM_CL_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
3018 VM_CL_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
3019 VM_CL_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
3020 VM_CL_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
3021 VM_CL_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
3022 VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC)
3023 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
3024 VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3025 VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3026 VM_CL_getkeybind, // #342 string(float keynum) getkeybind (EXT_CSQC)
3027 VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3028 VM_getmousepos, // #344 vector() getmousepos (EXT_CSQC)
3029 VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC)
3030 VM_CL_setsensitivityscale, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3031 VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC)
3032 VM_CL_getplayerkey, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3033 VM_CL_isdemo, // #349 float() isdemo (EXT_CSQC)
3034 VM_isserver, // #350 float() isserver (EXT_CSQC)
3035 VM_CL_setlistener, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3036 VM_CL_registercmd, // #352 void(string cmdname) registercommand (EXT_CSQC)
3037 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3038 VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3044 VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC)
3045 VM_CL_ReadChar, // #361 float() readchar (EXT_CSQC)
3046 VM_CL_ReadShort, // #362 float() readshort (EXT_CSQC)
3047 VM_CL_ReadLong, // #363 float() readlong (EXT_CSQC)
3048 VM_CL_ReadCoord, // #364 float() readcoord (EXT_CSQC)
3049 VM_CL_ReadAngle, // #365 float() readangle (EXT_CSQC)
3050 VM_CL_ReadString, // #366 string() readstring (EXT_CSQC)
3051 VM_CL_ReadFloat, // #367 float() readfloat (EXT_CSQC)
3084 // LordHavoc's range #400-#499
3085 VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3086 NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3087 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3088 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3089 VM_CL_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3090 VM_CL_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3091 VM_CL_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3092 VM_CL_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3093 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)
3094 VM_CL_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3095 VM_CL_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3096 VM_CL_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3097 VM_CL_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3098 VM_CL_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3099 VM_CL_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3100 VM_CL_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3101 VM_CL_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3102 VM_CL_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3103 VM_CL_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3104 VM_CL_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3105 VM_CL_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3106 VM_CL_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3107 VM_CL_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3108 VM_CL_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3109 VM_CL_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3110 VM_CL_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3111 VM_CL_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3112 VM_CL_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3113 VM_CL_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3114 VM_CL_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3115 VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3116 VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3117 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3118 VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3119 VM_CL_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3120 VM_CL_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3121 VM_CL_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3122 VM_CL_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3123 VM_CL_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3124 VM_CL_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3125 NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3126 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3127 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3128 VM_CL_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3129 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3130 VM_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3131 VM_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3132 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3133 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3134 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3135 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3136 VM_CL_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3137 VM_CL_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3138 NULL, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3139 NULL, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3140 NULL, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3141 NULL, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3142 VM_CL_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3144 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3145 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3146 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3147 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3148 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3149 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3150 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3151 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3152 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3153 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3154 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3155 NULL, // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3156 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3157 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3158 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3159 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3160 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3161 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3162 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3163 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3164 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3165 VM_strtolower, // #480 string(string s) VM_strtolower : DRESK - Return string as lowercase
3166 VM_strtoupper, // #481 string(string s) VM_strtoupper : DRESK - Return string as uppercase
3187 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3189 void VM_CL_Cmd_Init(void)
3191 // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3192 if(vm_polygons_initialized)
3194 Mem_FreePool(&vm_polygons_pool);
3195 vm_polygons_initialized = false;
3199 void VM_CL_Cmd_Reset(void)
3201 if(vm_polygons_initialized)
3203 Mem_FreePool(&vm_polygons_pool);
3204 vm_polygons_initialized = false;