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