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