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