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