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