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