remove two unnecessary externs
[xonotic/darkplaces.git] / sv_main.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // sv_main.c -- server main program
21
22 #include "quakedef.h"
23 #include "sv_demo.h"
24 #include "libcurl.h"
25 #include "csprogs.h"
26
27 static void SV_SaveEntFile_f(void);
28 static void SV_StartDownload_f(void);
29 static void SV_Download_f(void);
30 static void SV_VM_Setup();
31
32 void VM_CustomStats_Clear (void);
33 void VM_SV_UpdateCustomStats (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats);
34 void EntityFrameCSQC_WriteFrame (sizebuf_t *msg, int maxsize, int numstates, const entity_state_t *states);
35
36 cvar_t coop = {0, "coop","0", "coop mode, 0 = no coop, 1 = coop mode, multiple players playing through the singleplayer game (coop mode also shuts off deathmatch)"};
37 cvar_t deathmatch = {0, "deathmatch","0", "deathmatch mode, values depend on mod but typically 0 = no deathmatch, 1 = normal deathmatch with respawning weapons, 2 = weapons stay (players can only pick up new weapons)"};
38 cvar_t fraglimit = {CVAR_NOTIFY, "fraglimit","0", "ends level if this many frags is reached by any player"};
39 cvar_t gamecfg = {0, "gamecfg", "0", "unused cvar in quake, can be used by mods"};
40 cvar_t noexit = {CVAR_NOTIFY, "noexit","0", "kills anyone attempting to use an exit"};
41 cvar_t nomonsters = {0, "nomonsters", "0", "unused cvar in quake, can be used by mods"};
42 cvar_t pausable = {0, "pausable","1", "allow players to pause or not"};
43 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)"};
44 cvar_t samelevel = {CVAR_NOTIFY, "samelevel","0", "repeats same level if level ends (due to timelimit or someone hitting an exit)"};
45 cvar_t skill = {0, "skill","1", "difficulty level of game, affects monster layouts in levels, 0 = easy, 1 = normal, 2 = hard, 3 = nightmare (same layout as hard but monsters fire twice)"};
46 cvar_t slowmo = {0, "slowmo", "1.0", "controls game speed, 0.5 is half speed, 2 is double speed"};
47
48 cvar_t sv_accelerate = {0, "sv_accelerate", "10", "rate at which a player accelerates to sv_maxspeed"};
49 cvar_t sv_aim = {CVAR_SAVE, "sv_aim", "2", "maximum cosine angle for quake's vertical autoaim, a value above 1 completely disables the autoaim, quake used 0.93"};
50 cvar_t sv_airaccel_qw = {0, "sv_airaccel_qw", "1", "ratio of QW-style air control as opposed to simple acceleration"};
51 cvar_t sv_airaccel_sideways_friction = {0, "sv_airaccel_sideways_friction", "", "anti-sideways movement stabilization (reduces speed gain when zigzagging)"};
52 cvar_t sv_airaccelerate = {0, "sv_airaccelerate", "-1", "rate at which a player accelerates to sv_maxairspeed while in the air, if less than 0 the sv_accelerate variable is used instead"};
53 cvar_t sv_allowdownloads = {0, "sv_allowdownloads", "1", "whether to allow clients to download files from the server (does not affect http downloads)"};
54 cvar_t sv_allowdownloads_archive = {0, "sv_allowdownloads_archive", "0", "whether to allow downloads of archives (pak/pk3)"};
55 cvar_t sv_allowdownloads_config = {0, "sv_allowdownloads_config", "0", "whether to allow downloads of config files (cfg)"};
56 cvar_t sv_allowdownloads_dlcache = {0, "sv_allowdownloads_dlcache", "0", "whether to allow downloads of dlcache files (dlcache/)"};
57 cvar_t sv_allowdownloads_inarchive = {0, "sv_allowdownloads_inarchive", "0", "whether to allow downloads from archives (pak/pk3)"};
58 cvar_t sv_areagrid_mingridsize = {CVAR_NOTIFY, "sv_areagrid_mingridsize", "64", "minimum areagrid cell size, smaller values work better for lots of small objects, higher values for large objects"};
59 cvar_t sv_checkforpacketsduringsleep = {0, "sv_checkforpacketsduringsleep", "0", "uses select() function to wait between frames which can be interrupted by packets being received, instead of Sleep()/usleep()/SDL_Sleep() functions which do not check for packets"};
60 cvar_t sv_clmovement_enable = {0, "sv_clmovement_enable", "1", "whether to allow clients to use cl_movement prediction, which can cause choppy movement on the server which may annoy other players"};
61 cvar_t sv_clmovement_minping = {0, "sv_clmovement_minping", "0", "if client ping is below this time in milliseconds, then their ability to use cl_movement prediction is disabled for a while (as they don't need it)"};
62 cvar_t sv_clmovement_minping_disabletime = {0, "sv_clmovement_minping_disabletime", "1000", "when client falls below minping, disable their prediction for this many milliseconds (should be at least 1000 or else their prediction may turn on/off frequently)"};
63 cvar_t sv_clmovement_waitforinput = {0, "sv_clmovement_waitforinput", "4", "when a client does not send input for this many frames, force them to move anyway (unlike QuakeWorld)"};
64 cvar_t sv_cullentities_nevercullbmodels = {0, "sv_cullentities_nevercullbmodels", "0", "if enabled the clients are always notified of moving doors and lifts and other submodels of world (warning: eats a lot of network bandwidth on some levels!)"};
65 cvar_t sv_cullentities_pvs = {0, "sv_cullentities_pvs", "1", "fast but loose culling of hidden entities"};
66 cvar_t sv_cullentities_stats = {0, "sv_cullentities_stats", "0", "displays stats on network entities culled by various methods for each client"};
67 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"};
68 cvar_t sv_cullentities_trace_delay = {0, "sv_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
69 cvar_t sv_cullentities_trace_delay_players = {0, "sv_cullentities_trace_delay_players", "0.2", "number of seconds until the entity gets actually culled if it is a player entity"};
70 cvar_t sv_cullentities_trace_enlarge = {0, "sv_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
71 cvar_t sv_cullentities_trace_prediction = {0, "sv_cullentities_trace_prediction", "1", "also trace from the predicted player position"};
72 cvar_t sv_cullentities_trace_samples = {0, "sv_cullentities_trace_samples", "1", "number of samples to test for entity culling"};
73 cvar_t sv_cullentities_trace_samples_extra = {0, "sv_cullentities_trace_samples_extra", "2", "number of samples to test for entity culling when the entity affects its surroundings by e.g. dlight"};
74 cvar_t sv_cullentities_trace_samples_players = {0, "sv_cullentities_trace_samples_players", "8", "number of samples to test for entity culling when the entity is a player entity"};
75 cvar_t sv_debugmove = {CVAR_NOTIFY, "sv_debugmove", "0", "disables collision detection optimizations for debugging purposes"};
76 cvar_t sv_echobprint = {CVAR_SAVE, "sv_echobprint", "1", "prints gamecode bprint() calls to server console"};
77 cvar_t sv_edgefriction = {0, "edgefriction", "2", "how much you slow down when nearing a ledge you might fall off"};
78 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)"};
79 cvar_t sv_fixedframeratesingleplayer = {0, "sv_fixedframeratesingleplayer", "1", "allows you to use server-style timing system in singleplayer (don't run faster than sys_ticrate)"};
80 cvar_t sv_freezenonclients = {CVAR_NOTIFY, "sv_freezenonclients", "0", "freezes time, except for players, allowing you to walk around and take screenshots of explosions"};
81 cvar_t sv_friction = {CVAR_NOTIFY, "sv_friction","4", "how fast you slow down"};
82 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"};
83 cvar_t sv_gameplayfix_delayprojectiles = {0, "sv_gameplayfix_delayprojectiles", "1", "causes entities to not move on the same frame they are spawned, meaning that projectiles wait until the next frame to perform their first move, giving proper interpolation and rocket trails, but making weapons harder to use at low framerates"};
84 cvar_t sv_gameplayfix_droptofloorstartsolid = {0, "sv_gameplayfix_droptofloorstartsolid", "1", "prevents items and monsters that start in a solid area from falling out of the level (makes droptofloor treat trace_startsolid as an acceptable outcome)"};
85 cvar_t sv_gameplayfix_droptofloorstartsolid_nudgetocorrect = {0, "sv_gameplayfix_droptofloorstartsolid_nudgetocorrect", "1", "tries to nudge stuck items and monsters out of walls before droptofloor is performed"};
86 cvar_t sv_gameplayfix_easierwaterjump = {0, "sv_gameplayfix_easierwaterjump", "1", "changes water jumping to make it easier to get out of water (exactly like in QuakeWorld)"};
87 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"};
88 cvar_t sv_gameplayfix_grenadebouncedownslopes = {0, "sv_gameplayfix_grenadebouncedownslopes", "1", "prevents MOVETYPE_BOUNCE (grenades) from getting stuck when fired down a downward sloping surface"};
89 cvar_t sv_gameplayfix_multiplethinksperframe = {0, "sv_gameplayfix_multiplethinksperframe", "1", "allows entities to think more often than the server framerate, primarily useful for very high fire rate weapons"};
90 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"};
91 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"};
92 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)"};
93 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)"};
94 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"};
95 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"};
96 cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800", "how fast you fall (512 = roughly earth gravity)"};
97 cvar_t sv_idealpitchscale = {0, "sv_idealpitchscale","0.8", "how much to look up/down slopes and stairs when not using freelook"};
98 cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "0", "whether you can step up while jumping (sv_gameplayfix_stepwhilejumping must also be 1)"};
99 cvar_t sv_jumpvelocity = {0, "sv_jumpvelocity", "270", "cvar that can be used by QuakeC code for jump velocity"};
100 cvar_t sv_maxairspeed = {0, "sv_maxairspeed", "30", "maximum speed a player can accelerate to when airborn (note that it is possible to completely stop by moving the opposite direction)"};
101 cvar_t sv_maxrate = {CVAR_SAVE | CVAR_NOTIFY, "sv_maxrate", "1000000", "upper limit on client rate cvar, should reflect your network connection quality"};
102 cvar_t sv_maxspeed = {CVAR_NOTIFY, "sv_maxspeed", "320", "maximum speed a player can accelerate to when on ground (can be exceeded by tricks)"};
103 cvar_t sv_maxvelocity = {CVAR_NOTIFY, "sv_maxvelocity","2000", "universal speed limit on all entities"};
104 cvar_t sv_newflymove = {CVAR_NOTIFY, "sv_newflymove", "0", "enables simpler/buggier player physics (not recommended)"};
105 cvar_t sv_nostep = {CVAR_NOTIFY, "sv_nostep","0", "prevents MOVETYPE_STEP entities (monsters) from moving"};
106 cvar_t sv_playerphysicsqc = {CVAR_NOTIFY, "sv_playerphysicsqc", "1", "enables QuakeC function to override player physics"};
107 cvar_t sv_progs = {0, "sv_progs", "progs.dat", "selects which quakec progs.dat file to run" };
108 cvar_t sv_protocolname = {0, "sv_protocolname", "DP7", "selects network protocol to host for (values include QUAKE, QUAKEDP, NEHAHRAMOVIE, DP1 and up)"};
109 cvar_t sv_random_seed = {0, "sv_random_seed", "", "random seed; when set, on every map start this random seed is used to initialize the random number generator. Don't touch it unless for benchmarking or debugging"};
110 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)"};
111 cvar_t sv_sound_land = {0, "sv_sound_land", "demon/dland2.wav", "sound to play when MOVETYPE_STEP entity hits the ground at high speed (empty cvar disables the sound)"};
112 cvar_t sv_sound_watersplash = {0, "sv_sound_watersplash", "misc/h2ohit1.wav", "sound to play when MOVETYPE_FLY/TOSS/BOUNCE/STEP entity enters or leaves water (empty cvar disables the sound)"};
113 cvar_t sv_stepheight = {CVAR_NOTIFY, "sv_stepheight", "18", "how high you can step up (TW_SV_STEPCONTROL extension)"};
114 cvar_t sv_stopspeed = {CVAR_NOTIFY, "sv_stopspeed","100", "how fast you come to a complete stop"};
115 cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1", "how much you slow down when sliding along a wall"};
116 cvar_t sv_wateraccelerate = {0, "sv_wateraccelerate", "-1", "rate at which a player accelerates to sv_maxspeed while in the air, if less than 0 the sv_accelerate variable is used instead"};
117 cvar_t sv_waterfriction = {CVAR_NOTIFY, "sv_waterfriction","-1", "how fast you slow down, if less than 0 the sv_friction variable is used instead"};
118 cvar_t sys_ticrate = {CVAR_SAVE, "sys_ticrate","0.0138889", "how long a server frame is in seconds, 0.05 is 20fps server rate, 0.1 is 10fps (can not be set higher than 0.1), 0 runs as many server frames as possible (makes games against bots a little smoother, overwhelms network players), 0.0138889 matches QuakeWorld physics"};
119 cvar_t teamplay = {CVAR_NOTIFY, "teamplay","0", "teamplay mode, values depend on mod but typically 0 = no teams, 1 = no team damage no self damage, 2 = team damage and self damage, some mods support 3 = no team damage but can damage self"};
120 cvar_t timelimit = {CVAR_NOTIFY, "timelimit","0", "ends level at this time (in minutes)"};
121
122 cvar_t saved1 = {CVAR_SAVE, "saved1", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
123 cvar_t saved2 = {CVAR_SAVE, "saved2", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
124 cvar_t saved3 = {CVAR_SAVE, "saved3", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
125 cvar_t saved4 = {CVAR_SAVE, "saved4", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
126 cvar_t savedgamecfg = {CVAR_SAVE, "savedgamecfg", "0", "unused cvar in quake that is saved to config.cfg on exit, can be used by mods"};
127 cvar_t scratch1 = {0, "scratch1", "0", "unused cvar in quake, can be used by mods"};
128 cvar_t scratch2 = {0,"scratch2", "0", "unused cvar in quake, can be used by mods"};
129 cvar_t scratch3 = {0, "scratch3", "0", "unused cvar in quake, can be used by mods"};
130 cvar_t scratch4 = {0, "scratch4", "0", "unused cvar in quake, can be used by mods"};
131 cvar_t temp1 = {0, "temp1","0", "general cvar for mods to use, in stock id1 this selects which death animation to use on players (0 = random death, other values select specific death scenes)"};
132
133 cvar_t nehx00 = {0, "nehx00", "0", "nehahra data storage cvar (used in singleplayer)"};
134 cvar_t nehx01 = {0, "nehx01", "0", "nehahra data storage cvar (used in singleplayer)"};
135 cvar_t nehx02 = {0, "nehx02", "0", "nehahra data storage cvar (used in singleplayer)"};
136 cvar_t nehx03 = {0, "nehx03", "0", "nehahra data storage cvar (used in singleplayer)"};
137 cvar_t nehx04 = {0, "nehx04", "0", "nehahra data storage cvar (used in singleplayer)"};
138 cvar_t nehx05 = {0, "nehx05", "0", "nehahra data storage cvar (used in singleplayer)"};
139 cvar_t nehx06 = {0, "nehx06", "0", "nehahra data storage cvar (used in singleplayer)"};
140 cvar_t nehx07 = {0, "nehx07", "0", "nehahra data storage cvar (used in singleplayer)"};
141 cvar_t nehx08 = {0, "nehx08", "0", "nehahra data storage cvar (used in singleplayer)"};
142 cvar_t nehx09 = {0, "nehx09", "0", "nehahra data storage cvar (used in singleplayer)"};
143 cvar_t nehx10 = {0, "nehx10", "0", "nehahra data storage cvar (used in singleplayer)"};
144 cvar_t nehx11 = {0, "nehx11", "0", "nehahra data storage cvar (used in singleplayer)"};
145 cvar_t nehx12 = {0, "nehx12", "0", "nehahra data storage cvar (used in singleplayer)"};
146 cvar_t nehx13 = {0, "nehx13", "0", "nehahra data storage cvar (used in singleplayer)"};
147 cvar_t nehx14 = {0, "nehx14", "0", "nehahra data storage cvar (used in singleplayer)"};
148 cvar_t nehx15 = {0, "nehx15", "0", "nehahra data storage cvar (used in singleplayer)"};
149 cvar_t nehx16 = {0, "nehx16", "0", "nehahra data storage cvar (used in singleplayer)"};
150 cvar_t nehx17 = {0, "nehx17", "0", "nehahra data storage cvar (used in singleplayer)"};
151 cvar_t nehx18 = {0, "nehx18", "0", "nehahra data storage cvar (used in singleplayer)"};
152 cvar_t nehx19 = {0, "nehx19", "0", "nehahra data storage cvar (used in singleplayer)"};
153 cvar_t cutscene = {0, "cutscene", "1", "enables cutscenes in nehahra, can be used by other mods"};
154
155 cvar_t sv_autodemo_perclient = {CVAR_SAVE, "sv_autodemo_perclient", "0", "set to 1 to enable autorecorded per-client demos (they'll start to record at the beginning of a match); set it to 2 to also record client->server packets (for debugging)"};
156 cvar_t sv_autodemo_perclient_nameformat = {CVAR_SAVE, "sv_autodemo_perclient_nameformat", "sv_autodemos/%Y-%m-%d_%H-%M", "The format of the sv_autodemo_perclient filename, followed by the map name, the client number and the IP address + port number, separated by underscores" };
157
158
159 server_t sv;
160 server_static_t svs;
161
162 mempool_t *sv_mempool = NULL;
163
164 extern cvar_t slowmo;
165 extern float            scr_centertime_off;
166
167 // MUST match effectnameindex_t in client.h
168 static const char *standardeffectnames[EFFECT_TOTAL] =
169 {
170         "",
171         "TE_GUNSHOT",
172         "TE_GUNSHOTQUAD",
173         "TE_SPIKE",
174         "TE_SPIKEQUAD",
175         "TE_SUPERSPIKE",
176         "TE_SUPERSPIKEQUAD",
177         "TE_WIZSPIKE",
178         "TE_KNIGHTSPIKE",
179         "TE_EXPLOSION",
180         "TE_EXPLOSIONQUAD",
181         "TE_TAREXPLOSION",
182         "TE_TELEPORT",
183         "TE_LAVASPLASH",
184         "TE_SMALLFLASH",
185         "TE_FLAMEJET",
186         "EF_FLAME",
187         "TE_BLOOD",
188         "TE_SPARK",
189         "TE_PLASMABURN",
190         "TE_TEI_G3",
191         "TE_TEI_SMOKE",
192         "TE_TEI_BIGEXPLOSION",
193         "TE_TEI_PLASMAHIT",
194         "EF_STARDUST",
195         "TR_ROCKET",
196         "TR_GRENADE",
197         "TR_BLOOD",
198         "TR_WIZSPIKE",
199         "TR_SLIGHTBLOOD",
200         "TR_KNIGHTSPIKE",
201         "TR_VORESPIKE",
202         "TR_NEHAHRASMOKE",
203         "TR_NEXUIZPLASMA",
204         "TR_GLOWTRAIL",
205         "SVC_PARTICLE"
206 };
207
208 #define REQFIELDS (sizeof(reqfields) / sizeof(prvm_required_field_t))
209
210 prvm_required_field_t reqfields[] =
211 {
212         {ev_entity, "cursor_trace_ent"},
213         {ev_entity, "drawonlytoclient"},
214         {ev_entity, "exteriormodeltoclient"},
215         {ev_entity, "nodrawtoclient"},
216         {ev_entity, "tag_entity"},
217         {ev_entity, "viewmodelforclient"},
218         {ev_float, "Version"},
219         {ev_float, "alpha"},
220         {ev_float, "ammo_cells1"},
221         {ev_float, "ammo_lava_nails"},
222         {ev_float, "ammo_multi_rockets"},
223         {ev_float, "ammo_nails1"},
224         {ev_float, "ammo_plasma"},
225         {ev_float, "ammo_rockets1"},
226         {ev_float, "ammo_shells1"},
227         {ev_float, "button3"},
228         {ev_float, "button4"},
229         {ev_float, "button5"},
230         {ev_float, "button6"},
231         {ev_float, "button7"},
232         {ev_float, "button8"},
233         {ev_float, "button9"},
234         {ev_float, "button10"},
235         {ev_float, "button11"},
236         {ev_float, "button12"},
237         {ev_float, "button13"},
238         {ev_float, "button14"},
239         {ev_float, "button15"},
240         {ev_float, "button16"},
241         {ev_float, "buttonchat"},
242         {ev_float, "buttonuse"},
243         {ev_float, "clientcolors"},
244         {ev_float, "cursor_active"},
245         {ev_float, "disableclientprediction"},
246         {ev_float, "fullbright"},
247         {ev_float, "glow_color"},
248         {ev_float, "glow_size"},
249         {ev_float, "glow_trail"},
250         {ev_float, "gravity"},
251         {ev_float, "idealpitch"},
252         {ev_float, "items2"},
253         {ev_float, "light_lev"},
254         {ev_float, "modelflags"},
255         {ev_float, "pflags"},
256         {ev_float, "ping"},
257         {ev_float, "pitch_speed"},
258         {ev_float, "pmodel"},
259         {ev_float, "renderamt"}, // HalfLife support
260         {ev_float, "rendermode"}, // HalfLife support
261         {ev_float, "scale"},
262         {ev_float, "style"},
263         {ev_float, "tag_index"},
264         {ev_float, "viewzoom"},
265         {ev_function, "SendEntity"},
266         {ev_function, "contentstransition"}, // DRESK - Support for Entity Contents Transition Event
267         {ev_function, "customizeentityforclient"},
268         {ev_function, "movetypesteplandevent"}, // DRESK - Support for MOVETYPE_STEP Entity Land Event
269         {ev_string, "netaddress"},
270         {ev_string, "playermodel"},
271         {ev_string, "playerskin"},
272         {ev_vector, "color"},
273         {ev_vector, "colormod"},
274         {ev_vector, "cursor_screen"},
275         {ev_vector, "cursor_trace_endpos"},
276         {ev_vector, "cursor_trace_start"},
277         {ev_vector, "movement"},
278         {ev_vector, "punchvector"},
279 };
280
281
282
283 //============================================================================
284
285 void SV_AreaStats_f(void)
286 {
287         World_PrintAreaStats(&sv.world, "server");
288 }
289
290 /*
291 ===============
292 SV_Init
293 ===============
294 */
295 void SV_Init (void)
296 {
297         // init the csqc progs cvars, since they are updated/used by the server code
298         // TODO: fix this since this is a quick hack to make some of [515]'s broken code run ;) [9/13/2006 Black]
299         extern cvar_t csqc_progname;    //[515]: csqc crc check and right csprogs name according to progs.dat
300         extern cvar_t csqc_progcrc;
301         extern cvar_t csqc_progsize;
302         Cvar_RegisterVariable (&csqc_progname);
303         Cvar_RegisterVariable (&csqc_progcrc);
304         Cvar_RegisterVariable (&csqc_progsize);
305
306         Cmd_AddCommand("sv_saveentfile", SV_SaveEntFile_f, "save map entities to .ent file (to allow external editing)");
307         Cmd_AddCommand("sv_areastats", SV_AreaStats_f, "prints statistics on entity culling during collision traces");
308         Cmd_AddCommand_WithClientCommand("sv_startdownload", NULL, SV_StartDownload_f, "begins sending a file to the client (network protocol use only)");
309         Cmd_AddCommand_WithClientCommand("download", NULL, SV_Download_f, "downloads a specified file from the server");
310
311         Cvar_RegisterVariable (&coop);
312         Cvar_RegisterVariable (&deathmatch);
313         Cvar_RegisterVariable (&fraglimit);
314         Cvar_RegisterVariable (&gamecfg);
315         Cvar_RegisterVariable (&noexit);
316         Cvar_RegisterVariable (&nomonsters);
317         Cvar_RegisterVariable (&pausable);
318         Cvar_RegisterVariable (&pr_checkextension);
319         Cvar_RegisterVariable (&samelevel);
320         Cvar_RegisterVariable (&skill);
321         Cvar_RegisterVariable (&slowmo);
322         Cvar_RegisterVariable (&sv_accelerate);
323         Cvar_RegisterVariable (&sv_aim);
324         Cvar_RegisterVariable (&sv_airaccel_qw);
325         Cvar_RegisterVariable (&sv_airaccel_sideways_friction);
326         Cvar_RegisterVariable (&sv_airaccelerate);
327         Cvar_RegisterVariable (&sv_allowdownloads);
328         Cvar_RegisterVariable (&sv_allowdownloads_archive);
329         Cvar_RegisterVariable (&sv_allowdownloads_config);
330         Cvar_RegisterVariable (&sv_allowdownloads_dlcache);
331         Cvar_RegisterVariable (&sv_allowdownloads_inarchive);
332         Cvar_RegisterVariable (&sv_areagrid_mingridsize);
333         Cvar_RegisterVariable (&sv_checkforpacketsduringsleep);
334         Cvar_RegisterVariable (&sv_clmovement_enable);
335         Cvar_RegisterVariable (&sv_clmovement_minping);
336         Cvar_RegisterVariable (&sv_clmovement_minping_disabletime);
337         Cvar_RegisterVariable (&sv_clmovement_waitforinput);
338         Cvar_RegisterVariable (&sv_cullentities_nevercullbmodels);
339         Cvar_RegisterVariable (&sv_cullentities_pvs);
340         Cvar_RegisterVariable (&sv_cullentities_stats);
341         Cvar_RegisterVariable (&sv_cullentities_trace);
342         Cvar_RegisterVariable (&sv_cullentities_trace_delay);
343         Cvar_RegisterVariable (&sv_cullentities_trace_delay_players);
344         Cvar_RegisterVariable (&sv_cullentities_trace_enlarge);
345         Cvar_RegisterVariable (&sv_cullentities_trace_prediction);
346         Cvar_RegisterVariable (&sv_cullentities_trace_samples);
347         Cvar_RegisterVariable (&sv_cullentities_trace_samples_extra);
348         Cvar_RegisterVariable (&sv_cullentities_trace_samples_players);
349         Cvar_RegisterVariable (&sv_debugmove);
350         Cvar_RegisterVariable (&sv_echobprint);
351         Cvar_RegisterVariable (&sv_edgefriction);
352         Cvar_RegisterVariable (&sv_entpatch);
353         Cvar_RegisterVariable (&sv_fixedframeratesingleplayer);
354         Cvar_RegisterVariable (&sv_freezenonclients);
355         Cvar_RegisterVariable (&sv_friction);
356         Cvar_RegisterVariable (&sv_gameplayfix_blowupfallenzombies);
357         Cvar_RegisterVariable (&sv_gameplayfix_delayprojectiles);
358         Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid);
359         Cvar_RegisterVariable (&sv_gameplayfix_droptofloorstartsolid_nudgetocorrect);
360         Cvar_RegisterVariable (&sv_gameplayfix_easierwaterjump);
361         Cvar_RegisterVariable (&sv_gameplayfix_findradiusdistancetobox);
362         Cvar_RegisterVariable (&sv_gameplayfix_grenadebouncedownslopes);
363         Cvar_RegisterVariable (&sv_gameplayfix_multiplethinksperframe);
364         Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
365         Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
366         Cvar_RegisterVariable (&sv_gameplayfix_stepdown);
367         Cvar_RegisterVariable (&sv_gameplayfix_stepwhilejumping);
368         Cvar_RegisterVariable (&sv_gameplayfix_swiminbmodels);
369         Cvar_RegisterVariable (&sv_gameplayfix_upwardvelocityclearsongroundflag);
370         Cvar_RegisterVariable (&sv_gravity);
371         Cvar_RegisterVariable (&sv_idealpitchscale);
372         Cvar_RegisterVariable (&sv_jumpstep);
373         Cvar_RegisterVariable (&sv_jumpvelocity);
374         Cvar_RegisterVariable (&sv_maxairspeed);
375         Cvar_RegisterVariable (&sv_maxrate);
376         Cvar_RegisterVariable (&sv_maxspeed);
377         Cvar_RegisterVariable (&sv_maxvelocity);
378         Cvar_RegisterVariable (&sv_newflymove);
379         Cvar_RegisterVariable (&sv_nostep);
380         Cvar_RegisterVariable (&sv_playerphysicsqc);
381         Cvar_RegisterVariable (&sv_progs);
382         Cvar_RegisterVariable (&sv_protocolname);
383         Cvar_RegisterVariable (&sv_random_seed);
384         Cvar_RegisterVariable (&sv_ratelimitlocalplayer);
385         Cvar_RegisterVariable (&sv_sound_land);
386         Cvar_RegisterVariable (&sv_sound_watersplash);
387         Cvar_RegisterVariable (&sv_stepheight);
388         Cvar_RegisterVariable (&sv_stopspeed);
389         Cvar_RegisterVariable (&sv_wallfriction);
390         Cvar_RegisterVariable (&sv_wateraccelerate);
391         Cvar_RegisterVariable (&sv_waterfriction);
392         Cvar_RegisterVariable (&sys_ticrate);
393         Cvar_RegisterVariable (&teamplay);
394         Cvar_RegisterVariable (&timelimit);
395
396         Cvar_RegisterVariable (&saved1);
397         Cvar_RegisterVariable (&saved2);
398         Cvar_RegisterVariable (&saved3);
399         Cvar_RegisterVariable (&saved4);
400         Cvar_RegisterVariable (&savedgamecfg);
401         Cvar_RegisterVariable (&scratch1);
402         Cvar_RegisterVariable (&scratch2);
403         Cvar_RegisterVariable (&scratch3);
404         Cvar_RegisterVariable (&scratch4);
405         Cvar_RegisterVariable (&temp1);
406
407         // LordHavoc: Nehahra uses these to pass data around cutscene demos
408         if (gamemode == GAME_NEHAHRA)
409         {
410                 Cvar_RegisterVariable (&nehx00);
411                 Cvar_RegisterVariable (&nehx01);
412                 Cvar_RegisterVariable (&nehx02);
413                 Cvar_RegisterVariable (&nehx03);
414                 Cvar_RegisterVariable (&nehx04);
415                 Cvar_RegisterVariable (&nehx05);
416                 Cvar_RegisterVariable (&nehx06);
417                 Cvar_RegisterVariable (&nehx07);
418                 Cvar_RegisterVariable (&nehx08);
419                 Cvar_RegisterVariable (&nehx09);
420                 Cvar_RegisterVariable (&nehx10);
421                 Cvar_RegisterVariable (&nehx11);
422                 Cvar_RegisterVariable (&nehx12);
423                 Cvar_RegisterVariable (&nehx13);
424                 Cvar_RegisterVariable (&nehx14);
425                 Cvar_RegisterVariable (&nehx15);
426                 Cvar_RegisterVariable (&nehx16);
427                 Cvar_RegisterVariable (&nehx17);
428                 Cvar_RegisterVariable (&nehx18);
429                 Cvar_RegisterVariable (&nehx19);
430         }
431         Cvar_RegisterVariable (&cutscene); // for Nehahra but useful to other mods as well
432
433         Cvar_RegisterVariable (&sv_autodemo_perclient);
434         Cvar_RegisterVariable (&sv_autodemo_perclient_nameformat);
435
436         // any special defaults for gamemodes go here
437         if (gamemode == GAME_HIPNOTIC)
438         {
439                 // hipnotic mission pack has issues in their 'friendly monster' ai, which seem to attempt to attack themselves for some reason when findradius() returns non-solid entities.
440                 Cvar_SetValueQuick (&sv_gameplayfix_blowupfallenzombies, 0);
441                 // hipnotic mission pack has issues with bobbing water entities 'jittering' between different heights on alternate frames at the default 0.0138889 ticrate, 0.02 avoids this issue
442                 Cvar_SetValueQuick (&sys_ticrate, 0.02);
443         }
444         if (gamemode == GAME_ROGUE)
445         {
446                 // rogue mission pack has a guardian boss that does not wake up if findradius returns one of the entities around its spawn area
447                 Cvar_SetValueQuick (&sv_gameplayfix_findradiusdistancetobox, 0);
448         }
449
450         sv_mempool = Mem_AllocPool("server", 0, NULL);
451 }
452
453 static void SV_SaveEntFile_f(void)
454 {
455         char basename[MAX_QPATH];
456         if (!sv.active || !sv.worldmodel)
457         {
458                 Con_Print("Not running a server\n");
459                 return;
460         }
461         FS_StripExtension(sv.worldmodel->name, basename, sizeof(basename));
462         FS_WriteFile(va("%s.ent", basename), sv.worldmodel->brush.entities, (fs_offset_t)strlen(sv.worldmodel->brush.entities));
463 }
464
465
466 /*
467 =============================================================================
468
469 EVENT MESSAGES
470
471 =============================================================================
472 */
473
474 /*
475 ==================
476 SV_StartParticle
477
478 Make sure the event gets sent to all clients
479 ==================
480 */
481 void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)
482 {
483         int i;
484
485         if (sv.datagram.cursize > MAX_PACKETFRAGMENT-18)
486                 return;
487         MSG_WriteByte (&sv.datagram, svc_particle);
488         MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
489         MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
490         MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
491         for (i=0 ; i<3 ; i++)
492                 MSG_WriteChar (&sv.datagram, (int)bound(-128, dir[i]*16, 127));
493         MSG_WriteByte (&sv.datagram, count);
494         MSG_WriteByte (&sv.datagram, color);
495         SV_FlushBroadcastMessages();
496 }
497
498 /*
499 ==================
500 SV_StartEffect
501
502 Make sure the event gets sent to all clients
503 ==================
504 */
505 void SV_StartEffect (vec3_t org, int modelindex, int startframe, int framecount, int framerate)
506 {
507         if (modelindex >= 256 || startframe >= 256)
508         {
509                 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-19)
510                         return;
511                 MSG_WriteByte (&sv.datagram, svc_effect2);
512                 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
513                 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
514                 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
515                 MSG_WriteShort (&sv.datagram, modelindex);
516                 MSG_WriteShort (&sv.datagram, startframe);
517                 MSG_WriteByte (&sv.datagram, framecount);
518                 MSG_WriteByte (&sv.datagram, framerate);
519         }
520         else
521         {
522                 if (sv.datagram.cursize > MAX_PACKETFRAGMENT-17)
523                         return;
524                 MSG_WriteByte (&sv.datagram, svc_effect);
525                 MSG_WriteCoord (&sv.datagram, org[0], sv.protocol);
526                 MSG_WriteCoord (&sv.datagram, org[1], sv.protocol);
527                 MSG_WriteCoord (&sv.datagram, org[2], sv.protocol);
528                 MSG_WriteByte (&sv.datagram, modelindex);
529                 MSG_WriteByte (&sv.datagram, startframe);
530                 MSG_WriteByte (&sv.datagram, framecount);
531                 MSG_WriteByte (&sv.datagram, framerate);
532         }
533         SV_FlushBroadcastMessages();
534 }
535
536 /*
537 ==================
538 SV_StartSound
539
540 Each entity can have eight independant sound sources, like voice,
541 weapon, feet, etc.
542
543 Channel 0 is an auto-allocate channel, the others override anything
544 already running on that entity/channel pair.
545
546 An attenuation of 0 will play full volume everywhere in the level.
547 Larger attenuations will drop off.  (max 4 attenuation)
548
549 ==================
550 */
551 void SV_StartSound (prvm_edict_t *entity, int channel, const char *sample, int volume, float attenuation)
552 {
553         int sound_num, field_mask, i, ent;
554
555         if (volume < 0 || volume > 255)
556         {
557                 Con_Printf ("SV_StartSound: volume = %i\n", volume);
558                 return;
559         }
560
561         if (attenuation < 0 || attenuation > 4)
562         {
563                 Con_Printf ("SV_StartSound: attenuation = %f\n", attenuation);
564                 return;
565         }
566
567         if (channel < 0 || channel > 7)
568         {
569                 Con_Printf ("SV_StartSound: channel = %i\n", channel);
570                 return;
571         }
572
573         if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
574                 return;
575
576 // find precache number for sound
577         sound_num = SV_SoundIndex(sample, 1);
578         if (!sound_num)
579                 return;
580
581         ent = PRVM_NUM_FOR_EDICT(entity);
582
583         field_mask = 0;
584         if (volume != DEFAULT_SOUND_PACKET_VOLUME)
585                 field_mask |= SND_VOLUME;
586         if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
587                 field_mask |= SND_ATTENUATION;
588         if (ent >= 8192)
589                 field_mask |= SND_LARGEENTITY;
590         if (sound_num >= 256 || channel >= 8)
591                 field_mask |= SND_LARGESOUND;
592
593 // directed messages go only to the entity they are targeted on
594         MSG_WriteByte (&sv.datagram, svc_sound);
595         MSG_WriteByte (&sv.datagram, field_mask);
596         if (field_mask & SND_VOLUME)
597                 MSG_WriteByte (&sv.datagram, volume);
598         if (field_mask & SND_ATTENUATION)
599                 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
600         if (field_mask & SND_LARGEENTITY)
601         {
602                 MSG_WriteShort (&sv.datagram, ent);
603                 MSG_WriteByte (&sv.datagram, channel);
604         }
605         else
606                 MSG_WriteShort (&sv.datagram, (ent<<3) | channel);
607         if ((field_mask & SND_LARGESOUND) || sv.protocol == PROTOCOL_NEHAHRABJP2)
608                 MSG_WriteShort (&sv.datagram, sound_num);
609         else
610                 MSG_WriteByte (&sv.datagram, sound_num);
611         for (i = 0;i < 3;i++)
612                 MSG_WriteCoord (&sv.datagram, entity->fields.server->origin[i]+0.5*(entity->fields.server->mins[i]+entity->fields.server->maxs[i]), sv.protocol);
613         SV_FlushBroadcastMessages();
614 }
615
616 /*
617 ==================
618 SV_StartPointSound
619
620 Nearly the same logic as SV_StartSound, except an origin
621 instead of an entity is provided and channel is omitted.
622
623 The entity sent to the client is 0 (world) and the channel
624 is 0 (CHAN_AUTO).  SND_LARGEENTITY will never occur in this
625 function, therefore the check for it is omitted.
626
627 ==================
628 */
629 void SV_StartPointSound (vec3_t origin, const char *sample, int volume, float attenuation)
630 {
631         int sound_num, field_mask, i;
632
633         if (volume < 0 || volume > 255)
634         {
635                 Con_Printf ("SV_StartPointSound: volume = %i\n", volume);
636                 return;
637         }
638
639         if (attenuation < 0 || attenuation > 4)
640         {
641                 Con_Printf ("SV_StartPointSound: attenuation = %f\n", attenuation);
642                 return;
643         }
644
645         if (sv.datagram.cursize > MAX_PACKETFRAGMENT-21)
646                 return;
647
648         // find precache number for sound
649         sound_num = SV_SoundIndex(sample, 1);
650         if (!sound_num)
651                 return;
652
653         field_mask = 0;
654         if (volume != DEFAULT_SOUND_PACKET_VOLUME)
655                 field_mask |= SND_VOLUME;
656         if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)
657                 field_mask |= SND_ATTENUATION;
658         if (sound_num >= 256)
659                 field_mask |= SND_LARGESOUND;
660
661 // directed messages go only to the entity they are targeted on
662         MSG_WriteByte (&sv.datagram, svc_sound);
663         MSG_WriteByte (&sv.datagram, field_mask);
664         if (field_mask & SND_VOLUME)
665                 MSG_WriteByte (&sv.datagram, volume);
666         if (field_mask & SND_ATTENUATION)
667                 MSG_WriteByte (&sv.datagram, (int)(attenuation*64));
668         // Always write entnum 0 for the world entity
669         MSG_WriteShort (&sv.datagram, (0<<3) | 0);
670         if (field_mask & SND_LARGESOUND)
671                 MSG_WriteShort (&sv.datagram, sound_num);
672         else
673                 MSG_WriteByte (&sv.datagram, sound_num);
674         for (i = 0;i < 3;i++)
675                 MSG_WriteCoord (&sv.datagram, origin[i], sv.protocol);
676         SV_FlushBroadcastMessages();
677 }
678
679 /*
680 ==============================================================================
681
682 CLIENT SPAWNING
683
684 ==============================================================================
685 */
686
687 /*
688 ================
689 SV_SendServerinfo
690
691 Sends the first message from the server to a connected client.
692 This will be sent on the initial connection and upon each server load.
693 ================
694 */
695 void SV_SendServerinfo (client_t *client)
696 {
697         int i;
698         char message[128];
699
700         // we know that this client has a netconnection and thus is not a bot
701
702         // edicts get reallocated on level changes, so we need to update it here
703         client->edict = PRVM_EDICT_NUM((client - svs.clients) + 1);
704
705         // clear cached stuff that depends on the level
706         client->weaponmodel[0] = 0;
707         client->weaponmodelindex = 0;
708
709         // LordHavoc: clear entityframe tracking
710         client->latestframenum = 0;
711
712         // initialize the movetime, so a speedhack can't make use of the time before this client joined
713         client->cmd.time = sv.time;
714
715         if (client->entitydatabase)
716                 EntityFrame_FreeDatabase(client->entitydatabase);
717         if (client->entitydatabase4)
718                 EntityFrame4_FreeDatabase(client->entitydatabase4);
719         if (client->entitydatabase5)
720                 EntityFrame5_FreeDatabase(client->entitydatabase5);
721
722         memset(client->stats, 0, sizeof(client->stats));
723         memset(client->statsdeltabits, 0, sizeof(client->statsdeltabits));
724
725         if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3)
726         {
727                 if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3)
728                         client->entitydatabase = EntityFrame_AllocDatabase(sv_mempool);
729                 else if (sv.protocol == PROTOCOL_DARKPLACES4)
730                         client->entitydatabase4 = EntityFrame4_AllocDatabase(sv_mempool);
731                 else
732                         client->entitydatabase5 = EntityFrame5_AllocDatabase(sv_mempool);
733         }
734
735         // reset csqc entity versions
736         memset(client->csqcentityversion, 0, sizeof(client->csqcentityversion));
737
738         SZ_Clear (&client->netconnection->message);
739         MSG_WriteByte (&client->netconnection->message, svc_print);
740         dpsnprintf (message, sizeof (message), "\nServer: %s build %s (progs %i crc)", gamename, buildstring, prog->filecrc);
741         MSG_WriteString (&client->netconnection->message,message);
742
743         SV_StopDemoRecording(client); // to split up demos into different files
744         if(sv_autodemo_perclient.integer && client->netconnection)
745         {
746                 char demofile[MAX_OSPATH];
747                 char levelname[MAX_QPATH];
748                 char ipaddress[MAX_QPATH];
749                 size_t i;
750
751                 // start a new demo file
752                 strlcpy(levelname, FS_FileWithoutPath(sv.worldmodel->name), sizeof(levelname));
753                 if (strrchr(levelname, '.'))
754                         *(strrchr(levelname, '.')) = 0;
755
756                 LHNETADDRESS_ToString(&(client->netconnection->peeraddress), ipaddress, sizeof(ipaddress), true);
757                 for(i = 0; ipaddress[i]; ++i)
758                         if(!isalnum(ipaddress[i]))
759                                 ipaddress[i] = '-';
760                 dpsnprintf (demofile, sizeof(demofile), "%s_%s_%d_%s.dem", Sys_TimeString (sv_autodemo_perclient_nameformat.string), levelname, PRVM_NUM_FOR_EDICT(client->edict), ipaddress);
761
762                 SV_StartDemoRecording(client, demofile, -1);
763         }
764
765         //[515]: init csprogs according to version of svprogs, check the crc, etc.
766         if (sv.csqc_progname[0])
767         {
768                 prvm_eval_t *val;
769                 Con_DPrintf("sending csqc info to client (\"%s\" with size %i and crc %i)\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
770                 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
771                 MSG_WriteString (&client->netconnection->message, va("csqc_progname %s\n", sv.csqc_progname));
772                 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
773                 MSG_WriteString (&client->netconnection->message, va("csqc_progsize %i\n", sv.csqc_progsize));
774                 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
775                 MSG_WriteString (&client->netconnection->message, va("csqc_progcrc %i\n", sv.csqc_progcrc));
776
777                 if(client->sv_demo_file != NULL)
778                 {
779                         void *csqcbuf;
780                         fs_offset_t csqclen;
781                         int csqccrc;
782                         int i;
783                         char buf[NET_MAXMESSAGE];
784                         sizebuf_t sb;
785
786                         csqcbuf = FS_LoadFile(sv.csqc_progname, tempmempool, true, &csqclen);
787                         if(csqcbuf)
788                         {
789                                 csqccrc = CRC_Block(csqcbuf, csqclen);
790                                 sb.data = (void *) buf;
791                                 sb.maxsize = sizeof(buf);
792                                 i = 0;
793                                 while(MakeDownloadPacket(sv.csqc_progname, csqcbuf, csqclen, csqccrc, i++, &sb, sv.protocol))
794                                         SV_WriteDemoMessage(client, &sb, false);
795                                 Mem_Free(csqcbuf);
796                         }
797                 }
798
799                 //[515]: init stufftext string (it is sent before svc_serverinfo)
800                 val = PRVM_GLOBALFIELDVALUE(prog->globaloffsets.SV_InitCmd);
801                 if (val)
802                 {
803                         MSG_WriteByte (&client->netconnection->message, svc_stufftext);
804                         MSG_WriteString (&client->netconnection->message, va("%s\n", PRVM_GetString(val->string)));
805                 }
806         }
807
808         if (sv_allowdownloads.integer)
809         {
810                 MSG_WriteByte (&client->netconnection->message, svc_stufftext);
811                 MSG_WriteString (&client->netconnection->message, "cl_serverextension_download 1\n");
812         }
813
814         // send at this time so it's guaranteed to get executed at the right time
815         {
816                 client_t *save;
817                 save = host_client;
818                 host_client = client;
819                 Curl_SendRequirements();
820                 host_client = save;
821         }
822
823         MSG_WriteByte (&client->netconnection->message, svc_serverinfo);
824         MSG_WriteLong (&client->netconnection->message, Protocol_NumberForEnum(sv.protocol));
825         MSG_WriteByte (&client->netconnection->message, svs.maxclients);
826
827         if (!coop.integer && deathmatch.integer)
828                 MSG_WriteByte (&client->netconnection->message, GAME_DEATHMATCH);
829         else
830                 MSG_WriteByte (&client->netconnection->message, GAME_COOP);
831
832         MSG_WriteString (&client->netconnection->message,PRVM_GetString(prog->edicts->fields.server->message));
833
834         for (i = 1;i < MAX_MODELS && sv.model_precache[i][0];i++)
835                 MSG_WriteString (&client->netconnection->message, sv.model_precache[i]);
836         MSG_WriteByte (&client->netconnection->message, 0);
837
838         for (i = 1;i < MAX_SOUNDS && sv.sound_precache[i][0];i++)
839                 MSG_WriteString (&client->netconnection->message, sv.sound_precache[i]);
840         MSG_WriteByte (&client->netconnection->message, 0);
841
842 // send music
843         MSG_WriteByte (&client->netconnection->message, svc_cdtrack);
844         MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
845         MSG_WriteByte (&client->netconnection->message, (int)prog->edicts->fields.server->sounds);
846
847 // set view
848 // store this in clientcamera, too
849         client->clientcamera = PRVM_NUM_FOR_EDICT(client->edict);
850         MSG_WriteByte (&client->netconnection->message, svc_setview);
851         MSG_WriteShort (&client->netconnection->message, client->clientcamera);
852
853         MSG_WriteByte (&client->netconnection->message, svc_signonnum);
854         MSG_WriteByte (&client->netconnection->message, 1);
855
856         client->spawned = false;                // need prespawn, spawn, etc
857         client->sendsignon = 1;                 // send this message, and increment to 2, 2 will be set to 0 by the prespawn command
858
859         // clear movement info until client enters the new level properly
860         memset(&client->cmd, 0, sizeof(client->cmd));
861         client->movesequence = 0;
862 #ifdef NUM_PING_TIMES
863         for (i = 0;i < NUM_PING_TIMES;i++)
864                 client->ping_times[i] = 0;
865         client->num_pings = 0;
866 #endif
867         client->ping = 0;
868 }
869
870 /*
871 ================
872 SV_ConnectClient
873
874 Initializes a client_t for a new net connection.  This will only be called
875 once for a player each game, not once for each level change.
876 ================
877 */
878 void SV_ConnectClient (int clientnum, netconn_t *netconnection)
879 {
880         client_t                *client;
881         int                             i;
882         float                   spawn_parms[NUM_SPAWN_PARMS];
883
884         client = svs.clients + clientnum;
885
886 // set up the client_t
887         if (sv.loadgame)
888                 memcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));
889         memset (client, 0, sizeof(*client));
890         client->active = true;
891         client->netconnection = netconnection;
892
893         Con_DPrintf("Client %s connected\n", client->netconnection ? client->netconnection->address : "botclient");
894
895         strlcpy(client->name, "unconnected", sizeof(client->name));
896         strlcpy(client->old_name, "unconnected", sizeof(client->old_name));
897         client->spawned = false;
898         client->edict = PRVM_EDICT_NUM(clientnum+1);
899         if (client->netconnection)
900                 client->netconnection->message.allowoverflow = true;            // we can catch it
901         // prepare the unreliable message buffer
902         client->unreliablemsg.data = client->unreliablemsg_data;
903         client->unreliablemsg.maxsize = sizeof(client->unreliablemsg_data);
904         // updated by receiving "rate" command from client, this is also the default if not using a DP client
905         client->rate = 1000000000;
906         // no limits for local player
907         if (client->netconnection && LHNETADDRESS_GetAddressType(&client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP)
908                 client->rate = 1000000000;
909         client->connecttime = realtime;
910
911         if (sv.loadgame)
912                 memcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));
913         else
914         {
915                 // call the progs to get default spawn parms for the new client
916                 // set self to world to intentionally cause errors with broken SetNewParms code in some mods
917                 prog->globals.server->self = 0;
918                 PRVM_ExecuteProgram (prog->globals.server->SetNewParms, "QC function SetNewParms is missing");
919                 for (i=0 ; i<NUM_SPAWN_PARMS ; i++)
920                         client->spawn_parms[i] = (&prog->globals.server->parm1)[i];
921
922                 // set up the entity for this client (including .colormap, .team, etc)
923                 PRVM_ED_ClearEdict(client->edict);
924         }
925
926         // don't call SendServerinfo for a fresh botclient because its fields have
927         // not been set up by the qc yet
928         if (client->netconnection)
929                 SV_SendServerinfo (client);
930         else
931                 client->spawned = true;
932 }
933
934
935 /*
936 ===============================================================================
937
938 FRAME UPDATES
939
940 ===============================================================================
941 */
942
943 /*
944 =============================================================================
945
946 The PVS must include a small area around the client to allow head bobbing
947 or other small motion on the client side.  Otherwise, a bob might cause an
948 entity that should be visible to not show up, especially when the bob
949 crosses a waterline.
950
951 =============================================================================
952 */
953
954 static qboolean SV_PrepareEntityForSending (prvm_edict_t *ent, entity_state_t *cs, int enumber)
955 {
956         int i;
957         unsigned int modelindex, effects, flags, glowsize, lightstyle, lightpflags, light[4], specialvisibilityradius;
958         unsigned int customizeentityforclient;
959         float f;
960         vec3_t cullmins, cullmaxs;
961         dp_model_t *model;
962         prvm_eval_t *val;
963
964         // this 2 billion unit check is actually to detect NAN origins
965         // (we really don't want to send those)
966         if (!(VectorLength2(ent->fields.server->origin) < 2000000000.0*2000000000.0))
967                 return false;
968
969         // EF_NODRAW prevents sending for any reason except for your own
970         // client, so we must keep all clients in this superset
971         effects = (unsigned)ent->fields.server->effects;
972
973         // we can omit invisible entities with no effects that are not clients
974         // LordHavoc: this could kill tags attached to an invisible entity, I
975         // just hope we never have to support that case
976         i = (int)ent->fields.server->modelindex;
977         modelindex = (i >= 1 && i < MAX_MODELS && ent->fields.server->model && *PRVM_GetString(ent->fields.server->model)) ? i : 0;
978
979         flags = 0;
980         i = (int)(PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_size)->_float * 0.25f);
981         glowsize = (unsigned char)bound(0, i, 255);
982         if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_trail)->_float)
983                 flags |= RENDER_GLOWTRAIL;
984         if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)->edict)
985                 flags |= RENDER_VIEWMODEL;
986
987         f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[0]*256;
988         light[0] = (unsigned short)bound(0, f, 65535);
989         f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[1]*256;
990         light[1] = (unsigned short)bound(0, f, 65535);
991         f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.color)->vector[2]*256;
992         light[2] = (unsigned short)bound(0, f, 65535);
993         f = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.light_lev)->_float;
994         light[3] = (unsigned short)bound(0, f, 65535);
995         lightstyle = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.style)->_float;
996         lightpflags = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.pflags)->_float;
997
998         if (gamemode == GAME_TENEBRAE)
999         {
1000                 // tenebrae's EF_FULLDYNAMIC conflicts with Q2's EF_NODRAW
1001                 if (effects & 16)
1002                 {
1003                         effects &= ~16;
1004                         lightpflags |= PFLAGS_FULLDYNAMIC;
1005                 }
1006                 // tenebrae's EF_GREEN conflicts with DP's EF_ADDITIVE
1007                 if (effects & 32)
1008                 {
1009                         effects &= ~32;
1010                         light[0] = (int)(0.2*256);
1011                         light[1] = (int)(1.0*256);
1012                         light[2] = (int)(0.2*256);
1013                         light[3] = 200;
1014                         lightpflags |= PFLAGS_FULLDYNAMIC;
1015                 }
1016         }
1017
1018         specialvisibilityradius = 0;
1019         if (lightpflags & PFLAGS_FULLDYNAMIC)
1020                 specialvisibilityradius = max(specialvisibilityradius, light[3]);
1021         if (glowsize)
1022                 specialvisibilityradius = max(specialvisibilityradius, glowsize * 4);
1023         if (flags & RENDER_GLOWTRAIL)
1024                 specialvisibilityradius = max(specialvisibilityradius, 100);
1025         if (effects & (EF_BRIGHTFIELD | EF_MUZZLEFLASH | EF_BRIGHTLIGHT | EF_DIMLIGHT | EF_RED | EF_BLUE | EF_FLAME | EF_STARDUST))
1026         {
1027                 if (effects & EF_BRIGHTFIELD)
1028                         specialvisibilityradius = max(specialvisibilityradius, 80);
1029                 if (effects & EF_MUZZLEFLASH)
1030                         specialvisibilityradius = max(specialvisibilityradius, 100);
1031                 if (effects & EF_BRIGHTLIGHT)
1032                         specialvisibilityradius = max(specialvisibilityradius, 400);
1033                 if (effects & EF_DIMLIGHT)
1034                         specialvisibilityradius = max(specialvisibilityradius, 200);
1035                 if (effects & EF_RED)
1036                         specialvisibilityradius = max(specialvisibilityradius, 200);
1037                 if (effects & EF_BLUE)
1038                         specialvisibilityradius = max(specialvisibilityradius, 200);
1039                 if (effects & EF_FLAME)
1040                         specialvisibilityradius = max(specialvisibilityradius, 250);
1041                 if (effects & EF_STARDUST)
1042                         specialvisibilityradius = max(specialvisibilityradius, 100);
1043         }
1044
1045         // early culling checks
1046         // (final culling is done by SV_MarkWriteEntityStateToClient)
1047         customizeentityforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.customizeentityforclient)->function;
1048         if (!customizeentityforclient && enumber > svs.maxclients && (!modelindex && !specialvisibilityradius))
1049                 return false;
1050
1051         *cs = defaultstate;
1052         cs->active = true;
1053         cs->number = enumber;
1054         VectorCopy(ent->fields.server->origin, cs->origin);
1055         VectorCopy(ent->fields.server->angles, cs->angles);
1056         cs->flags = flags;
1057         cs->effects = effects;
1058         cs->colormap = (unsigned)ent->fields.server->colormap;
1059         cs->modelindex = modelindex;
1060         cs->skin = (unsigned)ent->fields.server->skin;
1061         cs->frame = (unsigned)ent->fields.server->frame;
1062         cs->viewmodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewmodelforclient)->edict;
1063         cs->exteriormodelforclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.exteriormodeltoclient)->edict;
1064         cs->nodrawtoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.nodrawtoclient)->edict;
1065         cs->drawonlytoclient = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.drawonlytoclient)->edict;
1066         cs->customizeentityforclient = customizeentityforclient;
1067         cs->tagentity = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_entity)->edict;
1068         cs->tagindex = (unsigned char)PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.tag_index)->_float;
1069         cs->glowsize = glowsize;
1070
1071         // don't need to init cs->colormod because the defaultstate did that for us
1072         //cs->colormod[0] = cs->colormod[1] = cs->colormod[2] = 32;
1073         val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.colormod);
1074         if (val->vector[0] || val->vector[1] || val->vector[2])
1075         {
1076                 i = (int)(val->vector[0] * 32.0f);cs->colormod[0] = bound(0, i, 255);
1077                 i = (int)(val->vector[1] * 32.0f);cs->colormod[1] = bound(0, i, 255);
1078                 i = (int)(val->vector[2] * 32.0f);cs->colormod[2] = bound(0, i, 255);
1079         }
1080
1081         cs->modelindex = modelindex;
1082
1083         cs->alpha = 255;
1084         f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.alpha)->_float * 255.0f);
1085         if (f)
1086         {
1087                 i = (int)f;
1088                 cs->alpha = (unsigned char)bound(0, i, 255);
1089         }
1090         // halflife
1091         f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.renderamt)->_float);
1092         if (f)
1093         {
1094                 i = (int)f;
1095                 cs->alpha = (unsigned char)bound(0, i, 255);
1096         }
1097
1098         cs->scale = 16;
1099         f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.scale)->_float * 16.0f);
1100         if (f)
1101         {
1102                 i = (int)f;
1103                 cs->scale = (unsigned char)bound(0, i, 255);
1104         }
1105
1106         cs->glowcolor = 254;
1107         f = (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.glow_color)->_float);
1108         if (f)
1109                 cs->glowcolor = (int)f;
1110
1111         if (PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.fullbright)->_float)
1112                 cs->effects |= EF_FULLBRIGHT;
1113
1114         val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.modelflags);
1115         if (val && val->_float)
1116                 cs->effects |= ((unsigned int)val->_float & 0xff) << 24;
1117
1118         if (ent->fields.server->movetype == MOVETYPE_STEP)
1119                 cs->flags |= RENDER_STEP;
1120         if (cs->number != sv.writeentitiestoclient_cliententitynumber && (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)
1121                 cs->flags |= RENDER_LOWPRECISION;
1122         if (ent->fields.server->colormap >= 1024)
1123                 cs->flags |= RENDER_COLORMAPPED;
1124         if (cs->viewmodelforclient)
1125                 cs->flags |= RENDER_VIEWMODEL; // show relative to the view
1126
1127         cs->light[0] = light[0];
1128         cs->light[1] = light[1];
1129         cs->light[2] = light[2];
1130         cs->light[3] = light[3];
1131         cs->lightstyle = lightstyle;
1132         cs->lightpflags = lightpflags;
1133
1134         cs->specialvisibilityradius = specialvisibilityradius;
1135
1136         // calculate the visible box of this entity (don't use the physics box
1137         // as that is often smaller than a model, and would not count
1138         // specialvisibilityradius)
1139         if ((model = sv.models[modelindex]))
1140         {
1141                 float scale = cs->scale * (1.0f / 16.0f);
1142                 if (cs->angles[0] || cs->angles[2]) // pitch and roll
1143                 {
1144                         VectorMA(cs->origin, scale, model->rotatedmins, cullmins);
1145                         VectorMA(cs->origin, scale, model->rotatedmaxs, cullmaxs);
1146                 }
1147                 else if (cs->angles[1])
1148                 {
1149                         VectorMA(cs->origin, scale, model->yawmins, cullmins);
1150                         VectorMA(cs->origin, scale, model->yawmaxs, cullmaxs);
1151                 }
1152                 else
1153                 {
1154                         VectorMA(cs->origin, scale, model->normalmins, cullmins);
1155                         VectorMA(cs->origin, scale, model->normalmaxs, cullmaxs);
1156                 }
1157         }
1158         else
1159         {
1160                 // if there is no model (or it could not be loaded), use the physics box
1161                 VectorAdd(cs->origin, ent->fields.server->mins, cullmins);
1162                 VectorAdd(cs->origin, ent->fields.server->maxs, cullmaxs);
1163         }
1164         if (specialvisibilityradius)
1165         {
1166                 cullmins[0] = min(cullmins[0], cs->origin[0] - specialvisibilityradius);
1167                 cullmins[1] = min(cullmins[1], cs->origin[1] - specialvisibilityradius);
1168                 cullmins[2] = min(cullmins[2], cs->origin[2] - specialvisibilityradius);
1169                 cullmaxs[0] = max(cullmaxs[0], cs->origin[0] + specialvisibilityradius);
1170                 cullmaxs[1] = max(cullmaxs[1], cs->origin[1] + specialvisibilityradius);
1171                 cullmaxs[2] = max(cullmaxs[2], cs->origin[2] + specialvisibilityradius);
1172         }
1173
1174         // calculate center of bbox for network prioritization purposes
1175         VectorMAM(0.5f, cullmins, 0.5f, cullmaxs, cs->netcenter);
1176
1177         // if culling box has moved, update pvs cluster links
1178         if (!VectorCompare(cullmins, ent->priv.server->cullmins) || !VectorCompare(cullmaxs, ent->priv.server->cullmaxs))
1179         {
1180                 VectorCopy(cullmins, ent->priv.server->cullmins);
1181                 VectorCopy(cullmaxs, ent->priv.server->cullmaxs);
1182                 // a value of -1 for pvs_numclusters indicates that the links are not
1183                 // cached, and should be re-tested each time, this is the case if the
1184                 // culling box touches too many pvs clusters to store, or if the world
1185                 // model does not support FindBoxClusters
1186                 ent->priv.server->pvs_numclusters = -1;
1187                 if (sv.worldmodel && sv.worldmodel->brush.FindBoxClusters)
1188                 {
1189                         i = sv.worldmodel->brush.FindBoxClusters(sv.worldmodel, cullmins, cullmaxs, MAX_ENTITYCLUSTERS, ent->priv.server->pvs_clusterlist);
1190                         if (i <= MAX_ENTITYCLUSTERS)
1191                                 ent->priv.server->pvs_numclusters = i;
1192                 }
1193         }
1194
1195         return true;
1196 }
1197
1198 void SV_PrepareEntitiesForSending(void)
1199 {
1200         int e;
1201         prvm_edict_t *ent;
1202         // send all entities that touch the pvs
1203         sv.numsendentities = 0;
1204         sv.sendentitiesindex[0] = NULL;
1205         memset(sv.sendentitiesindex, 0, prog->num_edicts * sizeof(*sv.sendentitiesindex));
1206         for (e = 1, ent = PRVM_NEXT_EDICT(prog->edicts);e < prog->num_edicts;e++, ent = PRVM_NEXT_EDICT(ent))
1207         {
1208                 if (!ent->priv.server->free && SV_PrepareEntityForSending(ent, sv.sendentities + sv.numsendentities, e))
1209                 {
1210                         sv.sendentitiesindex[e] = sv.sendentities + sv.numsendentities;
1211                         sv.numsendentities++;
1212                 }
1213         }
1214 }
1215
1216 void SV_MarkWriteEntityStateToClient(entity_state_t *s)
1217 {
1218         int isbmodel;
1219         dp_model_t *model;
1220         prvm_edict_t *ed;
1221         if (sv.sententitiesconsideration[s->number] == sv.sententitiesmark)
1222                 return;
1223         sv.sententitiesconsideration[s->number] = sv.sententitiesmark;
1224         sv.writeentitiestoclient_stats_totalentities++;
1225
1226         if (s->customizeentityforclient)
1227         {
1228                 prog->globals.server->self = s->number;
1229                 prog->globals.server->other = sv.writeentitiestoclient_cliententitynumber;
1230                 PRVM_ExecuteProgram(s->customizeentityforclient, "customizeentityforclient: NULL function");
1231                 if(!PRVM_G_FLOAT(OFS_RETURN) || !SV_PrepareEntityForSending(PRVM_EDICT_NUM(s->number), s, s->number))
1232                         return;
1233         }
1234
1235         // never reject player
1236         if (s->number != sv.writeentitiestoclient_cliententitynumber)
1237         {
1238                 // check various rejection conditions
1239                 if (s->nodrawtoclient == sv.writeentitiestoclient_cliententitynumber)
1240                         return;
1241                 if (s->drawonlytoclient && s->drawonlytoclient != sv.writeentitiestoclient_cliententitynumber)
1242                         return;
1243                 if (s->effects & EF_NODRAW)
1244                         return;
1245                 // LordHavoc: only send entities with a model or important effects
1246                 if (!s->modelindex && s->specialvisibilityradius == 0)
1247                         return;
1248
1249                 isbmodel = (model = sv.models[s->modelindex]) != NULL && model->name[0] == '*';
1250                 // viewmodels don't have visibility checking
1251                 if (s->viewmodelforclient)
1252                 {
1253                         if (s->viewmodelforclient != sv.writeentitiestoclient_cliententitynumber)
1254                                 return;
1255                 }
1256                 else if (s->tagentity)
1257                 {
1258                         // tag attached entities simply check their parent
1259                         if (!sv.sendentitiesindex[s->tagentity])
1260                                 return;
1261                         SV_MarkWriteEntityStateToClient(sv.sendentitiesindex[s->tagentity]);
1262                         if (sv.sententities[s->tagentity] != sv.sententitiesmark)
1263                                 return;
1264                 }
1265                 // always send world submodels in newer protocols because they don't
1266                 // generate much traffic (in old protocols they hog bandwidth)
1267                 // but only if sv_cullentities_nevercullbmodels is off
1268                 else if (!(s->effects & EF_NODEPTHTEST) && (!isbmodel || !sv_cullentities_nevercullbmodels.integer || sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE))
1269                 {
1270                         // entity has survived every check so far, check if visible
1271                         ed = PRVM_EDICT_NUM(s->number);
1272
1273                         // if not touching a visible leaf
1274                         if (sv_cullentities_pvs.integer && sv.writeentitiestoclient_pvsbytes)
1275                         {
1276                                 if (ed->priv.server->pvs_numclusters < 0)
1277                                 {
1278                                         // entity too big for clusters list
1279                                         if (sv.worldmodel && sv.worldmodel->brush.BoxTouchingPVS && !sv.worldmodel->brush.BoxTouchingPVS(sv.worldmodel, sv.writeentitiestoclient_pvs, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
1280                                         {
1281                                                 sv.writeentitiestoclient_stats_culled_pvs++;
1282                                                 return;
1283                                         }
1284                                 }
1285                                 else
1286                                 {
1287                                         int i;
1288                                         // check cached clusters list
1289                                         for (i = 0;i < ed->priv.server->pvs_numclusters;i++)
1290                                                 if (CHECKPVSBIT(sv.writeentitiestoclient_pvs, ed->priv.server->pvs_clusterlist[i]))
1291                                                         break;
1292                                         if (i == ed->priv.server->pvs_numclusters)
1293                                         {
1294                                                 sv.writeentitiestoclient_stats_culled_pvs++;
1295                                                 return;
1296                                         }
1297                                 }
1298                         }
1299
1300                         // or not seen by random tracelines
1301                         if (sv_cullentities_trace.integer && !isbmodel && sv.worldmodel->brush.TraceLineOfSight)
1302                         {
1303                                 int samples =
1304                                         s->number <= svs.maxclients
1305                                                 ? sv_cullentities_trace_samples_players.integer
1306                                                 :
1307                                         s->specialvisibilityradius
1308                                                 ? sv_cullentities_trace_samples_extra.integer
1309                                                 : sv_cullentities_trace_samples.integer;
1310                                 float enlarge = sv_cullentities_trace_enlarge.value;
1311
1312                                 qboolean visible = TRUE;
1313
1314                                 if(samples > 0)
1315                                 {
1316                                         do
1317                                         {
1318                                                 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, sv.writeentitiestoclient_testeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
1319                                                         break; // directly visible from the server's view
1320
1321                                                 if(sv_cullentities_trace_prediction.integer)
1322                                                 {
1323                                                         vec3_t predeye;
1324
1325                                                         // get player velocity
1326                                                         float predtime = bound(0, host_client->ping, 0.2); // / 2
1327                                                                 // sorry, no wallhacking by high ping please, and at 200ms
1328                                                                 // ping a FPS is annoying to play anyway and a player is
1329                                                                 // likely to have changed his direction
1330                                                         VectorMA(sv.writeentitiestoclient_testeye, predtime, host_client->edict->fields.server->velocity, predeye);
1331                                                         if(sv.worldmodel->brush.TraceLineOfSight(sv.worldmodel, sv.writeentitiestoclient_testeye, predeye)) // must be able to go there...
1332                                                         {
1333                                                                 if(Mod_CanSeeBox_Trace(samples, enlarge, sv.worldmodel, predeye, ed->priv.server->cullmins, ed->priv.server->cullmaxs))
1334                                                                         break; // directly visible from the predicted view
1335                                                         }
1336                                                         else
1337                                                         {
1338                                                                 //Con_DPrintf("Trying to walk into solid in a pingtime... not predicting for culling\n");
1339                                                         }
1340                                                 }
1341
1342                                                 // when we get here, we can't see the entity
1343                                                 visible = false;
1344                                         }
1345                                         while(0);
1346
1347                                         if(visible)
1348                                                 svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[s->number] =
1349                                                         realtime + (
1350                                                                 s->number <= svs.maxclients
1351                                                                         ? sv_cullentities_trace_delay_players.value
1352                                                                         : sv_cullentities_trace_delay.value
1353                                                         );
1354                                         else if (realtime > svs.clients[sv.writeentitiestoclient_clientnumber].visibletime[s->number])
1355                                         {
1356                                                 sv.writeentitiestoclient_stats_culled_trace++;
1357                                                 return;
1358                                         }
1359                                 }
1360                         }
1361                 }
1362         }
1363
1364         // this just marks it for sending
1365         // FIXME: it would be more efficient to send here, but the entity
1366         // compressor isn't that flexible
1367         sv.writeentitiestoclient_stats_visibleentities++;
1368         sv.sententities[s->number] = sv.sententitiesmark;
1369 }
1370
1371 void SV_WriteEntitiesToClient(client_t *client, prvm_edict_t *clent, sizebuf_t *msg, int maxsize)
1372 {
1373         int i, numsendstates;
1374         entity_state_t *s;
1375         prvm_edict_t *camera;
1376
1377         // if there isn't enough space to accomplish anything, skip it
1378         if (msg->cursize + 25 > maxsize)
1379                 return;
1380
1381         sv.writeentitiestoclient_msg = msg;
1382         sv.writeentitiestoclient_clientnumber = client - svs.clients;
1383
1384         sv.writeentitiestoclient_stats_culled_pvs = 0;
1385         sv.writeentitiestoclient_stats_culled_trace = 0;
1386         sv.writeentitiestoclient_stats_visibleentities = 0;
1387         sv.writeentitiestoclient_stats_totalentities = 0;
1388
1389 // find the client's PVS
1390         // the real place being tested from
1391         camera = PRVM_EDICT_NUM( client->clientcamera );
1392         VectorAdd(camera->fields.server->origin, clent->fields.server->view_ofs, sv.writeentitiestoclient_testeye);
1393         sv.writeentitiestoclient_pvsbytes = 0;
1394         if (sv.worldmodel && sv.worldmodel->brush.FatPVS)
1395                 sv.writeentitiestoclient_pvsbytes = sv.worldmodel->brush.FatPVS(sv.worldmodel, sv.writeentitiestoclient_testeye, 8, sv.writeentitiestoclient_pvs, sizeof(sv.writeentitiestoclient_pvs), false);
1396
1397         sv.writeentitiestoclient_cliententitynumber = PRVM_EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes
1398
1399         sv.sententitiesmark++;
1400
1401         for (i = 0;i < sv.numsendentities;i++)
1402                 SV_MarkWriteEntityStateToClient(sv.sendentities + i);
1403
1404         numsendstates = 0;
1405         for (i = 0;i < sv.numsendentities;i++)
1406         {
1407                 if (sv.sententities[sv.sendentities[i].number] == sv.sententitiesmark)
1408                 {
1409                         s = &sv.writeentitiestoclient_sendstates[numsendstates++];
1410                         *s = sv.sendentities[i];
1411                         if (s->exteriormodelforclient && s->exteriormodelforclient == sv.writeentitiestoclient_cliententitynumber)
1412                                 s->flags |= RENDER_EXTERIORMODEL;
1413                 }
1414         }
1415
1416         if (sv_cullentities_stats.integer)
1417                 Con_Printf("client \"%s\" entities: %d total, %d visible, %d culled by: %d pvs %d trace\n", client->name, sv.writeentitiestoclient_stats_totalentities, sv.writeentitiestoclient_stats_visibleentities, sv.writeentitiestoclient_stats_culled_pvs + sv.writeentitiestoclient_stats_culled_trace, sv.writeentitiestoclient_stats_culled_pvs, sv.writeentitiestoclient_stats_culled_trace);
1418
1419         EntityFrameCSQC_WriteFrame(msg, maxsize, numsendstates, sv.writeentitiestoclient_sendstates);
1420
1421         if (client->entitydatabase5)
1422                 EntityFrame5_WriteFrame(msg, maxsize, client->entitydatabase5, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1, client->movesequence);
1423         else if (client->entitydatabase4)
1424         {
1425                 EntityFrame4_WriteFrame(msg, maxsize, client->entitydatabase4, numsendstates, sv.writeentitiestoclient_sendstates);
1426                 Protocol_WriteStatsReliable();
1427         }
1428         else if (client->entitydatabase)
1429         {
1430                 EntityFrame_WriteFrame(msg, maxsize, client->entitydatabase, numsendstates, sv.writeentitiestoclient_sendstates, client - svs.clients + 1);
1431                 Protocol_WriteStatsReliable();
1432         }
1433         else
1434         {
1435                 EntityFrameQuake_WriteFrame(msg, maxsize, numsendstates, sv.writeentitiestoclient_sendstates);
1436                 Protocol_WriteStatsReliable();
1437         }
1438 }
1439
1440 /*
1441 =============
1442 SV_CleanupEnts
1443
1444 =============
1445 */
1446 static void SV_CleanupEnts (void)
1447 {
1448         int             e;
1449         prvm_edict_t    *ent;
1450
1451         ent = PRVM_NEXT_EDICT(prog->edicts);
1452         for (e=1 ; e<prog->num_edicts ; e++, ent = PRVM_NEXT_EDICT(ent))
1453                 ent->fields.server->effects = (int)ent->fields.server->effects & ~EF_MUZZLEFLASH;
1454 }
1455
1456 /*
1457 ==================
1458 SV_WriteClientdataToMessage
1459
1460 ==================
1461 */
1462 void SV_WriteClientdataToMessage (client_t *client, prvm_edict_t *ent, sizebuf_t *msg, int *stats)
1463 {
1464         int             bits;
1465         int             i;
1466         prvm_edict_t    *other;
1467         int             items;
1468         prvm_eval_t     *val;
1469         vec3_t  punchvector;
1470         int             viewzoom;
1471         const char *s;
1472         float   *statsf = (float *)stats;
1473
1474 //
1475 // send a damage message
1476 //
1477         if (ent->fields.server->dmg_take || ent->fields.server->dmg_save)
1478         {
1479                 other = PRVM_PROG_TO_EDICT(ent->fields.server->dmg_inflictor);
1480                 MSG_WriteByte (msg, svc_damage);
1481                 MSG_WriteByte (msg, (int)ent->fields.server->dmg_save);
1482                 MSG_WriteByte (msg, (int)ent->fields.server->dmg_take);
1483                 for (i=0 ; i<3 ; i++)
1484                         MSG_WriteCoord (msg, other->fields.server->origin[i] + 0.5*(other->fields.server->mins[i] + other->fields.server->maxs[i]), sv.protocol);
1485
1486                 ent->fields.server->dmg_take = 0;
1487                 ent->fields.server->dmg_save = 0;
1488         }
1489
1490 //
1491 // send the current viewpos offset from the view entity
1492 //
1493         SV_SetIdealPitch ();            // how much to look up / down ideally
1494
1495 // a fixangle might get lost in a dropped packet.  Oh well.
1496         if(ent->fields.server->fixangle)
1497         {
1498                 // angle fixing was requested by global thinking code...
1499                 // so store the current angles for later use
1500                 memcpy(host_client->fixangle_angles, ent->fields.server->angles, sizeof(host_client->fixangle_angles));
1501                 host_client->fixangle_angles_set = TRUE;
1502
1503                 // and clear fixangle for the next frame
1504                 ent->fields.server->fixangle = 0;
1505         }
1506
1507         if (host_client->fixangle_angles_set)
1508         {
1509                 MSG_WriteByte (msg, svc_setangle);
1510                 for (i=0 ; i < 3 ; i++)
1511                         MSG_WriteAngle (msg, host_client->fixangle_angles[i], sv.protocol);
1512                 host_client->fixangle_angles_set = FALSE;
1513         }
1514
1515         // stuff the sigil bits into the high bits of items for sbar, or else
1516         // mix in items2
1517         val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.items2);
1518         if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1519                 items = (int)ent->fields.server->items | ((int)val->_float << 23);
1520         else
1521                 items = (int)ent->fields.server->items | ((int)prog->globals.server->serverflags << 28);
1522
1523         VectorClear(punchvector);
1524         if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.punchvector)))
1525                 VectorCopy(val->vector, punchvector);
1526
1527         // cache weapon model name and index in client struct to save time
1528         // (this search can be almost 1% of cpu time!)
1529         s = PRVM_GetString(ent->fields.server->weaponmodel);
1530         if (strcmp(s, client->weaponmodel))
1531         {
1532                 strlcpy(client->weaponmodel, s, sizeof(client->weaponmodel));
1533                 client->weaponmodelindex = SV_ModelIndex(s, 1);
1534         }
1535
1536         viewzoom = 255;
1537         if ((val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.viewzoom)))
1538                 viewzoom = (int)(val->_float * 255.0f);
1539         if (viewzoom == 0)
1540                 viewzoom = 255;
1541
1542         bits = 0;
1543
1544         if ((int)ent->fields.server->flags & FL_ONGROUND)
1545                 bits |= SU_ONGROUND;
1546         if (ent->fields.server->waterlevel >= 2)
1547                 bits |= SU_INWATER;
1548         if (ent->fields.server->idealpitch)
1549                 bits |= SU_IDEALPITCH;
1550
1551         for (i=0 ; i<3 ; i++)
1552         {
1553                 if (ent->fields.server->punchangle[i])
1554                         bits |= (SU_PUNCH1<<i);
1555                 if (sv.protocol != PROTOCOL_QUAKE && sv.protocol != PROTOCOL_QUAKEDP && sv.protocol != PROTOCOL_NEHAHRAMOVIE && sv.protocol != PROTOCOL_NEHAHRABJP && sv.protocol != PROTOCOL_NEHAHRABJP2 && sv.protocol != PROTOCOL_NEHAHRABJP3)
1556                         if (punchvector[i])
1557                                 bits |= (SU_PUNCHVEC1<<i);
1558                 if (ent->fields.server->velocity[i])
1559                         bits |= (SU_VELOCITY1<<i);
1560         }
1561
1562         memset(stats, 0, sizeof(int[MAX_CL_STATS]));
1563         stats[STAT_VIEWHEIGHT] = (int)ent->fields.server->view_ofs[2];
1564         stats[STAT_ITEMS] = items;
1565         stats[STAT_WEAPONFRAME] = (int)ent->fields.server->weaponframe;
1566         stats[STAT_ARMOR] = (int)ent->fields.server->armorvalue;
1567         stats[STAT_WEAPON] = client->weaponmodelindex;
1568         stats[STAT_HEALTH] = (int)ent->fields.server->health;
1569         stats[STAT_AMMO] = (int)ent->fields.server->currentammo;
1570         stats[STAT_SHELLS] = (int)ent->fields.server->ammo_shells;
1571         stats[STAT_NAILS] = (int)ent->fields.server->ammo_nails;
1572         stats[STAT_ROCKETS] = (int)ent->fields.server->ammo_rockets;
1573         stats[STAT_CELLS] = (int)ent->fields.server->ammo_cells;
1574         stats[STAT_ACTIVEWEAPON] = (int)ent->fields.server->weapon;
1575         stats[STAT_VIEWZOOM] = viewzoom;
1576         stats[STAT_TOTALSECRETS] = prog->globals.server->total_secrets;
1577         stats[STAT_TOTALMONSTERS] = prog->globals.server->total_monsters;
1578         // the QC bumps these itself by sending svc_'s, so we have to keep them
1579         // zero or they'll be corrected by the engine
1580         //stats[STAT_SECRETS] = prog->globals.server->found_secrets;
1581         //stats[STAT_MONSTERS] = prog->globals.server->killed_monsters;
1582
1583         // movement settings for prediction
1584         // note: these are not sent in protocols with lower MAX_CL_STATS limits
1585         statsf[STAT_MOVEVARS_TICRATE] = sys_ticrate.value;
1586         statsf[STAT_MOVEVARS_TIMESCALE] = slowmo.value;
1587         statsf[STAT_MOVEVARS_GRAVITY] = sv_gravity.value;
1588         statsf[STAT_MOVEVARS_STOPSPEED] = sv_stopspeed.value;
1589         statsf[STAT_MOVEVARS_MAXSPEED] = sv_maxspeed.value;
1590         statsf[STAT_MOVEVARS_SPECTATORMAXSPEED] = sv_maxspeed.value; // FIXME: QW has a separate cvar for this
1591         statsf[STAT_MOVEVARS_ACCELERATE] = sv_accelerate.value;
1592         statsf[STAT_MOVEVARS_AIRACCELERATE] = sv_airaccelerate.value >= 0 ? sv_airaccelerate.value : sv_accelerate.value;
1593         statsf[STAT_MOVEVARS_WATERACCELERATE] = sv_wateraccelerate.value >= 0 ? sv_wateraccelerate.value : sv_accelerate.value;
1594         val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.gravity);
1595         statsf[STAT_MOVEVARS_ENTGRAVITY] = (val && val->_float != 0) ? val->_float : 1.0f;
1596         statsf[STAT_MOVEVARS_JUMPVELOCITY] = sv_jumpvelocity.value;
1597         statsf[STAT_MOVEVARS_EDGEFRICTION] = sv_edgefriction.value;
1598         statsf[STAT_MOVEVARS_MAXAIRSPEED] = sv_maxairspeed.value;
1599         statsf[STAT_MOVEVARS_STEPHEIGHT] = sv_stepheight.value;
1600         statsf[STAT_MOVEVARS_AIRACCEL_QW] = sv_airaccel_qw.value;
1601         statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION] = sv_airaccel_sideways_friction.value;
1602         statsf[STAT_MOVEVARS_FRICTION] = sv_friction.value;
1603         statsf[STAT_MOVEVARS_WATERFRICTION] = sv_waterfriction.value >= 0 ? sv_waterfriction.value : sv_friction.value;
1604         statsf[STAT_FRAGLIMIT] = fraglimit.value;
1605         statsf[STAT_TIMELIMIT] = timelimit.value;
1606
1607         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1608         {
1609                 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1610                 bits |= SU_ITEMS;
1611                 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1612                 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1613                 bits |= SU_WEAPON;
1614                 // FIXME: which protocols support this?  does PROTOCOL_DARKPLACES3 support viewzoom?
1615                 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1616                         if (viewzoom != 255)
1617                                 bits |= SU_VIEWZOOM;
1618         }
1619
1620         if (bits >= 65536)
1621                 bits |= SU_EXTEND1;
1622         if (bits >= 16777216)
1623                 bits |= SU_EXTEND2;
1624
1625         // send the data
1626         MSG_WriteByte (msg, svc_clientdata);
1627         MSG_WriteShort (msg, bits);
1628         if (bits & SU_EXTEND1)
1629                 MSG_WriteByte(msg, bits >> 16);
1630         if (bits & SU_EXTEND2)
1631                 MSG_WriteByte(msg, bits >> 24);
1632
1633         if (bits & SU_VIEWHEIGHT)
1634                 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1635
1636         if (bits & SU_IDEALPITCH)
1637                 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1638
1639         for (i=0 ; i<3 ; i++)
1640         {
1641                 if (bits & (SU_PUNCH1<<i))
1642                 {
1643                         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1644                                 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1645                         else
1646                                 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1647                 }
1648                 if (bits & (SU_PUNCHVEC1<<i))
1649                 {
1650                         if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1651                                 MSG_WriteCoord16i(msg, punchvector[i]);
1652                         else
1653                                 MSG_WriteCoord32f(msg, punchvector[i]);
1654                 }
1655                 if (bits & (SU_VELOCITY1<<i))
1656                 {
1657                         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1658                                 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1659                         else
1660                                 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1661                 }
1662         }
1663
1664         if (bits & SU_ITEMS)
1665                 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1666
1667         if (sv.protocol == PROTOCOL_DARKPLACES5)
1668         {
1669                 if (bits & SU_WEAPONFRAME)
1670                         MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1671                 if (bits & SU_ARMOR)
1672                         MSG_WriteShort (msg, stats[STAT_ARMOR]);
1673                 if (bits & SU_WEAPON)
1674                         MSG_WriteShort (msg, stats[STAT_WEAPON]);
1675                 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1676                 MSG_WriteShort (msg, stats[STAT_AMMO]);
1677                 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1678                 MSG_WriteShort (msg, stats[STAT_NAILS]);
1679                 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1680                 MSG_WriteShort (msg, stats[STAT_CELLS]);
1681                 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1682                 if (bits & SU_VIEWZOOM)
1683                         MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1684         }
1685         else if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1686         {
1687                 if (bits & SU_WEAPONFRAME)
1688                         MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1689                 if (bits & SU_ARMOR)
1690                         MSG_WriteByte (msg, stats[STAT_ARMOR]);
1691                 if (bits & SU_WEAPON)
1692                 {
1693                         if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
1694                                 MSG_WriteShort (msg, stats[STAT_WEAPON]);
1695                         else
1696                                 MSG_WriteByte (msg, stats[STAT_WEAPON]);
1697                 }
1698                 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1699                 MSG_WriteByte (msg, stats[STAT_AMMO]);
1700                 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1701                 MSG_WriteByte (msg, stats[STAT_NAILS]);
1702                 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1703                 MSG_WriteByte (msg, stats[STAT_CELLS]);
1704                 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1705                 {
1706                         for (i = 0;i < 32;i++)
1707                                 if (stats[STAT_ACTIVEWEAPON] & (1<<i))
1708                                         break;
1709                         MSG_WriteByte (msg, i);
1710                 }
1711                 else
1712                         MSG_WriteByte (msg, stats[STAT_ACTIVEWEAPON]);
1713                 if (bits & SU_VIEWZOOM)
1714                 {
1715                         if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1716                                 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1717                         else
1718                                 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1719                 }
1720         }
1721 }
1722
1723 void SV_FlushBroadcastMessages(void)
1724 {
1725         int i;
1726         client_t *client;
1727         if (sv.datagram.cursize <= 0)
1728                 return;
1729         for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1730         {
1731                 if (!client->spawned || !client->netconnection || client->unreliablemsg.cursize + sv.datagram.cursize > client->unreliablemsg.maxsize || client->unreliablemsg_splitpoints >= (int)(sizeof(client->unreliablemsg_splitpoint)/sizeof(client->unreliablemsg_splitpoint[0])))
1732                         continue;
1733                 SZ_Write(&client->unreliablemsg, sv.datagram.data, sv.datagram.cursize);
1734                 client->unreliablemsg_splitpoint[client->unreliablemsg_splitpoints++] = client->unreliablemsg.cursize;
1735         }
1736         SZ_Clear(&sv.datagram);
1737 }
1738
1739 static void SV_WriteUnreliableMessages(client_t *client, sizebuf_t *msg, int maxsize)
1740 {
1741         // scan the splitpoints to find out how many we can fit in
1742         int numsegments, j, split;
1743         if (!client->unreliablemsg_splitpoints)
1744                 return;
1745         // always accept the first one if it's within 1024 bytes, this ensures
1746         // that very big datagrams which are over the rate limit still get
1747         // through, just to keep it working
1748         j = msg->cursize + client->unreliablemsg_splitpoint[0];
1749         if (maxsize < 1024 && j > maxsize && j <= 1024)
1750         {
1751                 numsegments = 1;
1752                 maxsize = 1024;
1753         }
1754         else
1755                 for (numsegments = 0;numsegments < client->unreliablemsg_splitpoints;numsegments++)
1756                         if (msg->cursize + client->unreliablemsg_splitpoint[numsegments] > maxsize)
1757                                 break;
1758         if (numsegments > 0)
1759         {
1760                 // some will fit, so add the ones that will fit
1761                 split = client->unreliablemsg_splitpoint[numsegments-1];
1762                 // note this discards ones that were accepted by the segments scan but
1763                 // can not fit, such as a really huge first one that will never ever
1764                 // fit in a packet...
1765                 if (msg->cursize + split <= maxsize)
1766                         SZ_Write(msg, client->unreliablemsg.data, split);
1767                 // remove the part we sent, keeping any remaining data
1768                 client->unreliablemsg.cursize -= split;
1769                 if (client->unreliablemsg.cursize > 0)
1770                         memmove(client->unreliablemsg.data, client->unreliablemsg.data + split, client->unreliablemsg.cursize);
1771                 // adjust remaining splitpoints
1772                 client->unreliablemsg_splitpoints -= numsegments;
1773                 for (j = 0;j < client->unreliablemsg_splitpoints;j++)
1774                         client->unreliablemsg_splitpoint[j] = client->unreliablemsg_splitpoint[numsegments + j] - split;
1775         }
1776 }
1777
1778 /*
1779 =======================
1780 SV_SendClientDatagram
1781 =======================
1782 */
1783 static void SV_SendClientDatagram (client_t *client)
1784 {
1785         int clientrate, maxrate, maxsize, maxsize2, downloadsize;
1786         sizebuf_t msg;
1787         int stats[MAX_CL_STATS];
1788         unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE];
1789
1790         // obey rate limit by limiting packet frequency if the packet size
1791         // limiting fails
1792         // (usually this is caused by reliable messages)
1793         if (!NetConn_CanSend(client->netconnection))
1794                 return;
1795
1796         // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1797         maxrate = max(NET_MINRATE, sv_maxrate.integer);
1798         if (sv_maxrate.integer != maxrate)
1799                 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1800
1801         // clientrate determines the 'cleartime' of a packet
1802         // (how long to wait before sending another, based on this packet's size)
1803         clientrate = bound(NET_MINRATE, client->rate, maxrate);
1804
1805         switch (sv.protocol)
1806         {
1807         case PROTOCOL_QUAKE:
1808         case PROTOCOL_QUAKEDP:
1809         case PROTOCOL_NEHAHRAMOVIE:
1810         case PROTOCOL_NEHAHRABJP:
1811         case PROTOCOL_NEHAHRABJP2:
1812         case PROTOCOL_NEHAHRABJP3:
1813         case PROTOCOL_QUAKEWORLD:
1814                 // no packet size limit support on Quake protocols because it just
1815                 // causes missing entities/effects
1816                 // packets are simply sent less often to obey the rate limit
1817                 maxsize = 1024;
1818                 maxsize2 = 1024;
1819                 break;
1820         case PROTOCOL_DARKPLACES1:
1821         case PROTOCOL_DARKPLACES2:
1822         case PROTOCOL_DARKPLACES3:
1823         case PROTOCOL_DARKPLACES4:
1824                 // no packet size limit support on DP1-4 protocols because they kick
1825                 // the client off if they overflow, and miss effects
1826                 // packets are simply sent less often to obey the rate limit
1827                 maxsize = sizeof(sv_sendclientdatagram_buf);
1828                 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1829                 break;
1830         default:
1831                 // DP5 and later protocols support packet size limiting which is a
1832                 // better method than limiting packet frequency as QW does
1833                 //
1834                 // at very low rates (or very small sys_ticrate) the packet size is
1835                 // not reduced below 128, but packets may be sent less often
1836                 maxsize = (int)(clientrate * sys_ticrate.value);
1837                 maxsize = bound(128, maxsize, 1400);
1838                 maxsize2 = 1400;
1839                 // csqc entities can easily exceed 128 bytes, so disable throttling in
1840                 // mods that use csqc (they are likely to use less bandwidth anyway)
1841                 if (sv.csqc_progsize > 0)
1842                         maxsize = maxsize2;
1843                 break;
1844         }
1845
1846         if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1847         {
1848                 // for good singleplayer, send huge packets
1849                 maxsize = sizeof(sv_sendclientdatagram_buf);
1850                 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1851                 // never limit frequency in singleplayer
1852                 clientrate = 1000000000;
1853         }
1854
1855         // while downloading, limit entity updates to half the packet
1856         // (any leftover space will be used for downloading)
1857         if (host_client->download_file)
1858                 maxsize /= 2;
1859
1860         msg.data = sv_sendclientdatagram_buf;
1861         msg.maxsize = sizeof(sv_sendclientdatagram_buf);
1862         msg.cursize = 0;
1863         msg.allowoverflow = false;
1864
1865         if (host_client->spawned)
1866         {
1867                 // the player is in the game
1868                 MSG_WriteByte (&msg, svc_time);
1869                 MSG_WriteFloat (&msg, sv.time);
1870
1871                 // add the client specific data to the datagram
1872                 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1873                 // now update the stats[] array using any registered custom fields
1874                 VM_SV_UpdateCustomStats (client, client->edict, &msg, stats);
1875                 // set host_client->statsdeltabits
1876                 Protocol_UpdateClientStats (stats);
1877
1878                 // add as many queued unreliable messages (effects) as we can fit
1879                 // limit effects to half of the remaining space
1880                 if (client->unreliablemsg.cursize)
1881                         SV_WriteUnreliableMessages (client, &msg, (msg.cursize + maxsize) / 2);
1882
1883                 // now write as many entities as we can fit, and also sends stats
1884                 SV_WriteEntitiesToClient (client, client->edict, &msg, maxsize);
1885         }
1886         else if (realtime > client->keepalivetime)
1887         {
1888                 // the player isn't totally in the game yet
1889                 // send small keepalive messages if too much time has passed
1890                 // (may also be sending downloads)
1891                 client->keepalivetime = realtime + 5;
1892                 MSG_WriteChar (&msg, svc_nop);
1893         }
1894
1895         // if a download is active, see if there is room to fit some download data
1896         // in this packet
1897         downloadsize = min(maxsize*2,maxsize2) - msg.cursize - 7;
1898         if (host_client->download_file && host_client->download_started && downloadsize > 0)
1899         {
1900                 fs_offset_t downloadstart;
1901                 unsigned char data[1400];
1902                 downloadstart = FS_Tell(host_client->download_file);
1903                 downloadsize = min(downloadsize, (int)sizeof(data));
1904                 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1905                 // note this sends empty messages if at the end of the file, which is
1906                 // necessary to keep the packet loss logic working
1907                 // (the last blocks may be lost and need to be re-sent, and that will
1908                 //  only occur if the client acks the empty end messages, revealing
1909                 //  a gap in the download progress, causing the last blocks to be
1910                 //  sent again)
1911                 MSG_WriteChar (&msg, svc_downloaddata);
1912                 MSG_WriteLong (&msg, downloadstart);
1913                 MSG_WriteShort (&msg, downloadsize);
1914                 if (downloadsize > 0)
1915                         SZ_Write (&msg, data, downloadsize);
1916         }
1917
1918         // reliable only if none is in progress
1919         if(client->sendsignon != 2 && !client->netconnection->sendMessageLength)
1920                 SV_WriteDemoMessage(client, &(client->netconnection->message), false);
1921         // unreliable
1922         SV_WriteDemoMessage(client, &msg, false);
1923
1924 // send the datagram
1925         NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate, client->sendsignon == 2);
1926         if (client->sendsignon == 1 && !client->netconnection->message.cursize)
1927                 client->sendsignon = 2; // prevent reliable until client sends prespawn (this is the keepalive phase)
1928 }
1929
1930 /*
1931 =======================
1932 SV_UpdateToReliableMessages
1933 =======================
1934 */
1935 static void SV_UpdateToReliableMessages (void)
1936 {
1937         int i, j;
1938         client_t *client;
1939         prvm_eval_t *val;
1940         const char *name;
1941         const char *model;
1942         const char *skin;
1943
1944 // check for changes to be sent over the reliable streams
1945         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1946         {
1947                 // update the host_client fields we care about according to the entity fields
1948                 host_client->edict = PRVM_EDICT_NUM(i+1);
1949
1950                 // DP_SV_CLIENTNAME
1951                 name = PRVM_GetString(host_client->edict->fields.server->netname);
1952                 if (name == NULL)
1953                         name = "";
1954                 // always point the string back at host_client->name to keep it safe
1955                 strlcpy (host_client->name, name, sizeof (host_client->name));
1956                 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1957                 if (strcmp(host_client->old_name, host_client->name))
1958                 {
1959                         if (host_client->spawned)
1960                                 SV_BroadcastPrintf("%s changed name to %s\n", host_client->old_name, host_client->name);
1961                         strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1962                         // send notification to all clients
1963                         MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1964                         MSG_WriteByte (&sv.reliable_datagram, i);
1965                         MSG_WriteString (&sv.reliable_datagram, host_client->name);
1966                         SV_WriteNetnameIntoDemo(host_client);
1967                 }
1968
1969                 // DP_SV_CLIENTCOLORS
1970                 // this is always found (since it's added by the progs loader)
1971                 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1972                         host_client->colors = (int)val->_float;
1973                 if (host_client->old_colors != host_client->colors)
1974                 {
1975                         host_client->old_colors = host_client->colors;
1976                         // send notification to all clients
1977                         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1978                         MSG_WriteByte (&sv.reliable_datagram, i);
1979                         MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1980                 }
1981
1982                 // NEXUIZ_PLAYERMODEL
1983                 if( prog->fieldoffsets.playermodel >= 0 ) {
1984                         model = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string);
1985                         if (model == NULL)
1986                                 model = "";
1987                         // always point the string back at host_client->name to keep it safe
1988                         strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1989                         PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1990                 }
1991
1992                 // NEXUIZ_PLAYERSKIN
1993                 if( prog->fieldoffsets.playerskin >= 0 ) {
1994                         skin = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string);
1995                         if (skin == NULL)
1996                                 skin = "";
1997                         // always point the string back at host_client->name to keep it safe
1998                         strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1999                         PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
2000                 }
2001
2002                 // TODO: add an extension name for this [1/17/2008 Black]
2003                 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcamera)) && val->edict > 0 ) {
2004                         int oldclientcamera = host_client->clientcamera;
2005                         if( val->edict >= prog->max_edicts || PRVM_EDICT_NUM( val->edict )->priv.required->free ) {
2006                                 val->edict = host_client->clientcamera = PRVM_NUM_FOR_EDICT( host_client->edict );
2007                         } else {
2008                                 host_client->clientcamera = val->edict;
2009                         }
2010
2011                         if( oldclientcamera != host_client->clientcamera ) {
2012                                 MSG_WriteByte (&sv.reliable_datagram, svc_setview );
2013                                 MSG_WriteShort (&host_client->netconnection->message, host_client->clientcamera);
2014                         }
2015                 }
2016
2017                 // frags
2018                 host_client->frags = (int)host_client->edict->fields.server->frags;
2019                 if(gamemode == GAME_NEXUIZ)
2020                         if(!host_client->spawned && host_client->netconnection)
2021                                 host_client->frags = -666;
2022                 if (host_client->old_frags != host_client->frags)
2023                 {
2024                         host_client->old_frags = host_client->frags;
2025                         // send notification to all clients
2026                         MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
2027                         MSG_WriteByte (&sv.reliable_datagram, i);
2028                         MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
2029                 }
2030         }
2031
2032         for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
2033                 if (client->netconnection && (client->spawned || client->clientconnectcalled)) // also send MSG_ALL to people who are past ClientConnect, but not spawned yet
2034                         SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
2035
2036         SZ_Clear (&sv.reliable_datagram);
2037 }
2038
2039
2040 /*
2041 =======================
2042 SV_SendClientMessages
2043 =======================
2044 */
2045 void SV_SendClientMessages (void)
2046 {
2047         int i, prepared = false;
2048
2049         if (sv.protocol == PROTOCOL_QUAKEWORLD)
2050                 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
2051
2052         SV_FlushBroadcastMessages();
2053
2054 // update frags, names, etc
2055         SV_UpdateToReliableMessages();
2056
2057 // build individual updates
2058         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2059         {
2060                 if (!host_client->active)
2061                         continue;
2062                 if (!host_client->netconnection)
2063                         continue;
2064
2065                 if (host_client->netconnection->message.overflowed)
2066                 {
2067                         SV_DropClient (true);   // if the message couldn't send, kick off
2068                         continue;
2069                 }
2070
2071                 if (!prepared)
2072                 {
2073                         prepared = true;
2074                         // only prepare entities once per frame
2075                         SV_PrepareEntitiesForSending();
2076                 }
2077                 SV_SendClientDatagram (host_client);
2078         }
2079
2080 // clear muzzle flashes
2081         SV_CleanupEnts();
2082 }
2083
2084 static void SV_StartDownload_f(void)
2085 {
2086         if (host_client->download_file)
2087                 host_client->download_started = true;
2088 }
2089
2090 static void SV_Download_f(void)
2091 {
2092         const char *whichpack, *whichpack2, *extension;
2093
2094         if (Cmd_Argc() != 2)
2095         {
2096                 SV_ClientPrintf("usage: download <filename>\n");
2097                 return;
2098         }
2099
2100         if (FS_CheckNastyPath(Cmd_Argv(1), false))
2101         {
2102                 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
2103                 return;
2104         }
2105
2106         if (host_client->download_file)
2107         {
2108                 // at this point we'll assume the previous download should be aborted
2109                 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
2110                 Host_ClientCommands("\nstopdownload\n");
2111
2112                 // close the file and reset variables
2113                 FS_Close(host_client->download_file);
2114                 host_client->download_file = NULL;
2115                 host_client->download_name[0] = 0;
2116                 host_client->download_expectedposition = 0;
2117                 host_client->download_started = false;
2118         }
2119
2120         if (!sv_allowdownloads.integer)
2121         {
2122                 SV_ClientPrintf("Downloads are disabled on this server\n");
2123                 Host_ClientCommands("\nstopdownload\n");
2124                 return;
2125         }
2126
2127         strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
2128         extension = FS_FileExtension(host_client->download_name);
2129
2130         // host_client is asking to download a specified file
2131         if (developer.integer >= 100)
2132                 Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
2133
2134         if (!FS_FileExists(host_client->download_name))
2135         {
2136                 SV_ClientPrintf("Download rejected: server does not have the file \"%s\"\nYou may need to separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
2137                 Host_ClientCommands("\nstopdownload\n");
2138                 return;
2139         }
2140
2141         // check if the user is trying to download part of registered Quake(r)
2142         whichpack = FS_WhichPack(host_client->download_name);
2143         whichpack2 = FS_WhichPack("gfx/pop.lmp");
2144         if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
2145         {
2146                 SV_ClientPrintf("Download rejected: file \"%s\" is part of registered Quake(r)\nYou must purchase Quake(r) from id Software or a retailer to get this file\nPlease go to http://www.idsoftware.com/games/quake/quake/index.php?game_section=buy\n", host_client->download_name);
2147                 Host_ClientCommands("\nstopdownload\n");
2148                 return;
2149         }
2150
2151         // check if the server has forbidden archive downloads entirely
2152         if (!sv_allowdownloads_inarchive.integer)
2153         {
2154                 whichpack = FS_WhichPack(host_client->download_name);
2155                 if (whichpack)
2156                 {
2157                         SV_ClientPrintf("Download rejected: file \"%s\" is in an archive (\"%s\")\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name, whichpack);
2158                         Host_ClientCommands("\nstopdownload\n");
2159                         return;
2160                 }
2161         }
2162
2163         if (!sv_allowdownloads_config.integer)
2164         {
2165                 if (!strcasecmp(extension, "cfg"))
2166                 {
2167                         SV_ClientPrintf("Download rejected: file \"%s\" is a .cfg file which is forbidden for security reasons\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
2168                         Host_ClientCommands("\nstopdownload\n");
2169                         return;
2170                 }
2171         }
2172
2173         if (!sv_allowdownloads_dlcache.integer)
2174         {
2175                 if (!strncasecmp(host_client->download_name, "dlcache/", 8))
2176                 {
2177                         SV_ClientPrintf("Download rejected: file \"%s\" is in the dlcache/ directory which is forbidden for security reasons\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
2178                         Host_ClientCommands("\nstopdownload\n");
2179                         return;
2180                 }
2181         }
2182
2183         if (!sv_allowdownloads_archive.integer)
2184         {
2185                 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
2186                 {
2187                         SV_ClientPrintf("Download rejected: file \"%s\" is an archive\nYou must separately download or purchase the data archives for this game/mod to get this file\n", host_client->download_name);
2188                         Host_ClientCommands("\nstopdownload\n");
2189                         return;
2190                 }
2191         }
2192
2193         host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
2194         if (!host_client->download_file)
2195         {
2196                 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
2197                 Host_ClientCommands("\nstopdownload\n");
2198                 return;
2199         }
2200
2201         if (FS_FileSize(host_client->download_file) > 1<<30)
2202         {
2203                 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
2204                 Host_ClientCommands("\nstopdownload\n");
2205                 FS_Close(host_client->download_file);
2206                 host_client->download_file = NULL;
2207                 return;
2208         }
2209
2210         Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
2211
2212         Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
2213
2214         host_client->download_expectedposition = 0;
2215         host_client->download_started = false;
2216         host_client->sendsignon = true; // make sure this message is sent
2217
2218         // the rest of the download process is handled in SV_SendClientDatagram
2219         // and other code dealing with svc_downloaddata and clc_ackdownloaddata
2220         //
2221         // no svc_downloaddata messages will be sent until sv_startdownload is
2222         // sent by the client
2223 }
2224
2225 /*
2226 ==============================================================================
2227
2228 SERVER SPAWNING
2229
2230 ==============================================================================
2231 */
2232
2233 /*
2234 ================
2235 SV_ModelIndex
2236
2237 ================
2238 */
2239 int SV_ModelIndex(const char *s, int precachemode)
2240 {
2241         int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) ? 256 : MAX_MODELS);
2242         char filename[MAX_QPATH];
2243         if (!s || !*s)
2244                 return 0;
2245         // testing
2246         //if (precachemode == 2)
2247         //      return 0;
2248         strlcpy(filename, s, sizeof(filename));
2249         for (i = 2;i < limit;i++)
2250         {
2251                 if (!sv.model_precache[i][0])
2252                 {
2253                         if (precachemode)
2254                         {
2255                                 if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5))
2256                                 {
2257                                         Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
2258                                         return 0;
2259                                 }
2260                                 if (precachemode == 1)
2261                                         Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
2262                                 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
2263                                 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
2264                                 if (sv.state != ss_loading)
2265                                 {
2266                                         MSG_WriteByte(&sv.reliable_datagram, svc_precache);
2267                                         MSG_WriteShort(&sv.reliable_datagram, i);
2268                                         MSG_WriteString(&sv.reliable_datagram, filename);
2269                                 }
2270                                 return i;
2271                         }
2272                         Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
2273                         return 0;
2274                 }
2275                 if (!strcmp(sv.model_precache[i], filename))
2276                         return i;
2277         }
2278         Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
2279         return 0;
2280 }
2281
2282 /*
2283 ================
2284 SV_SoundIndex
2285
2286 ================
2287 */
2288 int SV_SoundIndex(const char *s, int precachemode)
2289 {
2290         int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3) ? 256 : MAX_SOUNDS);
2291         char filename[MAX_QPATH];
2292         if (!s || !*s)
2293                 return 0;
2294         // testing
2295         //if (precachemode == 2)
2296         //      return 0;
2297         strlcpy(filename, s, sizeof(filename));
2298         for (i = 1;i < limit;i++)
2299         {
2300                 if (!sv.sound_precache[i][0])
2301                 {
2302                         if (precachemode)
2303                         {
2304                                 if (sv.state != ss_loading && (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3 || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5))
2305                                 {
2306                                         Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
2307                                         return 0;
2308                                 }
2309                                 if (precachemode == 1)
2310                                         Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
2311                                 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
2312                                 if (sv.state != ss_loading)
2313                                 {
2314                                         MSG_WriteByte(&sv.reliable_datagram, svc_precache);
2315                                         MSG_WriteShort(&sv.reliable_datagram, i + 32768);
2316                                         MSG_WriteString(&sv.reliable_datagram, filename);
2317                                 }
2318                                 return i;
2319                         }
2320                         Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
2321                         return 0;
2322                 }
2323                 if (!strcmp(sv.sound_precache[i], filename))
2324                         return i;
2325         }
2326         Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
2327         return 0;
2328 }
2329
2330 /*
2331 ================
2332 SV_ParticleEffectIndex
2333
2334 ================
2335 */
2336 int SV_ParticleEffectIndex(const char *name)
2337 {
2338         int i, argc, linenumber, effectnameindex;
2339         fs_offset_t filesize;
2340         unsigned char *filedata;
2341         const char *text, *textstart, *textend;
2342         char argv[16][1024];
2343         if (!sv.particleeffectnamesloaded)
2344         {
2345                 sv.particleeffectnamesloaded = true;
2346                 memset(sv.particleeffectname, 0, sizeof(sv.particleeffectname));
2347                 for (i = 0;i < EFFECT_TOTAL;i++)
2348                         strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i]));
2349                 filedata = FS_LoadFile("effectinfo.txt", tempmempool, true, &filesize);
2350                 if (filedata)
2351                 {
2352                         textstart = (const char *)filedata;
2353                         textend = (const char *)filedata + filesize;
2354                         text = textstart;
2355                         for (linenumber = 1;;linenumber++)
2356                         {
2357                                 argc = 0;
2358                                 for (;;)
2359                                 {
2360                                         if (!COM_ParseToken_Simple(&text, true, false) || !strcmp(com_token, "\n"))
2361                                                 break;
2362                                         if (argc < 16)
2363                                         {
2364                                                 strlcpy(argv[argc], com_token, sizeof(argv[argc]));
2365                                                 argc++;
2366                                         }
2367                                 }
2368                                 if (com_token[0] == 0)
2369                                         break; // if the loop exited and it's not a \n, it's EOF
2370                                 if (argc < 1)
2371                                         continue;
2372                                 if (!strcmp(argv[0], "effect"))
2373                                 {
2374                                         if (argc == 2)
2375                                         {
2376                                                 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME;effectnameindex++)
2377                                                 {
2378                                                         if (sv.particleeffectname[effectnameindex][0])
2379                                                         {
2380                                                                 if (!strcmp(sv.particleeffectname[effectnameindex], argv[1]))
2381                                                                         break;
2382                                                         }
2383                                                         else
2384                                                         {
2385                                                                 strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
2386                                                                 break;
2387                                                         }
2388                                                 }
2389                                                 // if we run out of names, abort
2390                                                 if (effectnameindex == SV_MAX_PARTICLEEFFECTNAME)
2391                                                 {
2392                                                         Con_Printf("effectinfo.txt:%i: too many effects!\n", linenumber);
2393                                                         break;
2394                                                 }
2395                                         }
2396                                 }
2397                         }
2398                         Mem_Free(filedata);
2399                 }
2400         }
2401         // search for the name
2402         for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME && sv.particleeffectname[effectnameindex][0];effectnameindex++)
2403                 if (!strcmp(sv.particleeffectname[effectnameindex], name))
2404                         return effectnameindex;
2405         // return 0 if we couldn't find it
2406         return 0;
2407 }
2408
2409 /*
2410 ================
2411 SV_CreateBaseline
2412
2413 ================
2414 */
2415 static void SV_CreateBaseline (void)
2416 {
2417         int i, entnum, large;
2418         prvm_edict_t *svent;
2419
2420         // LordHavoc: clear *all* states (note just active ones)
2421         for (entnum = 0;entnum < prog->max_edicts;entnum++)
2422         {
2423                 // get the current server version
2424                 svent = PRVM_EDICT_NUM(entnum);
2425
2426                 // LordHavoc: always clear state values, whether the entity is in use or not
2427                 svent->priv.server->baseline = defaultstate;
2428
2429                 if (svent->priv.server->free)
2430                         continue;
2431                 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
2432                         continue;
2433
2434                 // create entity baseline
2435                 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
2436                 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
2437                 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
2438                 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
2439                 if (entnum > 0 && entnum <= svs.maxclients)
2440                 {
2441                         svent->priv.server->baseline.colormap = entnum;
2442                         svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
2443                 }
2444                 else
2445                 {
2446                         svent->priv.server->baseline.colormap = 0;
2447                         svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
2448                 }
2449
2450                 large = false;
2451                 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
2452                 {
2453                         large = true;
2454                         if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
2455                                 large = false;
2456                 }
2457
2458                 // add to the message
2459                 if (large)
2460                         MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
2461                 else
2462                         MSG_WriteByte (&sv.signon, svc_spawnbaseline);
2463                 MSG_WriteShort (&sv.signon, entnum);
2464
2465                 if (large)
2466                 {
2467                         MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
2468                         MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
2469                 }
2470                 else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
2471                 {
2472                         MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
2473                         MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
2474                 }
2475                 else
2476                 {
2477                         MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
2478                         MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
2479                 }
2480                 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
2481                 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
2482                 for (i=0 ; i<3 ; i++)
2483                 {
2484                         MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
2485                         MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
2486                 }
2487         }
2488 }
2489
2490
2491 /*
2492 ================
2493 SV_SaveSpawnparms
2494
2495 Grabs the current state of each client for saving across the
2496 transition to another level
2497 ================
2498 */
2499 void SV_SaveSpawnparms (void)
2500 {
2501         int             i, j;
2502
2503         svs.serverflags = (int)prog->globals.server->serverflags;
2504
2505         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2506         {
2507                 if (!host_client->active)
2508                         continue;
2509
2510         // call the progs to get default spawn parms for the new client
2511                 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2512                 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
2513                 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
2514                         host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
2515         }
2516 }
2517
2518 /*
2519 ================
2520 SV_SpawnServer
2521
2522 This is called at the start of each level
2523 ================
2524 */
2525
2526 void SV_SpawnServer (const char *server)
2527 {
2528         prvm_edict_t *ent;
2529         int i;
2530         char *entities;
2531         dp_model_t *worldmodel;
2532         char modelname[sizeof(sv.modelname)];
2533
2534         Con_DPrintf("SpawnServer: %s\n", server);
2535
2536         dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
2537
2538         if (!FS_FileExists(modelname))
2539         {
2540                 Con_Printf("SpawnServer: no map file named %s\n", modelname);
2541                 return;
2542         }
2543
2544         if (cls.state != ca_dedicated)
2545         {
2546                 SCR_BeginLoadingPlaque();
2547                 S_StopAllSounds();
2548         }
2549
2550         if(sv.active)
2551         {
2552                 SV_VM_Begin();
2553                 if(prog->funcoffsets.SV_Shutdown)
2554                 {
2555                         func_t s = prog->funcoffsets.SV_Shutdown;
2556                         prog->funcoffsets.SV_Shutdown = 0; // prevent it from getting called again
2557                         PRVM_ExecuteProgram(s,"SV_Shutdown() required");
2558                 }
2559                 SV_VM_End();
2560         }
2561
2562         worldmodel = Mod_ForName(modelname, false, true, true);
2563         if (!worldmodel || !worldmodel->TraceBox)
2564         {
2565                 Con_Printf("Couldn't load map %s\n", modelname);
2566                 return;
2567         }
2568
2569         // let's not have any servers with no name
2570         if (hostname.string[0] == 0)
2571                 Cvar_Set ("hostname", "UNNAMED");
2572         scr_centertime_off = 0;
2573
2574         svs.changelevel_issued = false;         // now safe to issue another
2575
2576         // make the map a required file for clients
2577         Curl_ClearRequirements();
2578         Curl_RequireFile(modelname);
2579
2580 //
2581 // tell all connected clients that we are going to a new level
2582 //
2583         if (sv.active)
2584         {
2585                 client_t *client;
2586                 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
2587                 {
2588                         if (client->netconnection)
2589                         {
2590                                 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
2591                                 MSG_WriteString(&client->netconnection->message, "reconnect\n");
2592                         }
2593                 }
2594         }
2595         else
2596         {
2597                 // open server port
2598                 NetConn_OpenServerPorts(true);
2599         }
2600
2601 //
2602 // make cvars consistant
2603 //
2604         if (coop.integer)
2605                 Cvar_SetValue ("deathmatch", 0);
2606         // LordHavoc: it can be useful to have skills outside the range 0-3...
2607         //current_skill = bound(0, (int)(skill.value + 0.5), 3);
2608         //Cvar_SetValue ("skill", (float)current_skill);
2609         current_skill = (int)(skill.value + 0.5);
2610
2611 //
2612 // set up the new server
2613 //
2614         memset (&sv, 0, sizeof(sv));
2615         // if running a local client, make sure it doesn't try to access the last
2616         // level's data which is no longer valiud
2617         cls.signon = 0;
2618
2619         if(*sv_random_seed.string)
2620         {
2621                 srand(sv_random_seed.integer);
2622                 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);
2623         }
2624
2625         SV_VM_Setup();
2626
2627         sv.active = true;
2628
2629         strlcpy (sv.name, server, sizeof (sv.name));
2630
2631         sv.protocol = Protocol_EnumForName(sv_protocolname.string);
2632         if (sv.protocol == PROTOCOL_UNKNOWN)
2633         {
2634                 char buffer[1024];
2635                 Protocol_Names(buffer, sizeof(buffer));
2636                 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
2637                 sv.protocol = PROTOCOL_QUAKE;
2638         }
2639
2640         SV_VM_Begin();
2641
2642 // load progs to get entity field count
2643         //PR_LoadProgs ( sv_progs.string );
2644
2645         sv.datagram.maxsize = sizeof(sv.datagram_buf);
2646         sv.datagram.cursize = 0;
2647         sv.datagram.data = sv.datagram_buf;
2648
2649         sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
2650         sv.reliable_datagram.cursize = 0;
2651         sv.reliable_datagram.data = sv.reliable_datagram_buf;
2652
2653         sv.signon.maxsize = sizeof(sv.signon_buf);
2654         sv.signon.cursize = 0;
2655         sv.signon.data = sv.signon_buf;
2656
2657 // leave slots at start for clients only
2658         //prog->num_edicts = svs.maxclients+1;
2659
2660         sv.state = ss_loading;
2661         prog->allowworldwrites = true;
2662         sv.paused = false;
2663
2664         prog->globals.server->time = sv.time = 1.0;
2665
2666         Mod_ClearUsed();
2667         worldmodel->used = true;
2668
2669         strlcpy (sv.name, server, sizeof (sv.name));
2670         strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
2671         sv.worldmodel = worldmodel;
2672         sv.models[1] = sv.worldmodel;
2673
2674 //
2675 // clear world interaction links
2676 //
2677         World_SetSize(&sv.world, sv.worldmodel->name, sv.worldmodel->normalmins, sv.worldmodel->normalmaxs);
2678
2679         strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
2680
2681         strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
2682         strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
2683         for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
2684         {
2685                 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
2686                 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
2687         }
2688
2689 //
2690 // load the rest of the entities
2691 //
2692         // AK possible hack since num_edicts is still 0
2693         ent = PRVM_EDICT_NUM(0);
2694         memset (ent->fields.server, 0, prog->progs->entityfields * 4);
2695         ent->priv.server->free = false;
2696         ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
2697         ent->fields.server->modelindex = 1;             // world model
2698         ent->fields.server->solid = SOLID_BSP;
2699         ent->fields.server->movetype = MOVETYPE_PUSH;
2700         VectorCopy(sv.world.mins, ent->fields.server->mins);
2701         VectorCopy(sv.world.maxs, ent->fields.server->maxs);
2702         VectorCopy(sv.world.mins, ent->fields.server->absmin);
2703         VectorCopy(sv.world.maxs, ent->fields.server->absmax);
2704
2705         if (coop.value)
2706                 prog->globals.server->coop = coop.integer;
2707         else
2708                 prog->globals.server->deathmatch = deathmatch.integer;
2709
2710         prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2711
2712 // serverflags are for cross level information (sigils)
2713         prog->globals.server->serverflags = svs.serverflags;
2714
2715         // we need to reset the spawned flag on all connected clients here so that
2716         // their thinks don't run during startup (before PutClientInServer)
2717         // we also need to set up the client entities now
2718         // and we need to set the ->edict pointers to point into the progs edicts
2719         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2720         {
2721                 host_client->spawned = false;
2722                 host_client->edict = PRVM_EDICT_NUM(i + 1);
2723                 PRVM_ED_ClearEdict(host_client->edict);
2724         }
2725
2726         // load replacement entity file if found
2727         if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
2728         {
2729                 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2730                 PRVM_ED_LoadFromFile (entities);
2731                 Mem_Free(entities);
2732         }
2733         else
2734                 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2735
2736
2737         // LordHavoc: clear world angles (to fix e3m3.bsp)
2738         VectorClear(prog->edicts->fields.server->angles);
2739
2740 // all setup is completed, any further precache statements are errors
2741         sv.state = ss_active;
2742         prog->allowworldwrites = false;
2743
2744 // run two frames to allow everything to settle
2745         for (i = 0;i < 2;i++)
2746         {
2747                 sv.frametime = 0.1;
2748                 SV_Physics ();
2749         }
2750
2751         Mod_PurgeUnused();
2752
2753 // create a baseline for more efficient communications
2754         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE || sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
2755                 SV_CreateBaseline ();
2756
2757 // send serverinfo to all connected clients, and set up botclients coming back from a level change
2758         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2759         {
2760                 host_client->clientconnectcalled = false; // do NOT call ClientDisconnect if he drops before ClientConnect!
2761                 if (!host_client->active)
2762                         continue;
2763                 if (host_client->netconnection)
2764                         SV_SendServerinfo(host_client);
2765                 else
2766                 {
2767                         int j;
2768                         // if client is a botclient coming from a level change, we need to
2769                         // set up client info that normally requires networking
2770
2771                         // copy spawn parms out of the client_t
2772                         for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
2773                                 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
2774
2775                         // call the spawn function
2776                         host_client->clientconnectcalled = true;
2777                         prog->globals.server->time = sv.time;
2778                         prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2779                         PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
2780                         PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
2781                         host_client->spawned = true;
2782                 }
2783         }
2784
2785         Con_DPrint("Server spawned.\n");
2786         NetConn_Heartbeat (2);
2787
2788         SV_VM_End();
2789 }
2790
2791 /////////////////////////////////////////////////////
2792 // SV VM stuff
2793
2794 static void SV_VM_CB_BeginIncreaseEdicts(void)
2795 {
2796         // links don't survive the transition, so unlink everything
2797         World_UnlinkAll(&sv.world);
2798 }
2799
2800 static void SV_VM_CB_EndIncreaseEdicts(void)
2801 {
2802         int i;
2803         prvm_edict_t *ent;
2804
2805         // link every entity except world
2806         for (i = 1, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2807                 if (!ent->priv.server->free)
2808                         SV_LinkEdict(ent, false);
2809 }
2810
2811 static void SV_VM_CB_InitEdict(prvm_edict_t *e)
2812 {
2813         // LordHavoc: for consistency set these here
2814         int num = PRVM_NUM_FOR_EDICT(e) - 1;
2815
2816         e->priv.server->move = false; // don't move on first frame
2817
2818         if (num >= 0 && num < svs.maxclients)
2819         {
2820                 prvm_eval_t *val;
2821                 // set colormap and team on newly created player entity
2822                 e->fields.server->colormap = num + 1;
2823                 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
2824                 // set netname/clientcolors back to client values so that
2825                 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
2826                 // reset them
2827                 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
2828                 if ((val = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.clientcolors)))
2829                         val->_float = svs.clients[num].colors;
2830                 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
2831                 if( prog->fieldoffsets.playermodel >= 0 )
2832                         PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
2833                 if( prog->fieldoffsets.playerskin >= 0 )
2834                         PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2835                 // Assign netaddress (IP Address, etc)
2836                 if(prog->fieldoffsets.netaddress >= 0)
2837                 { // Valid Field; Process
2838                         if(svs.clients[num].netconnection != NULL)
2839                         {// Valid Address; Assign
2840                                 // Acquire Readable Address
2841                                 LHNETADDRESS_ToString(&svs.clients[num].netconnection->peeraddress, svs.clients[num].netaddress, sizeof(svs.clients[num].netaddress), false);
2842                                 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.netaddress)->string = PRVM_SetEngineString(svs.clients[num].netaddress);
2843                         }
2844                         else
2845                                 // Invalid / Bot
2846                                 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.netaddress)->string = PRVM_SetEngineString("null/botclient");
2847                 }
2848         }
2849 }
2850
2851 static void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2852 {
2853         World_UnlinkEdict(ed);          // unlink from world bsp
2854
2855         ed->fields.server->model = 0;
2856         ed->fields.server->takedamage = 0;
2857         ed->fields.server->modelindex = 0;
2858         ed->fields.server->colormap = 0;
2859         ed->fields.server->skin = 0;
2860         ed->fields.server->frame = 0;
2861         VectorClear(ed->fields.server->origin);
2862         VectorClear(ed->fields.server->angles);
2863         ed->fields.server->nextthink = -1;
2864         ed->fields.server->solid = 0;
2865 }
2866
2867 static void SV_VM_CB_CountEdicts(void)
2868 {
2869         int             i;
2870         prvm_edict_t    *ent;
2871         int             active, models, solid, step;
2872
2873         active = models = solid = step = 0;
2874         for (i=0 ; i<prog->num_edicts ; i++)
2875         {
2876                 ent = PRVM_EDICT_NUM(i);
2877                 if (ent->priv.server->free)
2878                         continue;
2879                 active++;
2880                 if (ent->fields.server->solid)
2881                         solid++;
2882                 if (ent->fields.server->model)
2883                         models++;
2884                 if (ent->fields.server->movetype == MOVETYPE_STEP)
2885                         step++;
2886         }
2887
2888         Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2889         Con_Printf("active    :%3i\n", active);
2890         Con_Printf("view      :%3i\n", models);
2891         Con_Printf("touch     :%3i\n", solid);
2892         Con_Printf("step      :%3i\n", step);
2893 }
2894
2895 static qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2896 {
2897         // remove things from different skill levels or deathmatch
2898         if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2899         {
2900                 if (deathmatch.integer)
2901                 {
2902                         if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2903                         {
2904                                 return false;
2905                         }
2906                 }
2907                 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY  ))
2908                         || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2909                         || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD  )))
2910                 {
2911                         return false;
2912                 }
2913         }
2914         return true;
2915 }
2916
2917 static void SV_VM_Setup(void)
2918 {
2919         extern cvar_t csqc_progname;    //[515]: csqc crc check and right csprogs name according to progs.dat
2920         size_t csprogsdatasize;
2921         PRVM_Begin;
2922         PRVM_InitProg( PRVM_SERVERPROG );
2923
2924         // allocate the mempools
2925         // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2926         prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2927         prog->builtins = vm_sv_builtins;
2928         prog->numbuiltins = vm_sv_numbuiltins;
2929         prog->headercrc = PROGHEADER_CRC;
2930         prog->headercrc2 = PROGHEADER_CRC_TENEBRAE;
2931         prog->max_edicts = 512;
2932         if (sv.protocol == PROTOCOL_QUAKE)
2933                 prog->limit_edicts = 640; // before quake mission pack 1 this was 512
2934         else if (sv.protocol == PROTOCOL_QUAKEDP)
2935                 prog->limit_edicts = 2048; // guessing
2936         else if (sv.protocol == PROTOCOL_NEHAHRAMOVIE)
2937                 prog->limit_edicts = 2048; // guessing!
2938         else if (sv.protocol == PROTOCOL_NEHAHRABJP || sv.protocol == PROTOCOL_NEHAHRABJP2 || sv.protocol == PROTOCOL_NEHAHRABJP3)
2939                 prog->limit_edicts = 4096; // guessing!
2940         else
2941                 prog->limit_edicts = MAX_EDICTS;
2942         prog->reserved_edicts = svs.maxclients;
2943         prog->edictprivate_size = sizeof(edict_engineprivate_t);
2944         prog->name = "server";
2945         prog->extensionstring = vm_sv_extensions;
2946         prog->loadintoworld = true;
2947
2948         prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2949         prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2950         prog->init_edict = SV_VM_CB_InitEdict;
2951         prog->free_edict = SV_VM_CB_FreeEdict;
2952         prog->count_edicts = SV_VM_CB_CountEdicts;
2953         prog->load_edict = SV_VM_CB_LoadEdict;
2954         prog->init_cmd = VM_SV_Cmd_Init;
2955         prog->reset_cmd = VM_SV_Cmd_Reset;
2956         prog->error_cmd = Host_Error;
2957
2958         // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2959         PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields, 0, NULL );
2960
2961         // some mods compiled with scrambling compilers lack certain critical
2962         // global names and field names such as "self" and "time" and "nextthink"
2963         // so we have to set these offsets manually, matching the entvars_t
2964         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles);
2965         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain);
2966         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname);
2967         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame);
2968         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity);
2969         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw);
2970         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink);
2971         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think);
2972         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed);
2973         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self);
2974         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time);
2975         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward);
2976         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right);
2977         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up);
2978         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid);
2979         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid);
2980         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction);
2981         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater);
2982         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen);
2983         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos);
2984         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal);
2985         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist);
2986         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent);
2987         // OP_STATE is always supported on server (due to entvars_t)
2988         prog->flag |= PRVM_OP_STATE;
2989
2990         VM_CustomStats_Clear();//[515]: csqc
2991
2992         PRVM_End;
2993
2994         // 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
2995         sv.csqc_progname[0] = 0;
2996         sv.csqc_progcrc = FS_CRCFile(csqc_progname.string, &csprogsdatasize);
2997         sv.csqc_progsize = csprogsdatasize;
2998         if (sv.csqc_progsize > 0)
2999         {
3000                 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
3001                 Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
3002         }
3003 }
3004
3005 void SV_VM_Begin(void)
3006 {
3007         PRVM_Begin;
3008         PRVM_SetProg( PRVM_SERVERPROG );
3009
3010         prog->globals.server->time = (float) sv.time;
3011 }
3012
3013 void SV_VM_End(void)
3014 {
3015         PRVM_End;
3016 }