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