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 // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
1335 static void VM_CL_te_gunshotquad (void)
1339 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshotquad);
1341 pos = PRVM_G_VECTOR(OFS_PARM0);
1342 CL_FindNonSolidLocation(pos, pos2, 4);
1343 CL_ParticleEffect(EFFECT_TE_GUNSHOTQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1346 // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
1347 static void VM_CL_te_spikequad (void)
1352 VM_SAFEPARMCOUNT(1, VM_CL_te_spikequad);
1354 pos = PRVM_G_VECTOR(OFS_PARM0);
1355 CL_FindNonSolidLocation(pos, pos2, 4);
1356 CL_ParticleEffect(EFFECT_TE_SPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1357 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1361 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1362 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1363 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1367 // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
1368 static void VM_CL_te_superspikequad (void)
1373 VM_SAFEPARMCOUNT(1, VM_CL_te_superspikequad);
1375 pos = PRVM_G_VECTOR(OFS_PARM0);
1376 CL_FindNonSolidLocation(pos, pos2, 4);
1377 CL_ParticleEffect(EFFECT_TE_SUPERSPIKEQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1378 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos, 1, 1);
1382 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1383 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1384 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1388 // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
1389 static void VM_CL_te_explosionquad (void)
1393 VM_SAFEPARMCOUNT(1, VM_CL_te_explosionquad);
1395 pos = PRVM_G_VECTOR(OFS_PARM0);
1396 CL_FindNonSolidLocation(pos, pos2, 10);
1397 CL_ParticleEffect(EFFECT_TE_EXPLOSIONQUAD, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1398 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1401 // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
1402 static void VM_CL_te_smallflash (void)
1406 VM_SAFEPARMCOUNT(1, VM_CL_te_smallflash);
1408 pos = PRVM_G_VECTOR(OFS_PARM0);
1409 CL_FindNonSolidLocation(pos, pos2, 10);
1410 CL_ParticleEffect(EFFECT_TE_SMALLFLASH, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1413 // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
1414 static void VM_CL_te_customflash (void)
1418 matrix4x4_t tempmatrix;
1419 VM_SAFEPARMCOUNT(4, VM_CL_te_customflash);
1421 pos = PRVM_G_VECTOR(OFS_PARM0);
1422 CL_FindNonSolidLocation(pos, pos2, 4);
1423 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1424 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);
1427 // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
1428 static void VM_CL_te_gunshot (void)
1432 VM_SAFEPARMCOUNT(1, VM_CL_te_gunshot);
1434 pos = PRVM_G_VECTOR(OFS_PARM0);
1435 CL_FindNonSolidLocation(pos, pos2, 4);
1436 CL_ParticleEffect(EFFECT_TE_GUNSHOT, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1439 // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
1440 static void VM_CL_te_spike (void)
1445 VM_SAFEPARMCOUNT(1, VM_CL_te_spike);
1447 pos = PRVM_G_VECTOR(OFS_PARM0);
1448 CL_FindNonSolidLocation(pos, pos2, 4);
1449 CL_ParticleEffect(EFFECT_TE_SPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1450 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1454 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1455 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1456 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1460 // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
1461 static void VM_CL_te_superspike (void)
1466 VM_SAFEPARMCOUNT(1, VM_CL_te_superspike);
1468 pos = PRVM_G_VECTOR(OFS_PARM0);
1469 CL_FindNonSolidLocation(pos, pos2, 4);
1470 CL_ParticleEffect(EFFECT_TE_SUPERSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1471 if (rand() % 5) S_StartSound(-1, 0, cl.sfx_tink1, pos2, 1, 1);
1475 if (rnd == 1) S_StartSound(-1, 0, cl.sfx_ric1, pos2, 1, 1);
1476 else if (rnd == 2) S_StartSound(-1, 0, cl.sfx_ric2, pos2, 1, 1);
1477 else S_StartSound(-1, 0, cl.sfx_ric3, pos2, 1, 1);
1481 // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
1482 static void VM_CL_te_explosion (void)
1486 VM_SAFEPARMCOUNT(1, VM_CL_te_explosion);
1488 pos = PRVM_G_VECTOR(OFS_PARM0);
1489 CL_FindNonSolidLocation(pos, pos2, 10);
1490 CL_ParticleEffect(EFFECT_TE_EXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1491 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1494 // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
1495 static void VM_CL_te_tarexplosion (void)
1499 VM_SAFEPARMCOUNT(1, VM_CL_te_tarexplosion);
1501 pos = PRVM_G_VECTOR(OFS_PARM0);
1502 CL_FindNonSolidLocation(pos, pos2, 10);
1503 CL_ParticleEffect(EFFECT_TE_TAREXPLOSION, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1504 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1507 // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
1508 static void VM_CL_te_wizspike (void)
1512 VM_SAFEPARMCOUNT(1, VM_CL_te_wizspike);
1514 pos = PRVM_G_VECTOR(OFS_PARM0);
1515 CL_FindNonSolidLocation(pos, pos2, 4);
1516 CL_ParticleEffect(EFFECT_TE_WIZSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1517 S_StartSound(-1, 0, cl.sfx_wizhit, pos2, 1, 1);
1520 // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
1521 static void VM_CL_te_knightspike (void)
1525 VM_SAFEPARMCOUNT(1, VM_CL_te_knightspike);
1527 pos = PRVM_G_VECTOR(OFS_PARM0);
1528 CL_FindNonSolidLocation(pos, pos2, 4);
1529 CL_ParticleEffect(EFFECT_TE_KNIGHTSPIKE, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1530 S_StartSound(-1, 0, cl.sfx_knighthit, pos2, 1, 1);
1533 // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
1534 static void VM_CL_te_lavasplash (void)
1536 VM_SAFEPARMCOUNT(1, VM_CL_te_lavasplash);
1537 CL_ParticleEffect(EFFECT_TE_LAVASPLASH, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1540 // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
1541 static void VM_CL_te_teleport (void)
1543 VM_SAFEPARMCOUNT(1, VM_CL_te_teleport);
1544 CL_ParticleEffect(EFFECT_TE_TELEPORT, 1, PRVM_G_VECTOR(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM0), vec3_origin, vec3_origin, NULL, 0);
1547 // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
1548 static void VM_CL_te_explosion2 (void)
1552 matrix4x4_t tempmatrix;
1553 int colorStart, colorLength;
1554 unsigned char *tempcolor;
1555 VM_SAFEPARMCOUNT(3, VM_CL_te_explosion2);
1557 pos = PRVM_G_VECTOR(OFS_PARM0);
1558 colorStart = (int)PRVM_G_FLOAT(OFS_PARM1);
1559 colorLength = (int)PRVM_G_FLOAT(OFS_PARM2);
1560 CL_FindNonSolidLocation(pos, pos2, 10);
1561 CL_ParticleExplosion2(pos2, colorStart, colorLength);
1562 tempcolor = (unsigned char *)&palette_complete[(rand()%colorLength) + colorStart];
1563 color[0] = tempcolor[0] * (2.0f / 255.0f);
1564 color[1] = tempcolor[1] * (2.0f / 255.0f);
1565 color[2] = tempcolor[2] * (2.0f / 255.0f);
1566 Matrix4x4_CreateTranslate(&tempmatrix, pos2[0], pos2[1], pos2[2]);
1567 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);
1568 S_StartSound(-1, 0, cl.sfx_r_exp3, pos2, 1, 1);
1572 // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
1573 static void VM_CL_te_lightning1 (void)
1575 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning1);
1576 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt, true);
1579 // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
1580 static void VM_CL_te_lightning2 (void)
1582 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning2);
1583 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt2, true);
1586 // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
1587 static void VM_CL_te_lightning3 (void)
1589 VM_SAFEPARMCOUNT(3, VM_CL_te_lightning3);
1590 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_bolt3, false);
1593 // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
1594 static void VM_CL_te_beam (void)
1596 VM_SAFEPARMCOUNT(3, VM_CL_te_beam);
1597 CL_NewBeam(PRVM_G_EDICTNUM(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM2), cl.model_beam, false);
1600 // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
1601 static void VM_CL_te_plasmaburn (void)
1605 VM_SAFEPARMCOUNT(1, VM_CL_te_plasmaburn);
1607 pos = PRVM_G_VECTOR(OFS_PARM0);
1608 CL_FindNonSolidLocation(pos, pos2, 4);
1609 CL_ParticleEffect(EFFECT_TE_PLASMABURN, 1, pos2, pos2, vec3_origin, vec3_origin, NULL, 0);
1612 // #457 void(vector org, vector velocity, float howmany) te_flamejet (DP_TE_FLAMEJET)
1613 static void VM_CL_te_flamejet (void)
1617 VM_SAFEPARMCOUNT(3, VM_CL_te_flamejet);
1618 if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1620 pos = PRVM_G_VECTOR(OFS_PARM0);
1621 CL_FindNonSolidLocation(pos, pos2, 4);
1622 CL_ParticleEffect(EFFECT_TE_FLAMEJET, PRVM_G_FLOAT(OFS_PARM2), pos2, pos2, PRVM_G_VECTOR(OFS_PARM1), PRVM_G_VECTOR(OFS_PARM1), NULL, 0);
1626 //====================================================================
1629 extern void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out);
1631 static msurface_t *cl_getsurface(model_t *model, int surfacenum)
1633 if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
1635 return model->data_surfaces + surfacenum + model->firstmodelsurface;
1638 // #434 float(entity e, float s) getsurfacenumpoints
1639 static void VM_CL_getsurfacenumpoints(void)
1642 msurface_t *surface;
1643 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenumpoints);
1644 // return 0 if no such surface
1645 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1647 PRVM_G_FLOAT(OFS_RETURN) = 0;
1651 // note: this (incorrectly) assumes it is a simple polygon
1652 PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
1655 // #435 vector(entity e, float s, float n) getsurfacepoint
1656 static void VM_CL_getsurfacepoint(void)
1660 msurface_t *surface;
1662 VM_SAFEPARMCOUNT(3, VM_CL_getsurfacenumpoints);
1663 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1664 ed = PRVM_G_EDICT(OFS_PARM0);
1665 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1667 // note: this (incorrectly) assumes it is a simple polygon
1668 pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
1669 if (pointnum < 0 || pointnum >= surface->num_vertices)
1671 // FIXME: implement rotation/scaling
1672 VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1675 // #436 vector(entity e, float s) getsurfacenormal
1676 static void VM_CL_getsurfacenormal(void)
1679 msurface_t *surface;
1681 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenormal);
1682 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1683 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1685 // FIXME: implement rotation/scaling
1686 // note: this (incorrectly) assumes it is a simple polygon
1687 // note: this only returns the first triangle, so it doesn't work very
1688 // well for curved surfaces or arbitrary meshes
1689 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);
1690 VectorNormalize(normal);
1691 VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
1694 // #437 string(entity e, float s) getsurfacetexture
1695 static void VM_CL_getsurfacetexture(void)
1698 msurface_t *surface;
1699 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacetexture);
1700 PRVM_G_INT(OFS_RETURN) = OFS_NULL;
1701 if (!(model = CL_GetModelFromEdict(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1703 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
1706 // #438 float(entity e, vector p) getsurfacenearpoint
1707 static void VM_CL_getsurfacenearpoint(void)
1709 int surfacenum, best;
1711 vec_t dist, bestdist;
1713 model_t *model = NULL;
1714 msurface_t *surface;
1716 VM_SAFEPARMCOUNT(2, VM_CL_getsurfacenearpoint);
1717 PRVM_G_FLOAT(OFS_RETURN) = -1;
1718 ed = PRVM_G_EDICT(OFS_PARM0);
1719 if(!(model = CL_GetModelFromEdict(ed)) || !model->num_surfaces)
1722 // FIXME: implement rotation/scaling
1723 point = PRVM_G_VECTOR(OFS_PARM1);
1724 VectorSubtract(point, ed->fields.client->origin, p);
1726 bestdist = 1000000000;
1727 for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
1729 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
1730 // first see if the nearest point on the surface's box is closer than the previous match
1731 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
1732 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
1733 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
1734 dist = VectorLength2(clipped);
1735 if (dist < bestdist)
1737 // it is, check the nearest point on the actual geometry
1738 clippointtosurface(model, surface, p, clipped);
1739 VectorSubtract(clipped, p, clipped);
1740 dist += VectorLength2(clipped);
1741 if (dist < bestdist)
1743 // that's closer too, store it as the best match
1749 PRVM_G_FLOAT(OFS_RETURN) = best;
1752 // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint
1753 static void VM_CL_getsurfaceclippedpoint(void)
1757 msurface_t *surface;
1759 VM_SAFEPARMCOUNT(3, VM_CL_getsurfaceclippedpoint);
1760 VectorClear(PRVM_G_VECTOR(OFS_RETURN));
1761 ed = PRVM_G_EDICT(OFS_PARM0);
1762 if (!(model = CL_GetModelFromEdict(ed)) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
1764 // FIXME: implement rotation/scaling
1765 VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.client->origin, p);
1766 clippointtosurface(model, surface, p, out);
1767 // FIXME: implement rotation/scaling
1768 VectorAdd(out, ed->fields.client->origin, PRVM_G_VECTOR(OFS_RETURN));
1771 // #443 void(entity e, entity tagentity, string tagname) setattachment
1772 static void VM_CL_setattachment (void)
1775 prvm_edict_t *tagentity;
1776 const char *tagname;
1780 VM_SAFEPARMCOUNT(3, VM_CL_setattachment);
1782 e = PRVM_G_EDICT(OFS_PARM0);
1783 tagentity = PRVM_G_EDICT(OFS_PARM1);
1784 tagname = PRVM_G_STRING(OFS_PARM2);
1786 if (e == prog->edicts)
1788 VM_Warning("setattachment: can not modify world entity\n");
1791 if (e->priv.server->free)
1793 VM_Warning("setattachment: can not modify free entity\n");
1797 if (tagentity == NULL)
1798 tagentity = prog->edicts;
1800 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_entity);
1802 v->edict = PRVM_EDICT_TO_PROG(tagentity);
1804 v = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.tag_index);
1807 if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
1809 modelindex = (int)tagentity->fields.client->modelindex;
1810 model = CL_GetModelByIndex(modelindex);
1813 v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.client->skin, tagname);
1815 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);
1818 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));
1822 /////////////////////////////////////////
1823 // DP_MD3_TAGINFO extension coded by VorteX
1825 int CL_GetTagIndex (prvm_edict_t *e, const char *tagname)
1827 model_t *model = CL_GetModelFromEdict(e);
1829 return Mod_Alias_GetTagIndexForName(model, (int)e->fields.client->skin, tagname);
1834 // Warnings/errors code:
1835 // 0 - normal (everything all-right)
1838 // 3 - null or non-precached model
1839 // 4 - no tags with requested index
1840 // 5 - runaway loop at attachment chain
1841 extern cvar_t cl_bob;
1842 extern cvar_t cl_bobcycle;
1843 extern cvar_t cl_bobup;
1844 int CL_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
1847 int reqframe, attachloop;
1848 matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
1849 prvm_edict_t *attachent;
1852 *out = identitymatrix; // warnings and errors return identical matrix
1854 if (ent == prog->edicts)
1856 if (ent->priv.server->free)
1859 model = CL_GetModelFromEdict(ent);
1864 if (ent->fields.client->frame >= 0 && ent->fields.client->frame < model->numframes && model->animscenes)
1865 reqframe = model->animscenes[(int)ent->fields.client->frame].firstframe;
1867 reqframe = 0; // if model has wrong frame, engine automatically switches to model first frame
1869 // get initial tag matrix
1872 int ret = Mod_Alias_GetTagMatrix(model, reqframe, tagindex - 1, &tagmatrix);
1877 tagmatrix = identitymatrix;
1879 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict)
1880 { // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
1884 attachent = PRVM_EDICT_NUM(val->edict); // to this it entity our entity is attached
1885 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index);
1887 model = CL_GetModelFromEdict(attachent);
1889 if (model && val->_float >= 1 && model->animscenes && attachent->fields.client->frame >= 0 && attachent->fields.client->frame < model->numframes)
1890 Mod_Alias_GetTagMatrix(model, model->animscenes[(int)attachent->fields.client->frame].firstframe, (int)val->_float - 1, &attachmatrix);
1892 attachmatrix = identitymatrix;
1894 // apply transformation by child entity matrix
1895 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1896 if (val->_float == 0)
1898 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);
1899 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1900 Matrix4x4_Copy(&tagmatrix, out);
1902 // finally transformate by matrix of tag on parent entity
1903 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
1904 Matrix4x4_Copy(&tagmatrix, out);
1908 if (attachloop > 255) // prevent runaway looping
1911 while ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)) && val->edict);
1914 // normal or RENDER_VIEWMODEL entity (or main parent entity on attach chain)
1915 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1916 if (val->_float == 0)
1918 // Alias models have inverse pitch, bmodels can't have tags, so don't check for modeltype...
1919 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);
1920 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1922 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderflags)) && (RF_VIEWMODEL & (int)val->_float))
1923 {// RENDER_VIEWMODEL magic
1924 Matrix4x4_Copy(&tagmatrix, out);
1926 val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale);
1927 if (val->_float == 0)
1930 Matrix4x4_CreateFromQuakeEntity(&entitymatrix, csqc_origin[0], csqc_origin[1], csqc_origin[2], csqc_angles[0], csqc_angles[1], csqc_angles[2], val->_float);
1931 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
1934 // Cl_bob, ported from rendering code
1935 if (ent->fields.client->health > 0 && cl_bob.value && cl_bobcycle.value)
1938 // LordHavoc: this code is *weird*, but not replacable (I think it
1939 // should be done in QC on the server, but oh well, quake is quake)
1940 // LordHavoc: figured out bobup: the time at which the sin is at 180
1941 // degrees (which allows lengthening or squishing the peak or valley)
1942 cycle = sv.time/cl_bobcycle.value;
1943 cycle -= (int)cycle;
1944 if (cycle < cl_bobup.value)
1945 cycle = sin(M_PI * cycle / cl_bobup.value);
1947 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
1948 // bob is proportional to velocity in the xy plane
1949 // (don't count Z, or jumping messes it up)
1950 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;
1951 bob = bob*0.3 + bob*0.7*cycle;
1952 Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
1959 // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
1960 static void VM_CL_gettagindex (void)
1963 const char *tag_name;
1964 int modelindex, tag_index;
1966 VM_SAFEPARMCOUNT(2, VM_CL_gettagindex);
1968 ent = PRVM_G_EDICT(OFS_PARM0);
1969 tag_name = PRVM_G_STRING(OFS_PARM1);
1970 if (ent == prog->edicts)
1972 VM_Warning("gettagindex: can't affect world entity\n");
1975 if (ent->priv.server->free)
1977 VM_Warning("gettagindex: can't affect free entity\n");
1981 modelindex = (int)ent->fields.client->modelindex;
1983 modelindex = -(modelindex+1);
1985 if (modelindex <= 0 || modelindex >= MAX_MODELS)
1986 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
1989 tag_index = CL_GetTagIndex(ent, tag_name);
1991 Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
1993 PRVM_G_FLOAT(OFS_RETURN) = tag_index;
1996 // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
1997 static void VM_CL_gettaginfo (void)
2001 matrix4x4_t tag_matrix;
2004 VM_SAFEPARMCOUNT(2, VM_CL_gettaginfo);
2006 e = PRVM_G_EDICT(OFS_PARM0);
2007 tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2008 returncode = CL_GetTagMatrix(&tag_matrix, e, tagindex);
2009 Matrix4x4_ToVectors(&tag_matrix, prog->globals.client->v_forward, prog->globals.client->v_right, prog->globals.client->v_up, PRVM_G_VECTOR(OFS_RETURN));
2014 VM_Warning("gettagindex: can't affect world entity\n");
2017 VM_Warning("gettagindex: can't affect free entity\n");
2020 Con_DPrintf("CL_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2023 Con_DPrintf("CL_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2026 Con_DPrintf("CL_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2031 //============================================================================
2033 //====================
2034 //QC POLYGON functions
2035 //====================
2040 float data[36]; //[515]: enough for polygons
2041 unsigned char flags; //[515]: + VM_POLYGON_2D and VM_POLYGON_FL4V flags
2044 //static float vm_polygon_linewidth = 1;
2045 static mempool_t *vm_polygons_pool = NULL;
2046 static unsigned char vm_current_vertices = 0;
2047 static qboolean vm_polygons_initialized = false;
2048 static vm_polygon_t *vm_polygons = NULL;
2049 static unsigned long vm_polygons_num = 0, vm_drawpolygons_num = 0; //[515]: ok long on 64bit ?
2050 static qboolean vm_polygonbegin = false; //[515]: for "no-crap-on-the-screen" check
2051 #define VM_DEFPOLYNUM 64 //[515]: enough for default ?
2053 #define VM_POLYGON_FL3V 16 //more than 2 vertices (used only for lines)
2054 #define VM_POLYGON_FLLINES 32
2055 #define VM_POLYGON_FL2D 64
2056 #define VM_POLYGON_FL4V 128 //4 vertices
2058 static void VM_InitPolygons (void)
2060 vm_polygons_pool = Mem_AllocPool("VMPOLY", 0, NULL);
2061 vm_polygons = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2062 memset(vm_polygons, 0, VM_DEFPOLYNUM*sizeof(vm_polygon_t));
2063 vm_polygons_num = VM_DEFPOLYNUM;
2064 vm_drawpolygons_num = 0;
2065 vm_polygonbegin = false;
2066 vm_polygons_initialized = true;
2069 static void VM_DrawPolygonCallback (const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2071 int surfacelistindex;
2072 // LordHavoc: FIXME: this is stupid code
2073 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2075 const vm_polygon_t *p = &vm_polygons[surfacelist[surfacelistindex]];
2076 int flags = p->flags & 0x0f;
2078 if(flags == DRAWFLAG_ADDITIVE)
2079 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2080 else if(flags == DRAWFLAG_MODULATE)
2081 GL_BlendFunc(GL_DST_COLOR, GL_ZERO);
2082 else if(flags == DRAWFLAG_2XMODULATE)
2083 GL_BlendFunc(GL_DST_COLOR,GL_SRC_COLOR);
2085 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2087 R_Mesh_TexBind(0, R_GetTexture(p->tex));
2090 //[515]: is speed is max ?
2091 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2093 qglLineWidth(p->data[13]);CHECKGLERROR
2094 qglBegin(GL_LINE_LOOP);
2095 qglTexCoord1f (p->data[12]);
2096 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2097 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2099 qglTexCoord1f (p->data[14]);
2100 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2101 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2103 if(p->flags & VM_POLYGON_FL3V)
2105 qglTexCoord1f (p->data[16]);
2106 qglColor4f (p->data[28], p->data[29], p->data[30], p->data[31]);
2107 qglVertex3f (p->data[6] , p->data[7], p->data[8]);
2109 if(p->flags & VM_POLYGON_FL4V)
2111 qglTexCoord1f (p->data[18]);
2112 qglColor4f (p->data[32], p->data[33], p->data[34], p->data[35]);
2113 qglVertex3f (p->data[9] , p->data[10], p->data[11]);
2121 qglBegin(GL_POLYGON);
2122 qglTexCoord2f (p->data[12], p->data[13]);
2123 qglColor4f (p->data[20], p->data[21], p->data[22], p->data[23]);
2124 qglVertex3f (p->data[0] , p->data[1], p->data[2]);
2126 qglTexCoord2f (p->data[14], p->data[15]);
2127 qglColor4f (p->data[24], p->data[25], p->data[26], p->data[27]);
2128 qglVertex3f (p->data[3] , p->data[4], p->data[5]);
2130 qglTexCoord2f (p->data[16], p->data[17]);
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 qglTexCoord2f (p->data[18], p->data[19]);
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 static void VM_CL_AddPolygonTo2DScene (vm_polygon_t *p)
2148 drawqueuemesh_t mesh;
2149 static int picelements[6] = {0, 1, 2, 0, 2, 3};
2151 mesh.texture = p->tex;
2152 mesh.data_element3i = picelements;
2153 mesh.data_vertex3f = p->data;
2154 mesh.data_texcoord2f = p->data + 12;
2155 mesh.data_color4f = p->data + 20;
2156 if(p->flags & VM_POLYGON_FL4V)
2158 mesh.num_vertices = 4;
2159 mesh.num_triangles = 2;
2163 mesh.num_vertices = 3;
2164 mesh.num_triangles = 1;
2166 if(p->flags & VM_POLYGON_FLLINES) //[515]: lines
2167 DrawQ_LineLoop (&mesh, (p->flags&0x0f));
2169 DrawQ_Mesh (&mesh, (p->flags&0x0f));
2172 void VM_CL_AddPolygonsToMeshQueue (void)
2175 if(!vm_drawpolygons_num)
2177 R_Mesh_Matrix(&identitymatrix);
2178 GL_CullFace(GL_NONE);
2179 for(i = 0;i < (int)vm_drawpolygons_num;i++)
2180 VM_DrawPolygonCallback(NULL, NULL, 1, &i);
2181 vm_drawpolygons_num = 0;
2184 //void(string texturename, float flag[, float 2d[, float lines]]) R_BeginPolygon
2185 static void VM_CL_R_PolygonBegin (void)
2188 const char *picname;
2189 VM_SAFEPARMCOUNTRANGE(2, 4, VM_CL_R_PolygonBegin);
2191 if(!vm_polygons_initialized)
2195 VM_Warning("VM_CL_R_PolygonBegin: called twice without VM_CL_R_PolygonEnd after first\n");
2198 if(vm_drawpolygons_num >= vm_polygons_num)
2200 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2201 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2202 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2203 Mem_Free(vm_polygons);
2205 vm_polygons_num *= 2;
2207 p = &vm_polygons[vm_drawpolygons_num];
2208 picname = PRVM_G_STRING(OFS_PARM0);
2210 p->tex = Draw_CachePic(picname, true)->tex;
2212 p->tex = r_texture_white;
2213 p->flags = (unsigned char)PRVM_G_FLOAT(OFS_PARM1);
2214 vm_current_vertices = 0;
2215 vm_polygonbegin = true;
2218 if(PRVM_G_FLOAT(OFS_PARM2))
2219 p->flags |= VM_POLYGON_FL2D;
2220 if(prog->argc >= 4 && PRVM_G_FLOAT(OFS_PARM3))
2222 p->data[13] = PRVM_G_FLOAT(OFS_PARM3); //[515]: linewidth
2223 p->flags |= VM_POLYGON_FLLINES;
2228 //void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2229 static void VM_CL_R_PolygonVertex (void)
2231 float *coords, *tx, *rgb, alpha;
2233 VM_SAFEPARMCOUNT(4, VM_CL_R_PolygonVertex);
2235 if(!vm_polygonbegin)
2237 VM_Warning("VM_CL_R_PolygonVertex: VM_CL_R_PolygonBegin wasn't called\n");
2240 coords = PRVM_G_VECTOR(OFS_PARM0);
2241 tx = PRVM_G_VECTOR(OFS_PARM1);
2242 rgb = PRVM_G_VECTOR(OFS_PARM2);
2243 alpha = PRVM_G_FLOAT(OFS_PARM3);
2245 p = &vm_polygons[vm_drawpolygons_num];
2246 if(vm_current_vertices > 4)
2248 VM_Warning("VM_CL_R_PolygonVertex: may have 4 vertices max\n");
2252 p->data[vm_current_vertices*3] = coords[0];
2253 p->data[1+vm_current_vertices*3] = coords[1];
2254 p->data[2+vm_current_vertices*3] = coords[2];
2256 p->data[12+vm_current_vertices*2] = tx[0];
2257 if(!(p->flags & VM_POLYGON_FLLINES))
2258 p->data[13+vm_current_vertices*2] = tx[1];
2260 p->data[20+vm_current_vertices*4] = rgb[0];
2261 p->data[21+vm_current_vertices*4] = rgb[1];
2262 p->data[22+vm_current_vertices*4] = rgb[2];
2263 p->data[23+vm_current_vertices*4] = alpha;
2265 vm_current_vertices++;
2266 if(vm_current_vertices == 4)
2267 p->flags |= VM_POLYGON_FL4V;
2269 if(vm_current_vertices == 3)
2270 p->flags |= VM_POLYGON_FL3V;
2273 //void() R_EndPolygon
2274 static void VM_CL_R_PolygonEnd (void)
2276 VM_SAFEPARMCOUNT(0, VM_CL_R_PolygonEnd);
2277 if(!vm_polygonbegin)
2279 VM_Warning("VM_CL_R_PolygonEnd: VM_CL_R_PolygonBegin wasn't called\n");
2282 vm_polygonbegin = false;
2283 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2285 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2286 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2288 vm_drawpolygons_num++;
2291 VM_Warning("VM_CL_R_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2294 void Debug_PolygonBegin(const char *picname, int flags, qboolean draw2d, float linewidth)
2298 if(!vm_polygons_initialized)
2302 Con_Printf("Debug_PolygonBegin: called twice without Debug_PolygonEnd after first\n");
2305 // limit polygons to a vaguely sane amount, beyond this each one just
2306 // replaces the last one
2307 vm_drawpolygons_num = min(vm_drawpolygons_num, (1<<20)-1);
2308 if(vm_drawpolygons_num >= vm_polygons_num)
2310 p = (vm_polygon_t *)Mem_Alloc(vm_polygons_pool, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2311 memset(p, 0, 2 * vm_polygons_num * sizeof(vm_polygon_t));
2312 memcpy(p, vm_polygons, vm_polygons_num * sizeof(vm_polygon_t));
2313 Mem_Free(vm_polygons);
2315 vm_polygons_num *= 2;
2317 p = &vm_polygons[vm_drawpolygons_num];
2318 if(picname && picname[0])
2319 p->tex = Draw_CachePic(picname, true)->tex;
2321 p->tex = r_texture_white;
2323 vm_current_vertices = 0;
2324 vm_polygonbegin = true;
2326 p->flags |= VM_POLYGON_FL2D;
2329 p->data[13] = linewidth; //[515]: linewidth
2330 p->flags |= VM_POLYGON_FLLINES;
2334 void Debug_PolygonVertex(float x, float y, float z, float s, float t, float r, float g, float b, float a)
2338 if(!vm_polygonbegin)
2340 Con_Printf("Debug_PolygonVertex: Debug_PolygonBegin wasn't called\n");
2344 p = &vm_polygons[vm_drawpolygons_num];
2345 if(vm_current_vertices > 4)
2347 Con_Printf("Debug_PolygonVertex: may have 4 vertices max\n");
2351 p->data[vm_current_vertices*3] = x;
2352 p->data[1+vm_current_vertices*3] = y;
2353 p->data[2+vm_current_vertices*3] = z;
2355 p->data[12+vm_current_vertices*2] = s;
2356 if(!(p->flags & VM_POLYGON_FLLINES))
2357 p->data[13+vm_current_vertices*2] = t;
2359 p->data[20+vm_current_vertices*4] = r;
2360 p->data[21+vm_current_vertices*4] = g;
2361 p->data[22+vm_current_vertices*4] = b;
2362 p->data[23+vm_current_vertices*4] = a;
2364 vm_current_vertices++;
2365 if(vm_current_vertices == 4)
2366 p->flags |= VM_POLYGON_FL4V;
2368 if(vm_current_vertices == 3)
2369 p->flags |= VM_POLYGON_FL3V;
2372 void Debug_PolygonEnd(void)
2374 if(!vm_polygonbegin)
2376 Con_Printf("Debug_PolygonEnd: Debug_PolygonBegin wasn't called\n");
2379 vm_polygonbegin = false;
2380 if(vm_current_vertices > 2 || (vm_current_vertices >= 2 && vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FLLINES))
2382 if(vm_polygons[vm_drawpolygons_num].flags & VM_POLYGON_FL2D) //[515]: don't use qcpolygons memory if 2D
2383 VM_CL_AddPolygonTo2DScene(&vm_polygons[vm_drawpolygons_num]);
2385 vm_drawpolygons_num++;
2388 Con_Printf("Debug_PolygonEnd: %i vertices isn't a good choice\n", vm_current_vertices);
2395 Returns false if any part of the bottom of the entity is off an edge that
2400 qboolean CL_CheckBottom (prvm_edict_t *ent)
2402 vec3_t mins, maxs, start, stop;
2407 VectorAdd (ent->fields.client->origin, ent->fields.client->mins, mins);
2408 VectorAdd (ent->fields.client->origin, ent->fields.client->maxs, maxs);
2410 // if all of the points under the corners are solid world, don't bother
2411 // with the tougher checks
2412 // the corners must be within 16 of the midpoint
2413 start[2] = mins[2] - 1;
2414 for (x=0 ; x<=1 ; x++)
2415 for (y=0 ; y<=1 ; y++)
2417 start[0] = x ? maxs[0] : mins[0];
2418 start[1] = y ? maxs[1] : mins[1];
2419 if (!(CL_PointSuperContents(start) & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY)))
2423 return true; // we got out easy
2427 // check it for real...
2431 // the midpoint must be within 16 of the bottom
2432 start[0] = stop[0] = (mins[0] + maxs[0])*0.5;
2433 start[1] = stop[1] = (mins[1] + maxs[1])*0.5;
2434 stop[2] = start[2] - 2*sv_stepheight.value;
2435 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2437 if (trace.fraction == 1.0)
2439 mid = bottom = trace.endpos[2];
2441 // the corners must be within 16 of the midpoint
2442 for (x=0 ; x<=1 ; x++)
2443 for (y=0 ; y<=1 ; y++)
2445 start[0] = stop[0] = x ? maxs[0] : mins[0];
2446 start[1] = stop[1] = y ? maxs[1] : mins[1];
2448 trace = CL_Move (start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2450 if (trace.fraction != 1.0 && trace.endpos[2] > bottom)
2451 bottom = trace.endpos[2];
2452 if (trace.fraction == 1.0 || mid - trace.endpos[2] > sv_stepheight.value)
2463 Called by monster program code.
2464 The move will be adjusted for slopes and stairs, but if the move isn't
2465 possible, no move is done and false is returned
2468 qboolean CL_movestep (prvm_edict_t *ent, vec3_t move, qboolean relink, qboolean noenemy, qboolean settrace)
2471 vec3_t oldorg, neworg, end, traceendpos;
2474 prvm_edict_t *enemy;
2478 VectorCopy (ent->fields.client->origin, oldorg);
2479 VectorAdd (ent->fields.client->origin, move, neworg);
2481 // flying monsters don't step up
2482 if ( (int)ent->fields.client->flags & (FL_SWIM | FL_FLY) )
2484 // try one move with vertical motion, then one without
2485 for (i=0 ; i<2 ; i++)
2487 VectorAdd (ent->fields.client->origin, move, neworg);
2488 enemy = PRVM_PROG_TO_EDICT(ent->fields.client->enemy);
2489 if (i == 0 && enemy != prog->edicts)
2491 dz = ent->fields.client->origin[2] - PRVM_PROG_TO_EDICT(ent->fields.client->enemy)->fields.client->origin[2];
2497 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);
2499 VM_SetTraceGlobals(&trace);
2501 if (trace.fraction == 1)
2503 VectorCopy(trace.endpos, traceendpos);
2504 if (((int)ent->fields.client->flags & FL_SWIM) && !(CL_PointSuperContents(traceendpos) & SUPERCONTENTS_LIQUIDSMASK))
2505 return false; // swim monster left water
2507 VectorCopy (traceendpos, ent->fields.client->origin);
2513 if (enemy == prog->edicts)
2520 // push down from a step height above the wished position
2521 neworg[2] += sv_stepheight.value;
2522 VectorCopy (neworg, end);
2523 end[2] -= sv_stepheight.value*2;
2525 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2527 VM_SetTraceGlobals(&trace);
2529 if (trace.startsolid)
2531 neworg[2] -= sv_stepheight.value;
2532 trace = CL_Move (neworg, ent->fields.client->mins, ent->fields.client->maxs, end, MOVE_NORMAL, ent, CL_GenericHitSuperContentsMask(ent), true, true, NULL, true);
2534 VM_SetTraceGlobals(&trace);
2535 if (trace.startsolid)
2538 if (trace.fraction == 1)
2540 // if monster had the ground pulled out, go ahead and fall
2541 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2543 VectorAdd (ent->fields.client->origin, move, ent->fields.client->origin);
2546 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_ONGROUND;
2550 return false; // walked off an edge
2553 // check point traces down for dangling corners
2554 VectorCopy (trace.endpos, ent->fields.client->origin);
2556 if (!CL_CheckBottom (ent))
2558 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2559 { // entity had floor mostly pulled out from underneath it
2560 // and is trying to correct
2565 VectorCopy (oldorg, ent->fields.client->origin);
2569 if ( (int)ent->fields.client->flags & FL_PARTIALGROUND )
2570 ent->fields.client->flags = (int)ent->fields.client->flags & ~FL_PARTIALGROUND;
2572 if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.groundentity)))
2573 val->edict = PRVM_EDICT_TO_PROG(trace.ent);
2585 float(float yaw, float dist[, settrace]) walkmove
2588 static void VM_CL_walkmove (void)
2597 VM_SAFEPARMCOUNTRANGE(2, 3, VM_CL_walkmove);
2599 // assume failure if it returns early
2600 PRVM_G_FLOAT(OFS_RETURN) = 0;
2602 ent = PRVM_PROG_TO_EDICT(prog->globals.client->self);
2603 if (ent == prog->edicts)
2605 VM_Warning("walkmove: can not modify world entity\n");
2608 if (ent->priv.server->free)
2610 VM_Warning("walkmove: can not modify free entity\n");
2613 yaw = PRVM_G_FLOAT(OFS_PARM0);
2614 dist = PRVM_G_FLOAT(OFS_PARM1);
2615 settrace = prog->argc >= 3 && PRVM_G_FLOAT(OFS_PARM2);
2617 if ( !( (int)ent->fields.client->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
2620 yaw = yaw*M_PI*2 / 360;
2622 move[0] = cos(yaw)*dist;
2623 move[1] = sin(yaw)*dist;
2626 // save program state, because CL_movestep may call other progs
2627 oldf = prog->xfunction;
2628 oldself = prog->globals.client->self;
2630 PRVM_G_FLOAT(OFS_RETURN) = CL_movestep(ent, move, true, false, settrace);
2633 // restore program state
2634 prog->xfunction = oldf;
2635 prog->globals.client->self = oldself;
2642 string(string key) serverkey
2645 void VM_CL_serverkey(void)
2647 char string[VM_STRINGTEMP_LENGTH];
2648 VM_SAFEPARMCOUNT(1, VM_CL_serverkey);
2649 InfoString_GetValue(cl.qw_serverinfo, PRVM_G_STRING(OFS_PARM0), string, sizeof(string));
2650 PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
2653 //============================================================================
2655 prvm_builtin_t vm_cl_builtins[] = {
2656 NULL, // #0 NULL function (not callable) (QUAKE)
2657 VM_CL_makevectors, // #1 void(vector ang) makevectors (QUAKE)
2658 VM_CL_setorigin, // #2 void(entity e, vector o) setorigin (QUAKE)
2659 VM_CL_setmodel, // #3 void(entity e, string m) setmodel (QUAKE)
2660 VM_CL_setsize, // #4 void(entity e, vector min, vector max) setsize (QUAKE)
2661 NULL, // #5 void(entity e, vector min, vector max) setabssize (QUAKE)
2662 VM_break, // #6 void() break (QUAKE)
2663 VM_random, // #7 float() random (QUAKE)
2664 VM_CL_sound, // #8 void(entity e, float chan, string samp) sound (QUAKE)
2665 VM_normalize, // #9 vector(vector v) normalize (QUAKE)
2666 VM_error, // #10 void(string e) error (QUAKE)
2667 VM_objerror, // #11 void(string e) objerror (QUAKE)
2668 VM_vlen, // #12 float(vector v) vlen (QUAKE)
2669 VM_vectoyaw, // #13 float(vector v) vectoyaw (QUAKE)
2670 VM_CL_spawn, // #14 entity() spawn (QUAKE)
2671 VM_remove, // #15 void(entity e) remove (QUAKE)
2672 VM_CL_traceline, // #16 float(vector v1, vector v2, float tryents) traceline (QUAKE)
2673 NULL, // #17 entity() checkclient (QUAKE)
2674 VM_find, // #18 entity(entity start, .string fld, string match) find (QUAKE)
2675 VM_precache_sound, // #19 void(string s) precache_sound (QUAKE)
2676 VM_CL_precache_model, // #20 void(string s) precache_model (QUAKE)
2677 NULL, // #21 void(entity client, string s, ...) stuffcmd (QUAKE)
2678 VM_CL_findradius, // #22 entity(vector org, float rad) findradius (QUAKE)
2679 NULL, // #23 void(string s, ...) bprint (QUAKE)
2680 NULL, // #24 void(entity client, string s, ...) sprint (QUAKE)
2681 VM_dprint, // #25 void(string s, ...) dprint (QUAKE)
2682 VM_ftos, // #26 string(float f) ftos (QUAKE)
2683 VM_vtos, // #27 string(vector v) vtos (QUAKE)
2684 VM_coredump, // #28 void() coredump (QUAKE)
2685 VM_traceon, // #29 void() traceon (QUAKE)
2686 VM_traceoff, // #30 void() traceoff (QUAKE)
2687 VM_eprint, // #31 void(entity e) eprint (QUAKE)
2688 VM_CL_walkmove, // #32 float(float yaw, float dist) walkmove (QUAKE)
2689 NULL, // #33 (QUAKE)
2690 VM_CL_droptofloor, // #34 float() droptofloor (QUAKE)
2691 VM_CL_lightstyle, // #35 void(float style, string value) lightstyle (QUAKE)
2692 VM_rint, // #36 float(float v) rint (QUAKE)
2693 VM_floor, // #37 float(float v) floor (QUAKE)
2694 VM_ceil, // #38 float(float v) ceil (QUAKE)
2695 NULL, // #39 (QUAKE)
2696 VM_CL_checkbottom, // #40 float(entity e) checkbottom (QUAKE)
2697 VM_CL_pointcontents, // #41 float(vector v) pointcontents (QUAKE)
2698 NULL, // #42 (QUAKE)
2699 VM_fabs, // #43 float(float f) fabs (QUAKE)
2700 NULL, // #44 vector(entity e, float speed) aim (QUAKE)
2701 VM_cvar, // #45 float(string s) cvar (QUAKE)
2702 VM_localcmd, // #46 void(string s) localcmd (QUAKE)
2703 VM_nextent, // #47 entity(entity e) nextent (QUAKE)
2704 VM_CL_particle, // #48 void(vector o, vector d, float color, float count) particle (QUAKE)
2705 VM_changeyaw, // #49 void() ChangeYaw (QUAKE)
2706 NULL, // #50 (QUAKE)
2707 VM_vectoangles, // #51 vector(vector v) vectoangles (QUAKE)
2708 NULL, // #52 void(float to, float f) WriteByte (QUAKE)
2709 NULL, // #53 void(float to, float f) WriteChar (QUAKE)
2710 NULL, // #54 void(float to, float f) WriteShort (QUAKE)
2711 NULL, // #55 void(float to, float f) WriteLong (QUAKE)
2712 NULL, // #56 void(float to, float f) WriteCoord (QUAKE)
2713 NULL, // #57 void(float to, float f) WriteAngle (QUAKE)
2714 NULL, // #58 void(float to, string s) WriteString (QUAKE)
2715 NULL, // #59 (QUAKE)
2716 VM_sin, // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2717 VM_cos, // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2718 VM_sqrt, // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2719 VM_changepitch, // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2720 VM_CL_tracetoss, // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2721 VM_etos, // #65 string(entity ent) etos (DP_QC_ETOS)
2722 NULL, // #66 (QUAKE)
2723 NULL, // #67 void(float step) movetogoal (QUAKE)
2724 VM_precache_file, // #68 string(string s) precache_file (QUAKE)
2725 VM_CL_makestatic, // #69 void(entity e) makestatic (QUAKE)
2726 NULL, // #70 void(string s) changelevel (QUAKE)
2727 NULL, // #71 (QUAKE)
2728 VM_cvar_set, // #72 void(string var, string val) cvar_set (QUAKE)
2729 NULL, // #73 void(entity client, strings) centerprint (QUAKE)
2730 VM_CL_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound (QUAKE)
2731 VM_CL_precache_model, // #75 string(string s) precache_model2 (QUAKE)
2732 VM_precache_sound, // #76 string(string s) precache_sound2 (QUAKE)
2733 VM_precache_file, // #77 string(string s) precache_file2 (QUAKE)
2734 NULL, // #78 void(entity e) setspawnparms (QUAKE)
2735 NULL, // #79 void(entity killer, entity killee) logfrag (QUAKEWORLD)
2736 NULL, // #80 string(entity e, string keyname) infokey (QUAKEWORLD)
2737 VM_stof, // #81 float(string s) stof (FRIK_FILE)
2738 NULL, // #82 void(vector where, float set) multicast (QUAKEWORLD)
2739 NULL, // #83 (QUAKE)
2740 NULL, // #84 (QUAKE)
2741 NULL, // #85 (QUAKE)
2742 NULL, // #86 (QUAKE)
2743 NULL, // #87 (QUAKE)
2744 NULL, // #88 (QUAKE)
2745 NULL, // #89 (QUAKE)
2746 VM_CL_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2747 VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC)
2748 VM_CL_getlight, // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2749 VM_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2750 VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2751 VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2752 VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2753 VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2754 VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2755 VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system)
2756 // FrikaC and Telejano range #100-#199
2767 VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE)
2768 VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE)
2769 VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE)
2770 VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2771 VM_strlen, // #114 float(string s) strlen (FRIK_FILE)
2772 VM_strcat, // #115 string(string s1, string s2, ...) strcat (FRIK_FILE)
2773 VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE)
2774 VM_stov, // #117 vector(string) stov (FRIK_FILE)
2775 VM_strzone, // #118 string(string s) strzone (FRIK_FILE)
2776 VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE)
2857 // FTEQW range #200-#299
2876 VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
2880 VM_str2chr, // #222 float(string str, float ofs) str2chr (FTE_STRINGS)
2881 VM_chr2str, // #223 string(float c, ...) chr2str (FTE_STRINGS)
2886 VM_strncmp, // #228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
2890 NULL, // #232 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
2958 // CSQC range #300-#399
2959 VM_CL_R_ClearScene, // #300 void() clearscene (EXT_CSQC)
2960 VM_CL_R_AddEntities, // #301 void(float mask) addentities (EXT_CSQC)
2961 VM_CL_R_AddEntity, // #302 void(entity ent) addentity (EXT_CSQC)
2962 VM_CL_R_SetView, // #303 float(float property, ...) setproperty (EXT_CSQC)
2963 VM_CL_R_RenderScene, // #304 void() renderscene (EXT_CSQC)
2964 VM_CL_R_AddDynamicLight, // #305 void(vector org, float radius, vector lightcolours) adddynamiclight (EXT_CSQC)
2965 VM_CL_R_PolygonBegin, // #306 void(string texturename, float flag[, float is2d, float lines]) R_BeginPolygon
2966 VM_CL_R_PolygonVertex, // #307 void(vector org, vector texcoords, vector rgb, float alpha) R_PolygonVertex
2967 VM_CL_R_PolygonEnd, // #308 void() R_EndPolygon
2969 VM_CL_unproject, // #310 vector (vector v) cs_unproject (EXT_CSQC)
2970 VM_CL_project, // #311 vector (vector v) cs_project (EXT_CSQC)
2974 VM_drawline, // #315 void(float width, vector pos1, vector pos2, float flag) drawline (EXT_CSQC)
2975 VM_iscachedpic, // #316 float(string name) iscachedpic (EXT_CSQC)
2976 VM_precache_pic, // #317 string(string name, float trywad) precache_pic (EXT_CSQC)
2977 VM_getimagesize, // #318 vector(string picname) draw_getimagesize (EXT_CSQC)
2978 VM_freepic, // #319 void(string name) freepic (EXT_CSQC)
2979 VM_drawcharacter, // #320 float(vector position, float character, vector scale, vector rgb, float alpha, float flag) drawcharacter (EXT_CSQC)
2980 VM_drawstring, // #321 float(vector position, string text, vector scale, vector rgb, float alpha, float flag) drawstring (EXT_CSQC)
2981 VM_drawpic, // #322 float(vector position, string pic, vector size, vector rgb, float alpha, float flag) drawpic (EXT_CSQC)
2982 VM_drawfill, // #323 float(vector position, vector size, vector rgb, float alpha, float flag) drawfill (EXT_CSQC)
2983 VM_drawsetcliparea, // #324 void(float x, float y, float width, float height) drawsetcliparea
2984 VM_drawresetcliparea, // #325 void(void) drawresetcliparea
2989 VM_CL_getstatf, // #330 float(float stnum) getstatf (EXT_CSQC)
2990 VM_CL_getstati, // #331 float(float stnum) getstati (EXT_CSQC)
2991 VM_CL_getstats, // #332 string(float firststnum) getstats (EXT_CSQC)
2992 VM_CL_setmodelindex, // #333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
2993 VM_CL_modelnameforindex, // #334 string(float mdlindex) modelnameforindex (EXT_CSQC)
2994 VM_CL_particleeffectnum, // #335 float(string effectname) particleeffectnum (EXT_CSQC)
2995 VM_CL_trailparticles, // #336 void(entity ent, float effectnum, vector start, vector end) trailparticles (EXT_CSQC)
2996 VM_CL_pointparticles, // #337 void(float effectnum, vector origin [, vector dir, float count]) pointparticles (EXT_CSQC)
2997 VM_centerprint, // #338 void(string s, ...) centerprint (EXT_CSQC)
2998 VM_print, // #339 void(string s, ...) print (EXT_CSQC, DP_SV_PRINT)
2999 VM_keynumtostring, // #340 string(float keynum) keynumtostring (EXT_CSQC)
3000 VM_stringtokeynum, // #341 float(string keyname) stringtokeynum (EXT_CSQC)
3001 VM_CL_getkeybind, // #342 string(float keynum) getkeybind (EXT_CSQC)
3002 VM_CL_setcursormode, // #343 void(float usecursor) setcursormode (EXT_CSQC)
3003 VM_getmousepos, // #344 vector() getmousepos (EXT_CSQC)
3004 VM_CL_getinputstate, // #345 float(float framenum) getinputstate (EXT_CSQC)
3005 VM_CL_setsensitivityscale, // #346 void(float sens) setsensitivityscaler (EXT_CSQC)
3006 VM_CL_runplayerphysics, // #347 void() runstandardplayerphysics (EXT_CSQC)
3007 VM_CL_getplayerkey, // #348 string(float playernum, string keyname) getplayerkeyvalue (EXT_CSQC)
3008 VM_CL_isdemo, // #349 float() isdemo (EXT_CSQC)
3009 VM_isserver, // #350 float() isserver (EXT_CSQC)
3010 VM_CL_setlistener, // #351 void(vector origin, vector forward, vector right, vector up) SetListener (EXT_CSQC)
3011 VM_CL_registercmd, // #352 void(string cmdname) registercommand (EXT_CSQC)
3012 VM_wasfreed, // #353 float(entity ent) wasfreed (EXT_CSQC) (should be availabe on server too)
3013 VM_CL_serverkey, // #354 string(string key) serverkey (EXT_CSQC)
3019 VM_CL_ReadByte, // #360 float() readbyte (EXT_CSQC)
3020 VM_CL_ReadChar, // #361 float() readchar (EXT_CSQC)
3021 VM_CL_ReadShort, // #362 float() readshort (EXT_CSQC)
3022 VM_CL_ReadLong, // #363 float() readlong (EXT_CSQC)
3023 VM_CL_ReadCoord, // #364 float() readcoord (EXT_CSQC)
3024 VM_CL_ReadAngle, // #365 float() readangle (EXT_CSQC)
3025 VM_CL_ReadString, // #366 string() readstring (EXT_CSQC)
3026 VM_CL_ReadFloat, // #367 float() readfloat (EXT_CSQC)
3059 // LordHavoc's range #400-#499
3060 VM_CL_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
3061 NULL, // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
3062 VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
3063 VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
3064 VM_CL_effect, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
3065 VM_CL_te_blood, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
3066 VM_CL_te_bloodshower, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
3067 VM_CL_te_explosionrgb, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
3068 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)
3069 VM_CL_te_particlerain, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
3070 VM_CL_te_particlesnow, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
3071 VM_CL_te_spark, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
3072 VM_CL_te_gunshotquad, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
3073 VM_CL_te_spikequad, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
3074 VM_CL_te_superspikequad, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
3075 VM_CL_te_explosionquad, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
3076 VM_CL_te_smallflash, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
3077 VM_CL_te_customflash, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
3078 VM_CL_te_gunshot, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
3079 VM_CL_te_spike, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
3080 VM_CL_te_superspike, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
3081 VM_CL_te_explosion, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
3082 VM_CL_te_tarexplosion, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
3083 VM_CL_te_wizspike, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
3084 VM_CL_te_knightspike, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
3085 VM_CL_te_lavasplash, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
3086 VM_CL_te_teleport, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
3087 VM_CL_te_explosion2, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
3088 VM_CL_te_lightning1, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
3089 VM_CL_te_lightning2, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
3090 VM_CL_te_lightning3, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
3091 VM_CL_te_beam, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
3092 VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
3093 VM_CL_te_plasmaburn, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
3094 VM_CL_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
3095 VM_CL_getsurfacepoint, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
3096 VM_CL_getsurfacenormal, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
3097 VM_CL_getsurfacetexture, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
3098 VM_CL_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
3099 VM_CL_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
3100 NULL, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
3101 VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
3102 VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
3103 VM_CL_setattachment, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
3104 VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
3105 VM_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH)
3106 VM_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH)
3107 VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
3108 VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
3109 VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
3110 VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
3111 VM_CL_gettagindex, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
3112 VM_CL_gettaginfo, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
3113 NULL, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
3114 NULL, // #454 entity() spawnclient (DP_SV_BOTCLIENT)
3115 NULL, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
3116 NULL, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
3117 VM_CL_te_flamejet, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
3119 VM_ftoe, // #459 entity(float num) entitybyindex (DP_QC_EDICT_NUM)
3120 VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS)
3121 VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
3122 VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
3123 VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
3124 VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
3125 VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
3126 VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
3127 VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
3128 VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
3129 VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
3130 NULL, // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
3131 VM_asin, // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
3132 VM_acos, // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
3133 VM_atan, // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
3134 VM_atan2, // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
3135 VM_tan, // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
3136 VM_strlennocol, // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
3137 VM_strdecolorize, // #477 string(string s) : DRESK - Decolorized String (DP_QC_STRINGCOLORFUNCTIONS)
3138 VM_strftime, // #478 string(float uselocaltime, string format, ...) (DP_QC_STRFTIME)
3139 VM_tokenizebyseparator, // #479 float(string s) tokenizebyseparator (DP_QC_TOKENIZEBYSEPARATOR)
3162 const int vm_cl_numbuiltins = sizeof(vm_cl_builtins) / sizeof(prvm_builtin_t);
3164 void VM_CL_Cmd_Init(void)
3166 // TODO: replace vm_polygons stuff with a more general debugging polygon system, and make vm_polygons functions use that system
3167 if(vm_polygons_initialized)
3169 Mem_FreePool(&vm_polygons_pool);
3170 vm_polygons_initialized = false;
3174 void VM_CL_Cmd_Reset(void)
3176 if(vm_polygons_initialized)
3178 Mem_FreePool(&vm_polygons_pool);
3179 vm_polygons_initialized = false;