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