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