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