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