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