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