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