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