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