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