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