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