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