]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - svvm_cmds.c
added framecount and framerate checks to PF_effect
[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)
942         {
943                 VectorCopy (trace.endpos, ent->fields.server->origin);
944                 SV_LinkEdict (ent, false);
945                 ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
946                 ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
947                 PRVM_G_FLOAT(OFS_RETURN) = 1;
948                 // if support is destroyed, keep suspended (gross hack for floating items in various maps)
949                 ent->priv.server->suspendedinairflag = true;
950         }
951 }
952
953 /*
954 ===============
955 PF_lightstyle
956
957 void(float style, string value) lightstyle
958 ===============
959 */
960 void PF_lightstyle (void)
961 {
962         int             style;
963         const char      *val;
964         client_t        *client;
965         int                     j;
966
967         style = (int)PRVM_G_FLOAT(OFS_PARM0);
968         val = PRVM_G_STRING(OFS_PARM1);
969
970         if( (unsigned) style >= MAX_LIGHTSTYLES ) {
971                 PRVM_ERROR( "PF_lightstyle: style: %i >= 64", style );
972         }
973
974 // change the string in sv
975         strlcpy(sv.lightstyles[style], val, sizeof(sv.lightstyles[style]));
976
977 // send message to all clients on this server
978         if (sv.state != ss_active)
979                 return;
980
981         for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
982         {
983                 if (client->active && client->netconnection)
984                 {
985                         MSG_WriteChar (&client->netconnection->message, svc_lightstyle);
986                         MSG_WriteChar (&client->netconnection->message,style);
987                         MSG_WriteString (&client->netconnection->message, val);
988                 }
989         }
990 }
991
992 /*
993 =============
994 PF_checkbottom
995 =============
996 */
997 void PF_checkbottom (void)
998 {
999         PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0));
1000 }
1001
1002 /*
1003 =============
1004 PF_pointcontents
1005 =============
1006 */
1007 void PF_pointcontents (void)
1008 {
1009         PRVM_G_FLOAT(OFS_RETURN) = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_G_VECTOR(OFS_PARM0)));
1010 }
1011
1012 /*
1013 =============
1014 PF_aim
1015
1016 Pick a vector for the player to shoot along
1017 vector aim(entity, missilespeed)
1018 =============
1019 */
1020 void PF_aim (void)
1021 {
1022         prvm_edict_t    *ent, *check, *bestent;
1023         vec3_t  start, dir, end, bestdir;
1024         int             i, j;
1025         trace_t tr;
1026         float   dist, bestdist;
1027         float   speed;
1028
1029         // assume failure if it returns early
1030         VectorCopy(prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1031         // if sv_aim is so high it can't possibly accept anything, skip out early
1032         if (sv_aim.value >= 1)
1033                 return;
1034
1035         ent = PRVM_G_EDICT(OFS_PARM0);
1036         if (ent == prog->edicts)
1037         {
1038                 VM_Warning("aim: can not use world entity\n");
1039                 return;
1040         }
1041         if (ent->priv.server->free)
1042         {
1043                 VM_Warning("aim: can not use free entity\n");
1044                 return;
1045         }
1046         speed = PRVM_G_FLOAT(OFS_PARM1);
1047
1048         VectorCopy (ent->fields.server->origin, start);
1049         start[2] += 20;
1050
1051 // try sending a trace straight
1052         VectorCopy (prog->globals.server->v_forward, dir);
1053         VectorMA (start, 2048, dir, end);
1054         tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1055         if (tr.ent && ((prvm_edict_t *)tr.ent)->fields.server->takedamage == DAMAGE_AIM
1056         && (!teamplay.integer || ent->fields.server->team <=0 || ent->fields.server->team != ((prvm_edict_t *)tr.ent)->fields.server->team) )
1057         {
1058                 VectorCopy (prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN));
1059                 return;
1060         }
1061
1062
1063 // try all possible entities
1064         VectorCopy (dir, bestdir);
1065         bestdist = sv_aim.value;
1066         bestent = NULL;
1067
1068         check = PRVM_NEXT_EDICT(prog->edicts);
1069         for (i=1 ; i<prog->num_edicts ; i++, check = PRVM_NEXT_EDICT(check) )
1070         {
1071                 prog->xfunction->builtinsprofile++;
1072                 if (check->fields.server->takedamage != DAMAGE_AIM)
1073                         continue;
1074                 if (check == ent)
1075                         continue;
1076                 if (teamplay.integer && ent->fields.server->team > 0 && ent->fields.server->team == check->fields.server->team)
1077                         continue;       // don't aim at teammate
1078                 for (j=0 ; j<3 ; j++)
1079                         end[j] = check->fields.server->origin[j]
1080                         + 0.5*(check->fields.server->mins[j] + check->fields.server->maxs[j]);
1081                 VectorSubtract (end, start, dir);
1082                 VectorNormalize (dir);
1083                 dist = DotProduct (dir, prog->globals.server->v_forward);
1084                 if (dist < bestdist)
1085                         continue;       // to far to turn
1086                 tr = SV_Move (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent);
1087                 if (tr.ent == check)
1088                 {       // can shoot at this one
1089                         bestdist = dist;
1090                         bestent = check;
1091                 }
1092         }
1093
1094         if (bestent)
1095         {
1096                 VectorSubtract (bestent->fields.server->origin, ent->fields.server->origin, dir);
1097                 dist = DotProduct (dir, prog->globals.server->v_forward);
1098                 VectorScale (prog->globals.server->v_forward, dist, end);
1099                 end[2] = dir[2];
1100                 VectorNormalize (end);
1101                 VectorCopy (end, PRVM_G_VECTOR(OFS_RETURN));
1102         }
1103         else
1104         {
1105                 VectorCopy (bestdir, PRVM_G_VECTOR(OFS_RETURN));
1106         }
1107 }
1108
1109 /*
1110 ==============
1111 PF_changeyaw
1112
1113 This was a major timewaster in progs, so it was converted to C
1114 ==============
1115 */
1116 void PF_changeyaw (void)
1117 {
1118         prvm_edict_t            *ent;
1119         float           ideal, current, move, speed;
1120
1121         ent = PRVM_PROG_TO_EDICT(prog->globals.server->self);
1122         if (ent == prog->edicts)
1123         {
1124                 VM_Warning("changeyaw: can not modify world entity\n");
1125                 return;
1126         }
1127         if (ent->priv.server->free)
1128         {
1129                 VM_Warning("changeyaw: can not modify free entity\n");
1130                 return;
1131         }
1132         current = ANGLEMOD(ent->fields.server->angles[1]);
1133         ideal = ent->fields.server->ideal_yaw;
1134         speed = ent->fields.server->yaw_speed;
1135
1136         if (current == ideal)
1137                 return;
1138         move = ideal - current;
1139         if (ideal > current)
1140         {
1141                 if (move >= 180)
1142                         move = move - 360;
1143         }
1144         else
1145         {
1146                 if (move <= -180)
1147                         move = move + 360;
1148         }
1149         if (move > 0)
1150         {
1151                 if (move > speed)
1152                         move = speed;
1153         }
1154         else
1155         {
1156                 if (move < -speed)
1157                         move = -speed;
1158         }
1159
1160         ent->fields.server->angles[1] = ANGLEMOD (current + move);
1161 }
1162
1163 /*
1164 ==============
1165 PF_changepitch
1166 ==============
1167 */
1168 void PF_changepitch (void)
1169 {
1170         prvm_edict_t            *ent;
1171         float           ideal, current, move, speed;
1172         prvm_eval_t             *val;
1173
1174         ent = PRVM_G_EDICT(OFS_PARM0);
1175         if (ent == prog->edicts)
1176         {
1177                 VM_Warning("changepitch: can not modify world entity\n");
1178                 return;
1179         }
1180         if (ent->priv.server->free)
1181         {
1182                 VM_Warning("changepitch: can not modify free entity\n");
1183                 return;
1184         }
1185         current = ANGLEMOD( ent->fields.server->angles[0] );
1186         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_idealpitch)))
1187                 ideal = val->_float;
1188         else
1189         {
1190                 VM_Warning("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1191                 return;
1192         }
1193         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_pitch_speed)))
1194                 speed = val->_float;
1195         else
1196         {
1197                 VM_Warning("PF_changepitch: .float idealpitch and .float pitch_speed must be defined to use changepitch\n");
1198                 return;
1199         }
1200
1201         if (current == ideal)
1202                 return;
1203         move = ideal - current;
1204         if (ideal > current)
1205         {
1206                 if (move >= 180)
1207                         move = move - 360;
1208         }
1209         else
1210         {
1211                 if (move <= -180)
1212                         move = move + 360;
1213         }
1214         if (move > 0)
1215         {
1216                 if (move > speed)
1217                         move = speed;
1218         }
1219         else
1220         {
1221                 if (move < -speed)
1222                         move = -speed;
1223         }
1224
1225         ent->fields.server->angles[0] = ANGLEMOD (current + move);
1226 }
1227
1228 /*
1229 ===============================================================================
1230
1231 MESSAGE WRITING
1232
1233 ===============================================================================
1234 */
1235
1236 #define MSG_BROADCAST   0               // unreliable to all
1237 #define MSG_ONE                 1               // reliable to one (msg_entity)
1238 #define MSG_ALL                 2               // reliable to all
1239 #define MSG_INIT                3               // write to the init string
1240 #define MSG_ENTITY              5
1241
1242 sizebuf_t *WriteDest (void)
1243 {
1244         int             entnum;
1245         int             dest;
1246         prvm_edict_t    *ent;
1247         extern sizebuf_t *sv2csqcbuf;
1248
1249         dest = (int)PRVM_G_FLOAT(OFS_PARM0);
1250         switch (dest)
1251         {
1252         case MSG_BROADCAST:
1253                 return &sv.datagram;
1254
1255         case MSG_ONE:
1256                 ent = PRVM_PROG_TO_EDICT(prog->globals.server->msg_entity);
1257                 entnum = PRVM_NUM_FOR_EDICT(ent);
1258                 if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active || !svs.clients[entnum-1].netconnection)
1259                 {
1260                         VM_Warning ("WriteDest: tried to write to non-client\n");
1261                         return &sv.reliable_datagram;
1262                 }
1263                 else
1264                         return &svs.clients[entnum-1].netconnection->message;
1265
1266         default:
1267                 VM_Warning ("WriteDest: bad destination\n");
1268         case MSG_ALL:
1269                 return &sv.reliable_datagram;
1270
1271         case MSG_INIT:
1272                 return &sv.signon;
1273
1274         case MSG_ENTITY:
1275                 return sv2csqcbuf;
1276         }
1277
1278         return NULL;
1279 }
1280
1281 void PF_WriteByte (void)
1282 {
1283         MSG_WriteByte (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1284 }
1285
1286 void PF_WriteChar (void)
1287 {
1288         MSG_WriteChar (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1289 }
1290
1291 void PF_WriteShort (void)
1292 {
1293         MSG_WriteShort (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1294 }
1295
1296 void PF_WriteLong (void)
1297 {
1298         MSG_WriteLong (WriteDest(), (int)PRVM_G_FLOAT(OFS_PARM1));
1299 }
1300
1301 void PF_WriteAngle (void)
1302 {
1303         MSG_WriteAngle (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1304 }
1305
1306 void PF_WriteCoord (void)
1307 {
1308         MSG_WriteCoord (WriteDest(), PRVM_G_FLOAT(OFS_PARM1), sv.protocol);
1309 }
1310
1311 void PF_WriteString (void)
1312 {
1313         MSG_WriteString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1314 }
1315
1316 void PF_WriteUnterminatedString (void)
1317 {
1318         MSG_WriteUnterminatedString (WriteDest(), PRVM_G_STRING(OFS_PARM1));
1319 }
1320
1321
1322 void PF_WriteEntity (void)
1323 {
1324         MSG_WriteShort (WriteDest(), PRVM_G_EDICTNUM(OFS_PARM1));
1325 }
1326
1327 //////////////////////////////////////////////////////////
1328
1329 void PF_makestatic (void)
1330 {
1331         prvm_edict_t *ent;
1332         int i, large;
1333
1334         ent = PRVM_G_EDICT(OFS_PARM0);
1335         if (ent == prog->edicts)
1336         {
1337                 VM_Warning("makestatic: can not modify world entity\n");
1338                 return;
1339         }
1340         if (ent->priv.server->free)
1341         {
1342                 VM_Warning("makestatic: can not modify free entity\n");
1343                 return;
1344         }
1345
1346         large = false;
1347         if (ent->fields.server->modelindex >= 256 || ent->fields.server->frame >= 256)
1348                 large = true;
1349
1350         if (large)
1351         {
1352                 MSG_WriteByte (&sv.signon,svc_spawnstatic2);
1353                 MSG_WriteShort (&sv.signon, (int)ent->fields.server->modelindex);
1354                 MSG_WriteShort (&sv.signon, (int)ent->fields.server->frame);
1355         }
1356         else
1357         {
1358                 MSG_WriteByte (&sv.signon,svc_spawnstatic);
1359                 MSG_WriteByte (&sv.signon, (int)ent->fields.server->modelindex);
1360                 MSG_WriteByte (&sv.signon, (int)ent->fields.server->frame);
1361         }
1362
1363         MSG_WriteByte (&sv.signon, (int)ent->fields.server->colormap);
1364         MSG_WriteByte (&sv.signon, (int)ent->fields.server->skin);
1365         for (i=0 ; i<3 ; i++)
1366         {
1367                 MSG_WriteCoord(&sv.signon, ent->fields.server->origin[i], sv.protocol);
1368                 MSG_WriteAngle(&sv.signon, ent->fields.server->angles[i], sv.protocol);
1369         }
1370
1371 // throw the entity away now
1372         PRVM_ED_Free (ent);
1373 }
1374
1375 //=============================================================================
1376
1377 /*
1378 ==============
1379 PF_setspawnparms
1380 ==============
1381 */
1382 void PF_setspawnparms (void)
1383 {
1384         prvm_edict_t    *ent;
1385         int             i;
1386         client_t        *client;
1387
1388         ent = PRVM_G_EDICT(OFS_PARM0);
1389         i = PRVM_NUM_FOR_EDICT(ent);
1390         if (i < 1 || i > svs.maxclients || !svs.clients[i-1].active)
1391         {
1392                 Con_Print("tried to setspawnparms on a non-client\n");
1393                 return;
1394         }
1395
1396         // copy spawn parms out of the client_t
1397         client = svs.clients + i-1;
1398         for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
1399                 (&prog->globals.server->parm1)[i] = client->spawn_parms[i];
1400 }
1401
1402 /*
1403 =================
1404 PF_getlight
1405
1406 Returns a color vector indicating the lighting at the requested point.
1407
1408 (Internal Operation note: actually measures the light beneath the point, just like
1409                           the model lighting on the client)
1410
1411 getlight(vector)
1412 =================
1413 */
1414 void PF_getlight (void)
1415 {
1416         vec3_t ambientcolor, diffusecolor, diffusenormal;
1417         vec_t *p;
1418         p = PRVM_G_VECTOR(OFS_PARM0);
1419         VectorClear(ambientcolor);
1420         VectorClear(diffusecolor);
1421         VectorClear(diffusenormal);
1422         if (sv.worldmodel && sv.worldmodel->brush.LightPoint)
1423                 sv.worldmodel->brush.LightPoint(sv.worldmodel, p, ambientcolor, diffusecolor, diffusenormal);
1424         VectorMA(ambientcolor, 0.5, diffusecolor, PRVM_G_VECTOR(OFS_RETURN));
1425 }
1426
1427 void PF_registercvar (void)
1428 {
1429         const char *name, *value;
1430         name = PRVM_G_STRING(OFS_PARM0);
1431         value = PRVM_G_STRING(OFS_PARM1);
1432         PRVM_G_FLOAT(OFS_RETURN) = 0;
1433
1434 // first check to see if it has already been defined
1435         if (Cvar_FindVar (name))
1436                 return;
1437
1438 // check for overlap with a command
1439         if (Cmd_Exists (name))
1440         {
1441                 VM_Warning("PF_registercvar: %s is a command\n", name);
1442                 return;
1443         }
1444
1445         Cvar_Get(name, value, 0);
1446
1447         PRVM_G_FLOAT(OFS_RETURN) = 1; // success
1448 }
1449
1450 typedef struct
1451 {
1452         unsigned char   type;   // 1/2/8 or other value if isn't used
1453         int             fieldoffset;
1454 }autosentstat_t;
1455
1456 static autosentstat_t *vm_autosentstats = NULL; //[515]: it starts from 0, not 32
1457 static int vm_autosentstats_last;
1458
1459 void VM_AutoSentStats_Clear (void)
1460 {
1461         if(vm_autosentstats)
1462         {
1463                 Z_Free(vm_autosentstats);
1464                 vm_autosentstats = NULL;
1465                 vm_autosentstats_last = -1;
1466         }
1467 }
1468
1469 //[515]: add check if even bigger ? "try to use two stats, cause it's too big" ?
1470 #define VM_SENDSTAT(a,b,c)\
1471 {\
1472 /*      if((c))*/\
1473         if((c)==(unsigned char)(c))\
1474         {\
1475                 MSG_WriteByte((a), svc_updatestatubyte);\
1476                 MSG_WriteByte((a), (b));\
1477                 MSG_WriteByte((a), (c));\
1478         }\
1479         else\
1480         {\
1481                 MSG_WriteByte((a), svc_updatestat);\
1482                 MSG_WriteByte((a), (b));\
1483                 MSG_WriteLong((a), (c));\
1484         }\
1485 }\
1486
1487 void VM_SV_WriteAutoSentStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1488 {
1489         int                     i, v, *si;
1490         char            s[17];
1491         const char      *t;
1492         qboolean        send;
1493         union
1494         {
1495                 float   f;
1496                 int             i;
1497         }k;
1498
1499         if(!vm_autosentstats)
1500                 return;
1501
1502         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);
1503
1504         for(i=0; i<vm_autosentstats_last+1 ;i++)
1505         {
1506                 if(!vm_autosentstats[i].type)
1507                         continue;
1508                 switch(vm_autosentstats[i].type)
1509                 {
1510                 //string
1511                 case 1:
1512                         t = PRVM_E_STRING(ent, vm_autosentstats[i].fieldoffset);
1513                         if(t && t[0])
1514                         {
1515                                 memset(s, 0, 17);
1516                                 strlcpy(s, t, 16);
1517                                 si = (int*)s;
1518                                 if (!send)
1519                                 {
1520                                         stats[i+32] = si[0];
1521                                         stats[i+33] = si[1];
1522                                         stats[i+34] = si[2];
1523                                         stats[i+35] = si[3];
1524                                 }
1525                                 else
1526                                 {
1527                                         VM_SENDSTAT(msg, i+32, si[0]);
1528                                         VM_SENDSTAT(msg, i+33, si[1]);
1529                                         VM_SENDSTAT(msg, i+34, si[2]);
1530                                         VM_SENDSTAT(msg, i+35, si[3]);
1531                                 }
1532                         }
1533                         break;
1534                 //float
1535                 case 2:
1536                         k.f = PRVM_E_FLOAT(ent, vm_autosentstats[i].fieldoffset);       //[515]: use PRVM_E_INT ?
1537                         k.i = LittleLong (k.i);
1538                         if (!send)
1539                                 stats[i+32] = k.i;
1540                         else
1541                                 VM_SENDSTAT(msg, i+32, k.i);
1542                         break;
1543                 //integer
1544                 case 8:
1545                         v = (int)PRVM_E_FLOAT(ent, vm_autosentstats[i].fieldoffset);    //[515]: use PRVM_E_INT ?
1546                         if (!send)
1547                                 stats[i+32] = v;
1548                         else
1549                                 VM_SENDSTAT(msg, i+32, v);
1550                         break;
1551                 default:
1552                         break;
1553                 }
1554         }
1555 }
1556
1557 // void(float index, float type, .void field) SV_AddStat = #470;
1558 // Set up an auto-sent player stat.
1559 // Client's get thier own fields sent to them. Index may not be less than 32.
1560 // Type is a value equating to the ev_ values found in qcc to dictate types. Valid ones are:
1561 //          1: string (4 stats carrying a total of 16 charactures)
1562 //          2: float (one stat, float converted to an integer for transportation)
1563 //          8: integer (one stat, not converted to an int, so this can be used to transport floats as floats - what a unique idea!)
1564 void PF_SV_AddStat (void)
1565 {
1566         int             off, i;
1567         unsigned char   type;
1568
1569         if(!vm_autosentstats)
1570         {
1571                 vm_autosentstats = (autosentstat_t *)Z_Malloc((MAX_CL_STATS-32) * sizeof(autosentstat_t));
1572                 if(!vm_autosentstats)
1573                 {
1574                         VM_Warning("PF_SV_AddStat: not enough memory\n");
1575                         return;
1576                 }
1577         }
1578         i               = (int)PRVM_G_FLOAT(OFS_PARM0);
1579         type    = (int)PRVM_G_FLOAT(OFS_PARM1);
1580         off             = PRVM_G_INT  (OFS_PARM2);
1581         i -= 32;
1582
1583         if(i < 0)
1584         {
1585                 VM_Warning("PF_SV_AddStat: index may not be less than 32\n");
1586                 return;
1587         }
1588         if(i >= (MAX_CL_STATS-32))
1589         {
1590                 VM_Warning("PF_SV_AddStat: index >= MAX_CL_STATS\n");
1591                 return;
1592         }
1593         if(i > (MAX_CL_STATS-32-4) && type == 1)
1594         {
1595                 VM_Warning("PF_SV_AddStat: index > (MAX_CL_STATS-4) with string\n");
1596                 return;
1597         }
1598         vm_autosentstats[i].type                = type;
1599         vm_autosentstats[i].fieldoffset = off;
1600         if(vm_autosentstats_last < i)
1601                 vm_autosentstats_last = i;
1602 }
1603
1604 /*
1605 =================
1606 PF_copyentity
1607
1608 copies data from one entity to another
1609
1610 copyentity(src, dst)
1611 =================
1612 */
1613 void PF_copyentity (void)
1614 {
1615         prvm_edict_t *in, *out;
1616         in = PRVM_G_EDICT(OFS_PARM0);
1617         if (in == prog->edicts)
1618         {
1619                 VM_Warning("copyentity: can not read world entity\n");
1620                 return;
1621         }
1622         if (in->priv.server->free)
1623         {
1624                 VM_Warning("copyentity: can not read free entity\n");
1625                 return;
1626         }
1627         out = PRVM_G_EDICT(OFS_PARM1);
1628         if (out == prog->edicts)
1629         {
1630                 VM_Warning("copyentity: can not modify world entity\n");
1631                 return;
1632         }
1633         if (out->priv.server->free)
1634         {
1635                 VM_Warning("copyentity: can not modify free entity\n");
1636                 return;
1637         }
1638         memcpy(out->fields.server, in->fields.server, prog->progs->entityfields * 4);
1639 }
1640
1641
1642 /*
1643 =================
1644 PF_setcolor
1645
1646 sets the color of a client and broadcasts the update to all connected clients
1647
1648 setcolor(clientent, value)
1649 =================
1650 */
1651 void PF_setcolor (void)
1652 {
1653         client_t *client;
1654         int entnum, i;
1655         prvm_eval_t *val;
1656
1657         entnum = PRVM_G_EDICTNUM(OFS_PARM0);
1658         i = (int)PRVM_G_FLOAT(OFS_PARM1);
1659
1660         if (entnum < 1 || entnum > svs.maxclients || !svs.clients[entnum-1].active)
1661         {
1662                 Con_Print("tried to setcolor a non-client\n");
1663                 return;
1664         }
1665
1666         client = svs.clients + entnum-1;
1667         if (client->edict)
1668         {
1669                 if ((val = PRVM_GETEDICTFIELDVALUE(client->edict, eval_clientcolors)))
1670                         val->_float = i;
1671                 client->edict->fields.server->team = (i & 15) + 1;
1672         }
1673         client->colors = i;
1674         if (client->old_colors != client->colors)
1675         {
1676                 client->old_colors = client->colors;
1677                 // send notification to all clients
1678                 MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1679                 MSG_WriteByte (&sv.reliable_datagram, client - svs.clients);
1680                 MSG_WriteByte (&sv.reliable_datagram, client->colors);
1681         }
1682 }
1683
1684 /*
1685 =================
1686 PF_effect
1687
1688 effect(origin, modelname, startframe, framecount, framerate)
1689 =================
1690 */
1691 void PF_effect (void)
1692 {
1693         int i;
1694         const char *s;
1695         s = PRVM_G_STRING(OFS_PARM1);
1696         if (!s || !s[0])
1697         {
1698                 VM_Warning("effect: no model specified\n");
1699                 return;
1700         }
1701
1702         i = SV_ModelIndex(s, 1);
1703         if (!i)
1704         {
1705                 VM_Warning("effect: model not precached\n");
1706                 return;
1707         }
1708
1709         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1710         {
1711                 VM_Warning("effect: framecount < 1\n");
1712                 return;
1713         }
1714
1715         if (PRVM_G_FLOAT(OFS_PARM4) < 1)
1716         {
1717                 VM_Warning("effect: framerate < 1\n");
1718                 return;
1719         }
1720
1721         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));
1722 }
1723
1724 void PF_te_blood (void)
1725 {
1726         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1727                 return;
1728         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1729         MSG_WriteByte(&sv.datagram, TE_BLOOD);
1730         // origin
1731         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1732         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1733         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1734         // velocity
1735         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1736         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1737         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1738         // count
1739         MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1740 }
1741
1742 void PF_te_bloodshower (void)
1743 {
1744         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1745                 return;
1746         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1747         MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1748         // min
1749         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1750         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1751         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1752         // max
1753         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1754         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1755         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1756         // speed
1757         MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1758         // count
1759         MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1760 }
1761
1762 void PF_te_explosionrgb (void)
1763 {
1764         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1765         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1766         // origin
1767         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1768         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1769         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1770         // color
1771         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1772         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1773         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1774 }
1775
1776 void PF_te_particlecube (void)
1777 {
1778         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1779                 return;
1780         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1781         MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1782         // min
1783         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1784         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1785         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1786         // max
1787         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1788         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1789         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1790         // velocity
1791         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1792         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1793         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1794         // count
1795         MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1796         // color
1797         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1798         // gravity true/false
1799         MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1800         // randomvel
1801         MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1802 }
1803
1804 void PF_te_particlerain (void)
1805 {
1806         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1807                 return;
1808         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1809         MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1810         // min
1811         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1812         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1813         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1814         // max
1815         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1816         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1817         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1818         // velocity
1819         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1820         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1821         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1822         // count
1823         MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1824         // color
1825         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1826 }
1827
1828 void PF_te_particlesnow (void)
1829 {
1830         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1831                 return;
1832         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1833         MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1834         // min
1835         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1836         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1837         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1838         // max
1839         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1840         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1841         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1842         // velocity
1843         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1844         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1845         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1846         // count
1847         MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1848         // color
1849         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1850 }
1851
1852 void PF_te_spark (void)
1853 {
1854         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1855                 return;
1856         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1857         MSG_WriteByte(&sv.datagram, TE_SPARK);
1858         // origin
1859         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1860         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1861         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1862         // velocity
1863         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1864         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1865         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1866         // count
1867         MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1868 }
1869
1870 void PF_te_gunshotquad (void)
1871 {
1872         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1873         MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
1874         // origin
1875         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1876         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1877         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1878 }
1879
1880 void PF_te_spikequad (void)
1881 {
1882         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1883         MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
1884         // origin
1885         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1886         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1887         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1888 }
1889
1890 void PF_te_superspikequad (void)
1891 {
1892         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1893         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
1894         // origin
1895         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1896         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1897         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1898 }
1899
1900 void PF_te_explosionquad (void)
1901 {
1902         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1903         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
1904         // origin
1905         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1906         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1907         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1908 }
1909
1910 void PF_te_smallflash (void)
1911 {
1912         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1913         MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
1914         // origin
1915         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1916         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1917         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1918 }
1919
1920 void PF_te_customflash (void)
1921 {
1922         if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
1923                 return;
1924         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1925         MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
1926         // origin
1927         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1928         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1929         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1930         // radius
1931         MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
1932         // lifetime
1933         MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
1934         // color
1935         MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
1936         MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
1937         MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
1938 }
1939
1940 void PF_te_gunshot (void)
1941 {
1942         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1943         MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
1944         // origin
1945         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1946         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1947         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1948 }
1949
1950 void PF_te_spike (void)
1951 {
1952         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1953         MSG_WriteByte(&sv.datagram, TE_SPIKE);
1954         // origin
1955         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1956         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1957         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1958 }
1959
1960 void PF_te_superspike (void)
1961 {
1962         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1963         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
1964         // origin
1965         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1966         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1967         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1968 }
1969
1970 void PF_te_explosion (void)
1971 {
1972         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1973         MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
1974         // origin
1975         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1976         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1977         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1978 }
1979
1980 void PF_te_tarexplosion (void)
1981 {
1982         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1983         MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
1984         // origin
1985         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1986         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1987         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1988 }
1989
1990 void PF_te_wizspike (void)
1991 {
1992         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1993         MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
1994         // origin
1995         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1996         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1997         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1998 }
1999
2000 void PF_te_knightspike (void)
2001 {
2002         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2003         MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
2004         // origin
2005         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2006         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2007         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2008 }
2009
2010 void PF_te_lavasplash (void)
2011 {
2012         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2013         MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2014         // origin
2015         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2016         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2017         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2018 }
2019
2020 void PF_te_teleport (void)
2021 {
2022         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2023         MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2024         // origin
2025         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2026         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2027         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2028 }
2029
2030 void PF_te_explosion2 (void)
2031 {
2032         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2033         MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2034         // origin
2035         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2036         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2037         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2038         // color
2039         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2040         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2041 }
2042
2043 void PF_te_lightning1 (void)
2044 {
2045         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2046         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2047         // owner entity
2048         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2049         // start
2050         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2051         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2052         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2053         // end
2054         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2055         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2056         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2057 }
2058
2059 void PF_te_lightning2 (void)
2060 {
2061         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2062         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2063         // owner entity
2064         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2065         // start
2066         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2067         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2068         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2069         // end
2070         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2071         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2072         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2073 }
2074
2075 void PF_te_lightning3 (void)
2076 {
2077         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2078         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2079         // owner entity
2080         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2081         // start
2082         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2083         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2084         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2085         // end
2086         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2087         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2088         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2089 }
2090
2091 void PF_te_beam (void)
2092 {
2093         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2094         MSG_WriteByte(&sv.datagram, TE_BEAM);
2095         // owner entity
2096         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2097         // start
2098         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2099         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2100         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2101         // end
2102         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2103         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2104         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2105 }
2106
2107 void PF_te_plasmaburn (void)
2108 {
2109         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2110         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2111         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2112         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2113         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2114 }
2115
2116 void PF_te_flamejet (void)
2117 {
2118         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2119         MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2120         // org
2121         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2122         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2123         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2124         // vel
2125         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2126         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2127         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2128         // count
2129         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2130 }
2131
2132 void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
2133 {
2134         int i, j, k;
2135         float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2136         const int *e;
2137         bestdist = 1000000000;
2138         VectorCopy(p, out);
2139         for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2140         {
2141                 // clip original point to each triangle of the surface and find the
2142                 // triangle that is closest
2143                 v[0] = model->surfmesh.data_vertex3f + e[0] * 3;
2144                 v[1] = model->surfmesh.data_vertex3f + e[1] * 3;
2145                 v[2] = model->surfmesh.data_vertex3f + e[2] * 3;
2146                 TriangleNormal(v[0], v[1], v[2], facenormal);
2147                 VectorNormalize(facenormal);
2148                 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2149                 VectorMA(p, offsetdist, facenormal, temp);
2150                 for (j = 0, k = 2;j < 3;k = j, j++)
2151                 {
2152                         VectorSubtract(v[k], v[j], edgenormal);
2153                         CrossProduct(edgenormal, facenormal, sidenormal);
2154                         VectorNormalize(sidenormal);
2155                         offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2156                         if (offsetdist < 0)
2157                                 VectorMA(temp, offsetdist, sidenormal, temp);
2158                 }
2159                 dist = VectorDistance2(temp, p);
2160                 if (bestdist > dist)
2161                 {
2162                         bestdist = dist;
2163                         VectorCopy(temp, out);
2164                 }
2165         }
2166 }
2167
2168 static model_t *getmodel(prvm_edict_t *ed)
2169 {
2170         int modelindex;
2171         if (!ed || ed->priv.server->free)
2172                 return NULL;
2173         modelindex = (int)ed->fields.server->modelindex;
2174         if (modelindex < 1 || modelindex >= MAX_MODELS)
2175                 return NULL;
2176         return sv.models[modelindex];
2177 }
2178
2179 static msurface_t *getsurface(model_t *model, int surfacenum)
2180 {
2181         if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2182                 return NULL;
2183         return model->data_surfaces + surfacenum + model->firstmodelsurface;
2184 }
2185
2186
2187 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2188 void PF_getsurfacenumpoints(void)
2189 {
2190         model_t *model;
2191         msurface_t *surface;
2192         // return 0 if no such surface
2193         if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2194         {
2195                 PRVM_G_FLOAT(OFS_RETURN) = 0;
2196                 return;
2197         }
2198
2199         // note: this (incorrectly) assumes it is a simple polygon
2200         PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
2201 }
2202 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2203 void PF_getsurfacepoint(void)
2204 {
2205         prvm_edict_t *ed;
2206         model_t *model;
2207         msurface_t *surface;
2208         int pointnum;
2209         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2210         ed = PRVM_G_EDICT(OFS_PARM0);
2211         if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2212                 return;
2213         // note: this (incorrectly) assumes it is a simple polygon
2214         pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2215         if (pointnum < 0 || pointnum >= surface->num_vertices)
2216                 return;
2217         // FIXME: implement rotation/scaling
2218         VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2219 }
2220 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
2221 void PF_getsurfacenormal(void)
2222 {
2223         model_t *model;
2224         msurface_t *surface;
2225         vec3_t normal;
2226         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2227         if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2228                 return;
2229         // FIXME: implement rotation/scaling
2230         // note: this (incorrectly) assumes it is a simple polygon
2231         // note: this only returns the first triangle, so it doesn't work very
2232         // well for curved surfaces or arbitrary meshes
2233         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);
2234         VectorNormalize(normal);
2235         VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
2236 }
2237 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
2238 void PF_getsurfacetexture(void)
2239 {
2240         model_t *model;
2241         msurface_t *surface;
2242         PRVM_G_INT(OFS_RETURN) = 0;
2243         if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2244                 return;
2245         PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(surface->texture->name);
2246 }
2247 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2248 void PF_getsurfacenearpoint(void)
2249 {
2250         int surfacenum, best;
2251         vec3_t clipped, p;
2252         vec_t dist, bestdist;
2253         prvm_edict_t *ed;
2254         model_t *model;
2255         msurface_t *surface;
2256         vec_t *point;
2257         PRVM_G_FLOAT(OFS_RETURN) = -1;
2258         ed = PRVM_G_EDICT(OFS_PARM0);
2259         point = PRVM_G_VECTOR(OFS_PARM1);
2260
2261         if (!ed || ed->priv.server->free)
2262                 return;
2263         model = getmodel(ed);
2264         if (!model || !model->num_surfaces)
2265                 return;
2266
2267         // FIXME: implement rotation/scaling
2268         VectorSubtract(point, ed->fields.server->origin, p);
2269         best = -1;
2270         bestdist = 1000000000;
2271         for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2272         {
2273                 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2274                 // first see if the nearest point on the surface's box is closer than the previous match
2275                 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2276                 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2277                 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2278                 dist = VectorLength2(clipped);
2279                 if (dist < bestdist)
2280                 {
2281                         // it is, check the nearest point on the actual geometry
2282                         clippointtosurface(model, surface, p, clipped);
2283                         VectorSubtract(clipped, p, clipped);
2284                         dist += VectorLength2(clipped);
2285                         if (dist < bestdist)
2286                         {
2287                                 // that's closer too, store it as the best match
2288                                 best = surfacenum;
2289                                 bestdist = dist;
2290                         }
2291                 }
2292         }
2293         PRVM_G_FLOAT(OFS_RETURN) = best;
2294 }
2295 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2296 void PF_getsurfaceclippedpoint(void)
2297 {
2298         prvm_edict_t *ed;
2299         model_t *model;
2300         msurface_t *surface;
2301         vec3_t p, out;
2302         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2303         ed = PRVM_G_EDICT(OFS_PARM0);
2304         if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2305                 return;
2306         // FIXME: implement rotation/scaling
2307         VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
2308         clippointtosurface(model, surface, p, out);
2309         // FIXME: implement rotation/scaling
2310         VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2311 }
2312
2313 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2314 //this function originally written by KrimZon, made shorter by LordHavoc
2315 void PF_clientcommand (void)
2316 {
2317         client_t *temp_client;
2318         int i;
2319
2320         //find client for this entity
2321         i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2322         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2323         {
2324                 Con_Print("PF_clientcommand: entity is not a client\n");
2325                 return;
2326         }
2327
2328         temp_client = host_client;
2329         host_client = svs.clients + i;
2330         Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2331         host_client = temp_client;
2332 }
2333
2334 //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)
2335 void PF_setattachment (void)
2336 {
2337         prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2338         prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2339         const char *tagname = PRVM_G_STRING(OFS_PARM2);
2340         prvm_eval_t *v;
2341         int modelindex;
2342         model_t *model;
2343
2344         if (e == prog->edicts)
2345         {
2346                 VM_Warning("setattachment: can not modify world entity\n");
2347                 return;
2348         }
2349         if (e->priv.server->free)
2350         {
2351                 VM_Warning("setattachment: can not modify free entity\n");
2352                 return;
2353         }
2354
2355         if (tagentity == NULL)
2356                 tagentity = prog->edicts;
2357
2358         v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_entity);
2359         if (v)
2360                 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2361
2362         v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_index);
2363         if (v)
2364                 v->_float = 0;
2365         if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2366         {
2367                 modelindex = (int)tagentity->fields.server->modelindex;
2368                 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
2369                 {
2370                         v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.server->skin, tagname);
2371                         if (v->_float == 0)
2372                                 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);
2373                 }
2374                 else
2375                         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));
2376         }
2377 }
2378
2379 /////////////////////////////////////////
2380 // DP_MD3_TAGINFO extension coded by VorteX
2381
2382 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
2383 {
2384         int i;
2385         model_t *model;
2386
2387         i = (int)e->fields.server->modelindex;
2388         if (i < 1 || i >= MAX_MODELS)
2389                 return -1;
2390         model = sv.models[i];
2391
2392         return Mod_Alias_GetTagIndexForName(model, (int)e->fields.server->skin, tagname);
2393 };
2394
2395 void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2396 {
2397         float scale = PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float;
2398         if (scale == 0)
2399                 scale = 1;
2400         if (viewmatrix)
2401                 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);
2402         else
2403                 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);
2404 }
2405
2406 int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2407 {
2408         int modelindex;
2409         int frame;
2410         model_t *model;
2411         if (tagindex >= 0
2412          && (modelindex = (int)ent->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS
2413          && (model = sv.models[(int)ent->fields.server->modelindex])
2414          && model->animscenes)
2415         {
2416                 // if model has wrong frame, engine automatically switches to model first frame
2417                 frame = (int)ent->fields.server->frame;
2418                 if (frame < 0 || frame >= model->numframes)
2419                         frame = 0;
2420                 return Mod_Alias_GetTagMatrix(model, model->animscenes[frame].firstframe, tagindex, out);
2421         }
2422         *out = identitymatrix;
2423         return 0;
2424 }
2425
2426 // Warnings/errors code:
2427 // 0 - normal (everything all-right)
2428 // 1 - world entity
2429 // 2 - free entity
2430 // 3 - null or non-precached model
2431 // 4 - no tags with requested index
2432 // 5 - runaway loop at attachment chain
2433 extern cvar_t cl_bob;
2434 extern cvar_t cl_bobcycle;
2435 extern cvar_t cl_bobup;
2436 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2437 {
2438         int ret;
2439         prvm_eval_t *val;
2440         int modelindex, attachloop;
2441         matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2442         model_t *model;
2443
2444         *out = identitymatrix; // warnings and errors return identical matrix
2445
2446         if (ent == prog->edicts)
2447                 return 1;
2448         if (ent->priv.server->free)
2449                 return 2;
2450
2451         modelindex = (int)ent->fields.server->modelindex;
2452         if (modelindex <= 0 || modelindex > MAX_MODELS)
2453                 return 3;
2454
2455         model = sv.models[modelindex];
2456
2457         tagmatrix = identitymatrix;
2458         // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2459         attachloop = 0;
2460         for (;;)
2461         {
2462                 if (attachloop >= 256) // prevent runaway looping
2463                         return 5;
2464                 // apply transformation by child's tagindex on parent entity and then
2465                 // by parent entity itself
2466                 ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
2467                 if (ret && attachloop == 0)
2468                         return ret;
2469                 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
2470                 SV_GetEntityMatrix(ent, &entitymatrix, false);
2471                 Matrix4x4_Concat(&tagmatrix, &entitymatrix, out);
2472                 // next iteration we process the parent entity
2473                 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
2474                 {
2475                         tagindex = (int)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
2476                         ent = PRVM_EDICT_NUM(val->edict);
2477                 }
2478                 else
2479                         break;
2480                 attachloop++;
2481         }
2482
2483         // RENDER_VIEWMODEL magic
2484         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
2485         {
2486                 Matrix4x4_Copy(&tagmatrix, out);
2487                 ent = PRVM_EDICT_NUM(val->edict);
2488
2489                 SV_GetEntityMatrix(ent, &entitymatrix, true);
2490                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2491
2492                 /*
2493                 // Cl_bob, ported from rendering code
2494                 if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
2495                 {
2496                         double bob, cycle;
2497                         // LordHavoc: this code is *weird*, but not replacable (I think it
2498                         // should be done in QC on the server, but oh well, quake is quake)
2499                         // LordHavoc: figured out bobup: the time at which the sin is at 180
2500                         // degrees (which allows lengthening or squishing the peak or valley)
2501                         cycle = sv.time/cl_bobcycle.value;
2502                         cycle -= (int)cycle;
2503                         if (cycle < cl_bobup.value)
2504                                 cycle = sin(M_PI * cycle / cl_bobup.value);
2505                         else
2506                                 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2507                         // bob is proportional to velocity in the xy plane
2508                         // (don't count Z, or jumping messes it up)
2509                         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;
2510                         bob = bob*0.3 + bob*0.7*cycle;
2511                         Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2512                 }
2513                 */
2514         }
2515         return 0;
2516 }
2517
2518 //float(entity ent, string tagname) gettagindex;
2519
2520 void PF_gettagindex (void)
2521 {
2522         prvm_edict_t *ent = PRVM_G_EDICT(OFS_PARM0);
2523         const char *tag_name = PRVM_G_STRING(OFS_PARM1);
2524         int modelindex, tag_index;
2525
2526         if (ent == prog->edicts)
2527         {
2528                 VM_Warning("gettagindex: can't affect world entity\n");
2529                 return;
2530         }
2531         if (ent->priv.server->free)
2532         {
2533                 VM_Warning("gettagindex: can't affect free entity\n");
2534                 return;
2535         }
2536
2537         modelindex = (int)ent->fields.server->modelindex;
2538         tag_index = 0;
2539         if (modelindex <= 0 || modelindex > MAX_MODELS)
2540                 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2541         else
2542         {
2543                 tag_index = SV_GetTagIndex(ent, tag_name);
2544                 if (tag_index == 0)
2545                         Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2546         }
2547         PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2548 };
2549
2550 //vector(entity ent, float tagindex) gettaginfo;
2551 void PF_gettaginfo (void)
2552 {
2553         prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2554         int tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2555         matrix4x4_t tag_matrix;
2556         int returncode;
2557
2558         returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
2559         Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
2560
2561         switch(returncode)
2562         {
2563                 case 1:
2564                         VM_Warning("gettagindex: can't affect world entity\n");
2565                         break;
2566                 case 2:
2567                         VM_Warning("gettagindex: can't affect free entity\n");
2568                         break;
2569                 case 3:
2570                         Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2571                         break;
2572                 case 4:
2573                         Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2574                         break;
2575                 case 5:
2576                         Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2577                         break;
2578         }
2579 }
2580
2581 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2582 void PF_dropclient (void)
2583 {
2584         int clientnum;
2585         client_t *oldhostclient;
2586         clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2587         if (clientnum < 0 || clientnum >= svs.maxclients)
2588         {
2589                 VM_Warning("dropclient: not a client\n");
2590                 return;
2591         }
2592         if (!svs.clients[clientnum].active)
2593         {
2594                 VM_Warning("dropclient: that client slot is not connected\n");
2595                 return;
2596         }
2597         oldhostclient = host_client;
2598         host_client = svs.clients + clientnum;
2599         SV_DropClient(false);
2600         host_client = oldhostclient;
2601 }
2602
2603 //entity() spawnclient (DP_SV_BOTCLIENT)
2604 void PF_spawnclient (void)
2605 {
2606         int i;
2607         prvm_edict_t    *ed;
2608         prog->xfunction->builtinsprofile += 2;
2609         ed = prog->edicts;
2610         for (i = 0;i < svs.maxclients;i++)
2611         {
2612                 if (!svs.clients[i].active)
2613                 {
2614                         prog->xfunction->builtinsprofile += 100;
2615                         SV_ConnectClient (i, NULL);
2616                         // this has to be set or else ClientDisconnect won't be called
2617                         // we assume the qc will call ClientConnect...
2618                         svs.clients[i].clientconnectcalled = true;
2619                         ed = PRVM_EDICT_NUM(i + 1);
2620                         break;
2621                 }
2622         }
2623         VM_RETURN_EDICT(ed);
2624 }
2625
2626 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2627 void PF_clienttype (void)
2628 {
2629         int clientnum;
2630         clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2631         if (clientnum < 0 || clientnum >= svs.maxclients)
2632                 PRVM_G_FLOAT(OFS_RETURN) = 3;
2633         else if (!svs.clients[clientnum].active)
2634                 PRVM_G_FLOAT(OFS_RETURN) = 0;
2635         else if (svs.clients[clientnum].netconnection)
2636                 PRVM_G_FLOAT(OFS_RETURN) = 1;
2637         else
2638                 PRVM_G_FLOAT(OFS_RETURN) = 2;
2639 }
2640
2641 void PF_edict_num (void)
2642 {
2643         VM_RETURN_EDICT(PRVM_EDICT_NUM((int)PRVM_G_FLOAT(OFS_PARM0)));
2644 }
2645
2646 prvm_builtin_t vm_sv_builtins[] = {
2647 NULL,                                           // #0
2648 PF_makevectors,                         // #1 void(vector ang) makevectors
2649 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
2650 PF_setmodel,                            // #3 void(entity e, string m) setmodel
2651 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
2652 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
2653 VM_break,                                       // #6 void() break
2654 VM_random,                                      // #7 float() random
2655 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
2656 VM_normalize,                           // #9 vector(vector v) normalize
2657 VM_error,                                       // #10 void(string e) error
2658 VM_objerror,                            // #11 void(string e) objerror
2659 VM_vlen,                                        // #12 float(vector v) vlen
2660 VM_vectoyaw,                            // #13 float(vector v) vectoyaw
2661 VM_spawn,                                       // #14 entity() spawn
2662 VM_remove,                                      // #15 void(entity e) remove
2663 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
2664 PF_checkclient,                         // #17 entity() clientlist
2665 VM_find,                                        // #18 entity(entity start, .string fld, string match) find
2666 PF_precache_sound,                      // #19 void(string s) precache_sound
2667 PF_precache_model,                      // #20 void(string s) precache_model
2668 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
2669 PF_findradius,                          // #22 entity(vector org, float rad) findradius
2670 VM_bprint,                                      // #23 void(string s) bprint
2671 PF_sprint,                                      // #24 void(entity client, string s) sprint
2672 VM_dprint,                                      // #25 void(string s) dprint
2673 VM_ftos,                                        // #26 void(string s) ftos
2674 VM_vtos,                                        // #27 void(string s) vtos
2675 VM_coredump,                            // #28 void() coredump
2676 VM_traceon,                                     // #29 void() traceon
2677 VM_traceoff,                            // #30 void() traceoff
2678 VM_eprint,                                      // #31 void(entity e) eprint
2679 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
2680 NULL,                                           // #33
2681 PF_droptofloor,                         // #34 float() droptofloor
2682 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
2683 VM_rint,                                        // #36 float(float v) rint
2684 VM_floor,                                       // #37 float(float v) floor
2685 VM_ceil,                                        // #38 float(float v) ceil
2686 NULL,                                           // #39
2687 PF_checkbottom,                         // #40 float(entity e) checkbottom
2688 PF_pointcontents,                       // #41 float(vector v) pointcontents
2689 NULL,                                           // #42
2690 VM_fabs,                                        // #43 float(float f) fabs
2691 PF_aim,                                         // #44 vector(entity e, float speed) aim
2692 VM_cvar,                                        // #45 float(string s) cvar
2693 VM_localcmd,                            // #46 void(string s) localcmd
2694 VM_nextent,                                     // #47 entity(entity e) nextent
2695 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
2696 PF_changeyaw,                           // #49 void() ChangeYaw
2697 NULL,                                           // #50
2698 VM_vectoangles,                         // #51 vector(vector v) vectoangles
2699 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
2700 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
2701 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
2702 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
2703 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
2704 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
2705 PF_WriteString,                         // #58 void(float to, string s) WriteString
2706 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
2707 VM_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2708 VM_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2709 VM_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2710 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2711 PF_tracetoss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2712 VM_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
2713 NULL,                                           // #66
2714 SV_MoveToGoal,                          // #67 void(float step) movetogoal
2715 PF_precache_file,                       // #68 string(string s) precache_file
2716 PF_makestatic,                          // #69 void(entity e) makestatic
2717 VM_changelevel,                         // #70 void(string s) changelevel
2718 NULL,                                           // #71
2719 VM_cvar_set,                            // #72 void(string var, string val) cvar_set
2720 PF_centerprint,                         // #73 void(entity client, strings) centerprint
2721 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
2722 PF_precache_model,                      // #75 string(string s) precache_model2
2723 PF_precache_sound,                      // #76 string(string s) precache_sound2
2724 PF_precache_file,                       // #77 string(string s) precache_file2
2725 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
2726 NULL,                                           // #79
2727 NULL,                                           // #80
2728 VM_stof,                                        // #81 float(string s) stof (FRIK_FILE)
2729 NULL,                                           // #82
2730 NULL,                                           // #83
2731 NULL,                                           // #84
2732 NULL,                                           // #85
2733 NULL,                                           // #86
2734 NULL,                                           // #87
2735 NULL,                                           // #88
2736 NULL,                                           // #89
2737 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2738 VM_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
2739 PF_getlight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2740 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2741 VM_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2742 VM_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2743 VM_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2744 VM_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2745 VM_findfloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2746 VM_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
2747 NULL,                                           // #100
2748 NULL,                                           // #101
2749 NULL,                                           // #102
2750 NULL,                                           // #103
2751 NULL,                                           // #104
2752 NULL,                                           // #105
2753 NULL,                                           // #106
2754 NULL,                                           // #107
2755 NULL,                                           // #108
2756 NULL,                                           // #109
2757 VM_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
2758 VM_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
2759 VM_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
2760 VM_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2761 VM_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
2762 VM_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
2763 VM_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
2764 VM_stov,                                        // #117 vector(string) stov (FRIK_FILE)
2765 VM_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
2766 VM_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
2767 e10, e10, e10, e10, e10, e10, e10, e10,         // #120-199
2768 // FTEQW range #200-#299
2769 NULL,                                           // #200
2770 NULL,                                           // #201
2771 NULL,                                           // #202
2772 NULL,                                           // #203
2773 NULL,                                           // #204
2774 NULL,                                           // #205
2775 NULL,                                           // #206
2776 NULL,                                           // #207
2777 NULL,                                           // #208
2778 NULL,                                           // #209
2779 NULL,                                           // #210
2780 NULL,                                           // #211
2781 NULL,                                           // #212
2782 NULL,                                           // #213
2783 NULL,                                           // #214
2784 NULL,                                           // #215
2785 NULL,                                           // #216
2786 NULL,                                           // #217
2787 VM_bitshift,                            // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
2788 NULL,                                           // #219
2789 e10,                                            // #220-#229
2790 e10,                                            // #230-#239
2791 e10,                                            // #240-#249
2792 e10,                                            // #250-#259
2793 e10,                                            // #260-#269
2794 e10,                                            // #270-#279
2795 e10,                                            // #280-#289
2796 e10,                                            // #290-#299
2797 e10, e10, e10, e10, e10, e10, e10, e10, e10, e10,       // #300-399
2798 VM_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
2799 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
2800 VM_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
2801 VM_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
2802 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
2803 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
2804 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
2805 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
2806 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
2807 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
2808 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
2809 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
2810 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
2811 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
2812 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
2813 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
2814 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
2815 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
2816 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
2817 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
2818 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
2819 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
2820 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
2821 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
2822 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
2823 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
2824 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
2825 PF_te_explosion2,                       // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
2826 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
2827 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
2828 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
2829 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
2830 VM_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
2831 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
2832 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
2833 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
2834 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
2835 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
2836 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
2837 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
2838 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
2839 VM_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
2840 VM_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
2841 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
2842 VM_search_begin,                        // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
2843 VM_search_end,                          // #445 void(float handle) search_end (DP_FS_SEARCH)
2844 VM_search_getsize,                      // #446 float(float handle) search_getsize (DP_FS_SEARCH)
2845 VM_search_getfilename,          // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
2846 VM_cvar_string,                         // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
2847 VM_findflags,                           // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
2848 VM_findchainflags,                      // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
2849 PF_gettagindex,                         // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
2850 PF_gettaginfo,                          // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2851 PF_dropclient,                          // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
2852 PF_spawnclient,                         // #454 entity() spawnclient (DP_SV_BOTCLIENT)
2853 PF_clienttype,                          // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
2854 PF_WriteUnterminatedString,     // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
2855 PF_te_flamejet,                         // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
2856 NULL,                                           // #458
2857 PF_edict_num,                           // #459 entity(float num) (??)
2858 VM_buf_create,                          // #460 float() buf_create (DP_QC_STRINGBUFFERS)
2859 VM_buf_del,                                     // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
2860 VM_buf_getsize,                         // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
2861 VM_buf_copy,                            // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
2862 VM_buf_sort,                            // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
2863 VM_buf_implode,                         // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
2864 VM_bufstr_get,                          // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
2865 VM_bufstr_set,                          // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
2866 VM_bufstr_add,                          // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
2867 VM_bufstr_free,                         // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
2868 PF_SV_AddStat,                          // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
2869 VM_asin,                                        // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
2870 VM_acos,                                        // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
2871 VM_atan,                                        // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
2872 VM_atan2,                                       // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
2873 VM_tan,                                         // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
2874 VM_strlennocol,                         // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
2875 VM_strdecolorize,                       // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
2876 NULL,                                           // #478
2877 NULL,                                           // #479
2878 e10, e10                                        // #480-499 (LordHavoc)
2879 };
2880
2881 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
2882
2883 void VM_SV_Cmd_Init(void)
2884 {
2885         VM_Cmd_Init();
2886 }
2887
2888 void VM_SV_Cmd_Reset(void)
2889 {
2890         VM_Cmd_Reset();
2891 }
2892