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