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