eliminated model->meshlist, replaced with an embedded model->surfmesh to cut down...
[xonotic/darkplaces.git] / svvm_cmds.c
1 #include "prvm_cmds.h"
2
3 //============================================================================
4 // Server
5
6 #define PF_WARNING(s) do{Con_Printf(s);PRVM_PrintState();return;}while(0)
7 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2", "maximum cosine angle for quake's vertical autoaim, a value above 1 completely disables the autoaim, quake used 0.93"}; //"0.93"}; // LordHavoc: disabled autoaim by default
8
9
10 char *vm_sv_extensions =
11 "DP_CON_EXPANDCVAR "
12 "DP_CON_ALIASPARAMETERS "
13 "DP_BUTTONCHAT "
14 "DP_BUTTONUSE "
15 "DP_CL_LOADSKY "
16 "DP_CON_SET "
17 "DP_CON_SETA "
18 "DP_CON_STARTMAP "
19 "DP_EF_ADDITIVE "
20 "DP_EF_BLUE "
21 "DP_EF_FLAME "
22 "DP_EF_FULLBRIGHT "
23 "DP_EF_DOUBLESIDED "
24 "DP_EF_NODEPTHTEST "
25 "DP_EF_NODRAW "
26 "DP_EF_NOSHADOW "
27 "DP_EF_RED "
28 "DP_EF_STARDUST "
29 "DP_ENT_ALPHA "
30 "DP_ENT_COLORMOD "
31 "DP_ENT_CUSTOMCOLORMAP "
32 "DP_ENT_EXTERIORMODELTOCLIENT "
33 "DP_ENT_GLOW "
34 "DP_ENT_LOWPRECISION "
35 "DP_ENT_SCALE "
36 "DP_ENT_VIEWMODEL "
37 "DP_GFX_EXTERNALTEXTURES "
38 "DP_GFX_FOG "
39 "DP_GFX_QUAKE3MODELTAGS "
40 "DP_GFX_SKINFILES "
41 "DP_GFX_SKYBOX "
42 "DP_HALFLIFE_MAP "
43 "DP_HALFLIFE_MAP_CVAR "
44 "DP_HALFLIFE_SPRITE "
45 "DP_INPUTBUTTONS "
46 "DP_LITSPRITES "
47 "DP_LITSUPPORT "
48 "DP_MONSTERWALK "
49 "DP_MOVETYPEBOUNCEMISSILE "
50 "DP_MOVETYPEFOLLOW "
51 "DP_QC_CHANGEPITCH "
52 "DP_QC_COPYENTITY "
53 "DP_QC_CVAR_STRING "
54 "DP_QC_ETOS "
55 "DP_QC_FINDCHAIN "
56 "DP_QC_FINDCHAINFLAGS "
57 "DP_QC_FINDCHAINFLOAT "
58 "DP_QC_FINDFLAGS "
59 "DP_QC_FINDFLOAT "
60 "DP_QC_FS_SEARCH " // Black: same as in the menu qc
61 "DP_QC_GETLIGHT "
62 "DP_QC_GETSURFACE "
63 "DP_QC_GETTAGINFO "
64 "DP_QC_MINMAXBOUND "
65 "DP_QC_MULTIPLETEMPSTRINGS "
66 "DP_QC_RANDOMVEC "
67 "DP_QC_SINCOSSQRTPOW "
68 "DP_QC_STRINGBUFFERS "
69 "DP_QC_TRACEBOX "
70 "DP_QC_TRACETOSS "
71 "DP_QC_TRACE_MOVETYPE_HITMODEL "
72 "DP_QC_TRACE_MOVETYPE_WORLDONLY "
73 "DP_QC_VECTORVECTORS "
74 "DP_QUAKE2_MODEL "
75 "DP_QUAKE2_SPRITE "
76 "DP_QUAKE3_MAP "
77 "DP_QUAKE3_MODEL "
78 "DP_REGISTERCVAR "
79 "DP_SND_DIRECTIONLESSATTNNONE "
80 "DP_SND_FAKETRACKS "
81 "DP_SND_OGGVORBIS "
82 "DP_SND_STEREOWAV "
83 "DP_SOLIDCORPSE "
84 "DP_SPRITE32 "
85 "DP_SV_BOTCLIENT "
86 "DP_SV_CLIENTCOLORS "
87 "DP_SV_CLIENTNAME "
88 "DP_SV_CUSTOMIZEENTITYFORCLIENT "
89 "DP_SV_DRAWONLYTOCLIENT "
90 "DP_SV_DROPCLIENT "
91 "DP_SV_EFFECT "
92 "DP_SV_NODRAWTOCLIENT "
93 "DP_SV_PING "
94 "DP_SV_PLAYERPHYSICS "
95 "DP_SV_PRECACHEANYTIME "
96 "DP_SV_PUNCHVECTOR "
97 "DP_SV_ROTATINGBMODEL "
98 "DP_SV_SETCOLOR "
99 "DP_SV_SLOWMO "
100 "DP_SV_WRITEUNTERMINATEDSTRING "
101 "DP_TE_BLOOD "
102 "DP_TE_BLOODSHOWER "
103 "DP_TE_CUSTOMFLASH "
104 "DP_TE_EXPLOSIONRGB "
105 "DP_TE_FLAMEJET "
106 "DP_TE_PARTICLECUBE "
107 "DP_TE_PARTICLERAIN "
108 "DP_TE_PARTICLESNOW "
109 "DP_TE_PLASMABURN "
110 "DP_TE_QUADEFFECTS1 "
111 "DP_TE_SMALLFLASH "
112 "DP_TE_SPARK "
113 "DP_TE_STANDARDEFFECTBUILTINS "
114 "DP_TRACE_HITCONTENTSMASK_SURFACEINFO "
115 "DP_VIEWZOOM "
116 "EXT_BITSHIFT "
117 //"EXT_CSQC " // not ready yet
118 "FRIK_FILE "
119 "KRIMZON_SV_PARSECLIENTCOMMAND "
120 "NEH_CMD_PLAY2 "
121 "NEH_RESTOREGAME "
122 "NXQ_GFX_LETTERBOX "
123 "PRYDON_CLIENTCURSOR "
124 "TENEBRAE_GFX_DLIGHTS "
125 "TW_SV_STEPCONTROL "
126 "NEXUIZ_PLAYERMODEL "
127 ;
128
129 /*
130 ==============
131 PF_makevectors
132
133 Writes new values for v_forward, v_up, and v_right based on angles
134 makevectors(vector)
135 ==============
136 */
137 void PF_makevectors (void)
138 {
139         AngleVectors (PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up);
140 }
141
142 /*
143 =================
144 PF_setorigin
145
146 This is the only valid way to move an object without using the physics of the world (setting velocity and waiting).  Directly changing origin will not set internal links correctly, so clipping would be messed up.  This should be called when an object is spawned, and then only if it is teleported.
147
148 setorigin (entity, origin)
149 =================
150 */
151 void PF_setorigin (void)
152 {
153         prvm_edict_t    *e;
154         float   *org;
155
156         e = PRVM_G_EDICT(OFS_PARM0);
157         if (e == prog->edicts)
158                 PF_WARNING("setorigin: can not modify world entity\n");
159         if (e->priv.server->free)
160                 PF_WARNING("setorigin: can not modify free entity\n");
161         org = PRVM_G_VECTOR(OFS_PARM1);
162         VectorCopy (org, e->fields.server->origin);
163         SV_LinkEdict (e, false);
164 }
165
166
167 void SetMinMaxSize (prvm_edict_t *e, float *min, float *max, qboolean rotate)
168 {
169         int             i;
170
171         for (i=0 ; i<3 ; i++)
172                 if (min[i] > max[i])
173                         PRVM_ERROR("SetMinMaxSize: backwards mins/maxs");
174
175 // set derived values
176         VectorCopy (min, e->fields.server->mins);
177         VectorCopy (max, e->fields.server->maxs);
178         VectorSubtract (max, min, e->fields.server->size);
179
180         SV_LinkEdict (e, false);
181 }
182
183 /*
184 =================
185 PF_setsize
186
187 the size box is rotated by the current angle
188 LordHavoc: no it isn't...
189
190 setsize (entity, minvector, maxvector)
191 =================
192 */
193 void PF_setsize (void)
194 {
195         prvm_edict_t    *e;
196         float   *min, *max;
197
198         e = PRVM_G_EDICT(OFS_PARM0);
199         if (e == prog->edicts)
200                 PF_WARNING("setsize: can not modify world entity\n");
201         if (e->priv.server->free)
202                 PF_WARNING("setsize: can not modify free entity\n");
203         min = PRVM_G_VECTOR(OFS_PARM1);
204         max = PRVM_G_VECTOR(OFS_PARM2);
205         SetMinMaxSize (e, min, max, false);
206 }
207
208
209 /*
210 =================
211 PF_setmodel
212
213 setmodel(entity, model)
214 =================
215 */
216 static vec3_t quakemins = {-16, -16, -16}, quakemaxs = {16, 16, 16};
217 void PF_setmodel (void)
218 {
219         prvm_edict_t    *e;
220         model_t *mod;
221         int             i;
222
223         e = PRVM_G_EDICT(OFS_PARM0);
224         if (e == prog->edicts)
225                 PF_WARNING("setmodel: can not modify world entity\n");
226         if (e->priv.server->free)
227                 PF_WARNING("setmodel: can not modify free entity\n");
228         i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1), 1);
229         e->fields.server->model = PRVM_SetEngineString(sv.model_precache[i]);
230         e->fields.server->modelindex = i;
231
232         mod = sv.models[i];
233
234         if (mod)
235         {
236                 if (mod->type != mod_alias || sv_gameplayfix_setmodelrealbox.integer)
237                         SetMinMaxSize (e, mod->normalmins, mod->normalmaxs, true);
238                 else
239                         SetMinMaxSize (e, quakemins, quakemaxs, true);
240         }
241         else
242                 SetMinMaxSize (e, vec3_origin, vec3_origin, true);
243 }
244
245 /*
246 =================
247 PF_sprint
248
249 single print to a specific client
250
251 sprint(clientent, value)
252 =================
253 */
254 void PF_sprint (void)
255 {
256         client_t        *client;
257         int                     entnum;
258         char string[VM_STRINGTEMP_LENGTH];
259
260         entnum = PRVM_G_EDICTNUM(OFS_PARM0);
261
262         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
263         {
264                 Con_Print("tried to sprint to a non-client\n");
265                 return;
266         }
267
268         client = svs.clients + entnum-1;
269         if (!client->netconnection)
270                 return;
271
272         VM_VarString(1, string, sizeof(string));
273         MSG_WriteChar(&client->netconnection->message,svc_print);
274         MSG_WriteString(&client->netconnection->message, string);
275 }
276
277
278 /*
279 =================
280 PF_centerprint
281
282 single print to a specific client
283
284 centerprint(clientent, value)
285 =================
286 */
287 void PF_centerprint (void)
288 {
289         client_t        *client;
290         int                     entnum;
291         char string[VM_STRINGTEMP_LENGTH];
292
293         entnum = PRVM_G_EDICTNUM(OFS_PARM0);
294
295         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
296         {
297                 Con_Print("tried to sprint to a non-client\n");
298                 return;
299         }
300
301         client = svs.clients + entnum-1;
302         if (!client->netconnection)
303                 return;
304
305         VM_VarString(1, string, sizeof(string));
306         MSG_WriteChar(&client->netconnection->message,svc_centerprint);
307         MSG_WriteString(&client->netconnection->message, string);
308 }
309
310 /*
311 =================
312 PF_particle
313
314 particle(origin, color, count)
315 =================
316 */
317 void PF_particle (void)
318 {
319         float           *org, *dir;
320         float           color;
321         float           count;
322
323         org = PRVM_G_VECTOR(OFS_PARM0);
324         dir = PRVM_G_VECTOR(OFS_PARM1);
325         color = PRVM_G_FLOAT(OFS_PARM2);
326         count = PRVM_G_FLOAT(OFS_PARM3);
327         SV_StartParticle (org, dir, color, count);
328 }
329
330
331 /*
332 =================
333 PF_ambientsound
334
335 =================
336 */
337 void PF_ambientsound (void)
338 {
339         const char      *samp;
340         float           *pos;
341         float           vol, attenuation;
342         int                     soundnum, large;
343
344         pos = PRVM_G_VECTOR (OFS_PARM0);
345         samp = PRVM_G_STRING(OFS_PARM1);
346         vol = PRVM_G_FLOAT(OFS_PARM2);
347         attenuation = PRVM_G_FLOAT(OFS_PARM3);
348
349 // check to see if samp was properly precached
350         soundnum = SV_SoundIndex(samp, 1);
351         if (!soundnum)
352                 return;
353
354         large = false;
355         if (soundnum >= 256)
356                 large = true;
357
358         // add an svc_spawnambient command to the level signon packet
359
360         if (large)
361                 MSG_WriteByte (&sv.signon, svc_spawnstaticsound2);
362         else
363                 MSG_WriteByte (&sv.signon, svc_spawnstaticsound);
364
365         MSG_WriteVector(&sv.signon, pos, sv.protocol);
366
367         if (large)
368                 MSG_WriteShort (&sv.signon, soundnum);
369         else
370                 MSG_WriteByte (&sv.signon, soundnum);
371
372         MSG_WriteByte (&sv.signon, vol*255);
373         MSG_WriteByte (&sv.signon, attenuation*64);
374
375 }
376
377 /*
378 =================
379 PF_sound
380
381 Each entity can have eight independant sound sources, like voice,
382 weapon, feet, etc.
383
384 Channel 0 is an auto-allocate channel, the others override anything
385 already running on that entity/channel pair.
386
387 An attenuation of 0 will play full volume everywhere in the level.
388 Larger attenuations will drop off.
389
390 =================
391 */
392 void PF_sound (void)
393 {
394         const char      *sample;
395         int                     channel;
396         prvm_edict_t            *entity;
397         int             volume;
398         float attenuation;
399
400         entity = PRVM_G_EDICT(OFS_PARM0);
401         channel = PRVM_G_FLOAT(OFS_PARM1);
402         sample = PRVM_G_STRING(OFS_PARM2);
403         volume = PRVM_G_FLOAT(OFS_PARM3) * 255;
404         attenuation = PRVM_G_FLOAT(OFS_PARM4);
405
406         if (volume < 0 || volume > 255)
407                 PF_WARNING("SV_StartSound: volume must be in range 0-1\n");
408
409         if (attenuation < 0 || attenuation > 4)
410                 PF_WARNING("SV_StartSound: attenuation must be in range 0-4\n");
411
412         if (channel < 0 || channel > 7)
413                 PF_WARNING("SV_StartSound: channel must be in range 0-7\n");
414
415         SV_StartSound (entity, channel, sample, volume, attenuation);
416 }
417
418 /*
419 =================
420 PF_traceline
421
422 Used for use tracing and shot targeting
423 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
424 if the tryents flag is set.
425
426 traceline (vector1, vector2, tryents)
427 =================
428 */
429 void PF_traceline (void)
430 {
431         float   *v1, *v2;
432         trace_t trace;
433         int             move;
434         prvm_edict_t    *ent;
435         prvm_eval_t *val;
436
437         prog->xfunction->builtinsprofile += 30;
438
439         v1 = PRVM_G_VECTOR(OFS_PARM0);
440         v2 = PRVM_G_VECTOR(OFS_PARM1);
441         move = PRVM_G_FLOAT(OFS_PARM2);
442         ent = PRVM_G_EDICT(OFS_PARM3);
443
444         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]))
445                 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));
446
447         trace = SV_Move (v1, vec3_origin, vec3_origin, v2, move, ent);
448
449         prog->globals.server->trace_allsolid = trace.allsolid;
450         prog->globals.server->trace_startsolid = trace.startsolid;
451         prog->globals.server->trace_fraction = trace.fraction;
452         prog->globals.server->trace_inwater = trace.inwater;
453         prog->globals.server->trace_inopen = trace.inopen;
454         VectorCopy (trace.endpos, prog->globals.server->trace_endpos);
455         VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal);
456         prog->globals.server->trace_plane_dist =  trace.plane.dist;
457         if (trace.ent)
458                 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent);
459         else
460                 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts);
461         if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dpstartcontents)))
462                 val->_float = trace.startsupercontents;
463         if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitcontents)))
464                 val->_float = trace.hitsupercontents;
465         if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitq3surfaceflags)))
466                 val->_float = trace.hitq3surfaceflags;
467         if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename)))
468         {
469                 if (trace.hittexture)
470                 {
471                         char *s = VM_GetTempString();
472                         strlcpy(s, trace.hittexture->name, VM_STRINGTEMP_LENGTH);
473                         val->string = PRVM_SetEngineString(s);
474                 }
475                 else
476                         val->string = 0;
477         }
478 }
479
480
481 /*
482 =================
483 PF_tracebox
484
485 Used for use tracing and shot targeting
486 Traces are blocked by bbox and exact bsp entityes, and also slide box entities
487 if the tryents flag is set.
488
489 tracebox (vector1, vector mins, vector maxs, vector2, tryents)
490 =================
491 */
492 // LordHavoc: added this for my own use, VERY useful, similar to traceline
493 void PF_tracebox (void)
494 {
495         float   *v1, *v2, *m1, *m2;
496         trace_t trace;
497         int             move;
498         prvm_edict_t    *ent;
499         prvm_eval_t *val;
500
501         prog->xfunction->builtinsprofile += 30;
502
503         v1 = PRVM_G_VECTOR(OFS_PARM0);
504         m1 = PRVM_G_VECTOR(OFS_PARM1);
505         m2 = PRVM_G_VECTOR(OFS_PARM2);
506         v2 = PRVM_G_VECTOR(OFS_PARM3);
507         move = PRVM_G_FLOAT(OFS_PARM4);
508         ent = PRVM_G_EDICT(OFS_PARM5);
509
510         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]))
511                 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));
512
513         trace = SV_Move (v1, m1, m2, v2, move, ent);
514
515         prog->globals.server->trace_allsolid = trace.allsolid;
516         prog->globals.server->trace_startsolid = trace.startsolid;
517         prog->globals.server->trace_fraction = trace.fraction;
518         prog->globals.server->trace_inwater = trace.inwater;
519         prog->globals.server->trace_inopen = trace.inopen;
520         VectorCopy (trace.endpos, prog->globals.server->trace_endpos);
521         VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal);
522         prog->globals.server->trace_plane_dist =  trace.plane.dist;
523         if (trace.ent)
524                 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent);
525         else
526                 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts);
527         if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dpstartcontents)))
528                 val->_float = trace.startsupercontents;
529         if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitcontents)))
530                 val->_float = trace.hitsupercontents;
531         if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitq3surfaceflags)))
532                 val->_float = trace.hitq3surfaceflags;
533         if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename)))
534         {
535                 if (trace.hittexture)
536                 {
537                         char *s = VM_GetTempString();
538                         strlcpy(s, trace.hittexture->name, VM_STRINGTEMP_LENGTH);
539                         val->string = PRVM_SetEngineString(s);
540                 }
541                 else
542                         val->string = 0;
543         }
544 }
545
546 extern trace_t SV_Trace_Toss (prvm_edict_t *ent, prvm_edict_t *ignore);
547 void PF_tracetoss (void)
548 {
549         trace_t trace;
550         prvm_edict_t    *ent;
551         prvm_edict_t    *ignore;
552         prvm_eval_t *val;
553
554         prog->xfunction->builtinsprofile += 600;
555
556         ent = PRVM_G_EDICT(OFS_PARM0);
557         if (ent == prog->edicts)
558                 PF_WARNING("tracetoss: can not use world entity\n");
559         ignore = PRVM_G_EDICT(OFS_PARM1);
560
561         trace = SV_Trace_Toss (ent, ignore);
562
563         prog->globals.server->trace_allsolid = trace.allsolid;
564         prog->globals.server->trace_startsolid = trace.startsolid;
565         prog->globals.server->trace_fraction = trace.fraction;
566         prog->globals.server->trace_inwater = trace.inwater;
567         prog->globals.server->trace_inopen = trace.inopen;
568         VectorCopy (trace.endpos, prog->globals.server->trace_endpos);
569         VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal);
570         prog->globals.server->trace_plane_dist =  trace.plane.dist;
571         if (trace.ent)
572                 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent);
573         else
574                 prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts);
575         if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dpstartcontents)))
576                 val->_float = trace.startsupercontents;
577         if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitcontents)))
578                 val->_float = trace.hitsupercontents;
579         if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitq3surfaceflags)))
580                 val->_float = trace.hitq3surfaceflags;
581         if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename)))
582         {
583                 if (trace.hittexture)
584                 {
585                         char *s = VM_GetTempString();
586                         strlcpy(s, trace.hittexture->name, VM_STRINGTEMP_LENGTH);
587                         val->string = PRVM_SetEngineString(s);
588                 }
589                 else
590                         val->string = 0;
591         }
592 }
593
594
595 /*
596 =================
597 PF_checkpos
598
599 Returns true if the given entity can move to the given position from it's
600 current position by walking or rolling.
601 FIXME: make work...
602 scalar checkpos (entity, vector)
603 =================
604 */
605 void PF_checkpos (void)
606 {
607 }
608
609 //============================================================================
610
611 int checkpvsbytes;
612 unsigned char checkpvs[MAX_MAP_LEAFS/8];
613
614 int PF_newcheckclient (int check)
615 {
616         int             i;
617         prvm_edict_t    *ent;
618         vec3_t  org;
619
620 // cycle to the next one
621
622         check = bound(1, check, svs.maxclients);
623         if (check == svs.maxclients)
624                 i = 1;
625         else
626                 i = check + 1;
627
628         for ( ;  ; i++)
629         {
630                 // count the cost
631                 prog->xfunction->builtinsprofile++;
632                 // wrap around
633                 if (i == svs.maxclients+1)
634                         i = 1;
635                 // look up the client's edict
636                 ent = PRVM_EDICT_NUM(i);
637                 // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop)
638                 if (i != check && (ent->priv.server->free || ent->fields.server->health <= 0 || ((int)ent->fields.server->flags & FL_NOTARGET)))
639                         continue;
640                 // found a valid client (possibly the same one again)
641                 break;
642         }
643
644 // get the PVS for the entity
645         VectorAdd(ent->fields.server->origin, ent->fields.server->view_ofs, org);
646         checkpvsbytes = 0;
647         if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
648                 checkpvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, org, 0, checkpvs, sizeof(checkpvs));
649
650         return i;
651 }
652
653 /*
654 =================
655 PF_checkclient
656
657 Returns a client (or object that has a client enemy) that would be a
658 valid target.
659
660 If there is more than one valid option, they are cycled each frame
661
662 If (self.origin + self.viewofs) is not in the PVS of the current target,
663 it is not returned at all.
664
665 name checkclient ()
666 =================
667 */
668 int c_invis, c_notvis;
669 void PF_checkclient (void)
670 {
671         prvm_edict_t    *ent, *self;
672         vec3_t  view;
673
674         // find a new check if on a new frame
675         if (sv.time - sv.lastchecktime >= 0.1)
676         {
677                 sv.lastcheck = PF_newcheckclient (sv.lastcheck);
678                 sv.lastchecktime = sv.time;
679         }
680
681         // return check if it might be visible
682         ent = PRVM_EDICT_NUM(sv.lastcheck);
683         if (ent->priv.server->free || ent->fields.server->health <= 0)
684         {
685                 VM_RETURN_EDICT(prog->edicts);
686                 return;
687         }
688
689         // if current entity can't possibly see the check entity, return 0
690         self = PRVM_PROG_TO_EDICT(prog->globals.server->self);
691         VectorAdd(self->fields.server->origin, self->fields.server->view_ofs, view);
692         if (sv.worldmodel && checkpvsbytes && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, checkpvs, view, view))
693         {
694                 c_notvis++;
695                 VM_RETURN_EDICT(prog->edicts);
696                 return;
697         }
698
699         // might be able to see it
700         c_invis++;
701         VM_RETURN_EDICT(ent);
702 }
703
704 //============================================================================
705
706
707 /*
708 =================
709 PF_stuffcmd
710
711 Sends text over to the client's execution buffer
712
713 stuffcmd (clientent, value, ...)
714 =================
715 */
716 void PF_stuffcmd (void)
717 {
718         int             entnum;
719         client_t        *old;
720         char    string[VM_STRINGTEMP_LENGTH];
721
722         entnum = PRVM_G_EDICTNUM(OFS_PARM0);
723         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
724         {
725                 Con_Print("Can't stuffcmd to a non-client\n");
726                 return;
727         }
728
729         VM_VarString(1, string, sizeof(string));
730
731         old = host_client;
732         host_client = svs.clients + entnum-1;
733         Host_ClientCommands ("%s", string);
734         host_client = old;
735 }
736
737 /*
738 =================
739 PF_findradius
740
741 Returns a chain of entities that have origins within a spherical area
742
743 findradius (origin, radius)
744 =================
745 */
746 void PF_findradius (void)
747 {
748         prvm_edict_t *ent, *chain;
749         vec_t radius, radius2;
750         vec3_t org, eorg, mins, maxs;
751         int i;
752         int numtouchedicts;
753         prvm_edict_t *touchedicts[MAX_EDICTS];
754
755         chain = (prvm_edict_t *)prog->edicts;
756
757         VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org);
758         radius = PRVM_G_FLOAT(OFS_PARM1);
759         radius2 = radius * radius;
760
761         mins[0] = org[0] - (radius + 1);
762         mins[1] = org[1] - (radius + 1);
763         mins[2] = org[2] - (radius + 1);
764         maxs[0] = org[0] + (radius + 1);
765         maxs[1] = org[1] + (radius + 1);
766         maxs[2] = org[2] + (radius + 1);
767         numtouchedicts = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts);
768         if (numtouchedicts > MAX_EDICTS)
769         {
770                 // this never happens
771                 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
772                 numtouchedicts = MAX_EDICTS;
773         }
774         for (i = 0;i < numtouchedicts;i++)
775         {
776                 ent = touchedicts[i];
777                 prog->xfunction->builtinsprofile++;
778                 // Quake did not return non-solid entities but darkplaces does
779                 // (note: this is the reason you can't blow up fallen zombies)
780                 if (ent->fields.server->solid == SOLID_NOT && !sv_gameplayfix_blowupfallenzombies.integer)
781                         continue;
782                 // LordHavoc: compare against bounding box rather than center so it
783                 // doesn't miss large objects, and use DotProduct instead of Length
784                 // for a major speedup
785                 VectorSubtract(org, ent->fields.server->origin, eorg);
786                 if (sv_gameplayfix_findradiusdistancetobox.integer)
787                 {
788                         eorg[0] -= bound(ent->fields.server->mins[0], eorg[0], ent->fields.server->maxs[0]);
789                         eorg[1] -= bound(ent->fields.server->mins[1], eorg[1], ent->fields.server->maxs[1]);
790                         eorg[2] -= bound(ent->fields.server->mins[2], eorg[2], ent->fields.server->maxs[2]);
791                 }
792                 else
793                         VectorMAMAM(1, eorg, 0.5f, ent->fields.server->mins, 0.5f, ent->fields.server->maxs, eorg);
794                 if (DotProduct(eorg, eorg) < radius2)
795                 {
796                         ent->fields.server->chain = PRVM_EDICT_TO_PROG(chain);
797                         chain = ent;
798                 }
799         }
800
801         VM_RETURN_EDICT(chain);
802 }
803
804 void PF_precache_file (void)
805 {       // precache_file is only used to copy files with qcc, it does nothing
806         PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
807 }
808
809
810 void PF_precache_sound (void)
811 {
812         SV_SoundIndex(PRVM_G_STRING(OFS_PARM0), 2);
813         PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
814 }
815
816 void PF_precache_model (void)
817 {
818         SV_ModelIndex(PRVM_G_STRING(OFS_PARM0), 2);
819         PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
820 }
821
822 /*
823 ===============
824 PF_walkmove
825
826 float(float yaw, float dist) walkmove
827 ===============
828 */
829 void PF_walkmove (void)
830 {
831         prvm_edict_t    *ent;
832         float   yaw, dist;
833         vec3_t  move;
834         mfunction_t     *oldf;
835         int     oldself;
836
837         // assume failure if it returns early
838         PRVM_G_FLOAT(OFS_RETURN) = 0;
839
840         ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
841         if (ent == prog->edicts)
842                 PF_WARNING("walkmove: can not modify world entity\n");
843         if (ent->priv.server->free)
844                 PF_WARNING("walkmove: can not modify free entity\n");
845         yaw = PRVM_G_FLOAT(OFS_PARM0);
846         dist = PRVM_G_FLOAT(OFS_PARM1);
847
848         if ( !( (int)ent->fields.server->flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )
849                 return;
850
851         yaw = yaw*M_PI*2 / 360;
852
853         move[0] = cos(yaw)*dist;
854         move[1] = sin(yaw)*dist;
855         move[2] = 0;
856
857 // save program state, because SV_movestep may call other progs
858         oldf = prog->xfunction;
859         oldself = prog->globals.server->self;
860
861         PRVM_G_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);
862
863
864 // restore program state
865         prog->xfunction = oldf;
866         prog->globals.server->self = oldself;
867 }
868
869 /*
870 ===============
871 PF_droptofloor
872
873 void() droptofloor
874 ===============
875 */
876 void PF_droptofloor (void)
877 {
878         prvm_edict_t            *ent;
879         vec3_t          end;
880         trace_t         trace;
881
882         // assume failure if it returns early
883         PRVM_G_FLOAT(OFS_RETURN) = 0;
884
885         ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
886         if (ent == prog->edicts)
887                 PF_WARNING("droptofloor: can not modify world entity\n");
888         if (ent->priv.server->free)
889                 PF_WARNING("droptofloor: can not modify free entity\n");
890
891         VectorCopy (ent->fields.server->origin, end);
892         end[2] -= 256;
893
894         trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent);
895
896         if (trace.fraction != 1)
897         {
898                 VectorCopy (trace.endpos, ent->fields.server->origin);
899                 SV_LinkEdict (ent, false);
900                 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
901                 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
902                 PRVM_G_FLOAT(OFS_RETURN) = 1;
903                 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
904                 ent->priv.server->suspendedinairflag = true;
905         }
906 }
907
908 /*
909 ===============
910 PF_lightstyle
911
912 void(float style, string value) lightstyle
913 ===============
914 */
915 void PF_lightstyle (void)
916 {
917         int             style;
918         const char      *val;
919         client_t        *client;
920         int                     j;
921
922         style = PRVM_G_FLOAT(OFS_PARM0);
923         val = PRVM_G_STRING(OFS_PARM1);
924
925         if( (unsigned) style >= MAX_LIGHTSTYLES ) {
926                 PRVM_ERROR( "PF_lightstyle: style: %i >= 64", style );
927         }
928
929 // change the string in sv
930         strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
931
932 // send message to all clients on this server
933         if (sv.state != ss_active)
934                 return;
935
936         for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
937         {
938                 if (client->active && client->netconnection)
939                 {
940                         MSG_WriteChar (&client->netconnection->message, svc_lightstyle);
941                         MSG_WriteChar (&client->netconnection->message,style);
942                         MSG_WriteString (&client->netconnection->message, val);
943                 }
944         }
945 }
946
947 /*
948 =============
949 PF_checkbottom
950 =============
951 */
952 void PF_checkbottom (void)
953 {
954         PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
955 }
956
957 /*
958 =============
959 PF_pointcontents
960 =============
961 */
962 void PF_pointcontents (void)
963 {
964         PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
965 }
966
967 /*
968 =============
969 PF_aim
970
971 Pick a vector for the player to shoot along
972 vector aim(entity, missilespeed)
973 =============
974 */
975 void PF_aim (void)
976 {
977         prvm_edict_t    *ent, *check, *bestent;
978         vec3_t  start, dir, end, bestdir;
979         int             i, j;
980         trace_t tr;
981         float   dist, bestdist;
982         float   speed;
983
984         // assume failure if it returns early
985         VectorCopy(prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
986         // if sv_aim is so high it can't possibly accept anything, skip out early
987         if (sv_aim.value >= 1)
988                 return;
989
990         ent = PRVM_G_EDICT(OFS_PARM0);
991         if (ent == prog->edicts)
992                 PF_WARNING("aim: can not use world entity\n");
993         if (ent->priv.server->free)
994                 PF_WARNING("aim: can not use free entity\n");
995         speed = PRVM_G_FLOAT(OFS_PARM1);
996
997         VectorCopy (ent->fields.server->origin, start);
998         start[2] += 20;
999
1000 // try sending a trace straight
1001         VectorCopy (prog->globals.server->v_forward, dir);
1002         VectorMA (start, 2048, dir, end);
1003         tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1004         if (tr.ent && ((prvm_edict_t *)tr.ent)->fields.server->takedamage == DAMAGE_AIM
1005         && (!teamplay.integer || ent->fields.server->team <=0 || ent->fields.server->team != ((prvm_edict_t *)tr.ent)->fields.server->team) )
1006         {
1007                 VectorCopy (prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1008                 return;
1009         }
1010
1011
1012 // try all possible entities
1013         VectorCopy (dir, bestdir);
1014         bestdist = sv_aim.value;
1015         bestent = NULL;
1016
1017         check = PRVM_NEXT_EDICT(prog->edicts);
1018         for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1019         {
1020                 prog->xfunction->builtinsprofile++;
1021                 if (check->fields.server->takedamage != DAMAGE_AIM)
1022                         continue;
1023                 if (check == ent)
1024                         continue;
1025                 if (teamplay.integer && ent->fields.server->team > 0 && ent->fields.server->team == check->fields.server->team)
1026                         continue;       // don't aim at teammate
1027                 for (j=0 ; j<3 ; j++)
1028                         end[j] = check->fields.server->origin[j]
1029                         + 0.5*(check->fields.server->mins[j] + check->fields.server->maxs[j]);
1030                 VectorSubtract (end, start, dir);
1031                 VectorNormalize (dir);
1032                 dist = DotProduct (dir, prog->globals.server->v_forward);
1033                 if (dist < bestdist)
1034                         continue;       // to far to turn
1035                 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1036                 if (tr.ent == check)
1037                 {       // can shoot at this one
1038                         bestdist = dist;
1039                         bestent = check;
1040                 }
1041         }
1042
1043         if (bestent)
1044         {
1045                 VectorSubtract (bestent->fields.server->origin, ent->fields.server->origin, dir);
1046                 dist = DotProduct (dir, prog->globals.server->v_forward);
1047                 VectorScale (prog->globals.server->v_forward, dist, end);
1048                 end[2] = dir[2];
1049                 VectorNormalize (end);
1050                 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1051         }
1052         else
1053         {
1054                 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1055         }
1056 }
1057
1058 /*
1059 ==============
1060 PF_changeyaw
1061
1062 This was a major timewaster in progs, so it was converted to C
1063 ==============
1064 */
1065 void PF_changeyaw (void)
1066 {
1067         prvm_edict_t            *ent;
1068         float           ideal, current, move, speed;
1069
1070         ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1071         if (ent == prog->edicts)
1072                 PF_WARNING("changeyaw: can not modify world entity\n");
1073         if (ent->priv.server->free)
1074                 PF_WARNING("changeyaw: can not modify free entity\n");
1075         current = ANGLEMOD(ent->fields.server->angles[1]);
1076         ideal = ent->fields.server->ideal_yaw;
1077         speed = ent->fields.server->yaw_speed;
1078
1079         if (current == ideal)
1080                 return;
1081         move = ideal - current;
1082         if (ideal > current)
1083         {
1084                 if (move >= 180)
1085                         move = move - 360;
1086         }
1087         else
1088         {
1089                 if (move <= -180)
1090                         move = move + 360;
1091         }
1092         if (move > 0)
1093         {
1094                 if (move > speed)
1095                         move = speed;
1096         }
1097         else
1098         {
1099                 if (move < -speed)
1100                         move = -speed;
1101         }
1102
1103         ent->fields.server->angles[1] = ANGLEMOD (current + move);
1104 }
1105
1106 /*
1107 ==============
1108 PF_changepitch
1109 ==============
1110 */
1111 void PF_changepitch (void)
1112 {
1113         prvm_edict_t            *ent;
1114         float           ideal, current, move, speed;
1115         prvm_eval_t             *val;
1116
1117         ent = PRVM_G_EDICT(OFS_PARM0);
1118         if (ent == prog->edicts)
1119                 PF_WARNING("changepitch: can not modify world entity\n");
1120         if (ent->priv.server->free)
1121                 PF_WARNING("changepitch: can not modify free entity\n");
1122         current = ANGLEMOD( ent->fields.server->angles[0] );
1123         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1124                 ideal = val->_float;
1125         else
1126         {
1127                 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1128                 return;
1129         }
1130         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1131                 speed = val->_float;
1132         else
1133         {
1134                 PF_WARNING("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1135                 return;
1136         }
1137
1138         if (current == ideal)
1139                 return;
1140         move = ideal - current;
1141         if (ideal > current)
1142         {
1143                 if (move >= 180)
1144                         move = move - 360;
1145         }
1146         else
1147         {
1148                 if (move <= -180)
1149                         move = move + 360;
1150         }
1151         if (move > 0)
1152         {
1153                 if (move > speed)
1154                         move = speed;
1155         }
1156         else
1157         {
1158                 if (move < -speed)
1159                         move = -speed;
1160         }
1161
1162         ent->fields.server->angles[0] = ANGLEMOD (current + move);
1163 }
1164
1165 /*
1166 ===============================================================================
1167
1168 MESSAGE WRITING
1169
1170 ===============================================================================
1171 */
1172
1173 #define MSG_BROADCAST   0               // unreliable to all
1174 #define MSG_ONE                 1               // reliable to one (msg_entity)
1175 #define MSG_ALL                 2               // reliable to all
1176 #define MSG_INIT                3               // write to the init string
1177 #define MSG_ENTITY              5
1178
1179 sizebuf_t *WriteDest (void)
1180 {
1181         int             entnum;
1182         int             dest;
1183         prvm_edict_t    *ent;
1184         extern sizebuf_t *sv2csqcbuf;
1185
1186         dest = PRVM_G_FLOAT(OFS_PARM0);
1187         switch (dest)
1188         {
1189         case MSG_BROADCAST:
1190                 return &sv.datagram;
1191
1192         case MSG_ONE:
1193                 ent = PRVM_PROG_TO_EDICT(prog->globals.server->msg_entity);
1194                 entnum = PRVM_NUM_FOR_EDICT(ent);
1195                 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
1196                 {
1197                         Con_Printf ("WriteDest: tried to write to non-client\n");
1198                         return &sv.reliable_datagram;
1199                 }
1200                 else
1201                         return &svs.clients[entnum-1].netconnection->message;
1202
1203         default:
1204                 Con_Printf ("WriteDest: bad destination\n");
1205         case MSG_ALL:
1206                 return &sv.reliable_datagram;
1207
1208         case MSG_INIT:
1209                 return &sv.signon;
1210
1211         case MSG_ENTITY:
1212                 return sv2csqcbuf;
1213         }
1214
1215         return NULL;
1216 }
1217
1218 void PF_WriteByte (void)
1219 {
1220         MSG_WriteByte (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1221 }
1222
1223 void PF_WriteChar (void)
1224 {
1225         MSG_WriteChar (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1226 }
1227
1228 void PF_WriteShort (void)
1229 {
1230         MSG_WriteShort (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1231 }
1232
1233 void PF_WriteLong (void)
1234 {
1235         MSG_WriteLong (WriteDest(), PRVM_G_FLOAT(OFS_PARM1));
1236 }
1237
1238 void PF_WriteAngle (void)
1239 {
1240         MSG_WriteAngle (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1241 }
1242
1243 void PF_WriteCoord (void)
1244 {
1245         MSG_WriteCoord (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1246 }
1247
1248 void PF_WriteString (void)
1249 {
1250         MSG_WriteString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1251 }
1252
1253 void PF_WriteUnterminatedString (void)
1254 {
1255         MSG_WriteUnterminatedString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1256 }
1257
1258
1259 void PF_WriteEntity (void)
1260 {
1261         MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
1262 }
1263
1264 //////////////////////////////////////////////////////////
1265
1266 void PF_makestatic (void)
1267 {
1268         prvm_edict_t *ent;
1269         int i, large;
1270
1271         ent = PRVM_G_EDICT(OFS_PARM0);
1272         if (ent == prog->edicts)
1273                 PF_WARNING("makestatic: can not modify world entity\n");
1274         if (ent->priv.server->free)
1275                 PF_WARNING("makestatic: can not modify free entity\n");
1276
1277         large = false;
1278         if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
1279                 large = true;
1280
1281         if (large)
1282         {
1283                 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1284                 MSG_WriteShort (&sv.signon, ent->fields.server->modelindex);
1285                 MSG_WriteShort (&sv.signon, ent->fields.server->frame);
1286         }
1287         else
1288         {
1289                 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1290                 MSG_WriteByte (&sv.signon, ent->fields.server->modelindex);
1291                 MSG_WriteByte (&sv.signon, ent->fields.server->frame);
1292         }
1293
1294         MSG_WriteByte (&sv.signon, ent->fields.server->colormap);
1295         MSG_WriteByte (&sv.signon, ent->fields.server->skin);
1296         for (i=0 ; i<3 ; i++)
1297         {
1298                 MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
1299                 MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
1300         }
1301
1302 // throw the entity away now
1303         PRVM_ED_Free (ent);
1304 }
1305
1306 //=============================================================================
1307
1308 /*
1309 ==============
1310 PF_setspawnparms
1311 ==============
1312 */
1313 void PF_setspawnparms (void)
1314 {
1315         prvm_edict_t    *ent;
1316         int             i;
1317         client_t        *client;
1318
1319         ent = PRVM_G_EDICT(OFS_PARM0);
1320         i = PRVM_NUM_FOR_EDICT(ent);
1321         if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1322         {
1323                 Con_Print("tried to setspawnparms on a non-client\n");
1324                 return;
1325         }
1326
1327         // copy spawn parms out of the client_t
1328         client = svs.clients + i-1;
1329         for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1330                 (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
1331 }
1332
1333 /*
1334 =================
1335 PF_getlight
1336
1337 Returns a color vector indicating the lighting at the requested point.
1338
1339 (Internal Operation note: actually measures the light beneath the point, just like
1340                           the model lighting on the client)
1341
1342 getlight(vector)
1343 =================
1344 */
1345 void PF_getlight (void)
1346 {
1347         vec3_t ambientcolor, diffusecolor, diffusenormal;
1348         vec_t *p;
1349         p = PRVM_G_VECTOR(OFS_PARM0);
1350         VectorClear(ambientcolor);
1351         VectorClear(diffusecolor);
1352         VectorClear(diffusenormal);
1353         if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1354                 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1355         VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1356 }
1357
1358 void PF_registercvar (void)
1359 {
1360         const char *name, *value;
1361         name = PRVM_G_STRING(OFS_PARM0);
1362         value = PRVM_G_STRING(OFS_PARM1);
1363         PRVM_G_FLOAT(OFS_RETURN) = 0;
1364
1365 // first check to see if it has already been defined
1366         if (Cvar_FindVar (name))
1367                 return;
1368
1369 // check for overlap with a command
1370         if (Cmd_Exists (name))
1371         {
1372                 Con_Printf("PF_registercvar: %s is a command\n", name);
1373                 return;
1374         }
1375
1376         Cvar_Get(name, value, 0);
1377
1378         PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1379 }
1380
1381 typedef struct
1382 {
1383         unsigned char   type;   // 1/2/8 or other value if isn't used
1384         int             fieldoffset;
1385 }autosentstat_t;
1386
1387 static autosentstat_t *vm_autosentstats = NULL; //[515]: it starts from 0, not 32
1388 static int vm_autosentstats_last;
1389
1390 void VM_AutoSentStats_Clear (void)
1391 {
1392         if(vm_autosentstats)
1393         {
1394                 free(vm_autosentstats);
1395                 vm_autosentstats = NULL;
1396                 vm_autosentstats_last = -1;
1397         }
1398 }
1399
1400 //[515]: add check if even bigger ? "try to use two stats, cause it's too big" ?
1401 #define VM_SENDSTAT(a,b,c)\
1402 {\
1403 /*      if((c))*/\
1404         if((c)==(unsigned char)(c))\
1405         {\
1406                 MSG_WriteByte((a), svc_updatestatubyte);\
1407                 MSG_WriteByte((a), (b));\
1408                 MSG_WriteByte((a), (c));\
1409         }\
1410         else\
1411         {\
1412                 MSG_WriteByte((a), svc_updatestat);\
1413                 MSG_WriteByte((a), (b));\
1414                 MSG_WriteLong((a), (c));\
1415         }\
1416 }\
1417
1418 void VM_SV_WriteAutoSentStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1419 {
1420         int                     i, v, *si;
1421         char            s[17];
1422         const char      *t;
1423         qboolean        send;
1424         union
1425         {
1426                 float   f;
1427                 int             i;
1428         }k;
1429
1430         if(!vm_autosentstats)
1431                 return;
1432
1433         send = (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_DARKPLACES1 && sv.protocol != PROTOCOL_DARKPLACES2 && sv.protocol != PROTOCOL_DARKPLACES3 && sv.protocol != PROTOCOL_DARKPLACES4 && sv.protocol != PROTOCOL_DARKPLACES5);
1434
1435         for(i=0; i<vm_autosentstats_last+1 ;i++)
1436         {
1437                 if(!vm_autosentstats[i].type)
1438                         continue;
1439                 switch(vm_autosentstats[i].type)
1440                 {
1441                 //string
1442                 case 1:
1443                         t = PRVM_E_STRING(ent, vm_autosentstats[i].fieldoffset);
1444                         if(t && t[0])
1445                         {
1446                                 memset(s, 0, 17);
1447                                 strlcpy(s, t, 16);
1448                                 si = (int*)s;
1449                                 if (!send)
1450                                 {
1451                                         stats[i+32] = si[0];
1452                                         stats[i+33] = si[1];
1453                                         stats[i+34] = si[2];
1454                                         stats[i+35] = si[3];
1455                                 }
1456                                 else
1457                                 {
1458                                         VM_SENDSTAT(msg, i+32, si[0]);
1459                                         VM_SENDSTAT(msg, i+33, si[1]);
1460                                         VM_SENDSTAT(msg, i+34, si[2]);
1461                                         VM_SENDSTAT(msg, i+35, si[3]);
1462                                 }
1463                         }
1464                         break;
1465                 //float
1466                 case 2:
1467                         k.f = PRVM_E_FLOAT(ent, vm_autosentstats[i].fieldoffset);       //[515]: use PRVM_E_INT ?
1468                         k.i = LittleLong (k.i);
1469                         if (!send)
1470                                 stats[i+32] = k.i;
1471                         else
1472                                 VM_SENDSTAT(msg, i+32, k.i);
1473                         break;
1474                 //integer
1475                 case 8:
1476                         v = PRVM_E_FLOAT(ent, vm_autosentstats[i].fieldoffset); //[515]: use PRVM_E_INT ?
1477                         if (!send)
1478                                 stats[i+32] = v;
1479                         else
1480                                 VM_SENDSTAT(msg, i+32, v);
1481                         break;
1482                 default:
1483                         break;
1484                 }
1485         }
1486 }
1487
1488 // void(float index, float type, .void field) SV_AddStat = #470;
1489 // Set up an auto-sent player stat.
1490 // Client's get thier own fields sent to them. Index may not be less than 32.
1491 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1492 //          1: string (4 stats carrying a total of 16 charactures)
1493 //          2: float (one stat, float converted to an integer for transportation)
1494 //          8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1495 void PF_SV_AddStat (void)
1496 {
1497         int             off, i;
1498         unsigned char   type;
1499
1500         if(!vm_autosentstats)
1501         {
1502                 vm_autosentstats = malloc((MAX_CL_STATS-32) * sizeof(autosentstat_t));
1503                 if(!vm_autosentstats)
1504                 {
1505                         Con_Printf("PF_SV_AddStat: not enough memory\n");
1506                         return;
1507                 }
1508         }
1509         i               = PRVM_G_FLOAT(OFS_PARM0);
1510         type    = PRVM_G_FLOAT(OFS_PARM1);
1511         off             = PRVM_G_INT  (OFS_PARM2);
1512         i -= 32;
1513
1514         if(i < 0)
1515         {
1516                 Con_Printf("PF_SV_AddStat: index may not be less than 32\n");
1517                 return;
1518         }
1519         if(i >= (MAX_CL_STATS-32))
1520         {
1521                 Con_Printf("PF_SV_AddStat: index >= MAX_CL_STATS\n");
1522                 return;
1523         }
1524         if(i > (MAX_CL_STATS-32-4) && type == 1)
1525         {
1526                 Con_Printf("PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
1527                 return;
1528         }
1529         vm_autosentstats[i].type                = type;
1530         vm_autosentstats[i].fieldoffset = off;
1531         if(vm_autosentstats_last < i)
1532                 vm_autosentstats_last = i;
1533 }
1534
1535 /*
1536 =================
1537 PF_copyentity
1538
1539 copies data from one entity to another
1540
1541 copyentity(src, dst)
1542 =================
1543 */
1544 void PF_copyentity (void)
1545 {
1546         prvm_edict_t *in, *out;
1547         in = PRVM_G_EDICT(OFS_PARM0);
1548         if (in == prog->edicts)
1549                 PF_WARNING("copyentity: can not read world entity\n");
1550         if (in->priv.server->free)
1551                 PF_WARNING("copyentity: can not read free entity\n");
1552         out = PRVM_G_EDICT(OFS_PARM1);
1553         if (out == prog->edicts)
1554                 PF_WARNING("copyentity: can not modify world entity\n");
1555         if (out->priv.server->free)
1556                 PF_WARNING("copyentity: can not modify free entity\n");
1557         memcpy(out->fields.server, in->fields.server, prog->progs->entityfields * 4);
1558 }
1559
1560
1561 /*
1562 =================
1563 PF_setcolor
1564
1565 sets the color of a client and broadcasts the update to all connected clients
1566
1567 setcolor(clientent, value)
1568 =================
1569 */
1570 void PF_setcolor (void)
1571 {
1572         client_t *client;
1573         int entnum, i;
1574         prvm_eval_t *val;
1575
1576         entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1577         i = PRVM_G_FLOAT(OFS_PARM1);
1578
1579         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1580         {
1581                 Con_Print("tried to setcolor a non-client\n");
1582                 return;
1583         }
1584
1585         client = svs.clients + entnum-1;
1586         if (client->edict)
1587         {
1588                 if ((val = PRVM_GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
1589                         val->_float = i;
1590                 client->edict->fields.server->team = (i & 15) + 1;
1591         }
1592         client->colors = i;
1593         if (client->old_colors != client->colors)
1594         {
1595                 client->old_colors = client->colors;
1596                 // send notification to all clients
1597                 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1598                 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1599                 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1600         }
1601 }
1602
1603 /*
1604 =================
1605 PF_effect
1606
1607 effect(origin, modelname, startframe, framecount, framerate)
1608 =================
1609 */
1610 void PF_effect (void)
1611 {
1612         int i;
1613         const char *s;
1614         s = PRVM_G_STRING(OFS_PARM1);
1615         if (!s || !s[0])
1616                 PF_WARNING("effect: no model specified\n");
1617
1618         i = SV_ModelIndex(s, 1);
1619         if (!i)
1620                 PF_WARNING("effect: model not precached\n");
1621         SV_StartEffect(PRVM_G_VECTOR(OFS_PARM0), i, PRVM_G_FLOAT(OFS_PARM2), PRVM_G_FLOAT(OFS_PARM3), PRVM_G_FLOAT(OFS_PARM4));
1622 }
1623
1624 void PF_te_blood (void)
1625 {
1626         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1627                 return;
1628         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1629         MSG_WriteByte(&sv.datagram, TE_BLOOD);
1630         // origin
1631         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1632         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1633         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1634         // velocity
1635         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1636         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1637         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1638         // count
1639         MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1640 }
1641
1642 void PF_te_bloodshower (void)
1643 {
1644         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1645                 return;
1646         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1647         MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1648         // min
1649         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1650         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1651         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1652         // max
1653         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1654         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1655         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1656         // speed
1657         MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1658         // count
1659         MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1660 }
1661
1662 void PF_te_explosionrgb (void)
1663 {
1664         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1665         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1666         // origin
1667         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1668         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1669         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1670         // color
1671         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1672         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1673         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1674 }
1675
1676 void PF_te_particlecube (void)
1677 {
1678         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1679                 return;
1680         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1681         MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1682         // min
1683         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1684         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1685         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1686         // max
1687         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1688         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1689         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1690         // velocity
1691         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1692         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1693         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1694         // count
1695         MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1696         // color
1697         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
1698         // gravity true/false
1699         MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1700         // randomvel
1701         MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1702 }
1703
1704 void PF_te_particlerain (void)
1705 {
1706         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1707                 return;
1708         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1709         MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1710         // min
1711         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1712         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1713         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1714         // max
1715         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1716         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1717         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1718         // velocity
1719         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1720         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1721         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1722         // count
1723         MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1724         // color
1725         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
1726 }
1727
1728 void PF_te_particlesnow (void)
1729 {
1730         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1731                 return;
1732         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1733         MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1734         // min
1735         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1736         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1737         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1738         // max
1739         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1740         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1741         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1742         // velocity
1743         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1744         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1745         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1746         // count
1747         MSG_WriteShort(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1748         // color
1749         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM4));
1750 }
1751
1752 void PF_te_spark (void)
1753 {
1754         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1755                 return;
1756         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1757         MSG_WriteByte(&sv.datagram, TE_SPARK);
1758         // origin
1759         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1760         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1761         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1762         // velocity
1763         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1764         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1765         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1766         // count
1767         MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1768 }
1769
1770 void PF_te_gunshotquad (void)
1771 {
1772         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1773         MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
1774         // origin
1775         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1776         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1777         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1778 }
1779
1780 void PF_te_spikequad (void)
1781 {
1782         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1783         MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
1784         // origin
1785         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1786         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1787         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1788 }
1789
1790 void PF_te_superspikequad (void)
1791 {
1792         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1793         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
1794         // origin
1795         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1796         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1797         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1798 }
1799
1800 void PF_te_explosionquad (void)
1801 {
1802         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1803         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
1804         // origin
1805         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1806         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1807         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1808 }
1809
1810 void PF_te_smallflash (void)
1811 {
1812         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1813         MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
1814         // origin
1815         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1816         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1817         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1818 }
1819
1820 void PF_te_customflash (void)
1821 {
1822         if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
1823                 return;
1824         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1825         MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
1826         // origin
1827         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1828         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1829         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1830         // radius
1831         MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
1832         // lifetime
1833         MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
1834         // color
1835         MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
1836         MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
1837         MSG_WriteByte(&sv.datagram, bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
1838 }
1839
1840 void PF_te_gunshot (void)
1841 {
1842         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1843         MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
1844         // origin
1845         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1846         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1847         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1848 }
1849
1850 void PF_te_spike (void)
1851 {
1852         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1853         MSG_WriteByte(&sv.datagram, TE_SPIKE);
1854         // origin
1855         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1856         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1857         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1858 }
1859
1860 void PF_te_superspike (void)
1861 {
1862         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1863         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
1864         // origin
1865         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1866         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1867         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1868 }
1869
1870 void PF_te_explosion (void)
1871 {
1872         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1873         MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
1874         // origin
1875         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1876         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1877         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1878 }
1879
1880 void PF_te_tarexplosion (void)
1881 {
1882         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1883         MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
1884         // origin
1885         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1886         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1887         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1888 }
1889
1890 void PF_te_wizspike (void)
1891 {
1892         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1893         MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
1894         // origin
1895         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1896         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1897         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1898 }
1899
1900 void PF_te_knightspike (void)
1901 {
1902         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1903         MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
1904         // origin
1905         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1906         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1907         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1908 }
1909
1910 void PF_te_lavasplash (void)
1911 {
1912         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1913         MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
1914         // origin
1915         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1916         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1917         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1918 }
1919
1920 void PF_te_teleport (void)
1921 {
1922         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1923         MSG_WriteByte(&sv.datagram, TE_TELEPORT);
1924         // origin
1925         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1926         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1927         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1928 }
1929
1930 void PF_te_explosion2 (void)
1931 {
1932         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1933         MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
1934         // origin
1935         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1936         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1937         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1938         // color
1939         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM1));
1940         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2));
1941 }
1942
1943 void PF_te_lightning1 (void)
1944 {
1945         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1946         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
1947         // owner entity
1948         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1949         // start
1950         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1951         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1952         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1953         // end
1954         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1955         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1956         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1957 }
1958
1959 void PF_te_lightning2 (void)
1960 {
1961         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1962         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
1963         // owner entity
1964         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1965         // start
1966         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1967         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1968         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1969         // end
1970         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1971         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1972         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1973 }
1974
1975 void PF_te_lightning3 (void)
1976 {
1977         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1978         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
1979         // owner entity
1980         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1981         // start
1982         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1983         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1984         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1985         // end
1986         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1987         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1988         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1989 }
1990
1991 void PF_te_beam (void)
1992 {
1993         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1994         MSG_WriteByte(&sv.datagram, TE_BEAM);
1995         // owner entity
1996         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
1997         // start
1998         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1999         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2000         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2001         // end
2002         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2003         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2004         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2005 }
2006
2007 void PF_te_plasmaburn (void)
2008 {
2009         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2010         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2011         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2012         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2013         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2014 }
2015
2016 void PF_te_flamejet (void)
2017 {
2018         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2019         MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2020         // org
2021         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2022         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2023         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2024         // vel
2025         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2026         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2027         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2028         // count
2029         MSG_WriteByte(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2));
2030 }
2031
2032 void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
2033 {
2034         int i, j, k;
2035         float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2036         const int *e;
2037         bestdist = 1000000000;
2038         VectorCopy(p, out);
2039         for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2040         {
2041                 // clip original point to each triangle of the surface and find the
2042                 // triangle that is closest
2043                 v[0] = model->surfmesh.data_vertex3f + e[0] * 3;
2044                 v[1] = model->surfmesh.data_vertex3f + e[1] * 3;
2045                 v[2] = model->surfmesh.data_vertex3f + e[2] * 3;
2046                 TriangleNormal(v[0], v[1], v[2], facenormal);
2047                 VectorNormalize(facenormal);
2048                 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2049                 VectorMA(p, offsetdist, facenormal, temp);
2050                 for (j = 0, k = 2;j < 3;k = j, j++)
2051                 {
2052                         VectorSubtract(v[k], v[j], edgenormal);
2053                         CrossProduct(edgenormal, facenormal, sidenormal);
2054                         VectorNormalize(sidenormal);
2055                         offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2056                         if (offsetdist < 0)
2057                                 VectorMA(temp, offsetdist, sidenormal, temp);
2058                 }
2059                 dist = VectorDistance2(temp, p);
2060                 if (bestdist > dist)
2061                 {
2062                         bestdist = dist;
2063                         VectorCopy(temp, out);
2064                 }
2065         }
2066 }
2067
2068 static model_t *getmodel(prvm_edict_t *ed)
2069 {
2070         int modelindex;
2071         if (!ed || ed->priv.server->free)
2072                 return NULL;
2073         modelindex = ed->fields.server->modelindex;
2074         if (modelindex < 1 || modelindex >= MAX_MODELS)
2075                 return NULL;
2076         return sv.models[modelindex];
2077 }
2078
2079 static msurface_t *getsurface(model_t *model, int surfacenum)
2080 {
2081         if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2082                 return NULL;
2083         return model->data_surfaces + surfacenum + model->firstmodelsurface;
2084 }
2085
2086
2087 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2088 void PF_getsurfacenumpoints(void)
2089 {
2090         model_t *model;
2091         msurface_t *surface;
2092         // return 0 if no such surface
2093         if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, PRVM_G_FLOAT(OFS_PARM1))))
2094         {
2095                 PRVM_G_FLOAT(OFS_RETURN) = 0;
2096                 return;
2097         }
2098
2099         // note: this (incorrectly) assumes it is a simple polygon
2100         PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
2101 }
2102 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2103 void PF_getsurfacepoint(void)
2104 {
2105         prvm_edict_t *ed;
2106         model_t *model;
2107         msurface_t *surface;
2108         int pointnum;
2109         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2110         ed = PRVM_G_EDICT(OFS_PARM0);
2111         if (!(model = getmodel(ed)) || !(surface = getsurface(model, PRVM_G_FLOAT(OFS_PARM1))))
2112                 return;
2113         // note: this (incorrectly) assumes it is a simple polygon
2114         pointnum = PRVM_G_FLOAT(OFS_PARM2);
2115         if (pointnum < 0 || pointnum >= surface->num_vertices)
2116                 return;
2117         // FIXME: implement rotation/scaling
2118         VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2119 }
2120 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
2121 void PF_getsurfacenormal(void)
2122 {
2123         model_t *model;
2124         msurface_t *surface;
2125         vec3_t normal;
2126         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2127         if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, PRVM_G_FLOAT(OFS_PARM1))))
2128                 return;
2129         // FIXME: implement rotation/scaling
2130         // note: this (incorrectly) assumes it is a simple polygon
2131         // note: this only returns the first triangle, so it doesn't work very
2132         // well for curved surfaces or arbitrary meshes
2133         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);
2134         VectorNormalize(normal);
2135         VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
2136 }
2137 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
2138 void PF_getsurfacetexture(void)
2139 {
2140         model_t *model;
2141         msurface_t *surface;
2142         PRVM_G_INT(OFS_RETURN) = 0;
2143         if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, PRVM_G_FLOAT(OFS_PARM1))))
2144                 return;
2145         PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(surface->texture->name);
2146 }
2147 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2148 void PF_getsurfacenearpoint(void)
2149 {
2150         int surfacenum, best;
2151         vec3_t clipped, p;
2152         vec_t dist, bestdist;
2153         prvm_edict_t *ed;
2154         model_t *model;
2155         msurface_t *surface;
2156         vec_t *point;
2157         PRVM_G_FLOAT(OFS_RETURN) = -1;
2158         ed = PRVM_G_EDICT(OFS_PARM0);
2159         point = PRVM_G_VECTOR(OFS_PARM1);
2160
2161         if (!ed || ed->priv.server->free)
2162                 return;
2163         model = getmodel(ed);
2164         if (!model || !model->num_surfaces)
2165                 return;
2166
2167         // FIXME: implement rotation/scaling
2168         VectorSubtract(point, ed->fields.server->origin, p);
2169         best = -1;
2170         bestdist = 1000000000;
2171         for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2172         {
2173                 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2174                 // first see if the nearest point on the surface's box is closer than the previous match
2175                 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2176                 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2177                 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2178                 dist = VectorLength2(clipped);
2179                 if (dist < bestdist)
2180                 {
2181                         // it is, check the nearest point on the actual geometry
2182                         clippointtosurface(model, surface, p, clipped);
2183                         VectorSubtract(clipped, p, clipped);
2184                         dist += VectorLength2(clipped);
2185                         if (dist < bestdist)
2186                         {
2187                                 // that's closer too, store it as the best match
2188                                 best = surfacenum;
2189                                 bestdist = dist;
2190                         }
2191                 }
2192         }
2193         PRVM_G_FLOAT(OFS_RETURN) = best;
2194 }
2195 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2196 void PF_getsurfaceclippedpoint(void)
2197 {
2198         prvm_edict_t *ed;
2199         model_t *model;
2200         msurface_t *surface;
2201         vec3_t p, out;
2202         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2203         ed = PRVM_G_EDICT(OFS_PARM0);
2204         if (!(model = getmodel(ed)) || !(surface = getsurface(model, PRVM_G_FLOAT(OFS_PARM1))))
2205                 return;
2206         // FIXME: implement rotation/scaling
2207         VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
2208         clippointtosurface(model, surface, p, out);
2209         // FIXME: implement rotation/scaling
2210         VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2211 }
2212
2213 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2214 //this function originally written by KrimZon, made shorter by LordHavoc
2215 void PF_clientcommand (void)
2216 {
2217         client_t *temp_client;
2218         int i;
2219
2220         //find client for this entity
2221         i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2222         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2223         {
2224                 Con_Print("PF_clientcommand: entity is not a client\n");
2225                 return;
2226         }
2227
2228         temp_client = host_client;
2229         host_client = svs.clients + i;
2230         Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2231         host_client = temp_client;
2232 }
2233
2234 //void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag)
2235 void PF_setattachment (void)
2236 {
2237         prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2238         prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2239         const char *tagname = PRVM_G_STRING(OFS_PARM2);
2240         prvm_eval_t *v;
2241         int modelindex;
2242         model_t *model;
2243
2244         if (e == prog->edicts)
2245                 PF_WARNING("setattachment: can not modify world entity\n");
2246         if (e->priv.server->free)
2247                 PF_WARNING("setattachment: can not modify free entity\n");
2248
2249         if (tagentity == NULL)
2250                 tagentity = prog->edicts;
2251
2252         v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_entity);
2253         if (v)
2254                 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2255
2256         v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_index);
2257         if (v)
2258                 v->_float = 0;
2259         if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2260         {
2261                 modelindex = (int)tagentity->fields.server->modelindex;
2262                 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
2263                 {
2264                         v->_float = Mod_Alias_GetTagIndexForName(model, tagentity->fields.server->skin, tagname);
2265                         if (v->_float == 0)
2266                                 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);
2267                 }
2268                 else
2269                         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));
2270         }
2271 }
2272
2273 /////////////////////////////////////////
2274 // DP_MD3_TAGINFO extension coded by VorteX
2275
2276 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
2277 {
2278         int i;
2279         model_t *model;
2280
2281         i = e->fields.server->modelindex;
2282         if (i < 1 || i >= MAX_MODELS)
2283                 return -1;
2284         model = sv.models[i];
2285
2286         return Mod_Alias_GetTagIndexForName(model, e->fields.server->skin, tagname);
2287 };
2288
2289 void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2290 {
2291         float scale = PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float;
2292         if (scale == 0)
2293                 scale = 1;
2294         if (viewmatrix)
2295                 Matrix4x4_CreateFromQuakeEntity(out, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2] + ent->fields.server->view_ofs[2], ent->fields.server->v_angle[0], ent->fields.server->v_angle[1], ent->fields.server->v_angle[2], scale);
2296         else
2297                 Matrix4x4_CreateFromQuakeEntity(out, ent->fields.server->origin[0], ent->fields.server->origin[1], ent->fields.server->origin[2], -ent->fields.server->angles[0], ent->fields.server->angles[1], ent->fields.server->angles[2], scale * 0.333);
2298 }
2299
2300 int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2301 {
2302         int modelindex;
2303         int frame;
2304         model_t *model;
2305         if (tagindex >= 0
2306          && (modelindex = ent->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS
2307          && (model = sv.models[(int)ent->fields.server->modelindex])
2308          && model->animscenes)
2309         {
2310                 // if model has wrong frame, engine automatically switches to model first frame
2311                 frame = (int)ent->fields.server->frame;
2312                 if (frame < 0 || frame >= model->numframes)
2313                         frame = 0;
2314                 return Mod_Alias_GetTagMatrix(model, model->animscenes[frame].firstframe, tagindex, out);
2315         }
2316         *out = identitymatrix;
2317         return 0;
2318 }
2319
2320 // Warnings/errors code:
2321 // 0 - normal (everything all-right)
2322 // 1 - world entity
2323 // 2 - free entity
2324 // 3 - null or non-precached model
2325 // 4 - no tags with requested index
2326 // 5 - runaway loop at attachment chain
2327 extern cvar_t cl_bob;
2328 extern cvar_t cl_bobcycle;
2329 extern cvar_t cl_bobup;
2330 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2331 {
2332         int ret;
2333         prvm_eval_t *val;
2334         int modelindex, attachloop;
2335         matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2336         model_t *model;
2337
2338         *out = identitymatrix; // warnings and errors return identical matrix
2339
2340         if (ent == prog->edicts)
2341                 return 1;
2342         if (ent->priv.server->free)
2343                 return 2;
2344
2345         modelindex = (int)ent->fields.server->modelindex;
2346         if (modelindex <= 0 || modelindex > MAX_MODELS)
2347                 return 3;
2348
2349         model = sv.models[modelindex];
2350
2351         tagmatrix = identitymatrix;
2352         // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2353         attachloop = 0;
2354         for (;;)
2355         {
2356                 if (attachloop >= 256) // prevent runaway looping
2357                         return 5;
2358                 // apply transformation by child's tagindex on parent entity and then
2359                 // by parent entity itself
2360                 ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
2361                 if (ret && attachloop == 0)
2362                         return ret;
2363                 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
2364                 SV_GetEntityMatrix(ent, &entitymatrix, false);
2365                 Matrix4x4_Concat(&tagmatrix, &entitymatrix, out);
2366                 // next iteration we process the parent entity
2367                 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
2368                 {
2369                         tagindex = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
2370                         ent = PRVM_EDICT_NUM(val->edict);
2371                 }
2372                 else
2373                         break;
2374                 attachloop++;
2375         }
2376
2377         // RENDER_VIEWMODEL magic
2378         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
2379         {
2380                 Matrix4x4_Copy(&tagmatrix, out);
2381                 ent = PRVM_EDICT_NUM(val->edict);
2382
2383                 SV_GetEntityMatrix(ent, &entitymatrix, true);
2384                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2385
2386                 /*
2387                 // Cl_bob, ported from rendering code
2388                 if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
2389                 {
2390                         double bob, cycle;
2391                         // LordHavoc: this code is *weird*, but not replacable (I think it
2392                         // should be done in QC on the server, but oh well, quake is quake)
2393                         // LordHavoc: figured out bobup: the time at which the sin is at 180
2394                         // degrees (which allows lengthening or squishing the peak or valley)
2395                         cycle = sv.time/cl_bobcycle.value;
2396                         cycle -= (int)cycle;
2397                         if (cycle < cl_bobup.value)
2398                                 cycle = sin(M_PI * cycle / cl_bobup.value);
2399                         else
2400                                 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2401                         // bob is proportional to velocity in the xy plane
2402                         // (don't count Z, or jumping messes it up)
2403                         bob = sqrt(ent->fields.server->velocity[0]*ent->fields.server->velocity[0] + ent->fields.server->velocity[1]*ent->fields.server->velocity[1])*cl_bob.value;
2404                         bob = bob*0.3 + bob*0.7*cycle;
2405                         out->m[2][3] += bound(-7, bob, 4);
2406                 }
2407                 */
2408         }
2409         return 0;
2410 }
2411
2412 //float(entity ent, string tagname) gettagindex;
2413
2414 void PF_gettagindex (void)
2415 {
2416         prvm_edict_t *ent = PRVM_G_EDICT(OFS_PARM0);
2417         const char *tag_name = PRVM_G_STRING(OFS_PARM1);
2418         int modelindex, tag_index;
2419
2420         if (ent == prog->edicts)
2421                 PF_WARNING("gettagindex: can't affect world entity\n");
2422         if (ent->priv.server->free)
2423                 PF_WARNING("gettagindex: can't affect free entity\n");
2424
2425         modelindex = (int)ent->fields.server->modelindex;
2426         tag_index = 0;
2427         if (modelindex <= 0 || modelindex > MAX_MODELS)
2428                 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2429         else
2430         {
2431                 tag_index = SV_GetTagIndex(ent, tag_name);
2432                 if (tag_index == 0)
2433                         Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2434         }
2435         PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2436 };
2437
2438 //vector(entity ent, float tagindex) gettaginfo;
2439 void PF_gettaginfo (void)
2440 {
2441         prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2442         int tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2443         matrix4x4_t tag_matrix;
2444         int returncode;
2445
2446         returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
2447         Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
2448
2449         switch(returncode)
2450         {
2451                 case 1:
2452                         PF_WARNING("gettagindex: can't affect world entity\n");
2453                         break;
2454                 case 2:
2455                         PF_WARNING("gettagindex: can't affect free entity\n");
2456                         break;
2457                 case 3:
2458                         Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2459                         break;
2460                 case 4:
2461                         Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2462                         break;
2463                 case 5:
2464                         Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2465                         break;
2466         }
2467 }
2468
2469 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2470 void PF_dropclient (void)
2471 {
2472         int clientnum;
2473         client_t *oldhostclient;
2474         clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2475         if (clientnum < 0 || clientnum >= svs.maxclients)
2476                 PF_WARNING("dropclient: not a client\n");
2477         if (!svs.clients[clientnum].active)
2478                 PF_WARNING("dropclient: that client slot is not connected\n");
2479         oldhostclient = host_client;
2480         host_client = svs.clients + clientnum;
2481         SV_DropClient(false);
2482         host_client = oldhostclient;
2483 }
2484
2485 //entity() spawnclient (DP_SV_BOTCLIENT)
2486 void PF_spawnclient (void)
2487 {
2488         int i;
2489         prvm_edict_t    *ed;
2490         prog->xfunction->builtinsprofile += 2;
2491         ed = prog->edicts;
2492         for (i = 0;i < svs.maxclients;i++)
2493         {
2494                 if (!svs.clients[i].active)
2495                 {
2496                         prog->xfunction->builtinsprofile += 100;
2497                         SV_ConnectClient (i, NULL);
2498                         // this has to be set or else ClientDisconnect won't be called
2499                         // we assume the qc will call ClientConnect...
2500                         svs.clients[i].clientconnectcalled = true;
2501                         ed = PRVM_EDICT_NUM(i + 1);
2502                         break;
2503                 }
2504         }
2505         VM_RETURN_EDICT(ed);
2506 }
2507
2508 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2509 void PF_clienttype (void)
2510 {
2511         int clientnum;
2512         clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2513         if (clientnum < 0 || clientnum >= svs.maxclients)
2514                 PRVM_G_FLOAT(OFS_RETURN) = 3;
2515         else if (!svs.clients[clientnum].active)
2516                 PRVM_G_FLOAT(OFS_RETURN) = 0;
2517         else if (svs.clients[clientnum].netconnection)
2518                 PRVM_G_FLOAT(OFS_RETURN) = 1;
2519         else
2520                 PRVM_G_FLOAT(OFS_RETURN) = 2;
2521 }
2522
2523 void PF_edict_num (void)
2524 {
2525         VM_RETURN_EDICT(PRVM_EDICT_NUM((int)PRVM_G_FLOAT(OFS_PARM0)));
2526 }
2527
2528 prvm_builtin_t vm_sv_builtins[] = {
2529 NULL,                                           // #0
2530 PF_makevectors,                         // #1 void(vector ang) makevectors
2531 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
2532 PF_setmodel,                            // #3 void(entity e, string m) setmodel
2533 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
2534 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
2535 VM_break,                                       // #6 void() break
2536 VM_random,                                      // #7 float() random
2537 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
2538 VM_normalize,                           // #9 vector(vector v) normalize
2539 VM_error,                                       // #10 void(string e) error
2540 VM_objerror,                            // #11 void(string e) objerror
2541 VM_vlen,                                        // #12 float(vector v) vlen
2542 VM_vectoyaw,                            // #13 float(vector v) vectoyaw
2543 VM_spawn,                                       // #14 entity() spawn
2544 VM_remove,                                      // #15 void(entity e) remove
2545 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
2546 PF_checkclient,                         // #17 entity() clientlist
2547 VM_find,                                        // #18 entity(entity start, .string fld, string match) find
2548 PF_precache_sound,                      // #19 void(string s) precache_sound
2549 PF_precache_model,                      // #20 void(string s) precache_model
2550 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
2551 PF_findradius,                          // #22 entity(vector org, float rad) findradius
2552 VM_bprint,                                      // #23 void(string s) bprint
2553 PF_sprint,                                      // #24 void(entity client, string s) sprint
2554 VM_dprint,                                      // #25 void(string s) dprint
2555 VM_ftos,                                        // #26 void(string s) ftos
2556 VM_vtos,                                        // #27 void(string s) vtos
2557 VM_coredump,                            // #28 void() coredump
2558 VM_traceon,                                     // #29 void() traceon
2559 VM_traceoff,                            // #30 void() traceoff
2560 VM_eprint,                                      // #31 void(entity e) eprint
2561 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
2562 NULL,                                           // #33
2563 PF_droptofloor,                         // #34 float() droptofloor
2564 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
2565 VM_rint,                                        // #36 float(float v) rint
2566 VM_floor,                                       // #37 float(float v) floor
2567 VM_ceil,                                        // #38 float(float v) ceil
2568 NULL,                                           // #39
2569 PF_checkbottom,                         // #40 float(entity e) checkbottom
2570 PF_pointcontents,                       // #41 float(vector v) pointcontents
2571 NULL,                                           // #42
2572 VM_fabs,                                        // #43 float(float f) fabs
2573 PF_aim,                                         // #44 vector(entity e, float speed) aim
2574 VM_cvar,                                        // #45 float(string s) cvar
2575 VM_localcmd,                            // #46 void(string s) localcmd
2576 VM_nextent,                                     // #47 entity(entity e) nextent
2577 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
2578 PF_changeyaw,                           // #49 void() ChangeYaw
2579 NULL,                                           // #50
2580 VM_vectoangles,                         // #51 vector(vector v) vectoangles
2581 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
2582 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
2583 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
2584 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
2585 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
2586 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
2587 PF_WriteString,                         // #58 void(float to, string s) WriteString
2588 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
2589 VM_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2590 VM_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2591 VM_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2592 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2593 PF_tracetoss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2594 VM_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
2595 NULL,                                           // #66
2596 SV_MoveToGoal,                          // #67 void(float step) movetogoal
2597 PF_precache_file,                       // #68 string(string s) precache_file
2598 PF_makestatic,                          // #69 void(entity e) makestatic
2599 VM_changelevel,                         // #70 void(string s) changelevel
2600 NULL,                                           // #71
2601 VM_cvar_set,                            // #72 void(string var, string val) cvar_set
2602 PF_centerprint,                         // #73 void(entity client, strings) centerprint
2603 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
2604 PF_precache_model,                      // #75 string(string s) precache_model2
2605 PF_precache_sound,                      // #76 string(string s) precache_sound2
2606 PF_precache_file,                       // #77 string(string s) precache_file2
2607 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
2608 NULL,                                           // #79
2609 NULL,                                           // #80
2610 VM_stof,                                        // #81 float(string s) stof (FRIK_FILE)
2611 NULL,                                           // #82
2612 NULL,                                           // #83
2613 NULL,                                           // #84
2614 NULL,                                           // #85
2615 NULL,                                           // #86
2616 NULL,                                           // #87
2617 NULL,                                           // #88
2618 NULL,                                           // #89
2619 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2620 VM_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
2621 PF_getlight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2622 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2623 VM_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2624 VM_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2625 VM_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2626 VM_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2627 VM_findfloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2628 VM_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
2629 NULL,                                           // #100
2630 NULL,                                           // #101
2631 NULL,                                           // #102
2632 NULL,                                           // #103
2633 NULL,                                           // #104
2634 NULL,                                           // #105
2635 NULL,                                           // #106
2636 NULL,                                           // #107
2637 NULL,                                           // #108
2638 NULL,                                           // #109
2639 VM_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
2640 VM_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
2641 VM_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
2642 VM_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2643 VM_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
2644 VM_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
2645 VM_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
2646 VM_stov,                                        // #117 vector(string) stov (FRIK_FILE)
2647 VM_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
2648 VM_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
2649 e10, e10, e10, e10, e10, e10, e10, e10,         // #120-199
2650 // FTEQW range #200-#299
2651 NULL,                                           // #200
2652 NULL,                                           // #201
2653 NULL,                                           // #202
2654 NULL,                                           // #203
2655 NULL,                                           // #204
2656 NULL,                                           // #205
2657 NULL,                                           // #206
2658 NULL,                                           // #207
2659 NULL,                                           // #208
2660 NULL,                                           // #209
2661 NULL,                                           // #210
2662 NULL,                                           // #211
2663 NULL,                                           // #212
2664 NULL,                                           // #213
2665 NULL,                                           // #214
2666 NULL,                                           // #215
2667 NULL,                                           // #216
2668 NULL,                                           // #217
2669 VM_bitshift,                            // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
2670 NULL,                                           // #219
2671 e10,                                            // #220-#229
2672 e10,                                            // #230-#239
2673 e10,                                            // #240-#249
2674 e10,                                            // #250-#259
2675 e10,                                            // #260-#269
2676 e10,                                            // #270-#279
2677 e10,                                            // #280-#289
2678 e10,                                            // #290-#299
2679 e10, e10, e10, e10, e10, e10, e10, e10, e10, e10,       // #300-399
2680 VM_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
2681 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
2682 VM_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
2683 VM_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
2684 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
2685 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
2686 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
2687 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
2688 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
2689 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
2690 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
2691 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
2692 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
2693 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
2694 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
2695 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
2696 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
2697 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
2698 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
2699 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
2700 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
2701 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
2702 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
2703 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
2704 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
2705 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
2706 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
2707 PF_te_explosion2,                       // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
2708 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
2709 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
2710 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
2711 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
2712 VM_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
2713 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
2714 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
2715 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
2716 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
2717 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
2718 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
2719 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
2720 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
2721 VM_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
2722 VM_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
2723 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
2724 VM_search_begin,                        // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
2725 VM_search_end,                          // #445 void(float handle) search_end (DP_FS_SEARCH)
2726 VM_search_getsize,                      // #446 float(float handle) search_getsize (DP_FS_SEARCH)
2727 VM_search_getfilename,          // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
2728 VM_cvar_string,                         // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
2729 VM_findflags,                           // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
2730 VM_findchainflags,                      // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
2731 PF_gettagindex,                         // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
2732 PF_gettaginfo,                          // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2733 PF_dropclient,                          // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
2734 PF_spawnclient,                         // #454 entity() spawnclient (DP_SV_BOTCLIENT)
2735 PF_clienttype,                          // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
2736 PF_WriteUnterminatedString,     // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
2737 PF_te_flamejet,                         // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
2738 NULL,                                           // #458
2739 PF_edict_num,                           // #459 entity(float num) (??)
2740 VM_buf_create,                          // #460 float() buf_create (DP_QC_STRINGBUFFERS)
2741 VM_buf_del,                                     // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
2742 VM_buf_getsize,                         // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
2743 VM_buf_copy,                            // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
2744 VM_buf_sort,                            // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
2745 VM_buf_implode,                         // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
2746 VM_bufstr_get,                          // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
2747 VM_bufstr_set,                          // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
2748 VM_bufstr_add,                          // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
2749 VM_bufstr_free,                         // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
2750 PF_SV_AddStat,                          // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
2751 NULL,                                           // #471
2752 NULL,                                           // #472
2753 NULL,                                           // #473
2754 NULL,                                           // #474
2755 NULL,                                           // #475
2756 NULL,                                           // #476
2757 NULL,                                           // #477
2758 NULL,                                           // #478
2759 NULL,                                           // #479
2760 e10, e10                                        // #480-499 (LordHavoc)
2761 };
2762
2763 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
2764
2765 void VM_SV_Cmd_Init(void)
2766 {
2767         VM_Cmd_Init();
2768 }
2769
2770 void VM_SV_Cmd_Reset(void)
2771 {
2772         VM_Cmd_Reset();
2773 }
2774