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