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