]> icculus.org git repositories - divverent/darkplaces.git/blob - sv_main.c
removed NET_MAXRATE (as it served no useful purpose), changed description of rate...
[divverent/darkplaces.git] / sv_main.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // sv_main.c -- server main program
21
22 #include "quakedef.h"
23 #include "libcurl.h"
24
25 void SV_VM_Init();
26 void SV_VM_Setup();
27
28 void VM_AutoSentStats_Clear (void);
29 void EntityFrameCSQC_ClearVersions (void);
30 void EntityFrameCSQC_InitClientVersions (int client, qboolean clear);
31 void VM_SV_WriteAutoSentStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats);
32 void EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int numstates, const entity_state_t *states);
33
34
35 // select which protocol to host, this is fed to Protocol_EnumForName
36 cvar_t sv_protocolname = {0, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"};
37 cvar_t sv_ratelimitlocalplayer = {0, "sv_ratelimitlocalplayer", "0", "whether to apply rate limiting to the local player in a listen server (only useful for testing)"};
38 cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "10000", "upper limit on client rate cvar, should reflect your network connection quality"};
39
40 static cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"}; // fast but loose
41 static cvar_t sv_cullentities_trace = {0, "sv_cullentities_trace", "0", "somewhat slow but very tight culling of hidden entities, minimizes network traffic and makes wallhack cheats useless"}; // tends to get false negatives, uses a timeout to keep entities visible a short time after becoming hidden
42 static cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
43 static cvar_t sv_entpatch = {0, "sv_entpatch", "1", "enables loading of .ent files to override entities in the bsp (for example Threewave CTF server pack contains .ent patch files enabling play of CTF on id1 maps)"};
44
45 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
46 cvar_t sv_gameplayfix_noairborncorpse = {0, "sv_gameplayfix_noairborncorpse", "1", "causes entities (corpses) sitting ontop of moving entities (players) to fall when the moving entity (player) is no longer supporting them"};
47 cvar_t sv_gameplayfix_stepdown = {0, "sv_gameplayfix_stepdown", "0", "attempts to step down stairs, not just up them (prevents the familiar thud..thud..thud.. when running down stairs and slopes)"};
48 cvar_t sv_gameplayfix_stepwhilejumping = {0, "sv_gameplayfix_stepwhilejumping", "1", "applies step-up onto a ledge even while airborn, useful if you would otherwise just-miss the floor when running across small areas with gaps (for instance running across the moving platforms in dm2, or jumping to the megahealth and red armor in dm2 rather than using the bridge)"};
49 cvar_t sv_gameplayfix_swiminbmodels = {0, "sv_gameplayfix_swiminbmodels", "1", "causes pointcontents (used to determine if you are in a liquid) to check bmodel entities as well as the world model, so you can swim around in (possibly moving) water bmodel entities"};
50 cvar_t sv_gameplayfix_setmodelrealbox = {0, "sv_gameplayfix_setmodelrealbox", "1", "fixes a bug in Quake that made setmodel always set the entity box to ('-16 -16 -16', '16 16 16') rather than properly checking the model box, breaks some poorly coded mods"};
51 cvar_t sv_gameplayfix_blowupfallenzombies = {0, "sv_gameplayfix_blowupfallenzombies", "1", "causes findradius to detect SOLID_NOT entities such as zombies and corpses on the floor, allowing splash damage to apply to them"};
52 cvar_t sv_gameplayfix_findradiusdistancetobox = {0, "sv_gameplayfix_findradiusdistancetobox", "1", "causes findradius to check the distance to the corner of a box rather than the center of the box, makes findradius detect bmodels such as very large doors that would otherwise be unaffected by splash damage"};
53 cvar_t sv_gameplayfix_qwplayerphysics = {0, "sv_gameplayfix_qwplayerphysics", "1", "changes water jumping to make it easier to get out of water, and prevents friction on landing when bunnyhopping"};
54 cvar_t sv_gameplayfix_upwardvelocityclearsongroundflag = {0, "sv_gameplayfix_upwardvelocityclearsongroundflag", "1", "prevents monsters, items, and most other objects from being stuck to the floor when pushed around by damage, and other situations in mods"};
55
56 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
57
58 // TODO: move these cvars here
59 extern cvar_t sv_clmovement_enable;
60 extern cvar_t sv_clmovement_minping;
61 extern cvar_t sv_clmovement_minping_disabletime;
62 extern cvar_t sv_clmovement_waitforinput;
63
64 server_t sv;
65 server_static_t svs;
66
67 mempool_t *sv_mempool = NULL;
68
69 //============================================================================
70
71 extern void SV_Phys_Init (void);
72 extern void SV_World_Init (void);
73 static void SV_SaveEntFile_f(void);
74
75 /*
76 ===============
77 SV_Init
78 ===============
79 */
80 void SV_Init (void)
81 {
82         // init the csqc progs cvars, since they are updated/used by the server code
83         // TODO: fix this since this is a quick hack to make some of [515]'s broken code run ;) [9/13/2006 Black]
84         extern cvar_t csqc_progname;    //[515]: csqc crc check and right csprogs name according to progs.dat
85         extern cvar_t csqc_progcrc;
86         Cvar_RegisterVariable (&csqc_progname);
87         Cvar_RegisterVariable (&csqc_progcrc);
88
89         Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
90         Cvar_RegisterVariable (&sv_maxvelocity);
91         Cvar_RegisterVariable (&sv_gravity);
92         Cvar_RegisterVariable (&sv_friction);
93         Cvar_RegisterVariable (&sv_waterfriction);
94         Cvar_RegisterVariable (&sv_edgefriction);
95         Cvar_RegisterVariable (&sv_stopspeed);
96         Cvar_RegisterVariable (&sv_maxspeed);
97         Cvar_RegisterVariable (&sv_maxairspeed);
98         Cvar_RegisterVariable (&sv_accelerate);
99         Cvar_RegisterVariable (&sv_airaccelerate);
100         Cvar_RegisterVariable (&sv_wateraccelerate);
101         Cvar_RegisterVariable (&sv_clmovement_enable);
102         Cvar_RegisterVariable (&sv_clmovement_minping);
103         Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
104         Cvar_RegisterVariable (&sv_clmovement_waitforinput);
105         Cvar_RegisterVariable (&sv_idealpitchscale);
106         Cvar_RegisterVariable (&sv_aim);
107         Cvar_RegisterVariable (&sv_nostep);
108         Cvar_RegisterVariable (&sv_cullentities_pvs);
109         Cvar_RegisterVariable (&sv_cullentities_trace);
110         Cvar_RegisterVariable (&sv_cullentities_stats);
111         Cvar_RegisterVariable (&sv_entpatch);
112         Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
113         Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
114         Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
115         Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
116         Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
117         Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
118         Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
119         Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
120         Cvar_RegisterVariable (&sv_gameplayfix_qwplayerphysics);
121         Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
122         Cvar_RegisterVariable (&sv_protocolname);
123         Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
124         Cvar_RegisterVariable (&sv_maxrate);
125         Cvar_RegisterVariable (&sv_progs);
126
127         SV_VM_Init();
128         SV_Phys_Init();
129         SV_World_Init();
130
131         sv_mempool = Mem_AllocPool("server", 0, NULL);
132 }
133
134 static void SV_SaveEntFile_f(void)
135 {
136         char basename[MAX_QPATH];
137         if (!sv.active || !sv.worldmodel)
138         {
139                 Con_Print("Not running a server\n");
140                 return;
141         }
142         FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
143         FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
144 }
145
146
147 /*
148 =============================================================================
149
150 EVENT MESSAGES
151
152 =============================================================================
153 */
154
155 /*
156 ==================
157 SV_StartParticle
158
159 Make sure the event gets sent to all clients
160 ==================
161 */
162 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
163 {
164         int i;
165
166         if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
167                 return;
168         MSG_WriteByte (&sv.datagram, svc_particle);
169         MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
170         MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
171         MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
172         for (i=0 ; i<3 ; i++)
173                 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
174         MSG_WriteByte (&sv.datagram, count);
175         MSG_WriteByte (&sv.datagram, color);
176 }
177
178 /*
179 ==================
180 SV_StartEffect
181
182 Make sure the event gets sent to all clients
183 ==================
184 */
185 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
186 {
187         if (modelindex >= 256 || startframe >= 256)
188         {
189                 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
190                         return;
191                 MSG_WriteByte (&sv.datagram, svc_effect2);
192                 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
193                 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
194                 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
195                 MSG_WriteShort (&sv.datagram, modelindex);
196                 MSG_WriteShort (&sv.datagram, startframe);
197                 MSG_WriteByte (&sv.datagram, framecount);
198                 MSG_WriteByte (&sv.datagram, framerate);
199         }
200         else
201         {
202                 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
203                         return;
204                 MSG_WriteByte (&sv.datagram, svc_effect);
205                 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
206                 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
207                 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
208                 MSG_WriteByte (&sv.datagram, modelindex);
209                 MSG_WriteByte (&sv.datagram, startframe);
210                 MSG_WriteByte (&sv.datagram, framecount);
211                 MSG_WriteByte (&sv.datagram, framerate);
212         }
213 }
214
215 /*
216 ==================
217 SV_StartSound
218
219 Each entity can have eight independant sound sources, like voice,
220 weapon, feet, etc.
221
222 Channel 0 is an auto-allocate channel, the others override anything
223 already running on that entity/channel pair.
224
225 An attenuation of 0 will play full volume everywhere in the level.
226 Larger attenuations will drop off.  (max 4 attenuation)
227
228 ==================
229 */
230 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
231 {
232         int sound_num, field_mask, i, ent;
233
234         if (volume < 0 || volume > 255)
235         {
236                 Con_Printf ("SV_StartSound: volume = %i\n", volume);
237                 return;
238         }
239
240         if (attenuation < 0 || attenuation > 4)
241         {
242                 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
243                 return;
244         }
245
246         if (channel < 0 || channel > 7)
247         {
248                 Con_Printf ("SV_StartSound: channel = %i\n", channel);
249                 return;
250         }
251
252         if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
253                 return;
254
255 // find precache number for sound
256         sound_num = SV_SoundIndex(sample, 1);
257         if (!sound_num)
258                 return;
259
260         ent = PRVM_NUM_FOR_EDICT(entity);
261
262         field_mask = 0;
263         if (volume != DEFAULT_SOUND_PACKET_VOLUME)
264                 field_mask |= SND_VOLUME;
265         if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
266                 field_mask |= SND_ATTENUATION;
267         if (ent >= 8192)
268                 field_mask |= SND_LARGEENTITY;
269         if (sound_num >= 256 || channel >= 8)
270                 field_mask |= SND_LARGESOUND;
271
272 // directed messages go only to the entity they are targeted on
273         MSG_WriteByte (&sv.datagram, svc_sound);
274         MSG_WriteByte (&sv.datagram, field_mask);
275         if (field_mask & SND_VOLUME)
276                 MSG_WriteByte (&sv.datagram, volume);
277         if (field_mask & SND_ATTENUATION)
278                 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
279         if (field_mask & SND_LARGEENTITY)
280         {
281                 MSG_WriteShort (&sv.datagram, ent);
282                 MSG_WriteByte (&sv.datagram, channel);
283         }
284         else
285                 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
286         if (field_mask & SND_LARGESOUND)
287                 MSG_WriteShort (&sv.datagram, sound_num);
288         else
289                 MSG_WriteByte (&sv.datagram, sound_num);
290         for (i = 0;i < 3;i++)
291                 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
292 }
293
294 /*
295 ==============================================================================
296
297 CLIENT SPAWNING
298
299 ==============================================================================
300 */
301
302 /*
303 ================
304 SV_SendServerinfo
305
306 Sends the first message from the server to a connected client.
307 This will be sent on the initial connection and upon each server load.
308 ================
309 */
310 void SV_SendServerinfo (client_t *client)
311 {
312         int i;
313         char message[128];
314
315         // we know that this client has a netconnection and thus is not a bot
316
317         // edicts get reallocated on level changes, so we need to update it here
318         client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
319
320         // clear cached stuff that depends on the level
321         client->weaponmodel[0] = 0;
322         client->weaponmodelindex = 0;
323
324         // LordHavoc: clear entityframe tracking
325         client->latestframenum = 0;
326
327         if (client->entitydatabase)
328                 EntityFrame_FreeDatabase(client->entitydatabase);
329         if (client->entitydatabase4)
330                 EntityFrame4_FreeDatabase(client->entitydatabase4);
331         if (client->entitydatabase5)
332                 EntityFrame5_FreeDatabase(client->entitydatabase5);
333
334         if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
335         {
336                 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
337                         client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
338                 else if (sv.protocol == PROTOCOL_DARKPLACES4)
339                         client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
340                 else
341                         client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
342         }
343
344         SZ_Clear (&client->netconnection->message);
345         MSG_WriteByte (&client->netconnection->message, svc_print);
346         dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
347         MSG_WriteString (&client->netconnection->message,message);
348
349         //[515]: init csprogs according to version of svprogs, check the crc, etc.
350         if (sv.csqc_progcrc >= 0)
351         {
352                 prvm_eval_t *val;
353                 Con_DPrintf("sending csqc info to client (\"%s\" with crc %i)\n", sv.csqc_progname, sv.csqc_progcrc);
354                 //[515]: init stufftext string (it is sent before svc_serverinfo)
355                 val = PRVM_GETGLOBALFIELDVALUE(PRVM_ED_FindGlobalOffset("SV_InitCmd"));
356                 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
357                 MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname));
358                 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
359                 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc));
360                 if (val)
361                 {
362                         MSG_WriteByte (&client->netconnection->message, svc_stufftext);
363                         MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
364                 }
365         }
366
367         MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
368         MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
369         MSG_WriteByte (&client->netconnection->message, svs.maxclients);
370
371         if (!coop.integer && deathmatch.integer)
372                 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
373         else
374                 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
375
376         MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
377
378         for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
379                 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
380         MSG_WriteByte (&client->netconnection->message, 0);
381
382         for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
383                 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
384         MSG_WriteByte (&client->netconnection->message, 0);
385
386 // send music
387         MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
388         MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
389         MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
390
391 // set view
392         MSG_WriteByte (&client->netconnection->message, svc_setview);
393         MSG_WriteShort (&client->netconnection->message, PRVM_NUM_FOR_EDICT(client->edict));
394
395         MSG_WriteByte (&client->netconnection->message, svc_signonnum);
396         MSG_WriteByte (&client->netconnection->message, 1);
397
398         {
399                 client_t *save;
400                 save = host_client;
401                 host_client = client;
402                 Curl_SendRequirements();
403                 host_client = save;
404         }
405
406         client->spawned = false;                // need prespawn, spawn, etc
407 }
408
409 /*
410 ================
411 SV_ConnectClient
412
413 Initializes a client_t for a new net connection.  This will only be called
414 once for a player each game, not once for each level change.
415 ================
416 */
417 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
418 {
419         client_t                *client;
420         int                             i;
421         float                   spawn_parms[NUM_SPAWN_PARMS];
422
423         client = svs.clients + clientnum;
424
425         if(netconnection)//[515]: bots don't play with csqc =)
426                 EntityFrameCSQC_InitClientVersions(clientnum, false);
427
428 // set up the client_t
429         if (sv.loadgame)
430                 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
431         memset (client, 0, sizeof(*client));
432         client->active = true;
433         client->netconnection = netconnection;
434
435         Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
436
437         strlcpy(client->name, "unconnected", sizeof(client->name));
438         strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
439         client->spawned = false;
440         client->edict = PRVM_EDICT_NUM(clientnum+1);
441         if (client->netconnection)
442                 client->netconnection->message.allowoverflow = true;            // we can catch it
443         // updated by receiving "rate" command from client
444         client->rate = NET_MINRATE;
445         // no limits for local player
446         if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
447                 client->rate = 1000000000;
448         client->connecttime = realtime;
449
450         if (sv.loadgame)
451                 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
452         else
453         {
454                 // call the progs to get default spawn parms for the new client
455                 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
456                 prog->globals.server->self = 0;
457                 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
458                 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
459                         client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
460
461                 // set up the entity for this client (including .colormap, .team, etc)
462                 PRVM_ED_ClearEdict(client->edict);
463         }
464
465         // don't call SendServerinfo for a fresh botclient because its fields have
466         // not been set up by the qc yet
467         if (client->netconnection)
468                 SV_SendServerinfo (client);
469         else
470                 client->spawned = true;
471 }
472
473
474 /*
475 ===============================================================================
476
477 FRAME UPDATES
478
479 ===============================================================================
480 */
481
482 /*
483 ==================
484 SV_ClearDatagram
485
486 ==================
487 */
488 void SV_ClearDatagram (void)
489 {
490         SZ_Clear (&sv.datagram);
491 }
492
493 /*
494 =============================================================================
495
496 The PVS must include a small area around the client to allow head bobbing
497 or other small motion on the client side.  Otherwise, a bob might cause an
498 entity that should be visible to not show up, especially when the bob
499 crosses a waterline.
500
501 =============================================================================
502 */
503
504 int sv_writeentitiestoclient_pvsbytes;
505 unsigned char sv_writeentitiestoclient_pvs[MAX_MAP_LEAFS/8];
506
507 static int numsendentities;
508 static entity_state_t sendentities[MAX_EDICTS];
509 static entity_state_t *sendentitiesindex[MAX_EDICTS];
510
511 qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int e)
512 {
513         int i;
514         unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
515         unsigned int customizeentityforclient;
516         float f;
517         vec3_t cullmins, cullmaxs;
518         model_t *model;
519         prvm_eval_t *val;
520
521         // EF_NODRAW prevents sending for any reason except for your own
522         // client, so we must keep all clients in this superset
523         effects = (unsigned)ent->fields.server->effects;
524
525         // we can omit invisible entities with no effects that are not clients
526         // LordHavoc: this could kill tags attached to an invisible entity, I
527         // just hope we never have to support that case
528         i = (int)ent->fields.server->modelindex;
529         modelindex = (i >= 1 && i < MAX_MODELS && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
530
531         flags = 0;
532         i = (int)(PRVM_GETEDICTFIELDVALUE(ent, eval_glow_size)->_float * 0.25f);
533         glowsize = (unsigned char)bound(0, i, 255);
534         if (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_trail)->_float)
535                 flags |= RENDER_GLOWTRAIL;
536
537         f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[0]*256;
538         light[0] = (unsigned short)bound(0, f, 65535);
539         f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[1]*256;
540         light[1] = (unsigned short)bound(0, f, 65535);
541         f = PRVM_GETEDICTFIELDVALUE(ent, eval_color)->vector[2]*256;
542         light[2] = (unsigned short)bound(0, f, 65535);
543         f = PRVM_GETEDICTFIELDVALUE(ent, eval_light_lev)->_float;
544         light[3] = (unsigned short)bound(0, f, 65535);
545         lightstyle = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_style)->_float;
546         lightpflags = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_pflags)->_float;
547
548         if (gamemode == GAME_TENEBRAE)
549         {
550                 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
551                 if (effects & 16)
552                 {
553                         effects &= ~16;
554                         lightpflags |= PFLAGS_FULLDYNAMIC;
555                 }
556                 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
557                 if (effects & 32)
558                 {
559                         effects &= ~32;
560                         light[0] = (int)(0.2*256);
561                         light[1] = (int)(1.0*256);
562                         light[2] = (int)(0.2*256);
563                         light[3] = 200;
564                         lightpflags |= PFLAGS_FULLDYNAMIC;
565                 }
566         }
567
568         specialvisibilityradius = 0;
569         if (lightpflags & PFLAGS_FULLDYNAMIC)
570                 specialvisibilityradius = max(specialvisibilityradius, light[3]);
571         if (glowsize)
572                 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
573         if (flags & RENDER_GLOWTRAIL)
574                 specialvisibilityradius = max(specialvisibilityradius, 100);
575         if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
576         {
577                 if (effects & EF_BRIGHTFIELD)
578                         specialvisibilityradius = max(specialvisibilityradius, 80);
579                 if (effects & EF_MUZZLEFLASH)
580                         specialvisibilityradius = max(specialvisibilityradius, 100);
581                 if (effects & EF_BRIGHTLIGHT)
582                         specialvisibilityradius = max(specialvisibilityradius, 400);
583                 if (effects & EF_DIMLIGHT)
584                         specialvisibilityradius = max(specialvisibilityradius, 200);
585                 if (effects & EF_RED)
586                         specialvisibilityradius = max(specialvisibilityradius, 200);
587                 if (effects & EF_BLUE)
588                         specialvisibilityradius = max(specialvisibilityradius, 200);
589                 if (effects & EF_FLAME)
590                         specialvisibilityradius = max(specialvisibilityradius, 250);
591                 if (effects & EF_STARDUST)
592                         specialvisibilityradius = max(specialvisibilityradius, 100);
593         }
594
595         // early culling checks
596         // (final culling is done by SV_MarkWriteEntityStateToClient)
597         customizeentityforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_customizeentityforclient)->function;
598         if (!customizeentityforclient)
599         {
600                 if (e > svs.maxclients && (!modelindex && !specialvisibilityradius))
601                         return false;
602                 // this 2 billion unit check is actually to detect NAN origins
603                 // (we really don't want to send those)
604                 if (VectorLength2(ent->fields.server->origin) > 2000000000.0*2000000000.0)
605                         return false;
606         }
607
608
609         *cs = defaultstate;
610         cs->active = true;
611         cs->number = e;
612         VectorCopy(ent->fields.server->origin, cs->origin);
613         VectorCopy(ent->fields.server->angles, cs->angles);
614         cs->flags = flags;
615         cs->effects = effects;
616         cs->colormap = (unsigned)ent->fields.server->colormap;
617         cs->modelindex = modelindex;
618         cs->skin = (unsigned)ent->fields.server->skin;
619         cs->frame = (unsigned)ent->fields.server->frame;
620         cs->viewmodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_viewmodelforclient)->edict;
621         cs->exteriormodelforclient = PRVM_GETEDICTFIELDVALUE(ent, eval_exteriormodeltoclient)->edict;
622         cs->nodrawtoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)->edict;
623         cs->drawonlytoclient = PRVM_GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)->edict;
624         cs->customizeentityforclient = customizeentityforclient;
625         cs->tagentity = PRVM_GETEDICTFIELDVALUE(ent, eval_tag_entity)->edict;
626         cs->tagindex = (unsigned char)PRVM_GETEDICTFIELDVALUE(ent, eval_tag_index)->_float;
627         cs->glowsize = glowsize;
628
629         // don't need to init cs->colormod because the defaultstate did that for us
630         //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
631         val = PRVM_GETEDICTFIELDVALUE(ent, eval_colormod);
632         if (val->vector[0] || val->vector[1] || val->vector[2])
633         {
634                 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
635                 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
636                 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
637         }
638
639         cs->modelindex = modelindex;
640
641         cs->alpha = 255;
642         f = (PRVM_GETEDICTFIELDVALUE(ent, eval_alpha)->_float * 255.0f);
643         if (f)
644         {
645                 i = (int)f;
646                 cs->alpha = (unsigned char)bound(0, i, 255);
647         }
648         // halflife
649         f = (PRVM_GETEDICTFIELDVALUE(ent, eval_renderamt)->_float);
650         if (f)
651         {
652                 i = (int)f;
653                 cs->alpha = (unsigned char)bound(0, i, 255);
654         }
655
656         cs->scale = 16;
657         f = (PRVM_GETEDICTFIELDVALUE(ent, eval_scale)->_float * 16.0f);
658         if (f)
659         {
660                 i = (int)f;
661                 cs->scale = (unsigned char)bound(0, i, 255);
662         }
663
664         cs->glowcolor = 254;
665         f = (PRVM_GETEDICTFIELDVALUE(ent, eval_glow_color)->_float);
666         if (f)
667                 cs->glowcolor = (int)f;
668
669         if (PRVM_GETEDICTFIELDVALUE(ent, eval_fullbright)->_float)
670                 cs->effects |= EF_FULLBRIGHT;
671
672         if (ent->fields.server->movetype == MOVETYPE_STEP)
673                 cs->flags |= RENDER_STEP;
674         if ((cs->effects & EF_LOWPRECISION) && cs->origin[0] >= -32768 && cs->origin[1] >= -32768 && cs->origin[2] >= -32768 && cs->origin[0] <= 32767 && cs->origin[1] <= 32767 && cs->origin[2] <= 32767)
675                 cs->flags |= RENDER_LOWPRECISION;
676         if (ent->fields.server->colormap >= 1024)
677                 cs->flags |= RENDER_COLORMAPPED;
678         if (cs->viewmodelforclient)
679                 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
680
681         cs->light[0] = light[0];
682         cs->light[1] = light[1];
683         cs->light[2] = light[2];
684         cs->light[3] = light[3];
685         cs->lightstyle = lightstyle;
686         cs->lightpflags = lightpflags;
687
688         cs->specialvisibilityradius = specialvisibilityradius;
689
690         // calculate the visible box of this entity (don't use the physics box
691         // as that is often smaller than a model, and would not count
692         // specialvisibilityradius)
693         if ((model = sv.models[modelindex]))
694         {
695                 float scale = cs->scale * (1.0f / 16.0f);
696                 if (cs->angles[0] || cs->angles[2]) // pitch and roll
697                 {
698                         VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
699                         VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
700                 }
701                 else if (cs->angles[1])
702                 {
703                         VectorMA(cs->origin, scale, model->yawmins, cullmins);
704                         VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
705                 }
706                 else
707                 {
708                         VectorMA(cs->origin, scale, model->normalmins, cullmins);
709                         VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
710                 }
711         }
712         else
713         {
714                 // if there is no model (or it could not be loaded), use the physics box
715                 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
716                 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
717         }
718         if (specialvisibilityradius)
719         {
720                 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
721                 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
722                 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
723                 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
724                 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
725                 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
726         }
727         if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
728         {
729                 VectorCopy(cullmins, ent->priv.server->cullmins);
730                 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
731                 ent->priv.server->pvs_numclusters = -1;
732                 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
733                 {
734                         i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
735                         if (i <= MAX_ENTITYCLUSTERS)
736                                 ent->priv.server->pvs_numclusters = i;
737                 }
738         }
739
740         return true;
741 }
742
743 void SV_PrepareEntitiesForSending(void)
744 {
745         int e;
746         prvm_edict_t *ent;
747         // send all entities that touch the pvs
748         numsendentities = 0;
749         sendentitiesindex[0] = NULL;
750         memset(sendentitiesindex, 0, prog->num_edicts * sizeof(entity_state_t *));
751         for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
752         {
753                 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sendentities + numsendentities, e))
754                 {
755                         sendentitiesindex[e] = sendentities + numsendentities;
756                         numsendentities++;
757                 }
758         }
759 }
760
761 static int sententitiesmark = 0;
762 static int sententities[MAX_EDICTS];
763 static int sententitiesconsideration[MAX_EDICTS];
764 static int sv_writeentitiestoclient_culled_pvs;
765 static int sv_writeentitiestoclient_culled_trace;
766 static int sv_writeentitiestoclient_visibleentities;
767 static int sv_writeentitiestoclient_totalentities;
768 //static entity_frame_t sv_writeentitiestoclient_entityframe;
769 static int sv_writeentitiestoclient_clentnum;
770 static vec3_t sv_writeentitiestoclient_testeye;
771 static client_t *sv_writeentitiestoclient_client;
772
773 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
774 {
775         int isbmodel;
776         vec3_t testorigin;
777         model_t *model;
778         prvm_edict_t *ed;
779         trace_t trace;
780         if (sententitiesconsideration[s->number] == sententitiesmark)
781                 return;
782         sententitiesconsideration[s->number] = sententitiesmark;
783         sv_writeentitiestoclient_totalentities++;
784
785         if (s->customizeentityforclient)
786         {
787                 prog->globals.server->self = s->number;
788                 prog->globals.server->other = sv_writeentitiestoclient_clentnum;
789                 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
790                 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
791                         return;
792         }
793
794         // never reject player
795         if (s->number != sv_writeentitiestoclient_clentnum)
796         {
797                 // check various rejection conditions
798                 if (s->nodrawtoclient == sv_writeentitiestoclient_clentnum)
799                         return;
800                 if (s->drawonlytoclient && s->drawonlytoclient != sv_writeentitiestoclient_clentnum)
801                         return;
802                 if (s->effects & EF_NODRAW)
803                         return;
804                 // LordHavoc: only send entities with a model or important effects
805                 if (!s->modelindex && s->specialvisibilityradius == 0)
806                         return;
807
808                 // viewmodels don't have visibility checking
809                 if (s->viewmodelforclient)
810                 {
811                         if (s->viewmodelforclient != sv_writeentitiestoclient_clentnum)
812                                 return;
813                 }
814                 else if (s->tagentity)
815                 {
816                         // tag attached entities simply check their parent
817                         if (!sendentitiesindex[s->tagentity])
818                                 return;
819                         SV_MarkWriteEntityStateToClient(sendentitiesindex[s->tagentity]);
820                         if (sententities[s->tagentity] != sententitiesmark)
821                                 return;
822                 }
823                 // always send world submodels in newer protocols because they don't
824                 // generate much traffic (in old protocols they hog bandwidth)
825                 else if (!(s->effects & EF_NODEPTHTEST) && !((isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*') && (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)))
826                 {
827                         // entity has survived every check so far, check if visible
828                         ed = PRVM_EDICT_NUM(s->number);
829
830                         // if not touching a visible leaf
831                         if (sv_cullentities_pvs.integer && sv_writeentitiestoclient_pvsbytes)
832                         {
833                                 if (ed->priv.server->pvs_numclusters < 0)
834                                 {
835                                         // entity too big for clusters list
836                                         if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv_writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
837                                         {
838                                                 sv_writeentitiestoclient_culled_pvs++;
839                                                 return;
840                                         }
841                                 }
842                                 else
843                                 {
844                                         int i;
845                                         // check cached clusters list
846                                         for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
847                                                 if (CHECKPVSBIT(sv_writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
848                                                         break;
849                                         if (i == ed->priv.server->pvs_numclusters)
850                                         {
851                                                 sv_writeentitiestoclient_culled_pvs++;
852                                                 return;
853                                         }
854                                 }
855                         }
856
857                         // or not seen by random tracelines
858                         if (sv_cullentities_trace.integer && !isbmodel)
859                         {
860                                 // LordHavoc: test center first
861                                 testorigin[0] = (ed->priv.server->cullmins[0] + ed->priv.server->cullmaxs[0]) * 0.5f;
862                                 testorigin[1] = (ed->priv.server->cullmins[1] + ed->priv.server->cullmaxs[1]) * 0.5f;
863                                 testorigin[2] = (ed->priv.server->cullmins[2] + ed->priv.server->cullmaxs[2]) * 0.5f;
864                                 sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
865                                 if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
866                                         sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
867                                 else
868                                 {
869                                         // LordHavoc: test random offsets, to maximize chance of detection
870                                         testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
871                                         testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
872                                         testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
873                                         sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
874                                         if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
875                                                 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
876                                         else
877                                         {
878                                                 if (s->specialvisibilityradius)
879                                                 {
880                                                         // LordHavoc: test random offsets, to maximize chance of detection
881                                                         testorigin[0] = lhrandom(ed->priv.server->cullmins[0], ed->priv.server->cullmaxs[0]);
882                                                         testorigin[1] = lhrandom(ed->priv.server->cullmins[1], ed->priv.server->cullmaxs[1]);
883                                                         testorigin[2] = lhrandom(ed->priv.server->cullmins[2], ed->priv.server->cullmaxs[2]);
884                                                         sv.worldmodel->TraceBox(sv.worldmodel, 0, &trace, sv_writeentitiestoclient_testeye, vec3_origin, vec3_origin, testorigin, SUPERCONTENTS_SOLID);
885                                                         if (trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
886                                                                 sv_writeentitiestoclient_client->visibletime[s->number] = realtime + 1;
887                                                 }
888                                         }
889                                 }
890                                 if (realtime > sv_writeentitiestoclient_client->visibletime[s->number])
891                                 {
892                                         sv_writeentitiestoclient_culled_trace++;
893                                         return;
894                                 }
895                         }
896                 }
897         }
898
899         // this just marks it for sending
900         // FIXME: it would be more efficient to send here, but the entity
901         // compressor isn't that flexible
902         sv_writeentitiestoclient_visibleentities++;
903         sententities[s->number] = sententitiesmark;
904 }
905
906 entity_state_t sendstates[MAX_EDICTS];
907 extern int csqc_clent;
908
909 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int *stats)
910 {
911         int i, numsendstates;
912         entity_state_t *s;
913
914         // if there isn't enough space to accomplish anything, skip it
915         if (msg->cursize + 25 > msg->maxsize)
916                 return;
917
918         sv_writeentitiestoclient_client = client;
919
920         sv_writeentitiestoclient_culled_pvs = 0;
921         sv_writeentitiestoclient_culled_trace = 0;
922         sv_writeentitiestoclient_visibleentities = 0;
923         sv_writeentitiestoclient_totalentities = 0;
924
925 // find the client's PVS
926         // the real place being tested from
927         VectorAdd(clent->fields.server->origin, clent->fields.server->view_ofs, sv_writeentitiestoclient_testeye);
928         sv_writeentitiestoclient_pvsbytes = 0;
929         if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
930                 sv_writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv_writeentitiestoclient_testeye, 8, sv_writeentitiestoclient_pvs, sizeof(sv_writeentitiestoclient_pvs));
931
932         csqc_clent = sv_writeentitiestoclient_clentnum = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
933
934         sententitiesmark++;
935
936         for (i = 0;i < numsendentities;i++)
937                 SV_MarkWriteEntityStateToClient(sendentities + i);
938
939         numsendstates = 0;
940         for (i = 0;i < numsendentities;i++)
941         {
942                 if (sententities[sendentities[i].number] == sententitiesmark)
943                 {
944                         s = &sendstates[numsendstates++];
945                         *s = sendentities[i];
946                         if (s->exteriormodelforclient && s->exteriormodelforclient == sv_writeentitiestoclient_clentnum)
947                                 s->flags |= RENDER_EXTERIORMODEL;
948                 }
949         }
950
951         if (sv_cullentities_stats.integer)
952                 Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, sv_writeentitiestoclient_totalentities, sv_writeentitiestoclient_visibleentities, sv_writeentitiestoclient_culled_pvs + sv_writeentitiestoclient_culled_trace, sv_writeentitiestoclient_culled_pvs, sv_writeentitiestoclient_culled_trace);
953
954         EntityFrameCSQC_WriteFrame(msg, numsendstates, sendstates);
955
956         if (client->entitydatabase5)
957                 EntityFrame5_WriteFrame(msg, client->entitydatabase5, numsendstates, sendstates, client - svs.clients + 1, stats, client->movesequence);
958         else if (client->entitydatabase4)
959                 EntityFrame4_WriteFrame(msg, client->entitydatabase4, numsendstates, sendstates);
960         else if (client->entitydatabase)
961                 EntityFrame_WriteFrame(msg, client->entitydatabase, numsendstates, sendstates, client - svs.clients + 1);
962         else
963                 EntityFrameQuake_WriteFrame(msg, numsendstates, sendstates);
964 }
965
966 /*
967 =============
968 SV_CleanupEnts
969
970 =============
971 */
972 void SV_CleanupEnts (void)
973 {
974         int             e;
975         prvm_edict_t    *ent;
976
977         ent = PRVM_NEXT_EDICT(prog->edicts);
978         for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
979                 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
980 }
981
982 /*
983 ==================
984 SV_WriteClientdataToMessage
985
986 ==================
987 */
988 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
989 {
990         int             bits;
991         int             i;
992         prvm_edict_t    *other;
993         int             items;
994         prvm_eval_t     *val;
995         vec3_t  punchvector;
996         int             viewzoom;
997         const char *s;
998
999 //
1000 // send a damage message
1001 //
1002         if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1003         {
1004                 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1005                 MSG_WriteByte (msg, svc_damage);
1006                 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1007                 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1008                 for (i=0 ; i<3 ; i++)
1009                         MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1010
1011                 ent->fields.server->dmg_take = 0;
1012                 ent->fields.server->dmg_save = 0;
1013         }
1014
1015 //
1016 // send the current viewpos offset from the view entity
1017 //
1018         SV_SetIdealPitch ();            // how much to look up / down ideally
1019
1020 // a fixangle might get lost in a dropped packet.  Oh well.
1021         if ( ent->fields.server->fixangle )
1022         {
1023                 MSG_WriteByte (msg, svc_setangle);
1024                 for (i=0 ; i < 3 ; i++)
1025                         MSG_WriteAngle (msg, ent->fields.server->angles[i], sv.protocol);
1026                 ent->fields.server->fixangle = 0;
1027         }
1028
1029         // stuff the sigil bits into the high bits of items for sbar, or else
1030         // mix in items2
1031         val = PRVM_GETEDICTFIELDVALUE(ent, eval_items2);
1032         if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1033                 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1034         else
1035                 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1036
1037         VectorClear(punchvector);
1038         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_punchvector)))
1039                 VectorCopy(val->vector, punchvector);
1040
1041         // cache weapon model name and index in client struct to save time
1042         // (this search can be almost 1% of cpu time!)
1043         s = PRVM_GetString(ent->fields.server->weaponmodel);
1044         if (strcmp(s, client->weaponmodel))
1045         {
1046                 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1047                 client->weaponmodelindex = SV_ModelIndex(s, 1);
1048         }
1049
1050         viewzoom = 255;
1051         if ((val = PRVM_GETEDICTFIELDVALUE(ent, eval_viewzoom)))
1052                 viewzoom = (int)(val->_float * 255.0f);
1053         if (viewzoom == 0)
1054                 viewzoom = 255;
1055
1056         bits = 0;
1057
1058         if ((int)ent->fields.server->flags & FL_ONGROUND)
1059                 bits |= SU_ONGROUND;
1060         if (ent->fields.server->waterlevel >= 2)
1061                 bits |= SU_INWATER;
1062         if (ent->fields.server->idealpitch)
1063                 bits |= SU_IDEALPITCH;
1064
1065         for (i=0 ; i<3 ; i++)
1066         {
1067                 if (ent->fields.server->punchangle[i])
1068                         bits |= (SU_PUNCH1<<i);
1069                 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE)
1070                         if (punchvector[i])
1071                                 bits |= (SU_PUNCHVEC1<<i);
1072                 if (ent->fields.server->velocity[i])
1073                         bits |= (SU_VELOCITY1<<i);
1074         }
1075
1076         memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1077         stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1078         stats[STAT_ITEMS] = items;
1079         stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1080         stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1081         stats[STAT_WEAPON] = client->weaponmodelindex;
1082         stats[STAT_HEALTH] = (int)ent->fields.server->health;
1083         stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1084         stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1085         stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1086         stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1087         stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1088         stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1089         stats[STAT_VIEWZOOM] = viewzoom;
1090         // the QC bumps these itself by sending svc_'s, so we have to keep them
1091         // zero or they'll be corrected by the engine
1092         //stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1093         //stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1094         //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1095         //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1096
1097         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1098         {
1099                 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1100                 bits |= SU_ITEMS;
1101                 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1102                 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1103                 bits |= SU_WEAPON;
1104                 // FIXME: which protocols support this?  does PROTOCOL_DARKPLACES3 support viewzoom?
1105                 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1106                         if (viewzoom != 255)
1107                                 bits |= SU_VIEWZOOM;
1108         }
1109
1110         if (bits >= 65536)
1111                 bits |= SU_EXTEND1;
1112         if (bits >= 16777216)
1113                 bits |= SU_EXTEND2;
1114
1115         // send the data
1116         MSG_WriteByte (msg, svc_clientdata);
1117         MSG_WriteShort (msg, bits);
1118         if (bits & SU_EXTEND1)
1119                 MSG_WriteByte(msg, bits >> 16);
1120         if (bits & SU_EXTEND2)
1121                 MSG_WriteByte(msg, bits >> 24);
1122
1123         if (bits & SU_VIEWHEIGHT)
1124                 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1125
1126         if (bits & SU_IDEALPITCH)
1127                 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1128
1129         for (i=0 ; i<3 ; i++)
1130         {
1131                 if (bits & (SU_PUNCH1<<i))
1132                 {
1133                         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1134                                 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1135                         else
1136                                 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1137                 }
1138                 if (bits & (SU_PUNCHVEC1<<i))
1139                 {
1140                         if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1141                                 MSG_WriteCoord16i(msg, punchvector[i]);
1142                         else
1143                                 MSG_WriteCoord32f(msg, punchvector[i]);
1144                 }
1145                 if (bits & (SU_VELOCITY1<<i))
1146                 {
1147                         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1148                                 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1149                         else
1150                                 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1151                 }
1152         }
1153
1154         if (bits & SU_ITEMS)
1155                 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1156
1157         if (sv.protocol == PROTOCOL_DARKPLACES5)
1158         {
1159                 if (bits & SU_WEAPONFRAME)
1160                         MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1161                 if (bits & SU_ARMOR)
1162                         MSG_WriteShort (msg, stats[STAT_ARMOR]);
1163                 if (bits & SU_WEAPON)
1164                         MSG_WriteShort (msg, stats[STAT_WEAPON]);
1165                 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1166                 MSG_WriteShort (msg, stats[STAT_AMMO]);
1167                 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1168                 MSG_WriteShort (msg, stats[STAT_NAILS]);
1169                 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1170                 MSG_WriteShort (msg, stats[STAT_CELLS]);
1171                 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1172                 if (bits & SU_VIEWZOOM)
1173                         MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1174         }
1175         else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1176         {
1177                 if (bits & SU_WEAPONFRAME)
1178                         MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1179                 if (bits & SU_ARMOR)
1180                         MSG_WriteByte (msg, stats[STAT_ARMOR]);
1181                 if (bits & SU_WEAPON)
1182                         MSG_WriteByte (msg, stats[STAT_WEAPON]);
1183                 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1184                 MSG_WriteByte (msg, stats[STAT_AMMO]);
1185                 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1186                 MSG_WriteByte (msg, stats[STAT_NAILS]);
1187                 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1188                 MSG_WriteByte (msg, stats[STAT_CELLS]);
1189                 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1190                 {
1191                         for (i = 0;i < 32;i++)
1192                                 if (stats[STAT_WEAPON] & (1<<i))
1193                                         break;
1194                         MSG_WriteByte (msg, i);
1195                 }
1196                 else
1197                         MSG_WriteByte (msg, stats[STAT_WEAPON]);
1198                 if (bits & SU_VIEWZOOM)
1199                 {
1200                         if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1201                                 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1202                         else
1203                                 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1204                 }
1205         }
1206 }
1207
1208 /*
1209 =======================
1210 SV_SendClientDatagram
1211 =======================
1212 */
1213 static unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE]; // FIXME?
1214 void SV_SendClientDatagram (client_t *client)
1215 {
1216         int rate, maxrate, maxsize, maxsize2;
1217         sizebuf_t msg;
1218         int stats[MAX_CL_STATS];
1219
1220         if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1221         {
1222                 // for good singleplayer, send huge packets
1223                 maxsize = sizeof(sv_sendclientdatagram_buf);
1224                 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1225         }
1226         else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1227         {
1228                 // no rate limiting support on older protocols because dp protocols
1229                 // 1-4 kick the client off if they overflow, and quake protocol shows
1230                 // less than the full entity set if rate limited
1231                 maxsize = 1400;
1232                 maxsize2 = 1400;
1233         }
1234         else
1235         {
1236                 // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1237                 maxrate = max(NET_MINRATE, sv_maxrate.integer);
1238                 if (sv_maxrate.integer != maxrate)
1239                         Cvar_SetValueQuick(&sv_maxrate, maxrate);
1240
1241                 // this rate limiting does not understand sys_ticrate 0
1242                 // (but no one should be running that on a server!)
1243                 rate = bound(NET_MINRATE, client->rate, maxrate);
1244                 rate = (int)(rate * sys_ticrate.value);
1245                 maxsize = bound(100, rate, 1400);
1246                 maxsize2 = 1400;
1247         }
1248
1249         msg.data = sv_sendclientdatagram_buf;
1250         msg.maxsize = maxsize;
1251         msg.cursize = 0;
1252
1253         if (host_client->spawned)
1254         {
1255                 MSG_WriteByte (&msg, svc_time);
1256                 MSG_WriteFloat (&msg, sv.time);
1257
1258                 // add the client specific data to the datagram
1259                 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1260                 VM_SV_WriteAutoSentStats (client, client->edict, &msg, stats);
1261                 SV_WriteEntitiesToClient (client, client->edict, &msg, stats);
1262
1263                 // expand packet size to allow effects to go over the rate limit
1264                 // (dropping them is FAR too ugly)
1265                 msg.maxsize = maxsize2;
1266
1267                 // copy the server datagram if there is space
1268                 // FIXME: put in delayed queue of effects to send
1269                 if (sv.datagram.cursize > 0 && msg.cursize + sv.datagram.cursize <= msg.maxsize)
1270                         SZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);
1271         }
1272         else if (realtime > client->keepalivetime)
1273         {
1274                 // the player isn't totally in the game yet
1275                 // send small keepalive messages if too much time has passed
1276                 client->keepalivetime = realtime + 5;
1277                 MSG_WriteChar (&msg, svc_nop);
1278         }
1279
1280 // send the datagram
1281         NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol);
1282 }
1283
1284 /*
1285 =======================
1286 SV_UpdateToReliableMessages
1287 =======================
1288 */
1289 void SV_UpdateToReliableMessages (void)
1290 {
1291         int i, j;
1292         client_t *client;
1293         prvm_eval_t *val;
1294         const char *name;
1295         const char *model;
1296         const char *skin;
1297
1298 // check for changes to be sent over the reliable streams
1299         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1300         {
1301                 // update the host_client fields we care about according to the entity fields
1302                 host_client->edict = PRVM_EDICT_NUM(i+1);
1303
1304                 // DP_SV_CLIENTNAME
1305                 name = PRVM_GetString(host_client->edict->fields.server->netname);
1306                 if (name == NULL)
1307                         name = "";
1308                 // always point the string back at host_client->name to keep it safe
1309                 strlcpy (host_client->name, name, sizeof (host_client->name));
1310                 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1311                 if (strcmp(host_client->old_name, host_client->name))
1312                 {
1313                         if (host_client->spawned)
1314                                 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1315                         strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1316                         // send notification to all clients
1317                         MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1318                         MSG_WriteByte (&sv.reliable_datagram, i);
1319                         MSG_WriteString (&sv.reliable_datagram, host_client->name);
1320                 }
1321
1322                 // DP_SV_CLIENTCOLORS
1323                 // this is always found (since it's added by the progs loader)
1324                 if ((val = PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_clientcolors)))
1325                         host_client->colors = (int)val->_float;
1326                 if (host_client->old_colors != host_client->colors)
1327                 {
1328                         host_client->old_colors = host_client->colors;
1329                         // send notification to all clients
1330                         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1331                         MSG_WriteByte (&sv.reliable_datagram, i);
1332                         MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1333                 }
1334
1335                 // NEXUIZ_PLAYERMODEL
1336                 if( eval_playermodel ) {
1337                         model = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string);
1338                         if (model == NULL)
1339                                 model = "";
1340                         // always point the string back at host_client->name to keep it safe
1341                         strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1342                         PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1343                 }
1344
1345                 // NEXUIZ_PLAYERSKIN
1346                 if( eval_playerskin ) {
1347                         skin = PRVM_GetString(PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string);
1348                         if (skin == NULL)
1349                                 skin = "";
1350                         // always point the string back at host_client->name to keep it safe
1351                         strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1352                         PRVM_GETEDICTFIELDVALUE(host_client->edict, eval_playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1353                 }
1354
1355                 // frags
1356                 host_client->frags = (int)host_client->edict->fields.server->frags;
1357                 if (host_client->old_frags != host_client->frags)
1358                 {
1359                         host_client->old_frags = host_client->frags;
1360                         // send notification to all clients
1361                         MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1362                         MSG_WriteByte (&sv.reliable_datagram, i);
1363                         MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1364                 }
1365         }
1366
1367         for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1368                 if (client->netconnection)
1369                         SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1370
1371         SZ_Clear (&sv.reliable_datagram);
1372 }
1373
1374
1375 /*
1376 =======================
1377 SV_SendClientMessages
1378 =======================
1379 */
1380 void SV_SendClientMessages (void)
1381 {
1382         int i, prepared = false;
1383
1384         if (sv.protocol == PROTOCOL_QUAKEWORLD)
1385                 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1386
1387 // update frags, names, etc
1388         SV_UpdateToReliableMessages();
1389
1390 // build individual updates
1391         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1392         {
1393                 if (!host_client->active)
1394                         continue;
1395                 if (!host_client->netconnection)
1396                         continue;
1397
1398                 if (host_client->netconnection->message.overflowed)
1399                 {
1400                         SV_DropClient (true);   // if the message couldn't send, kick off
1401                         continue;
1402                 }
1403
1404                 if (!prepared)
1405                 {
1406                         prepared = true;
1407                         // only prepare entities once per frame
1408                         SV_PrepareEntitiesForSending();
1409                 }
1410                 SV_SendClientDatagram (host_client);
1411         }
1412
1413 // clear muzzle flashes
1414         SV_CleanupEnts();
1415 }
1416
1417
1418 /*
1419 ==============================================================================
1420
1421 SERVER SPAWNING
1422
1423 ==============================================================================
1424 */
1425
1426 /*
1427 ================
1428 SV_ModelIndex
1429
1430 ================
1431 */
1432 int SV_ModelIndex(const char *s, int precachemode)
1433 {
1434         int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1435         char filename[MAX_QPATH];
1436         if (!s || !*s)
1437                 return 0;
1438         // testing
1439         //if (precachemode == 2)
1440         //      return 0;
1441         strlcpy(filename, s, sizeof(filename));
1442         for (i = 2;i < limit;i++)
1443         {
1444                 if (!sv.model_precache[i][0])
1445                 {
1446                         if (precachemode)
1447                         {
1448                                 if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5))
1449                                 {
1450                                         Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1451                                         return 0;
1452                                 }
1453                                 if (precachemode == 1)
1454                                         Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1455                                 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1456                                 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1457                                 if (sv.state != ss_loading)
1458                                 {
1459                                         MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1460                                         MSG_WriteShort(&sv.reliable_datagram, i);
1461                                         MSG_WriteString(&sv.reliable_datagram, filename);
1462                                 }
1463                                 return i;
1464                         }
1465                         Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1466                         return 0;
1467                 }
1468                 if (!strcmp(sv.model_precache[i], filename))
1469                         return i;
1470         }
1471         Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
1472         return 0;
1473 }
1474
1475 /*
1476 ================
1477 SV_SoundIndex
1478
1479 ================
1480 */
1481 int SV_SoundIndex(const char *s, int precachemode)
1482 {
1483         int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
1484         char filename[MAX_QPATH];
1485         if (!s || !*s)
1486                 return 0;
1487         // testing
1488         //if (precachemode == 2)
1489         //      return 0;
1490         strlcpy(filename, s, sizeof(filename));
1491         for (i = 1;i < limit;i++)
1492         {
1493                 if (!sv.sound_precache[i][0])
1494                 {
1495                         if (precachemode)
1496                         {
1497                                 if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5))
1498                                 {
1499                                         Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
1500                                         return 0;
1501                                 }
1502                                 if (precachemode == 1)
1503                                         Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1504                                 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
1505                                 if (sv.state != ss_loading)
1506                                 {
1507                                         MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1508                                         MSG_WriteShort(&sv.reliable_datagram, i + 32768);
1509                                         MSG_WriteString(&sv.reliable_datagram, filename);
1510                                 }
1511                                 return i;
1512                         }
1513                         Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
1514                         return 0;
1515                 }
1516                 if (!strcmp(sv.sound_precache[i], filename))
1517                         return i;
1518         }
1519         Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
1520         return 0;
1521 }
1522
1523 /*
1524 ================
1525 SV_CreateBaseline
1526
1527 ================
1528 */
1529 void SV_CreateBaseline (void)
1530 {
1531         int i, entnum, large;
1532         prvm_edict_t *svent;
1533
1534         // LordHavoc: clear *all* states (note just active ones)
1535         for (entnum = 0;entnum < prog->max_edicts;entnum++)
1536         {
1537                 // get the current server version
1538                 svent = PRVM_EDICT_NUM(entnum);
1539
1540                 // LordHavoc: always clear state values, whether the entity is in use or not
1541                 svent->priv.server->baseline = defaultstate;
1542
1543                 if (svent->priv.server->free)
1544                         continue;
1545                 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
1546                         continue;
1547
1548                 // create entity baseline
1549                 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
1550                 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
1551                 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
1552                 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
1553                 if (entnum > 0 && entnum <= svs.maxclients)
1554                 {
1555                         svent->priv.server->baseline.colormap = entnum;
1556                         svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
1557                 }
1558                 else
1559                 {
1560                         svent->priv.server->baseline.colormap = 0;
1561                         svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
1562                 }
1563
1564                 large = false;
1565                 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
1566                         large = true;
1567
1568                 // add to the message
1569                 if (large)
1570                         MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
1571                 else
1572                         MSG_WriteByte (&sv.signon, svc_spawnbaseline);
1573                 MSG_WriteShort (&sv.signon, entnum);
1574
1575                 if (large)
1576                 {
1577                         MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
1578                         MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
1579                 }
1580                 else
1581                 {
1582                         MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
1583                         MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
1584                 }
1585                 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
1586                 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
1587                 for (i=0 ; i<3 ; i++)
1588                 {
1589                         MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
1590                         MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
1591                 }
1592         }
1593 }
1594
1595
1596 /*
1597 ================
1598 SV_SaveSpawnparms
1599
1600 Grabs the current state of each client for saving across the
1601 transition to another level
1602 ================
1603 */
1604 void SV_SaveSpawnparms (void)
1605 {
1606         int             i, j;
1607
1608         svs.serverflags = (int)prog->globals.server->serverflags;
1609
1610         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1611         {
1612                 if (!host_client->active)
1613                         continue;
1614
1615         // call the progs to get default spawn parms for the new client
1616                 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1617                 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
1618                 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
1619                         host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
1620         }
1621 }
1622 /*
1623 void SV_IncreaseEdicts(void)
1624 {
1625         int i;
1626         prvm_edict_t *ent;
1627         int oldmax_edicts = prog->max_edicts;
1628         void *oldedictsengineprivate = prog->edictprivate;
1629         void *oldedictsfields = prog->edictsfields;
1630         void *oldmoved_edicts = sv.moved_edicts;
1631
1632         if (prog->max_edicts >= MAX_EDICTS)
1633                 return;
1634
1635         // links don't survive the transition, so unlink everything
1636         for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1637         {
1638                 if (!ent->priv.server->free)
1639                         SV_UnlinkEdict(prog->edicts + i);
1640                 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1641         }
1642         SV_ClearWorld();
1643
1644         prog->max_edicts   = min(prog->max_edicts + 256, MAX_EDICTS);
1645         prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1646         prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);
1647         sv.moved_edicts = PR_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1648
1649         memcpy(prog->edictprivate, oldedictsengineprivate, oldmax_edicts * sizeof(edict_engineprivate_t));
1650         memcpy(prog->edictsfields, oldedictsfields, oldmax_edicts * prog->edict_size);
1651
1652         for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1653         {
1654                 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1655                 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1656                 // link every entity except world
1657                 if (!ent->priv.server->free)
1658                         SV_LinkEdict(ent, false);
1659         }
1660
1661         PR_Free(oldedictsengineprivate);
1662         PR_Free(oldedictsfields);
1663         PR_Free(oldmoved_edicts);
1664 }*/
1665
1666 /*
1667 ================
1668 SV_SpawnServer
1669
1670 This is called at the start of each level
1671 ================
1672 */
1673 extern float            scr_centertime_off;
1674
1675 void SV_SpawnServer (const char *server)
1676 {
1677         prvm_edict_t *ent;
1678         int i;
1679         char *entities;
1680         model_t *worldmodel;
1681         char modelname[sizeof(sv.modelname)];
1682
1683         Con_DPrintf("SpawnServer: %s\n", server);
1684
1685         if (cls.state != ca_dedicated)
1686                 SCR_BeginLoadingPlaque();
1687
1688         dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
1689         worldmodel = Mod_ForName(modelname, false, true, true);
1690         if (!worldmodel || !worldmodel->TraceBox)
1691         {
1692                 Con_Printf("Couldn't load map %s\n", modelname);
1693                 return;
1694         }
1695
1696         // let's not have any servers with no name
1697         if (hostname.string[0] == 0)
1698                 Cvar_Set ("hostname", "UNNAMED");
1699         scr_centertime_off = 0;
1700
1701         svs.changelevel_issued = false;         // now safe to issue another
1702
1703         // make the map a required file for clients
1704         Curl_ClearRequirements();
1705         Curl_RequireFile(modelname);
1706
1707 //
1708 // tell all connected clients that we are going to a new level
1709 //
1710         if (sv.active)
1711         {
1712                 client_t *client;
1713                 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1714                 {
1715                         if (client->netconnection)
1716                         {
1717                                 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
1718                                 MSG_WriteString(&client->netconnection->message, "reconnect\n");
1719                         }
1720                 }
1721         }
1722         else
1723         {
1724                 // open server port
1725                 NetConn_OpenServerPorts(true);
1726         }
1727
1728 //
1729 // make cvars consistant
1730 //
1731         if (coop.integer)
1732                 Cvar_SetValue ("deathmatch", 0);
1733         // LordHavoc: it can be useful to have skills outside the range 0-3...
1734         //current_skill = bound(0, (int)(skill.value + 0.5), 3);
1735         //Cvar_SetValue ("skill", (float)current_skill);
1736         current_skill = (int)(skill.value + 0.5);
1737
1738 //
1739 // set up the new server
1740 //
1741         memset (&sv, 0, sizeof(sv));
1742         // if running a local client, make sure it doesn't try to access the last
1743         // level's data which is no longer valiud
1744         cls.signon = 0;
1745
1746         SV_VM_Setup();
1747
1748         sv.active = true;
1749
1750         strlcpy (sv.name, server, sizeof (sv.name));
1751
1752         sv.protocol = Protocol_EnumForName(sv_protocolname.string);
1753         if (sv.protocol == PROTOCOL_UNKNOWN)
1754         {
1755                 char buffer[1024];
1756                 Protocol_Names(buffer, sizeof(buffer));
1757                 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
1758                 sv.protocol = PROTOCOL_QUAKE;
1759         }
1760
1761         SV_VM_Begin();
1762
1763 // load progs to get entity field count
1764         //PR_LoadProgs ( sv_progs.string );
1765
1766         // allocate server memory
1767         /*// start out with just enough room for clients and a reasonable estimate of entities
1768         prog->max_edicts = max(svs.maxclients + 1, 512);
1769         prog->max_edicts = min(prog->max_edicts, MAX_EDICTS);
1770
1771         // prvm_edict_t structures (hidden from progs)
1772         prog->edicts = PR_Alloc(MAX_EDICTS * sizeof(prvm_edict_t));
1773         // engine private structures (hidden from progs)
1774         prog->edictprivate = PR_Alloc(prog->max_edicts * sizeof(edict_engineprivate_t));
1775         // progs fields, often accessed by server
1776         prog->edictsfields = PR_Alloc(prog->max_edicts * prog->edict_size);*/
1777         // used by PushMove to move back pushed entities
1778         sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1779         /*for (i = 0;i < prog->max_edicts;i++)
1780         {
1781                 ent = prog->edicts + i;
1782                 ent->priv.vp = (unsigned char*) prog->edictprivate + i * prog->edictprivate_size;
1783                 ent->fields.server = (void *)((unsigned char *)prog->edictsfields + i * prog->edict_size);
1784         }*/
1785
1786         // reset client csqc entity versions right away.
1787         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1788                 EntityFrameCSQC_InitClientVersions(i, true);
1789
1790         sv.datagram.maxsize = sizeof(sv.datagram_buf);
1791         sv.datagram.cursize = 0;
1792         sv.datagram.data = sv.datagram_buf;
1793
1794         sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
1795         sv.reliable_datagram.cursize = 0;
1796         sv.reliable_datagram.data = sv.reliable_datagram_buf;
1797
1798         sv.signon.maxsize = sizeof(sv.signon_buf);
1799         sv.signon.cursize = 0;
1800         sv.signon.data = sv.signon_buf;
1801
1802 // leave slots at start for clients only
1803         //prog->num_edicts = svs.maxclients+1;
1804
1805         sv.state = ss_loading;
1806         prog->allowworldwrites = true;
1807         sv.paused = false;
1808
1809         *prog->time = sv.time = 1.0;
1810
1811         Mod_ClearUsed();
1812         worldmodel->used = true;
1813
1814         strlcpy (sv.name, server, sizeof (sv.name));
1815         strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
1816         sv.worldmodel = worldmodel;
1817         sv.models[1] = sv.worldmodel;
1818
1819 //
1820 // clear world interaction links
1821 //
1822         SV_ClearWorld ();
1823
1824         strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
1825
1826         strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
1827         strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
1828         for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
1829         {
1830                 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
1831                 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
1832         }
1833
1834 //
1835 // load the rest of the entities
1836 //
1837         // AK possible hack since num_edicts is still 0
1838         ent = PRVM_EDICT_NUM(0);
1839         memset (ent->fields.server, 0, prog->progs->entityfields * 4);
1840         ent->priv.server->free = false;
1841         ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
1842         ent->fields.server->modelindex = 1;             // world model
1843         ent->fields.server->solid = SOLID_BSP;
1844         ent->fields.server->movetype = MOVETYPE_PUSH;
1845
1846         if (coop.value)
1847                 prog->globals.server->coop = coop.integer;
1848         else
1849                 prog->globals.server->deathmatch = deathmatch.integer;
1850
1851         prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
1852
1853 // serverflags are for cross level information (sigils)
1854         prog->globals.server->serverflags = svs.serverflags;
1855
1856         // we need to reset the spawned flag on all connected clients here so that
1857         // their thinks don't run during startup (before PutClientInServer)
1858         // we also need to set up the client entities now
1859         // and we need to set the ->edict pointers to point into the progs edicts
1860         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1861         {
1862                 host_client->spawned = false;
1863                 host_client->edict = PRVM_EDICT_NUM(i + 1);
1864                 PRVM_ED_ClearEdict(host_client->edict);
1865         }
1866
1867         // load replacement entity file if found
1868         if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
1869         {
1870                 Con_Printf("Loaded maps/%s.ent\n", sv.name);
1871                 PRVM_ED_LoadFromFile (entities);
1872                 Mem_Free(entities);
1873         }
1874         else
1875                 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
1876
1877
1878         // LordHavoc: clear world angles (to fix e3m3.bsp)
1879         VectorClear(prog->edicts->fields.server->angles);
1880
1881 // all setup is completed, any further precache statements are errors
1882         sv.state = ss_active;
1883         prog->allowworldwrites = false;
1884
1885 // run two frames to allow everything to settle
1886         for (i = 0;i < 2;i++)
1887         {
1888                 sv.frametime = 0.1;
1889                 SV_Physics ();
1890         }
1891
1892         Mod_PurgeUnused();
1893
1894 // create a baseline for more efficient communications
1895         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1896                 SV_CreateBaseline ();
1897
1898 // send serverinfo to all connected clients, and set up botclients coming back from a level change
1899         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1900         {
1901                 if (!host_client->active)
1902                         continue;
1903                 if (host_client->netconnection)
1904                         SV_SendServerinfo(host_client);
1905                 else
1906                 {
1907                         int j;
1908                         // if client is a botclient coming from a level change, we need to
1909                         // set up client info that normally requires networking
1910
1911                         // copy spawn parms out of the client_t
1912                         for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
1913                                 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
1914
1915                         // call the spawn function
1916                         host_client->clientconnectcalled = true;
1917                         prog->globals.server->time = sv.time;
1918                         prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
1919                         PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
1920                         PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
1921                         host_client->spawned = true;
1922                 }
1923         }
1924
1925         Con_DPrint("Server spawned.\n");
1926         NetConn_Heartbeat (2);
1927
1928         SV_VM_End();
1929 }
1930
1931 /////////////////////////////////////////////////////
1932 // SV VM stuff
1933
1934 void SV_VM_CB_BeginIncreaseEdicts(void)
1935 {
1936         int i;
1937         prvm_edict_t *ent;
1938
1939         PRVM_Free( sv.moved_edicts );
1940         sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *));
1941
1942         // links don't survive the transition, so unlink everything
1943         for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1944         {
1945                 if (!ent->priv.server->free)
1946                         SV_UnlinkEdict(prog->edicts + i);
1947                 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
1948         }
1949         SV_ClearWorld();
1950 }
1951
1952 void SV_VM_CB_EndIncreaseEdicts(void)
1953 {
1954         int i;
1955         prvm_edict_t *ent;
1956
1957         for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
1958         {
1959                 // link every entity except world
1960                 if (!ent->priv.server->free)
1961                         SV_LinkEdict(ent, false);
1962         }
1963 }
1964
1965 void SV_VM_CB_InitEdict(prvm_edict_t *e)
1966 {
1967         // LordHavoc: for consistency set these here
1968         int num = PRVM_NUM_FOR_EDICT(e) - 1;
1969
1970         e->priv.server->move = false; // don't move on first frame
1971
1972         if (num >= 0 && num < svs.maxclients)
1973         {
1974                 prvm_eval_t *val;
1975                 // set colormap and team on newly created player entity
1976                 e->fields.server->colormap = num + 1;
1977                 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
1978                 // set netname/clientcolors back to client values so that
1979                 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
1980                 // reset them
1981                 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
1982                 if ((val = PRVM_GETEDICTFIELDVALUE(e, eval_clientcolors)))
1983                         val->_float = svs.clients[num].colors;
1984                 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
1985                 if( eval_playermodel )
1986                         PRVM_GETEDICTFIELDVALUE(e, eval_playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
1987                 if( eval_playerskin )
1988                         PRVM_GETEDICTFIELDVALUE(e, eval_playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
1989         }
1990 }
1991
1992 void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
1993 {
1994         SV_UnlinkEdict (ed);            // unlink from world bsp
1995
1996         ed->fields.server->model = 0;
1997         ed->fields.server->takedamage = 0;
1998         ed->fields.server->modelindex = 0;
1999         ed->fields.server->colormap = 0;
2000         ed->fields.server->skin = 0;
2001         ed->fields.server->frame = 0;
2002         VectorClear(ed->fields.server->origin);
2003         VectorClear(ed->fields.server->angles);
2004         ed->fields.server->nextthink = -1;
2005         ed->fields.server->solid = 0;
2006 }
2007
2008 void SV_VM_CB_CountEdicts(void)
2009 {
2010         int             i;
2011         prvm_edict_t    *ent;
2012         int             active, models, solid, step;
2013
2014         active = models = solid = step = 0;
2015         for (i=0 ; i<prog->num_edicts ; i++)
2016         {
2017                 ent = PRVM_EDICT_NUM(i);
2018                 if (ent->priv.server->free)
2019                         continue;
2020                 active++;
2021                 if (ent->fields.server->solid)
2022                         solid++;
2023                 if (ent->fields.server->model)
2024                         models++;
2025                 if (ent->fields.server->movetype == MOVETYPE_STEP)
2026                         step++;
2027         }
2028
2029         Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2030         Con_Printf("active    :%3i\n", active);
2031         Con_Printf("view      :%3i\n", models);
2032         Con_Printf("touch     :%3i\n", solid);
2033         Con_Printf("step      :%3i\n", step);
2034 }
2035
2036 qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2037 {
2038         // remove things from different skill levels or deathmatch
2039         if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2040         {
2041                 if (deathmatch.integer)
2042                 {
2043                         if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2044                         {
2045                                 return false;
2046                         }
2047                 }
2048                 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY  ))
2049                         || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2050                         || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD  )))
2051                 {
2052                         return false;
2053                 }
2054         }
2055         return true;
2056 }
2057
2058 cvar_t pr_checkextension = {CVAR_READONLY, "pr_checkextension", "1", "indicates to QuakeC that the standard quakec extensions system is available (if 0, quakec should not attempt to use extensions)"};
2059 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
2060 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
2061 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
2062 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
2063 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
2064 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
2065 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2066 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2067 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2068 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2069 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
2070 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
2071 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
2072 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
2073 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
2074 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
2075 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
2076 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
2077 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
2078 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
2079 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
2080 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
2081 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
2082 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
2083 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
2084 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
2085 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
2086 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
2087 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
2088 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
2089 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
2090 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
2091
2092 void SV_VM_Init(void)
2093 {
2094         Cvar_RegisterVariable (&pr_checkextension);
2095         Cvar_RegisterVariable (&nomonsters);
2096         Cvar_RegisterVariable (&gamecfg);
2097         Cvar_RegisterVariable (&scratch1);
2098         Cvar_RegisterVariable (&scratch2);
2099         Cvar_RegisterVariable (&scratch3);
2100         Cvar_RegisterVariable (&scratch4);
2101         Cvar_RegisterVariable (&savedgamecfg);
2102         Cvar_RegisterVariable (&saved1);
2103         Cvar_RegisterVariable (&saved2);
2104         Cvar_RegisterVariable (&saved3);
2105         Cvar_RegisterVariable (&saved4);
2106         // LordHavoc: Nehahra uses these to pass data around cutscene demos
2107         if (gamemode == GAME_NEHAHRA)
2108         {
2109                 Cvar_RegisterVariable (&nehx00);
2110                 Cvar_RegisterVariable (&nehx01);
2111                 Cvar_RegisterVariable (&nehx02);
2112                 Cvar_RegisterVariable (&nehx03);
2113                 Cvar_RegisterVariable (&nehx04);
2114                 Cvar_RegisterVariable (&nehx05);
2115                 Cvar_RegisterVariable (&nehx06);
2116                 Cvar_RegisterVariable (&nehx07);
2117                 Cvar_RegisterVariable (&nehx08);
2118                 Cvar_RegisterVariable (&nehx09);
2119                 Cvar_RegisterVariable (&nehx10);
2120                 Cvar_RegisterVariable (&nehx11);
2121                 Cvar_RegisterVariable (&nehx12);
2122                 Cvar_RegisterVariable (&nehx13);
2123                 Cvar_RegisterVariable (&nehx14);
2124                 Cvar_RegisterVariable (&nehx15);
2125                 Cvar_RegisterVariable (&nehx16);
2126                 Cvar_RegisterVariable (&nehx17);
2127                 Cvar_RegisterVariable (&nehx18);
2128                 Cvar_RegisterVariable (&nehx19);
2129         }
2130         Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
2131 }
2132
2133 // LordHavoc: in an effort to eliminate time wasted on GetEdictFieldValue...  these are defined as externs in progs.h
2134 int eval_gravity;
2135 int eval_button3;
2136 int eval_button4;
2137 int eval_button5;
2138 int eval_button6;
2139 int eval_button7;
2140 int eval_button8;
2141 int eval_button9;
2142 int eval_button10;
2143 int eval_button11;
2144 int eval_button12;
2145 int eval_button13;
2146 int eval_button14;
2147 int eval_button15;
2148 int eval_button16;
2149 int eval_buttonuse;
2150 int eval_buttonchat;
2151 int eval_glow_size;
2152 int eval_glow_trail;
2153 int eval_glow_color;
2154 int eval_items2;
2155 int eval_scale;
2156 int eval_alpha;
2157 int eval_renderamt; // HalfLife support
2158 int eval_rendermode; // HalfLife support
2159 int eval_fullbright;
2160 int eval_ammo_shells1;
2161 int eval_ammo_nails1;
2162 int eval_ammo_lava_nails;
2163 int eval_ammo_rockets1;
2164 int eval_ammo_multi_rockets;
2165 int eval_ammo_cells1;
2166 int eval_ammo_plasma;
2167 int eval_idealpitch;
2168 int eval_pitch_speed;
2169 int eval_viewmodelforclient;
2170 int eval_nodrawtoclient;
2171 int eval_exteriormodeltoclient;
2172 int eval_drawonlytoclient;
2173 int eval_ping;
2174 int eval_movement;
2175 int eval_pmodel;
2176 int eval_punchvector;
2177 int eval_viewzoom;
2178 int eval_clientcolors;
2179 int eval_tag_entity;
2180 int eval_tag_index;
2181 int eval_light_lev;
2182 int eval_color;
2183 int eval_style;
2184 int eval_pflags;
2185 int eval_cursor_active;
2186 int eval_cursor_screen;
2187 int eval_cursor_trace_start;
2188 int eval_cursor_trace_endpos;
2189 int eval_cursor_trace_ent;
2190 int eval_colormod;
2191 int eval_playermodel;
2192 int eval_playerskin;
2193 int eval_SendEntity;
2194 int eval_Version;
2195 int eval_customizeentityforclient;
2196 int eval_dphitcontentsmask;
2197 // DRESK - Support for Entity Contents Transition Event
2198 int eval_contentstransition;
2199
2200 int gval_trace_dpstartcontents;
2201 int gval_trace_dphitcontents;
2202 int gval_trace_dphitq3surfaceflags;
2203 int gval_trace_dphittexturename;
2204
2205 mfunction_t *SV_PlayerPhysicsQC;
2206 mfunction_t *EndFrameQC;
2207 //KrimZon - SERVER COMMANDS IN QUAKEC
2208 mfunction_t *SV_ParseClientCommandQC;
2209
2210 void SV_VM_FindEdictFieldOffsets(void)
2211 {
2212         eval_gravity = PRVM_ED_FindFieldOffset("gravity");
2213         eval_button3 = PRVM_ED_FindFieldOffset("button3");
2214         eval_button4 = PRVM_ED_FindFieldOffset("button4");
2215         eval_button5 = PRVM_ED_FindFieldOffset("button5");
2216         eval_button6 = PRVM_ED_FindFieldOffset("button6");
2217         eval_button7 = PRVM_ED_FindFieldOffset("button7");
2218         eval_button8 = PRVM_ED_FindFieldOffset("button8");
2219         eval_button9 = PRVM_ED_FindFieldOffset("button9");
2220         eval_button10 = PRVM_ED_FindFieldOffset("button10");
2221         eval_button11 = PRVM_ED_FindFieldOffset("button11");
2222         eval_button12 = PRVM_ED_FindFieldOffset("button12");
2223         eval_button13 = PRVM_ED_FindFieldOffset("button13");
2224         eval_button14 = PRVM_ED_FindFieldOffset("button14");
2225         eval_button15 = PRVM_ED_FindFieldOffset("button15");
2226         eval_button16 = PRVM_ED_FindFieldOffset("button16");
2227         eval_buttonuse = PRVM_ED_FindFieldOffset("buttonuse");
2228         eval_buttonchat = PRVM_ED_FindFieldOffset("buttonchat");
2229         eval_glow_size = PRVM_ED_FindFieldOffset("glow_size");
2230         eval_glow_trail = PRVM_ED_FindFieldOffset("glow_trail");
2231         eval_glow_color = PRVM_ED_FindFieldOffset("glow_color");
2232         eval_items2 = PRVM_ED_FindFieldOffset("items2");
2233         eval_scale = PRVM_ED_FindFieldOffset("scale");
2234         eval_alpha = PRVM_ED_FindFieldOffset("alpha");
2235         eval_renderamt = PRVM_ED_FindFieldOffset("renderamt"); // HalfLife support
2236         eval_rendermode = PRVM_ED_FindFieldOffset("rendermode"); // HalfLife support
2237         eval_fullbright = PRVM_ED_FindFieldOffset("fullbright");
2238         eval_ammo_shells1 = PRVM_ED_FindFieldOffset("ammo_shells1");
2239         eval_ammo_nails1 = PRVM_ED_FindFieldOffset("ammo_nails1");
2240         eval_ammo_lava_nails = PRVM_ED_FindFieldOffset("ammo_lava_nails");
2241         eval_ammo_rockets1 = PRVM_ED_FindFieldOffset("ammo_rockets1");
2242         eval_ammo_multi_rockets = PRVM_ED_FindFieldOffset("ammo_multi_rockets");
2243         eval_ammo_cells1 = PRVM_ED_FindFieldOffset("ammo_cells1");
2244         eval_ammo_plasma = PRVM_ED_FindFieldOffset("ammo_plasma");
2245         eval_idealpitch = PRVM_ED_FindFieldOffset("idealpitch");
2246         eval_pitch_speed = PRVM_ED_FindFieldOffset("pitch_speed");
2247         eval_viewmodelforclient = PRVM_ED_FindFieldOffset("viewmodelforclient");
2248         eval_nodrawtoclient = PRVM_ED_FindFieldOffset("nodrawtoclient");
2249         eval_exteriormodeltoclient = PRVM_ED_FindFieldOffset("exteriormodeltoclient");
2250         eval_drawonlytoclient = PRVM_ED_FindFieldOffset("drawonlytoclient");
2251         eval_ping = PRVM_ED_FindFieldOffset("ping");
2252         eval_movement = PRVM_ED_FindFieldOffset("movement");
2253         eval_pmodel = PRVM_ED_FindFieldOffset("pmodel");
2254         eval_punchvector = PRVM_ED_FindFieldOffset("punchvector");
2255         eval_viewzoom = PRVM_ED_FindFieldOffset("viewzoom");
2256         eval_clientcolors = PRVM_ED_FindFieldOffset("clientcolors");
2257         eval_tag_entity = PRVM_ED_FindFieldOffset("tag_entity");
2258         eval_tag_index = PRVM_ED_FindFieldOffset("tag_index");
2259         eval_light_lev = PRVM_ED_FindFieldOffset("light_lev");
2260         eval_color = PRVM_ED_FindFieldOffset("color");
2261         eval_style = PRVM_ED_FindFieldOffset("style");
2262         eval_pflags = PRVM_ED_FindFieldOffset("pflags");
2263         eval_cursor_active = PRVM_ED_FindFieldOffset("cursor_active");
2264         eval_cursor_screen = PRVM_ED_FindFieldOffset("cursor_screen");
2265         eval_cursor_trace_start = PRVM_ED_FindFieldOffset("cursor_trace_start");
2266         eval_cursor_trace_endpos = PRVM_ED_FindFieldOffset("cursor_trace_endpos");
2267         eval_cursor_trace_ent = PRVM_ED_FindFieldOffset("cursor_trace_ent");
2268         eval_colormod = PRVM_ED_FindFieldOffset("colormod");
2269         eval_playermodel = PRVM_ED_FindFieldOffset("playermodel");
2270         eval_playerskin = PRVM_ED_FindFieldOffset("playerskin");
2271         eval_SendEntity = PRVM_ED_FindFieldOffset("SendEntity");
2272         eval_Version = PRVM_ED_FindFieldOffset("Version");
2273         eval_customizeentityforclient = PRVM_ED_FindFieldOffset("customizeentityforclient");
2274         eval_dphitcontentsmask = PRVM_ED_FindFieldOffset("dphitcontentsmask");
2275         // DRESK - Support for Entity Contents Transition Event
2276         eval_contentstransition = PRVM_ED_FindFieldOffset("contentstransition");
2277
2278         // LordHavoc: allowing QuakeC to override the player movement code
2279         SV_PlayerPhysicsQC = PRVM_ED_FindFunction ("SV_PlayerPhysics");
2280         // LordHavoc: support for endframe
2281         EndFrameQC = PRVM_ED_FindFunction ("EndFrame");
2282         //KrimZon - SERVER COMMANDS IN QUAKEC
2283         SV_ParseClientCommandQC = PRVM_ED_FindFunction ("SV_ParseClientCommand");
2284         gval_trace_dpstartcontents = PRVM_ED_FindGlobalOffset("trace_dpstartcontents");
2285         gval_trace_dphitcontents = PRVM_ED_FindGlobalOffset("trace_dphitcontents");
2286         gval_trace_dphitq3surfaceflags = PRVM_ED_FindGlobalOffset("trace_dphitq3surfaceflags");
2287         gval_trace_dphittexturename = PRVM_ED_FindGlobalOffset("trace_dphittexturename");
2288 }
2289
2290 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
2291
2292 prvm_required_field_t reqfields[] =
2293 {
2294         {ev_entity, "cursor_trace_ent"},
2295         {ev_entity, "drawonlytoclient"},
2296         {ev_entity, "exteriormodeltoclient"},
2297         {ev_entity, "nodrawtoclient"},
2298         {ev_entity, "tag_entity"},
2299         {ev_entity, "viewmodelforclient"},
2300         {ev_float, "alpha"},
2301         {ev_float, "ammo_cells1"},
2302         {ev_float, "ammo_lava_nails"},
2303         {ev_float, "ammo_multi_rockets"},
2304         {ev_float, "ammo_nails1"},
2305         {ev_float, "ammo_plasma"},
2306         {ev_float, "ammo_rockets1"},
2307         {ev_float, "ammo_shells1"},
2308         {ev_float, "button3"},
2309         {ev_float, "button4"},
2310         {ev_float, "button5"},
2311         {ev_float, "button6"},
2312         {ev_float, "button7"},
2313         {ev_float, "button8"},
2314         {ev_float, "button9"},
2315         {ev_float, "button10"},
2316         {ev_float, "button11"},
2317         {ev_float, "button12"},
2318         {ev_float, "button13"},
2319         {ev_float, "button14"},
2320         {ev_float, "button15"},
2321         {ev_float, "button16"},
2322         {ev_float, "buttonchat"},
2323         {ev_float, "buttonuse"},
2324         {ev_float, "clientcolors"},
2325         {ev_float, "cursor_active"},
2326         {ev_float, "fullbright"},
2327         {ev_float, "glow_color"},
2328         {ev_float, "glow_size"},
2329         {ev_float, "glow_trail"},
2330         {ev_float, "gravity"},
2331         {ev_float, "idealpitch"},
2332         {ev_float, "items2"},
2333         {ev_float, "light_lev"},
2334         {ev_float, "pflags"},
2335         {ev_float, "ping"},
2336         {ev_float, "pitch_speed"},
2337         {ev_float, "pmodel"},
2338         {ev_float, "renderamt"}, // HalfLife support
2339         {ev_float, "rendermode"}, // HalfLife support
2340         {ev_float, "scale"},
2341         {ev_float, "style"},
2342         {ev_float, "tag_index"},
2343         {ev_float, "Version"},
2344         {ev_float, "viewzoom"},
2345         {ev_vector, "color"},
2346         {ev_vector, "colormod"},
2347         {ev_vector, "cursor_screen"},
2348         {ev_vector, "cursor_trace_endpos"},
2349         {ev_vector, "cursor_trace_start"},
2350         {ev_vector, "movement"},
2351         {ev_vector, "punchvector"},
2352         {ev_string, "playermodel"},
2353         {ev_string, "playerskin"},
2354         {ev_function, "SendEntity"},
2355         {ev_function, "customizeentityforclient"},
2356         // DRESK - Support for Entity Contents Transition Event
2357         {ev_function, "contentstransition"},
2358 };
2359
2360 void SV_VM_Setup(void)
2361 {
2362         extern cvar_t csqc_progname;    //[515]: csqc crc check and right csprogs name according to progs.dat
2363         extern cvar_t csqc_progcrc;
2364         unsigned char *csprogsdata;
2365         fs_offset_t csprogsdatasize;
2366         PRVM_Begin;
2367         PRVM_InitProg( PRVM_SERVERPROG );
2368
2369         // allocate the mempools
2370         // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2371         prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2372         prog->builtins = vm_sv_builtins;
2373         prog->numbuiltins = vm_sv_numbuiltins;
2374         prog->headercrc = PROGHEADER_CRC;
2375         prog->max_edicts = 512;
2376         prog->limit_edicts = MAX_EDICTS;
2377         prog->reserved_edicts = svs.maxclients;
2378         prog->edictprivate_size = sizeof(edict_engineprivate_t);
2379         prog->name = "server";
2380         prog->extensionstring = vm_sv_extensions;
2381         prog->loadintoworld = true;
2382
2383         prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2384         prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2385         prog->init_edict = SV_VM_CB_InitEdict;
2386         prog->free_edict = SV_VM_CB_FreeEdict;
2387         prog->count_edicts = SV_VM_CB_CountEdicts;
2388         prog->load_edict = SV_VM_CB_LoadEdict;
2389         prog->init_cmd = VM_SV_Cmd_Init;
2390         prog->reset_cmd = VM_SV_Cmd_Reset;
2391         prog->error_cmd = Host_Error;
2392
2393         // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2394         PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields );
2395         SV_VM_FindEdictFieldOffsets();
2396
2397         VM_AutoSentStats_Clear();//[515]: csqc
2398         EntityFrameCSQC_ClearVersions();//[515]: csqc
2399
2400         PRVM_End;
2401
2402         // see if there is a csprogs.dat installed, and if so, set the csqc_progcrc accordingly, this will be sent to connecting clients to tell them to only load a matching csprogs.dat file
2403         sv.csqc_progcrc = -1;
2404         sv.csqc_progname[0] = 0;
2405         csprogsdata = FS_LoadFile(csqc_progname.string, tempmempool, true, &csprogsdatasize);
2406         if (csprogsdata)
2407         {
2408                 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2409                 sv.csqc_progcrc = CRC_Block(csprogsdata, csprogsdatasize);
2410                 Mem_Free(csprogsdata);
2411                 Con_DPrintf("server detected csqc progs file \"%s\" with crc %i\n", sv.csqc_progname, sv.csqc_progcrc);
2412         }
2413 }
2414
2415 void SV_VM_Begin(void)
2416 {
2417         PRVM_Begin;
2418         PRVM_SetProg( PRVM_SERVERPROG );
2419
2420         *prog->time = (float) sv.time;
2421 }
2422
2423 void SV_VM_End(void)
2424 {
2425         PRVM_End;
2426 }