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