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