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