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