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