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