]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - svvm_cmds.c
reorganized view rendering setup code a bit to reduce potential for state bugs (more...
[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         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));
1709 }
1710
1711 void PF_te_blood (void)
1712 {
1713         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1714                 return;
1715         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1716         MSG_WriteByte(&sv.datagram, TE_BLOOD);
1717         // origin
1718         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1719         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1720         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1721         // velocity
1722         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1723         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1724         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1725         // count
1726         MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1727 }
1728
1729 void PF_te_bloodshower (void)
1730 {
1731         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1732                 return;
1733         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1734         MSG_WriteByte(&sv.datagram, TE_BLOODSHOWER);
1735         // min
1736         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1737         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1738         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1739         // max
1740         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1741         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1742         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1743         // speed
1744         MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM2), sv.protocol);
1745         // count
1746         MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1747 }
1748
1749 void PF_te_explosionrgb (void)
1750 {
1751         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1752         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONRGB);
1753         // origin
1754         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1755         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1756         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1757         // color
1758         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[0] * 255), 255));
1759         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[1] * 255), 255));
1760         MSG_WriteByte(&sv.datagram, bound(0, (int) (PRVM_G_VECTOR(OFS_PARM1)[2] * 255), 255));
1761 }
1762
1763 void PF_te_particlecube (void)
1764 {
1765         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1766                 return;
1767         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1768         MSG_WriteByte(&sv.datagram, TE_PARTICLECUBE);
1769         // min
1770         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1771         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1772         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1773         // max
1774         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1775         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1776         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1777         // velocity
1778         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1779         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1780         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1781         // count
1782         MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1783         // color
1784         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1785         // gravity true/false
1786         MSG_WriteByte(&sv.datagram, ((int) PRVM_G_FLOAT(OFS_PARM5)) != 0);
1787         // randomvel
1788         MSG_WriteCoord(&sv.datagram, PRVM_G_FLOAT(OFS_PARM6), sv.protocol);
1789 }
1790
1791 void PF_te_particlerain (void)
1792 {
1793         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1794                 return;
1795         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1796         MSG_WriteByte(&sv.datagram, TE_PARTICLERAIN);
1797         // min
1798         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1799         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1800         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1801         // max
1802         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1803         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1804         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1805         // velocity
1806         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1807         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1808         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1809         // count
1810         MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1811         // color
1812         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1813 }
1814
1815 void PF_te_particlesnow (void)
1816 {
1817         if (PRVM_G_FLOAT(OFS_PARM3) < 1)
1818                 return;
1819         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1820         MSG_WriteByte(&sv.datagram, TE_PARTICLESNOW);
1821         // min
1822         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1823         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1824         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1825         // max
1826         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
1827         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
1828         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
1829         // velocity
1830         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
1831         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
1832         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
1833         // count
1834         MSG_WriteShort(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM3), 65535));
1835         // color
1836         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM4));
1837 }
1838
1839 void PF_te_spark (void)
1840 {
1841         if (PRVM_G_FLOAT(OFS_PARM2) < 1)
1842                 return;
1843         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1844         MSG_WriteByte(&sv.datagram, TE_SPARK);
1845         // origin
1846         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1847         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1848         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1849         // velocity
1850         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[0], 127));
1851         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[1], 127));
1852         MSG_WriteByte(&sv.datagram, bound(-128, (int) PRVM_G_VECTOR(OFS_PARM1)[2], 127));
1853         // count
1854         MSG_WriteByte(&sv.datagram, bound(0, (int) PRVM_G_FLOAT(OFS_PARM2), 255));
1855 }
1856
1857 void PF_te_gunshotquad (void)
1858 {
1859         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1860         MSG_WriteByte(&sv.datagram, TE_GUNSHOTQUAD);
1861         // origin
1862         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1863         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1864         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1865 }
1866
1867 void PF_te_spikequad (void)
1868 {
1869         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1870         MSG_WriteByte(&sv.datagram, TE_SPIKEQUAD);
1871         // origin
1872         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1873         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1874         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1875 }
1876
1877 void PF_te_superspikequad (void)
1878 {
1879         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1880         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKEQUAD);
1881         // origin
1882         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1883         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1884         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1885 }
1886
1887 void PF_te_explosionquad (void)
1888 {
1889         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1890         MSG_WriteByte(&sv.datagram, TE_EXPLOSIONQUAD);
1891         // origin
1892         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1893         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1894         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1895 }
1896
1897 void PF_te_smallflash (void)
1898 {
1899         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1900         MSG_WriteByte(&sv.datagram, TE_SMALLFLASH);
1901         // origin
1902         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1903         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1904         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1905 }
1906
1907 void PF_te_customflash (void)
1908 {
1909         if (PRVM_G_FLOAT(OFS_PARM1) < 8 || PRVM_G_FLOAT(OFS_PARM2) < (1.0 / 256.0))
1910                 return;
1911         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1912         MSG_WriteByte(&sv.datagram, TE_CUSTOMFLASH);
1913         // origin
1914         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1915         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1916         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1917         // radius
1918         MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM1) / 8 - 1, 255));
1919         // lifetime
1920         MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_FLOAT(OFS_PARM2) * 256 - 1, 255));
1921         // color
1922         MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[0] * 255, 255));
1923         MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[1] * 255, 255));
1924         MSG_WriteByte(&sv.datagram, (int)bound(0, PRVM_G_VECTOR(OFS_PARM3)[2] * 255, 255));
1925 }
1926
1927 void PF_te_gunshot (void)
1928 {
1929         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1930         MSG_WriteByte(&sv.datagram, TE_GUNSHOT);
1931         // origin
1932         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1933         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1934         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1935 }
1936
1937 void PF_te_spike (void)
1938 {
1939         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1940         MSG_WriteByte(&sv.datagram, TE_SPIKE);
1941         // origin
1942         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1943         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1944         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1945 }
1946
1947 void PF_te_superspike (void)
1948 {
1949         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1950         MSG_WriteByte(&sv.datagram, TE_SUPERSPIKE);
1951         // origin
1952         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1953         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1954         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1955 }
1956
1957 void PF_te_explosion (void)
1958 {
1959         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1960         MSG_WriteByte(&sv.datagram, TE_EXPLOSION);
1961         // origin
1962         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1963         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1964         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1965 }
1966
1967 void PF_te_tarexplosion (void)
1968 {
1969         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1970         MSG_WriteByte(&sv.datagram, TE_TAREXPLOSION);
1971         // origin
1972         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1973         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1974         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1975 }
1976
1977 void PF_te_wizspike (void)
1978 {
1979         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1980         MSG_WriteByte(&sv.datagram, TE_WIZSPIKE);
1981         // origin
1982         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1983         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1984         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1985 }
1986
1987 void PF_te_knightspike (void)
1988 {
1989         MSG_WriteByte(&sv.datagram, svc_temp_entity);
1990         MSG_WriteByte(&sv.datagram, TE_KNIGHTSPIKE);
1991         // origin
1992         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
1993         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
1994         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
1995 }
1996
1997 void PF_te_lavasplash (void)
1998 {
1999         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2000         MSG_WriteByte(&sv.datagram, TE_LAVASPLASH);
2001         // origin
2002         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2003         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2004         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2005 }
2006
2007 void PF_te_teleport (void)
2008 {
2009         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2010         MSG_WriteByte(&sv.datagram, TE_TELEPORT);
2011         // origin
2012         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2013         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2014         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2015 }
2016
2017 void PF_te_explosion2 (void)
2018 {
2019         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2020         MSG_WriteByte(&sv.datagram, TE_EXPLOSION2);
2021         // origin
2022         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2023         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2024         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2025         // color
2026         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM1));
2027         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2028 }
2029
2030 void PF_te_lightning1 (void)
2031 {
2032         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2033         MSG_WriteByte(&sv.datagram, TE_LIGHTNING1);
2034         // owner entity
2035         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2036         // start
2037         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2038         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2039         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2040         // end
2041         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2042         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2043         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2044 }
2045
2046 void PF_te_lightning2 (void)
2047 {
2048         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2049         MSG_WriteByte(&sv.datagram, TE_LIGHTNING2);
2050         // owner entity
2051         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2052         // start
2053         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2054         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2055         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2056         // end
2057         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2058         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2059         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2060 }
2061
2062 void PF_te_lightning3 (void)
2063 {
2064         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2065         MSG_WriteByte(&sv.datagram, TE_LIGHTNING3);
2066         // owner entity
2067         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2068         // start
2069         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2070         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2071         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2072         // end
2073         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2074         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2075         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2076 }
2077
2078 void PF_te_beam (void)
2079 {
2080         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2081         MSG_WriteByte(&sv.datagram, TE_BEAM);
2082         // owner entity
2083         MSG_WriteShort(&sv.datagram, PRVM_G_EDICTNUM(OFS_PARM0));
2084         // start
2085         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2086         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2087         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2088         // end
2089         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[0], sv.protocol);
2090         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[1], sv.protocol);
2091         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM2)[2], sv.protocol);
2092 }
2093
2094 void PF_te_plasmaburn (void)
2095 {
2096         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2097         MSG_WriteByte(&sv.datagram, TE_PLASMABURN);
2098         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2099         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2100         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2101 }
2102
2103 void PF_te_flamejet (void)
2104 {
2105         MSG_WriteByte(&sv.datagram, svc_temp_entity);
2106         MSG_WriteByte(&sv.datagram, TE_FLAMEJET);
2107         // org
2108         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[0], sv.protocol);
2109         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[1], sv.protocol);
2110         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM0)[2], sv.protocol);
2111         // vel
2112         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[0], sv.protocol);
2113         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[1], sv.protocol);
2114         MSG_WriteCoord(&sv.datagram, PRVM_G_VECTOR(OFS_PARM1)[2], sv.protocol);
2115         // count
2116         MSG_WriteByte(&sv.datagram, (int)PRVM_G_FLOAT(OFS_PARM2));
2117 }
2118
2119 void clippointtosurface(model_t *model, msurface_t *surface, vec3_t p, vec3_t out)
2120 {
2121         int i, j, k;
2122         float *v[3], facenormal[3], edgenormal[3], sidenormal[3], temp[3], offsetdist, dist, bestdist;
2123         const int *e;
2124         bestdist = 1000000000;
2125         VectorCopy(p, out);
2126         for (i = 0, e = (model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);i < surface->num_triangles;i++, e += 3)
2127         {
2128                 // clip original point to each triangle of the surface and find the
2129                 // triangle that is closest
2130                 v[0] = model->surfmesh.data_vertex3f + e[0] * 3;
2131                 v[1] = model->surfmesh.data_vertex3f + e[1] * 3;
2132                 v[2] = model->surfmesh.data_vertex3f + e[2] * 3;
2133                 TriangleNormal(v[0], v[1], v[2], facenormal);
2134                 VectorNormalize(facenormal);
2135                 offsetdist = DotProduct(v[0], facenormal) - DotProduct(p, facenormal);
2136                 VectorMA(p, offsetdist, facenormal, temp);
2137                 for (j = 0, k = 2;j < 3;k = j, j++)
2138                 {
2139                         VectorSubtract(v[k], v[j], edgenormal);
2140                         CrossProduct(edgenormal, facenormal, sidenormal);
2141                         VectorNormalize(sidenormal);
2142                         offsetdist = DotProduct(v[k], sidenormal) - DotProduct(temp, sidenormal);
2143                         if (offsetdist < 0)
2144                                 VectorMA(temp, offsetdist, sidenormal, temp);
2145                 }
2146                 dist = VectorDistance2(temp, p);
2147                 if (bestdist > dist)
2148                 {
2149                         bestdist = dist;
2150                         VectorCopy(temp, out);
2151                 }
2152         }
2153 }
2154
2155 static model_t *getmodel(prvm_edict_t *ed)
2156 {
2157         int modelindex;
2158         if (!ed || ed->priv.server->free)
2159                 return NULL;
2160         modelindex = (int)ed->fields.server->modelindex;
2161         if (modelindex < 1 || modelindex >= MAX_MODELS)
2162                 return NULL;
2163         return sv.models[modelindex];
2164 }
2165
2166 static msurface_t *getsurface(model_t *model, int surfacenum)
2167 {
2168         if (surfacenum < 0 || surfacenum >= model->nummodelsurfaces)
2169                 return NULL;
2170         return model->data_surfaces + surfacenum + model->firstmodelsurface;
2171 }
2172
2173
2174 //PF_getsurfacenumpoints, // #434 float(entity e, float s) getsurfacenumpoints = #434;
2175 void PF_getsurfacenumpoints(void)
2176 {
2177         model_t *model;
2178         msurface_t *surface;
2179         // return 0 if no such surface
2180         if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2181         {
2182                 PRVM_G_FLOAT(OFS_RETURN) = 0;
2183                 return;
2184         }
2185
2186         // note: this (incorrectly) assumes it is a simple polygon
2187         PRVM_G_FLOAT(OFS_RETURN) = surface->num_vertices;
2188 }
2189 //PF_getsurfacepoint,     // #435 vector(entity e, float s, float n) getsurfacepoint = #435;
2190 void PF_getsurfacepoint(void)
2191 {
2192         prvm_edict_t *ed;
2193         model_t *model;
2194         msurface_t *surface;
2195         int pointnum;
2196         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2197         ed = PRVM_G_EDICT(OFS_PARM0);
2198         if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2199                 return;
2200         // note: this (incorrectly) assumes it is a simple polygon
2201         pointnum = (int)PRVM_G_FLOAT(OFS_PARM2);
2202         if (pointnum < 0 || pointnum >= surface->num_vertices)
2203                 return;
2204         // FIXME: implement rotation/scaling
2205         VectorAdd(&(model->surfmesh.data_vertex3f + 3 * surface->num_firstvertex)[pointnum * 3], ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2206 }
2207 //PF_getsurfacenormal,    // #436 vector(entity e, float s) getsurfacenormal = #436;
2208 void PF_getsurfacenormal(void)
2209 {
2210         model_t *model;
2211         msurface_t *surface;
2212         vec3_t normal;
2213         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2214         if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2215                 return;
2216         // FIXME: implement rotation/scaling
2217         // note: this (incorrectly) assumes it is a simple polygon
2218         // note: this only returns the first triangle, so it doesn't work very
2219         // well for curved surfaces or arbitrary meshes
2220         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);
2221         VectorNormalize(normal);
2222         VectorCopy(normal, PRVM_G_VECTOR(OFS_RETURN));
2223 }
2224 //PF_getsurfacetexture,   // #437 string(entity e, float s) getsurfacetexture = #437;
2225 void PF_getsurfacetexture(void)
2226 {
2227         model_t *model;
2228         msurface_t *surface;
2229         PRVM_G_INT(OFS_RETURN) = 0;
2230         if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2231                 return;
2232         PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(surface->texture->name);
2233 }
2234 //PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
2235 void PF_getsurfacenearpoint(void)
2236 {
2237         int surfacenum, best;
2238         vec3_t clipped, p;
2239         vec_t dist, bestdist;
2240         prvm_edict_t *ed;
2241         model_t *model;
2242         msurface_t *surface;
2243         vec_t *point;
2244         PRVM_G_FLOAT(OFS_RETURN) = -1;
2245         ed = PRVM_G_EDICT(OFS_PARM0);
2246         point = PRVM_G_VECTOR(OFS_PARM1);
2247
2248         if (!ed || ed->priv.server->free)
2249                 return;
2250         model = getmodel(ed);
2251         if (!model || !model->num_surfaces)
2252                 return;
2253
2254         // FIXME: implement rotation/scaling
2255         VectorSubtract(point, ed->fields.server->origin, p);
2256         best = -1;
2257         bestdist = 1000000000;
2258         for (surfacenum = 0;surfacenum < model->nummodelsurfaces;surfacenum++)
2259         {
2260                 surface = model->data_surfaces + surfacenum + model->firstmodelsurface;
2261                 // first see if the nearest point on the surface's box is closer than the previous match
2262                 clipped[0] = bound(surface->mins[0], p[0], surface->maxs[0]) - p[0];
2263                 clipped[1] = bound(surface->mins[1], p[1], surface->maxs[1]) - p[1];
2264                 clipped[2] = bound(surface->mins[2], p[2], surface->maxs[2]) - p[2];
2265                 dist = VectorLength2(clipped);
2266                 if (dist < bestdist)
2267                 {
2268                         // it is, check the nearest point on the actual geometry
2269                         clippointtosurface(model, surface, p, clipped);
2270                         VectorSubtract(clipped, p, clipped);
2271                         dist += VectorLength2(clipped);
2272                         if (dist < bestdist)
2273                         {
2274                                 // that's closer too, store it as the best match
2275                                 best = surfacenum;
2276                                 bestdist = dist;
2277                         }
2278                 }
2279         }
2280         PRVM_G_FLOAT(OFS_RETURN) = best;
2281 }
2282 //PF_getsurfaceclippedpoint, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint = #439;
2283 void PF_getsurfaceclippedpoint(void)
2284 {
2285         prvm_edict_t *ed;
2286         model_t *model;
2287         msurface_t *surface;
2288         vec3_t p, out;
2289         VectorClear(PRVM_G_VECTOR(OFS_RETURN));
2290         ed = PRVM_G_EDICT(OFS_PARM0);
2291         if (!(model = getmodel(ed)) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
2292                 return;
2293         // FIXME: implement rotation/scaling
2294         VectorSubtract(PRVM_G_VECTOR(OFS_PARM2), ed->fields.server->origin, p);
2295         clippointtosurface(model, surface, p, out);
2296         // FIXME: implement rotation/scaling
2297         VectorAdd(out, ed->fields.server->origin, PRVM_G_VECTOR(OFS_RETURN));
2298 }
2299
2300 //void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client
2301 //this function originally written by KrimZon, made shorter by LordHavoc
2302 void PF_clientcommand (void)
2303 {
2304         client_t *temp_client;
2305         int i;
2306
2307         //find client for this entity
2308         i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1);
2309         if (i < 0 || i >= svs.maxclients || !svs.clients[i].active)
2310         {
2311                 Con_Print("PF_clientcommand: entity is not a client\n");
2312                 return;
2313         }
2314
2315         temp_client = host_client;
2316         host_client = svs.clients + i;
2317         Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1), src_client);
2318         host_client = temp_client;
2319 }
2320
2321 //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)
2322 void PF_setattachment (void)
2323 {
2324         prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2325         prvm_edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1);
2326         const char *tagname = PRVM_G_STRING(OFS_PARM2);
2327         prvm_eval_t *v;
2328         int modelindex;
2329         model_t *model;
2330
2331         if (e == prog->edicts)
2332         {
2333                 VM_Warning("setattachment: can not modify world entity\n");
2334                 return;
2335         }
2336         if (e->priv.server->free)
2337         {
2338                 VM_Warning("setattachment: can not modify free entity\n");
2339                 return;
2340         }
2341
2342         if (tagentity == NULL)
2343                 tagentity = prog->edicts;
2344
2345         v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_entity);
2346         if (v)
2347                 v->edict = PRVM_EDICT_TO_PROG(tagentity);
2348
2349         v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_index);
2350         if (v)
2351                 v->_float = 0;
2352         if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0])
2353         {
2354                 modelindex = (int)tagentity->fields.server->modelindex;
2355                 if (modelindex >= 0 && modelindex < MAX_MODELS && (model = sv.models[modelindex]))
2356                 {
2357                         v->_float = Mod_Alias_GetTagIndexForName(model, (int)tagentity->fields.server->skin, tagname);
2358                         if (v->_float == 0)
2359                                 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);
2360                 }
2361                 else
2362                         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));
2363         }
2364 }
2365
2366 /////////////////////////////////////////
2367 // DP_MD3_TAGINFO extension coded by VorteX
2368
2369 int SV_GetTagIndex (prvm_edict_t *e, const char *tagname)
2370 {
2371         int i;
2372         model_t *model;
2373
2374         i = (int)e->fields.server->modelindex;
2375         if (i < 1 || i >= MAX_MODELS)
2376                 return -1;
2377         model = sv.models[i];
2378
2379         return Mod_Alias_GetTagIndexForName(model, (int)e->fields.server->skin, tagname);
2380 };
2381
2382 void SV_GetEntityMatrix (prvm_edict_t *ent, matrix4x4_t *out, qboolean viewmatrix)
2383 {
2384         float scale = PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float;
2385         if (scale == 0)
2386                 scale = 1;
2387         if (viewmatrix)
2388                 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);
2389         else
2390                 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);
2391 }
2392
2393 int SV_GetEntityLocalTagMatrix(prvm_edict_t *ent, int tagindex, matrix4x4_t *out)
2394 {
2395         int modelindex;
2396         int frame;
2397         model_t *model;
2398         if (tagindex >= 0
2399          && (modelindex = (int)ent->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS
2400          && (model = sv.models[(int)ent->fields.server->modelindex])
2401          && model->animscenes)
2402         {
2403                 // if model has wrong frame, engine automatically switches to model first frame
2404                 frame = (int)ent->fields.server->frame;
2405                 if (frame < 0 || frame >= model->numframes)
2406                         frame = 0;
2407                 return Mod_Alias_GetTagMatrix(model, model->animscenes[frame].firstframe, tagindex, out);
2408         }
2409         *out = identitymatrix;
2410         return 0;
2411 }
2412
2413 // Warnings/errors code:
2414 // 0 - normal (everything all-right)
2415 // 1 - world entity
2416 // 2 - free entity
2417 // 3 - null or non-precached model
2418 // 4 - no tags with requested index
2419 // 5 - runaway loop at attachment chain
2420 extern cvar_t cl_bob;
2421 extern cvar_t cl_bobcycle;
2422 extern cvar_t cl_bobup;
2423 int SV_GetTagMatrix (matrix4x4_t *out, prvm_edict_t *ent, int tagindex)
2424 {
2425         int ret;
2426         prvm_eval_t *val;
2427         int modelindex, attachloop;
2428         matrix4x4_t entitymatrix, tagmatrix, attachmatrix;
2429         model_t *model;
2430
2431         *out = identitymatrix; // warnings and errors return identical matrix
2432
2433         if (ent == prog->edicts)
2434                 return 1;
2435         if (ent->priv.server->free)
2436                 return 2;
2437
2438         modelindex = (int)ent->fields.server->modelindex;
2439         if (modelindex <= 0 || modelindex > MAX_MODELS)
2440                 return 3;
2441
2442         model = sv.models[modelindex];
2443
2444         tagmatrix = identitymatrix;
2445         // DP_GFX_QUAKE3MODELTAGS, scan all chain and stop on unattached entity
2446         attachloop = 0;
2447         for (;;)
2448         {
2449                 if (attachloop >= 256) // prevent runaway looping
2450                         return 5;
2451                 // apply transformation by child's tagindex on parent entity and then
2452                 // by parent entity itself
2453                 ret = SV_GetEntityLocalTagMatrix(ent, tagindex - 1, &attachmatrix);
2454                 if (ret && attachloop == 0)
2455                         return ret;
2456                 Matrix4x4_Concat(out, &attachmatrix, &tagmatrix);
2457                 SV_GetEntityMatrix(ent, &entitymatrix, false);
2458                 Matrix4x4_Concat(&tagmatrix, &entitymatrix, out);
2459                 // next iteration we process the parent entity
2460                 if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)) && val->edict)
2461                 {
2462                         tagindex = (int)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
2463                         ent = PRVM_EDICT_NUM(val->edict);
2464                 }
2465                 else
2466                         break;
2467                 attachloop++;
2468         }
2469
2470         // RENDER_VIEWMODEL magic
2471         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)) && val->edict)
2472         {
2473                 Matrix4x4_Copy(&tagmatrix, out);
2474                 ent = PRVM_EDICT_NUM(val->edict);
2475
2476                 SV_GetEntityMatrix(ent, &entitymatrix, true);
2477                 Matrix4x4_Concat(out, &entitymatrix, &tagmatrix);
2478
2479                 /*
2480                 // Cl_bob, ported from rendering code
2481                 if (ent->fields.server->health > 0 && cl_bob.value && cl_bobcycle.value)
2482                 {
2483                         double bob, cycle;
2484                         // LordHavoc: this code is *weird*, but not replacable (I think it
2485                         // should be done in QC on the server, but oh well, quake is quake)
2486                         // LordHavoc: figured out bobup: the time at which the sin is at 180
2487                         // degrees (which allows lengthening or squishing the peak or valley)
2488                         cycle = sv.time/cl_bobcycle.value;
2489                         cycle -= (int)cycle;
2490                         if (cycle < cl_bobup.value)
2491                                 cycle = sin(M_PI * cycle / cl_bobup.value);
2492                         else
2493                                 cycle = sin(M_PI + M_PI * (cycle-cl_bobup.value)/(1.0 - cl_bobup.value));
2494                         // bob is proportional to velocity in the xy plane
2495                         // (don't count Z, or jumping messes it up)
2496                         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;
2497                         bob = bob*0.3 + bob*0.7*cycle;
2498                         Matrix4x4_AdjustOrigin(out, 0, 0, bound(-7, bob, 4));
2499                 }
2500                 */
2501         }
2502         return 0;
2503 }
2504
2505 //float(entity ent, string tagname) gettagindex;
2506
2507 void PF_gettagindex (void)
2508 {
2509         prvm_edict_t *ent = PRVM_G_EDICT(OFS_PARM0);
2510         const char *tag_name = PRVM_G_STRING(OFS_PARM1);
2511         int modelindex, tag_index;
2512
2513         if (ent == prog->edicts)
2514         {
2515                 VM_Warning("gettagindex: can't affect world entity\n");
2516                 return;
2517         }
2518         if (ent->priv.server->free)
2519         {
2520                 VM_Warning("gettagindex: can't affect free entity\n");
2521                 return;
2522         }
2523
2524         modelindex = (int)ent->fields.server->modelindex;
2525         tag_index = 0;
2526         if (modelindex <= 0 || modelindex > MAX_MODELS)
2527                 Con_DPrintf("gettagindex(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(ent));
2528         else
2529         {
2530                 tag_index = SV_GetTagIndex(ent, tag_name);
2531                 if (tag_index == 0)
2532                         Con_DPrintf("gettagindex(entity #%i): tag \"%s\" not found\n", PRVM_NUM_FOR_EDICT(ent), tag_name);
2533         }
2534         PRVM_G_FLOAT(OFS_RETURN) = tag_index;
2535 };
2536
2537 //vector(entity ent, float tagindex) gettaginfo;
2538 void PF_gettaginfo (void)
2539 {
2540         prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0);
2541         int tagindex = (int)PRVM_G_FLOAT(OFS_PARM1);
2542         matrix4x4_t tag_matrix;
2543         int returncode;
2544
2545         returncode = SV_GetTagMatrix(&tag_matrix, e, tagindex);
2546         Matrix4x4_ToVectors(&tag_matrix, prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up, PRVM_G_VECTOR(OFS_RETURN));
2547
2548         switch(returncode)
2549         {
2550                 case 1:
2551                         VM_Warning("gettagindex: can't affect world entity\n");
2552                         break;
2553                 case 2:
2554                         VM_Warning("gettagindex: can't affect free entity\n");
2555                         break;
2556                 case 3:
2557                         Con_DPrintf("SV_GetTagMatrix(entity #%i): null or non-precached model\n", PRVM_NUM_FOR_EDICT(e));
2558                         break;
2559                 case 4:
2560                         Con_DPrintf("SV_GetTagMatrix(entity #%i): model has no tag with requested index %i\n", PRVM_NUM_FOR_EDICT(e), tagindex);
2561                         break;
2562                 case 5:
2563                         Con_DPrintf("SV_GetTagMatrix(entity #%i): runaway loop at attachment chain\n", PRVM_NUM_FOR_EDICT(e));
2564                         break;
2565         }
2566 }
2567
2568 //void(entity clent) dropclient (DP_SV_DROPCLIENT)
2569 void PF_dropclient (void)
2570 {
2571         int clientnum;
2572         client_t *oldhostclient;
2573         clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2574         if (clientnum < 0 || clientnum >= svs.maxclients)
2575         {
2576                 VM_Warning("dropclient: not a client\n");
2577                 return;
2578         }
2579         if (!svs.clients[clientnum].active)
2580         {
2581                 VM_Warning("dropclient: that client slot is not connected\n");
2582                 return;
2583         }
2584         oldhostclient = host_client;
2585         host_client = svs.clients + clientnum;
2586         SV_DropClient(false);
2587         host_client = oldhostclient;
2588 }
2589
2590 //entity() spawnclient (DP_SV_BOTCLIENT)
2591 void PF_spawnclient (void)
2592 {
2593         int i;
2594         prvm_edict_t    *ed;
2595         prog->xfunction->builtinsprofile += 2;
2596         ed = prog->edicts;
2597         for (i = 0;i < svs.maxclients;i++)
2598         {
2599                 if (!svs.clients[i].active)
2600                 {
2601                         prog->xfunction->builtinsprofile += 100;
2602                         SV_ConnectClient (i, NULL);
2603                         // this has to be set or else ClientDisconnect won't be called
2604                         // we assume the qc will call ClientConnect...
2605                         svs.clients[i].clientconnectcalled = true;
2606                         ed = PRVM_EDICT_NUM(i + 1);
2607                         break;
2608                 }
2609         }
2610         VM_RETURN_EDICT(ed);
2611 }
2612
2613 //float(entity clent) clienttype (DP_SV_BOTCLIENT)
2614 void PF_clienttype (void)
2615 {
2616         int clientnum;
2617         clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1;
2618         if (clientnum < 0 || clientnum >= svs.maxclients)
2619                 PRVM_G_FLOAT(OFS_RETURN) = 3;
2620         else if (!svs.clients[clientnum].active)
2621                 PRVM_G_FLOAT(OFS_RETURN) = 0;
2622         else if (svs.clients[clientnum].netconnection)
2623                 PRVM_G_FLOAT(OFS_RETURN) = 1;
2624         else
2625                 PRVM_G_FLOAT(OFS_RETURN) = 2;
2626 }
2627
2628 void PF_edict_num (void)
2629 {
2630         VM_RETURN_EDICT(PRVM_EDICT_NUM((int)PRVM_G_FLOAT(OFS_PARM0)));
2631 }
2632
2633 prvm_builtin_t vm_sv_builtins[] = {
2634 NULL,                                           // #0
2635 PF_makevectors,                         // #1 void(vector ang) makevectors
2636 PF_setorigin,                           // #2 void(entity e, vector o) setorigin
2637 PF_setmodel,                            // #3 void(entity e, string m) setmodel
2638 PF_setsize,                                     // #4 void(entity e, vector min, vector max) setsize
2639 NULL,                                           // #5 void(entity e, vector min, vector max) setabssize
2640 VM_break,                                       // #6 void() break
2641 VM_random,                                      // #7 float() random
2642 PF_sound,                                       // #8 void(entity e, float chan, string samp) sound
2643 VM_normalize,                           // #9 vector(vector v) normalize
2644 VM_error,                                       // #10 void(string e) error
2645 VM_objerror,                            // #11 void(string e) objerror
2646 VM_vlen,                                        // #12 float(vector v) vlen
2647 VM_vectoyaw,                            // #13 float(vector v) vectoyaw
2648 VM_spawn,                                       // #14 entity() spawn
2649 VM_remove,                                      // #15 void(entity e) remove
2650 PF_traceline,                           // #16 float(vector v1, vector v2, float tryents) traceline
2651 PF_checkclient,                         // #17 entity() clientlist
2652 VM_find,                                        // #18 entity(entity start, .string fld, string match) find
2653 PF_precache_sound,                      // #19 void(string s) precache_sound
2654 PF_precache_model,                      // #20 void(string s) precache_model
2655 PF_stuffcmd,                            // #21 void(entity client, string s)stuffcmd
2656 PF_findradius,                          // #22 entity(vector org, float rad) findradius
2657 VM_bprint,                                      // #23 void(string s) bprint
2658 PF_sprint,                                      // #24 void(entity client, string s) sprint
2659 VM_dprint,                                      // #25 void(string s) dprint
2660 VM_ftos,                                        // #26 void(string s) ftos
2661 VM_vtos,                                        // #27 void(string s) vtos
2662 VM_coredump,                            // #28 void() coredump
2663 VM_traceon,                                     // #29 void() traceon
2664 VM_traceoff,                            // #30 void() traceoff
2665 VM_eprint,                                      // #31 void(entity e) eprint
2666 PF_walkmove,                            // #32 float(float yaw, float dist) walkmove
2667 NULL,                                           // #33
2668 PF_droptofloor,                         // #34 float() droptofloor
2669 PF_lightstyle,                          // #35 void(float style, string value) lightstyle
2670 VM_rint,                                        // #36 float(float v) rint
2671 VM_floor,                                       // #37 float(float v) floor
2672 VM_ceil,                                        // #38 float(float v) ceil
2673 NULL,                                           // #39
2674 PF_checkbottom,                         // #40 float(entity e) checkbottom
2675 PF_pointcontents,                       // #41 float(vector v) pointcontents
2676 NULL,                                           // #42
2677 VM_fabs,                                        // #43 float(float f) fabs
2678 PF_aim,                                         // #44 vector(entity e, float speed) aim
2679 VM_cvar,                                        // #45 float(string s) cvar
2680 VM_localcmd,                            // #46 void(string s) localcmd
2681 VM_nextent,                                     // #47 entity(entity e) nextent
2682 PF_particle,                            // #48 void(vector o, vector d, float color, float count) particle
2683 PF_changeyaw,                           // #49 void() ChangeYaw
2684 NULL,                                           // #50
2685 VM_vectoangles,                         // #51 vector(vector v) vectoangles
2686 PF_WriteByte,                           // #52 void(float to, float f) WriteByte
2687 PF_WriteChar,                           // #53 void(float to, float f) WriteChar
2688 PF_WriteShort,                          // #54 void(float to, float f) WriteShort
2689 PF_WriteLong,                           // #55 void(float to, float f) WriteLong
2690 PF_WriteCoord,                          // #56 void(float to, float f) WriteCoord
2691 PF_WriteAngle,                          // #57 void(float to, float f) WriteAngle
2692 PF_WriteString,                         // #58 void(float to, string s) WriteString
2693 PF_WriteEntity,                         // #59 void(float to, entity e) WriteEntity
2694 VM_sin,                                         // #60 float(float f) sin (DP_QC_SINCOSSQRTPOW)
2695 VM_cos,                                         // #61 float(float f) cos (DP_QC_SINCOSSQRTPOW)
2696 VM_sqrt,                                        // #62 float(float f) sqrt (DP_QC_SINCOSSQRTPOW)
2697 PF_changepitch,                         // #63 void(entity ent) changepitch (DP_QC_CHANGEPITCH)
2698 PF_tracetoss,                           // #64 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS)
2699 VM_etos,                                        // #65 string(entity ent) etos (DP_QC_ETOS)
2700 NULL,                                           // #66
2701 SV_MoveToGoal,                          // #67 void(float step) movetogoal
2702 PF_precache_file,                       // #68 string(string s) precache_file
2703 PF_makestatic,                          // #69 void(entity e) makestatic
2704 VM_changelevel,                         // #70 void(string s) changelevel
2705 NULL,                                           // #71
2706 VM_cvar_set,                            // #72 void(string var, string val) cvar_set
2707 PF_centerprint,                         // #73 void(entity client, strings) centerprint
2708 PF_ambientsound,                        // #74 void(vector pos, string samp, float vol, float atten) ambientsound
2709 PF_precache_model,                      // #75 string(string s) precache_model2
2710 PF_precache_sound,                      // #76 string(string s) precache_sound2
2711 PF_precache_file,                       // #77 string(string s) precache_file2
2712 PF_setspawnparms,                       // #78 void(entity e) setspawnparms
2713 NULL,                                           // #79
2714 NULL,                                           // #80
2715 VM_stof,                                        // #81 float(string s) stof (FRIK_FILE)
2716 NULL,                                           // #82
2717 NULL,                                           // #83
2718 NULL,                                           // #84
2719 NULL,                                           // #85
2720 NULL,                                           // #86
2721 NULL,                                           // #87
2722 NULL,                                           // #88
2723 NULL,                                           // #89
2724 PF_tracebox,                            // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX)
2725 VM_randomvec,                           // #91 vector() randomvec (DP_QC_RANDOMVEC)
2726 PF_getlight,                            // #92 vector(vector org) getlight (DP_QC_GETLIGHT)
2727 PF_registercvar,                        // #93 float(string name, string value) registercvar (DP_REGISTERCVAR)
2728 VM_min,                                         // #94 float(float a, floats) min (DP_QC_MINMAXBOUND)
2729 VM_max,                                         // #95 float(float a, floats) max (DP_QC_MINMAXBOUND)
2730 VM_bound,                                       // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND)
2731 VM_pow,                                         // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW)
2732 VM_findfloat,                           // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT)
2733 VM_checkextension,                      // #99 float(string s) checkextension (the basis of the extension system)
2734 NULL,                                           // #100
2735 NULL,                                           // #101
2736 NULL,                                           // #102
2737 NULL,                                           // #103
2738 NULL,                                           // #104
2739 NULL,                                           // #105
2740 NULL,                                           // #106
2741 NULL,                                           // #107
2742 NULL,                                           // #108
2743 NULL,                                           // #109
2744 VM_fopen,                                       // #110 float(string filename, float mode) fopen (FRIK_FILE)
2745 VM_fclose,                                      // #111 void(float fhandle) fclose (FRIK_FILE)
2746 VM_fgets,                                       // #112 string(float fhandle) fgets (FRIK_FILE)
2747 VM_fputs,                                       // #113 void(float fhandle, string s) fputs (FRIK_FILE)
2748 VM_strlen,                                      // #114 float(string s) strlen (FRIK_FILE)
2749 VM_strcat,                                      // #115 string(string s1, string s2) strcat (FRIK_FILE)
2750 VM_substring,                           // #116 string(string s, float start, float length) substring (FRIK_FILE)
2751 VM_stov,                                        // #117 vector(string) stov (FRIK_FILE)
2752 VM_strzone,                                     // #118 string(string s) strzone (FRIK_FILE)
2753 VM_strunzone,                           // #119 void(string s) strunzone (FRIK_FILE)
2754 e10, e10, e10, e10, e10, e10, e10, e10,         // #120-199
2755 // FTEQW range #200-#299
2756 NULL,                                           // #200
2757 NULL,                                           // #201
2758 NULL,                                           // #202
2759 NULL,                                           // #203
2760 NULL,                                           // #204
2761 NULL,                                           // #205
2762 NULL,                                           // #206
2763 NULL,                                           // #207
2764 NULL,                                           // #208
2765 NULL,                                           // #209
2766 NULL,                                           // #210
2767 NULL,                                           // #211
2768 NULL,                                           // #212
2769 NULL,                                           // #213
2770 NULL,                                           // #214
2771 NULL,                                           // #215
2772 NULL,                                           // #216
2773 NULL,                                           // #217
2774 VM_bitshift,                            // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT)
2775 NULL,                                           // #219
2776 e10,                                            // #220-#229
2777 e10,                                            // #230-#239
2778 e10,                                            // #240-#249
2779 e10,                                            // #250-#259
2780 e10,                                            // #260-#269
2781 e10,                                            // #270-#279
2782 e10,                                            // #280-#289
2783 e10,                                            // #290-#299
2784 e10, e10, e10, e10, e10, e10, e10, e10, e10, e10,       // #300-399
2785 VM_copyentity,                          // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY)
2786 PF_setcolor,                            // #401 void(entity ent, float colors) setcolor (DP_QC_SETCOLOR)
2787 VM_findchain,                           // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN)
2788 VM_findchainfloat,                      // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT)
2789 PF_effect,                                      // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT)
2790 PF_te_blood,                            // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD)
2791 PF_te_bloodshower,                      // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER)
2792 PF_te_explosionrgb,                     // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB)
2793 PF_te_particlecube,                     // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE)
2794 PF_te_particlerain,                     // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN)
2795 PF_te_particlesnow,                     // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW)
2796 PF_te_spark,                            // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK)
2797 PF_te_gunshotquad,                      // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1)
2798 PF_te_spikequad,                        // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1)
2799 PF_te_superspikequad,           // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1)
2800 PF_te_explosionquad,            // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1)
2801 PF_te_smallflash,                       // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH)
2802 PF_te_customflash,                      // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH)
2803 PF_te_gunshot,                          // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS)
2804 PF_te_spike,                            // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS)
2805 PF_te_superspike,                       // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS)
2806 PF_te_explosion,                        // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS)
2807 PF_te_tarexplosion,                     // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS)
2808 PF_te_wizspike,                         // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS)
2809 PF_te_knightspike,                      // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS)
2810 PF_te_lavasplash,                       // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS)
2811 PF_te_teleport,                         // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS)
2812 PF_te_explosion2,                       // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS)
2813 PF_te_lightning1,                       // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS)
2814 PF_te_lightning2,                       // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS)
2815 PF_te_lightning3,                       // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS)
2816 PF_te_beam,                                     // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS)
2817 VM_vectorvectors,                       // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS)
2818 PF_te_plasmaburn,                       // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN)
2819 PF_getsurfacenumpoints,         // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE)
2820 PF_getsurfacepoint,                     // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE)
2821 PF_getsurfacenormal,            // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE)
2822 PF_getsurfacetexture,           // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE)
2823 PF_getsurfacenearpoint,         // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE)
2824 PF_getsurfaceclippedpoint,      // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE)
2825 PF_clientcommand,                       // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND)
2826 VM_tokenize,                            // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND)
2827 VM_argv,                                        // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND)
2828 PF_setattachment,                       // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS)
2829 VM_search_begin,                        // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH)
2830 VM_search_end,                          // #445 void(float handle) search_end (DP_FS_SEARCH)
2831 VM_search_getsize,                      // #446 float(float handle) search_getsize (DP_FS_SEARCH)
2832 VM_search_getfilename,          // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH)
2833 VM_cvar_string,                         // #448 string(string s) cvar_string (DP_QC_CVAR_STRING)
2834 VM_findflags,                           // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS)
2835 VM_findchainflags,                      // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS)
2836 PF_gettagindex,                         // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO)
2837 PF_gettaginfo,                          // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO)
2838 PF_dropclient,                          // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT)
2839 PF_spawnclient,                         // #454 entity() spawnclient (DP_SV_BOTCLIENT)
2840 PF_clienttype,                          // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT)
2841 PF_WriteUnterminatedString,     // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING)
2842 PF_te_flamejet,                         // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET)
2843 NULL,                                           // #458
2844 PF_edict_num,                           // #459 entity(float num) (??)
2845 VM_buf_create,                          // #460 float() buf_create (DP_QC_STRINGBUFFERS)
2846 VM_buf_del,                                     // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS)
2847 VM_buf_getsize,                         // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS)
2848 VM_buf_copy,                            // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS)
2849 VM_buf_sort,                            // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS)
2850 VM_buf_implode,                         // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS)
2851 VM_bufstr_get,                          // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS)
2852 VM_bufstr_set,                          // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS)
2853 VM_bufstr_add,                          // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS)
2854 VM_bufstr_free,                         // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS)
2855 PF_SV_AddStat,                          // #470 void(float index, float type, .void field) SV_AddStat (EXT_CSQC)
2856 VM_asin,                                        // #471 float(float s) VM_asin (DP_QC_ASINACOSATANATAN2TAN)
2857 VM_acos,                                        // #472 float(float c) VM_acos (DP_QC_ASINACOSATANATAN2TAN)
2858 VM_atan,                                        // #473 float(float t) VM_atan (DP_QC_ASINACOSATANATAN2TAN)
2859 VM_atan2,                                       // #474 float(float c, float s) VM_atan2 (DP_QC_ASINACOSATANATAN2TAN)
2860 VM_tan,                                         // #475 float(float a) VM_tan (DP_QC_ASINACOSATANATAN2TAN)
2861 VM_strlennocol,                         // #476 float(string s) : DRESK - String Length (not counting color codes) (DP_QC_STRINGCOLORFUNCTIONS)
2862 VM_strdecolorize,                       // #477 string(string s) : DRESK - Decolorized String (DP_SV_STRINGCOLORFUNCTIONS)
2863 NULL,                                           // #478
2864 NULL,                                           // #479
2865 e10, e10                                        // #480-499 (LordHavoc)
2866 };
2867
2868 const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t);
2869
2870 void VM_SV_Cmd_Init(void)
2871 {
2872         VM_Cmd_Init();
2873 }
2874
2875 void VM_SV_Cmd_Reset(void)
2876 {
2877         VM_Cmd_Reset();
2878 }
2879