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