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