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