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