]> icculus.org git repositories - divverent/darkplaces.git/blob - sv_main.c
also send friction/waterfriction as stats
[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         statsf[STAT_MOVEVARS_TICRATE] = sys_ticrate.value;
1368         statsf[STAT_MOVEVARS_TIMESCALE] = slowmo.value;
1369         statsf[STAT_MOVEVARS_GRAVITY] = sv_gravity.value;
1370         statsf[STAT_MOVEVARS_STOPSPEED] = sv_stopspeed.value;
1371         statsf[STAT_MOVEVARS_MAXSPEED] = sv_maxspeed.value;
1372         statsf[STAT_MOVEVARS_SPECTATORMAXSPEED] = sv_maxspeed.value; // FIXME: QW has a separate cvar for this
1373         statsf[STAT_MOVEVARS_ACCELERATE] = sv_accelerate.value;
1374         statsf[STAT_MOVEVARS_AIRACCELERATE] = sv_airaccelerate.value >= 0 ? sv_airaccelerate.value : sv_accelerate.value;
1375         statsf[STAT_MOVEVARS_WATERACCELERATE] = sv_wateraccelerate.value >= 0 ? sv_wateraccelerate.value : sv_accelerate.value;
1376         val = PRVM_EDICTFIELDVALUE(ent, prog->fieldoffsets.gravity);
1377         statsf[STAT_MOVEVARS_ENTGRAVITY] = val ? val->_float : 1.0f;
1378         statsf[STAT_MOVEVARS_JUMPVELOCITY] = sv_jumpvelocity.value;
1379         statsf[STAT_MOVEVARS_EDGEFRICTION] = sv_edgefriction.value;
1380         statsf[STAT_MOVEVARS_MAXAIRSPEED] = sv_maxairspeed.value;
1381         statsf[STAT_MOVEVARS_STEPHEIGHT] = sv_stepheight.value;
1382         statsf[STAT_MOVEVARS_AIRACCEL_QW] = sv_airaccel_qw.value;
1383         statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION] = sv_airaccel_sideways_friction.value;
1384         statsf[STAT_MOVEVARS_FRICTION] = sv_friction.value;
1385         statsf[STAT_MOVEVARS_WATERFRICTION] = sv_waterfriction.value >= 0 ? sv_waterfriction.value : sv_friction.value;
1386
1387         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)
1388         {
1389                 if (stats[STAT_VIEWHEIGHT] != DEFAULT_VIEWHEIGHT) bits |= SU_VIEWHEIGHT;
1390                 bits |= SU_ITEMS;
1391                 if (stats[STAT_WEAPONFRAME]) bits |= SU_WEAPONFRAME;
1392                 if (stats[STAT_ARMOR]) bits |= SU_ARMOR;
1393                 bits |= SU_WEAPON;
1394                 // FIXME: which protocols support this?  does PROTOCOL_DARKPLACES3 support viewzoom?
1395                 if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4 || sv.protocol == PROTOCOL_DARKPLACES5)
1396                         if (viewzoom != 255)
1397                                 bits |= SU_VIEWZOOM;
1398         }
1399
1400         if (bits >= 65536)
1401                 bits |= SU_EXTEND1;
1402         if (bits >= 16777216)
1403                 bits |= SU_EXTEND2;
1404
1405         // send the data
1406         MSG_WriteByte (msg, svc_clientdata);
1407         MSG_WriteShort (msg, bits);
1408         if (bits & SU_EXTEND1)
1409                 MSG_WriteByte(msg, bits >> 16);
1410         if (bits & SU_EXTEND2)
1411                 MSG_WriteByte(msg, bits >> 24);
1412
1413         if (bits & SU_VIEWHEIGHT)
1414                 MSG_WriteChar (msg, stats[STAT_VIEWHEIGHT]);
1415
1416         if (bits & SU_IDEALPITCH)
1417                 MSG_WriteChar (msg, (int)ent->fields.server->idealpitch);
1418
1419         for (i=0 ; i<3 ; i++)
1420         {
1421                 if (bits & (SU_PUNCH1<<i))
1422                 {
1423                         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
1424                                 MSG_WriteChar(msg, (int)ent->fields.server->punchangle[i]);
1425                         else
1426                                 MSG_WriteAngle16i(msg, ent->fields.server->punchangle[i]);
1427                 }
1428                 if (bits & (SU_PUNCHVEC1<<i))
1429                 {
1430                         if (sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1431                                 MSG_WriteCoord16i(msg, punchvector[i]);
1432                         else
1433                                 MSG_WriteCoord32f(msg, punchvector[i]);
1434                 }
1435                 if (bits & (SU_VELOCITY1<<i))
1436                 {
1437                         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_DARKPLACES1 || sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1438                                 MSG_WriteChar(msg, (int)(ent->fields.server->velocity[i] * (1.0f / 16.0f)));
1439                         else
1440                                 MSG_WriteCoord32f(msg, ent->fields.server->velocity[i]);
1441                 }
1442         }
1443
1444         if (bits & SU_ITEMS)
1445                 MSG_WriteLong (msg, stats[STAT_ITEMS]);
1446
1447         if (sv.protocol == PROTOCOL_DARKPLACES5)
1448         {
1449                 if (bits & SU_WEAPONFRAME)
1450                         MSG_WriteShort (msg, stats[STAT_WEAPONFRAME]);
1451                 if (bits & SU_ARMOR)
1452                         MSG_WriteShort (msg, stats[STAT_ARMOR]);
1453                 if (bits & SU_WEAPON)
1454                         MSG_WriteShort (msg, stats[STAT_WEAPON]);
1455                 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1456                 MSG_WriteShort (msg, stats[STAT_AMMO]);
1457                 MSG_WriteShort (msg, stats[STAT_SHELLS]);
1458                 MSG_WriteShort (msg, stats[STAT_NAILS]);
1459                 MSG_WriteShort (msg, stats[STAT_ROCKETS]);
1460                 MSG_WriteShort (msg, stats[STAT_CELLS]);
1461                 MSG_WriteShort (msg, stats[STAT_ACTIVEWEAPON]);
1462                 if (bits & SU_VIEWZOOM)
1463                         MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1464         }
1465         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)
1466         {
1467                 if (bits & SU_WEAPONFRAME)
1468                         MSG_WriteByte (msg, stats[STAT_WEAPONFRAME]);
1469                 if (bits & SU_ARMOR)
1470                         MSG_WriteByte (msg, stats[STAT_ARMOR]);
1471                 if (bits & SU_WEAPON)
1472                         MSG_WriteByte (msg, stats[STAT_WEAPON]);
1473                 MSG_WriteShort (msg, stats[STAT_HEALTH]);
1474                 MSG_WriteByte (msg, stats[STAT_AMMO]);
1475                 MSG_WriteByte (msg, stats[STAT_SHELLS]);
1476                 MSG_WriteByte (msg, stats[STAT_NAILS]);
1477                 MSG_WriteByte (msg, stats[STAT_ROCKETS]);
1478                 MSG_WriteByte (msg, stats[STAT_CELLS]);
1479                 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE || gamemode == GAME_NEXUIZ)
1480                 {
1481                         for (i = 0;i < 32;i++)
1482                                 if (stats[STAT_WEAPON] & (1<<i))
1483                                         break;
1484                         MSG_WriteByte (msg, i);
1485                 }
1486                 else
1487                         MSG_WriteByte (msg, stats[STAT_WEAPON]);
1488                 if (bits & SU_VIEWZOOM)
1489                 {
1490                         if (sv.protocol == PROTOCOL_DARKPLACES2 || sv.protocol == PROTOCOL_DARKPLACES3 || sv.protocol == PROTOCOL_DARKPLACES4)
1491                                 MSG_WriteByte (msg, bound(0, stats[STAT_VIEWZOOM], 255));
1492                         else
1493                                 MSG_WriteShort (msg, bound(0, stats[STAT_VIEWZOOM], 65535));
1494                 }
1495         }
1496 }
1497
1498 void SV_FlushBroadcastMessages(void)
1499 {
1500         int i;
1501         client_t *client;
1502         if (sv.datagram.cursize <= 0)
1503                 return;
1504         for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
1505         {
1506                 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])))
1507                         continue;
1508                 SZ_Write(&client->unreliablemsg, sv.datagram.data, sv.datagram.cursize);
1509                 client->unreliablemsg_splitpoint[client->unreliablemsg_splitpoints++] = client->unreliablemsg.cursize;
1510         }
1511         SZ_Clear(&sv.datagram);
1512 }
1513
1514 static void SV_WriteUnreliableMessages(client_t *client, sizebuf_t *msg)
1515 {
1516         // scan the splitpoints to find out how many we can fit in
1517         int numsegments, j, split;
1518         if (!client->unreliablemsg_splitpoints)
1519                 return;
1520         // always accept the first one if it's within 1400 bytes, this ensures
1521         // that very big datagrams which are over the rate limit still get
1522         // through, just to keep it working
1523         if (msg->cursize + client->unreliablemsg_splitpoint[0] > msg->maxsize && msg->maxsize < 1400)
1524         {
1525                 numsegments = 1;
1526                 msg->maxsize = 1400;
1527         }
1528         else
1529                 for (numsegments = 0;numsegments < client->unreliablemsg_splitpoints;numsegments++)
1530                         if (msg->cursize + client->unreliablemsg_splitpoint[numsegments] > msg->maxsize)
1531                                 break;
1532         if (numsegments > 0)
1533         {
1534                 // some will fit, so add the ones that will fit
1535                 split = client->unreliablemsg_splitpoint[numsegments-1];
1536                 // note this discards ones that were accepted by the segments scan but
1537                 // can not fit, such as a really huge first one that will never ever
1538                 // fit in a packet...
1539                 if (msg->cursize + split <= msg->maxsize)
1540                         SZ_Write(msg, client->unreliablemsg.data, split);
1541                 // remove the part we sent, keeping any remaining data
1542                 client->unreliablemsg.cursize -= split;
1543                 if (client->unreliablemsg.cursize > 0)
1544                         memmove(client->unreliablemsg.data, client->unreliablemsg.data + split, client->unreliablemsg.cursize);
1545                 // adjust remaining splitpoints
1546                 client->unreliablemsg_splitpoints -= numsegments;
1547                 for (j = 0;j < client->unreliablemsg_splitpoints;j++)
1548                         client->unreliablemsg_splitpoint[j] = client->unreliablemsg_splitpoint[numsegments + j] - split;
1549         }
1550 }
1551
1552 /*
1553 =======================
1554 SV_SendClientDatagram
1555 =======================
1556 */
1557 static void SV_SendClientDatagram (client_t *client)
1558 {
1559         int clientrate, maxrate, maxsize, maxsize2, downloadsize;
1560         sizebuf_t msg;
1561         int stats[MAX_CL_STATS];
1562         unsigned char sv_sendclientdatagram_buf[NET_MAXMESSAGE];
1563
1564         // PROTOCOL_DARKPLACES5 and later support packet size limiting of updates
1565         maxrate = max(NET_MINRATE, sv_maxrate.integer);
1566         if (sv_maxrate.integer != maxrate)
1567                 Cvar_SetValueQuick(&sv_maxrate, maxrate);
1568         // clientrate determines the 'cleartime' of a packet
1569         // (how long to wait before sending another, based on this packet's size)
1570         clientrate = bound(NET_MINRATE, client->rate, maxrate);
1571
1572         if (LHNETADDRESS_GetAddressType(&host_client->netconnection->peeraddress) == LHNETADDRESSTYPE_LOOP && !sv_ratelimitlocalplayer.integer)
1573         {
1574                 // for good singleplayer, send huge packets and never limit frequency
1575                 clientrate = 1000000000;
1576                 maxsize = sizeof(sv_sendclientdatagram_buf);
1577                 maxsize2 = sizeof(sv_sendclientdatagram_buf);
1578         }
1579         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)
1580         {
1581                 // no packet size limit support on older protocols because DP1-4 kick
1582                 // the client off if they overflow, and quake protocol shows less than
1583                 // the full entity set if rate limited
1584                 maxsize = 1400;
1585                 maxsize2 = 1400;
1586         }
1587         else
1588         {
1589                 // DP5 and later protocols support packet size limiting which is a
1590                 // better method than limiting packet frequency as QW does
1591                 //
1592                 // this rate limiting does not understand sys_ticrate 0
1593                 // (but no one should be running that on a server!)
1594                 maxsize = (int)(clientrate * sys_ticrate.value);
1595                 maxsize = bound(100, maxsize, 1400);
1596                 maxsize2 = 1400;
1597         }
1598
1599         // while downloading, limit entity updates to half the packet
1600         // (any leftover space will be used for downloading)
1601         if (host_client->download_file)
1602                 maxsize /= 2;
1603
1604         msg.data = sv_sendclientdatagram_buf;
1605         msg.maxsize = maxsize;
1606         msg.cursize = 0;
1607
1608         // obey rate limit by limiting packet frequency if the packet size
1609         // limiting fails
1610         // (usually this is caused by reliable messages)
1611         if (!NetConn_CanSend(client->netconnection))
1612         {
1613                 // send the datagram
1614                 //NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate);
1615                 return;
1616         }
1617         else if (host_client->spawned)
1618         {
1619                 MSG_WriteByte (&msg, svc_time);
1620                 MSG_WriteFloat (&msg, sv.time);
1621
1622                 // add the client specific data to the datagram
1623                 SV_WriteClientdataToMessage (client, client->edict, &msg, stats);
1624                 // now update the stats[] array using any registered custom fields
1625                 VM_SV_UpdateCustomStats (client, client->edict, &msg, stats);
1626                 // set host_client->statsdeltabits
1627                 Protocol_UpdateClientStats (stats);
1628
1629                 // add as many queued unreliable messages (effects) as we can fit
1630                 // limit effects to half of the remaining space
1631                 msg.maxsize -= (msg.maxsize - msg.cursize) / 2;
1632                 if (client->unreliablemsg.cursize)
1633                         SV_WriteUnreliableMessages (client, &msg);
1634
1635                 msg.maxsize = maxsize;
1636
1637                 // now write as many entities as we can fit, and also sends stats
1638                 SV_WriteEntitiesToClient (client, client->edict, &msg);
1639         }
1640         else if (realtime > client->keepalivetime)
1641         {
1642                 // the player isn't totally in the game yet
1643                 // send small keepalive messages if too much time has passed
1644                 msg.maxsize = maxsize2;
1645                 client->keepalivetime = realtime + 5;
1646                 MSG_WriteChar (&msg, svc_nop);
1647         }
1648
1649         msg.maxsize = maxsize2;
1650
1651         // if a download is active, see if there is room to fit some download data
1652         // in this packet
1653         downloadsize = maxsize * 2 - msg.cursize - 7;
1654         if (host_client->download_file && host_client->download_started && downloadsize > 0)
1655         {
1656                 fs_offset_t downloadstart;
1657                 unsigned char data[1400];
1658                 downloadstart = FS_Tell(host_client->download_file);
1659                 downloadsize = min(downloadsize, (int)sizeof(data));
1660                 downloadsize = FS_Read(host_client->download_file, data, downloadsize);
1661                 // note this sends empty messages if at the end of the file, which is
1662                 // necessary to keep the packet loss logic working
1663                 // (the last blocks may be lost and need to be re-sent, and that will
1664                 //  only occur if the client acks the empty end messages, revealing
1665                 //  a gap in the download progress, causing the last blocks to be
1666                 //  sent again)
1667                 MSG_WriteChar (&msg, svc_downloaddata);
1668                 MSG_WriteLong (&msg, downloadstart);
1669                 MSG_WriteShort (&msg, downloadsize);
1670                 if (downloadsize > 0)
1671                         SZ_Write (&msg, data, downloadsize);
1672         }
1673
1674 // send the datagram
1675         NetConn_SendUnreliableMessage (client->netconnection, &msg, sv.protocol, clientrate);
1676 }
1677
1678 /*
1679 =======================
1680 SV_UpdateToReliableMessages
1681 =======================
1682 */
1683 static void SV_UpdateToReliableMessages (void)
1684 {
1685         int i, j;
1686         client_t *client;
1687         prvm_eval_t *val;
1688         const char *name;
1689         const char *model;
1690         const char *skin;
1691
1692 // check for changes to be sent over the reliable streams
1693         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1694         {
1695                 // update the host_client fields we care about according to the entity fields
1696                 host_client->edict = PRVM_EDICT_NUM(i+1);
1697
1698                 // DP_SV_CLIENTNAME
1699                 name = PRVM_GetString(host_client->edict->fields.server->netname);
1700                 if (name == NULL)
1701                         name = "";
1702                 // always point the string back at host_client->name to keep it safe
1703                 strlcpy (host_client->name, name, sizeof (host_client->name));
1704                 host_client->edict->fields.server->netname = PRVM_SetEngineString(host_client->name);
1705                 if (strcmp(host_client->old_name, host_client->name))
1706                 {
1707                         if (host_client->spawned)
1708                                 SV_BroadcastPrintf("%s^%i changed name to %s\n", host_client->old_name, STRING_COLOR_DEFAULT, host_client->name);
1709                         strlcpy(host_client->old_name, host_client->name, sizeof(host_client->old_name));
1710                         // send notification to all clients
1711                         MSG_WriteByte (&sv.reliable_datagram, svc_updatename);
1712                         MSG_WriteByte (&sv.reliable_datagram, i);
1713                         MSG_WriteString (&sv.reliable_datagram, host_client->name);
1714                 }
1715
1716                 // DP_SV_CLIENTCOLORS
1717                 // this is always found (since it's added by the progs loader)
1718                 if ((val = PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.clientcolors)))
1719                         host_client->colors = (int)val->_float;
1720                 if (host_client->old_colors != host_client->colors)
1721                 {
1722                         host_client->old_colors = host_client->colors;
1723                         // send notification to all clients
1724                         MSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);
1725                         MSG_WriteByte (&sv.reliable_datagram, i);
1726                         MSG_WriteByte (&sv.reliable_datagram, host_client->colors);
1727                 }
1728
1729                 // NEXUIZ_PLAYERMODEL
1730                 if( prog->fieldoffsets.playermodel >= 0 ) {
1731                         model = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string);
1732                         if (model == NULL)
1733                                 model = "";
1734                         // always point the string back at host_client->name to keep it safe
1735                         strlcpy (host_client->playermodel, model, sizeof (host_client->playermodel));
1736                         PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(host_client->playermodel);
1737                 }
1738
1739                 // NEXUIZ_PLAYERSKIN
1740                 if( prog->fieldoffsets.playerskin >= 0 ) {
1741                         skin = PRVM_GetString(PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string);
1742                         if (skin == NULL)
1743                                 skin = "";
1744                         // always point the string back at host_client->name to keep it safe
1745                         strlcpy (host_client->playerskin, skin, sizeof (host_client->playerskin));
1746                         PRVM_EDICTFIELDVALUE(host_client->edict, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(host_client->playerskin);
1747                 }
1748
1749                 // frags
1750                 host_client->frags = (int)host_client->edict->fields.server->frags;
1751                 if (host_client->old_frags != host_client->frags)
1752                 {
1753                         host_client->old_frags = host_client->frags;
1754                         // send notification to all clients
1755                         MSG_WriteByte (&sv.reliable_datagram, svc_updatefrags);
1756                         MSG_WriteByte (&sv.reliable_datagram, i);
1757                         MSG_WriteShort (&sv.reliable_datagram, host_client->frags);
1758                 }
1759         }
1760
1761         for (j = 0, client = svs.clients;j < svs.maxclients;j++, client++)
1762                 if (client->netconnection)
1763                         SZ_Write (&client->netconnection->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);
1764
1765         SZ_Clear (&sv.reliable_datagram);
1766 }
1767
1768
1769 /*
1770 =======================
1771 SV_SendClientMessages
1772 =======================
1773 */
1774 void SV_SendClientMessages (void)
1775 {
1776         int i;
1777
1778         if (sv.protocol == PROTOCOL_QUAKEWORLD)
1779                 Sys_Error("SV_SendClientMessages: no quakeworld support\n");
1780
1781         SV_FlushBroadcastMessages();
1782
1783 // update frags, names, etc
1784         SV_UpdateToReliableMessages();
1785
1786 // build individual updates
1787         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
1788         {
1789                 if (!host_client->active)
1790                         continue;
1791                 if (!host_client->netconnection)
1792                         continue;
1793
1794                 if (host_client->netconnection->message.overflowed)
1795                 {
1796                         SV_DropClient (true);   // if the message couldn't send, kick off
1797                         continue;
1798                 }
1799
1800                 SV_SendClientDatagram (host_client);
1801         }
1802
1803 // clear muzzle flashes
1804         SV_CleanupEnts();
1805 }
1806
1807 static void SV_StartDownload_f(void)
1808 {
1809         if (host_client->download_file)
1810                 host_client->download_started = true;
1811 }
1812
1813 static void SV_Download_f(void)
1814 {
1815         const char *whichpack, *whichpack2, *extension;
1816
1817         if (Cmd_Argc() != 2)
1818         {
1819                 SV_ClientPrintf("usage: download <filename>\n");
1820                 return;
1821         }
1822
1823         if (FS_CheckNastyPath(Cmd_Argv(1), false))
1824         {
1825                 SV_ClientPrintf("Download rejected: nasty filename \"%s\"\n", Cmd_Argv(1));
1826                 return;
1827         }
1828
1829         if (host_client->download_file)
1830         {
1831                 // at this point we'll assume the previous download should be aborted
1832                 Con_DPrintf("Download of %s aborted by %s starting a new download\n", host_client->download_name, host_client->name);
1833                 Host_ClientCommands("\nstopdownload\n");
1834
1835                 // close the file and reset variables
1836                 FS_Close(host_client->download_file);
1837                 host_client->download_file = NULL;
1838                 host_client->download_name[0] = 0;
1839                 host_client->download_expectedposition = 0;
1840                 host_client->download_started = false;
1841         }
1842
1843         if (!sv_allowdownloads.integer)
1844         {
1845                 SV_ClientPrintf("Downloads are disabled on this server\n");
1846                 Host_ClientCommands("\nstopdownload\n");
1847                 return;
1848         }
1849
1850         strlcpy(host_client->download_name, Cmd_Argv(1), sizeof(host_client->download_name));
1851         extension = FS_FileExtension(host_client->download_name);
1852
1853         // host_client is asking to download a specified file
1854         if (developer.integer >= 100)
1855                 Con_Printf("Download request for %s by %s\n", host_client->download_name, host_client->name);
1856
1857         if (!FS_FileExists(host_client->download_name))
1858         {
1859                 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);
1860                 Host_ClientCommands("\nstopdownload\n");
1861                 return;
1862         }
1863
1864         // check if the user is trying to download part of registered Quake(r)
1865         whichpack = FS_WhichPack(host_client->download_name);
1866         whichpack2 = FS_WhichPack("gfx/pop.lmp");
1867         if ((whichpack && whichpack2 && !strcasecmp(whichpack, whichpack2)) || FS_IsRegisteredQuakePack(host_client->download_name))
1868         {
1869                 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);
1870                 Host_ClientCommands("\nstopdownload\n");
1871                 return;
1872         }
1873
1874         // check if the server has forbidden archive downloads entirely
1875         if (!sv_allowdownloads_inarchive.integer)
1876         {
1877                 whichpack = FS_WhichPack(host_client->download_name);
1878                 if (whichpack)
1879                 {
1880                         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);
1881                         Host_ClientCommands("\nstopdownload\n");
1882                         return;
1883                 }
1884         }
1885
1886         if (!sv_allowdownloads_config.integer)
1887         {
1888                 if (!strcasecmp(extension, "cfg"))
1889                 {
1890                         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);
1891                         Host_ClientCommands("\nstopdownload\n");
1892                         return;
1893                 }
1894         }
1895
1896         if (!sv_allowdownloads_dlcache.integer)
1897         {
1898                 if (!strncasecmp(host_client->download_name, "dlcache/", 8))
1899                 {
1900                         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);
1901                         Host_ClientCommands("\nstopdownload\n");
1902                         return;
1903                 }
1904         }
1905
1906         if (!sv_allowdownloads_archive.integer)
1907         {
1908                 if (!strcasecmp(extension, "pak") || !strcasecmp(extension, "pk3"))
1909                 {
1910                         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);
1911                         Host_ClientCommands("\nstopdownload\n");
1912                         return;
1913                 }
1914         }
1915
1916         host_client->download_file = FS_Open(host_client->download_name, "rb", true, false);
1917         if (!host_client->download_file)
1918         {
1919                 SV_ClientPrintf("Download rejected: server could not open the file \"%s\"\n", host_client->download_name);
1920                 Host_ClientCommands("\nstopdownload\n");
1921                 return;
1922         }
1923
1924         if (FS_FileSize(host_client->download_file) > 1<<30)
1925         {
1926                 SV_ClientPrintf("Download rejected: file \"%s\" is very large\n", host_client->download_name);
1927                 Host_ClientCommands("\nstopdownload\n");
1928                 FS_Close(host_client->download_file);
1929                 host_client->download_file = NULL;
1930                 return;
1931         }
1932
1933         Con_DPrintf("Downloading %s to %s\n", host_client->download_name, host_client->name);
1934
1935         Host_ClientCommands("\ncl_downloadbegin %i %s\n", (int)FS_FileSize(host_client->download_file), host_client->download_name);
1936
1937         host_client->download_expectedposition = 0;
1938         host_client->download_started = false;
1939
1940         // the rest of the download process is handled in SV_SendClientDatagram
1941         // and other code dealing with svc_downloaddata and clc_ackdownloaddata
1942         //
1943         // no svc_downloaddata messages will be sent until sv_startdownload is
1944         // sent by the client
1945 }
1946
1947 /*
1948 ==============================================================================
1949
1950 SERVER SPAWNING
1951
1952 ==============================================================================
1953 */
1954
1955 /*
1956 ================
1957 SV_ModelIndex
1958
1959 ================
1960 */
1961 int SV_ModelIndex(const char *s, int precachemode)
1962 {
1963         int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_MODELS);
1964         char filename[MAX_QPATH];
1965         if (!s || !*s)
1966                 return 0;
1967         // testing
1968         //if (precachemode == 2)
1969         //      return 0;
1970         strlcpy(filename, s, sizeof(filename));
1971         for (i = 2;i < limit;i++)
1972         {
1973                 if (!sv.model_precache[i][0])
1974                 {
1975                         if (precachemode)
1976                         {
1977                                 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))
1978                                 {
1979                                         Con_Printf("SV_ModelIndex(\"%s\"): precache_model can only be done in spawn functions\n", filename);
1980                                         return 0;
1981                                 }
1982                                 if (precachemode == 1)
1983                                         Con_Printf("SV_ModelIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
1984                                 strlcpy(sv.model_precache[i], filename, sizeof(sv.model_precache[i]));
1985                                 sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, false);
1986                                 if (sv.state != ss_loading)
1987                                 {
1988                                         MSG_WriteByte(&sv.reliable_datagram, svc_precache);
1989                                         MSG_WriteShort(&sv.reliable_datagram, i);
1990                                         MSG_WriteString(&sv.reliable_datagram, filename);
1991                                 }
1992                                 return i;
1993                         }
1994                         Con_Printf("SV_ModelIndex(\"%s\"): not precached\n", filename);
1995                         return 0;
1996                 }
1997                 if (!strcmp(sv.model_precache[i], filename))
1998                         return i;
1999         }
2000         Con_Printf("SV_ModelIndex(\"%s\"): i (%i) == MAX_MODELS (%i)\n", filename, i, MAX_MODELS);
2001         return 0;
2002 }
2003
2004 /*
2005 ================
2006 SV_SoundIndex
2007
2008 ================
2009 */
2010 int SV_SoundIndex(const char *s, int precachemode)
2011 {
2012         int i, limit = ((sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE) ? 256 : MAX_SOUNDS);
2013         char filename[MAX_QPATH];
2014         if (!s || !*s)
2015                 return 0;
2016         // testing
2017         //if (precachemode == 2)
2018         //      return 0;
2019         strlcpy(filename, s, sizeof(filename));
2020         for (i = 1;i < limit;i++)
2021         {
2022                 if (!sv.sound_precache[i][0])
2023                 {
2024                         if (precachemode)
2025                         {
2026                                 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))
2027                                 {
2028                                         Con_Printf("SV_SoundIndex(\"%s\"): precache_sound can only be done in spawn functions\n", filename);
2029                                         return 0;
2030                                 }
2031                                 if (precachemode == 1)
2032                                         Con_Printf("SV_SoundIndex(\"%s\"): not precached (fix your code), precaching anyway\n", filename);
2033                                 strlcpy(sv.sound_precache[i], filename, sizeof(sv.sound_precache[i]));
2034                                 if (sv.state != ss_loading)
2035                                 {
2036                                         MSG_WriteByte(&sv.reliable_datagram, svc_precache);
2037                                         MSG_WriteShort(&sv.reliable_datagram, i + 32768);
2038                                         MSG_WriteString(&sv.reliable_datagram, filename);
2039                                 }
2040                                 return i;
2041                         }
2042                         Con_Printf("SV_SoundIndex(\"%s\"): not precached\n", filename);
2043                         return 0;
2044                 }
2045                 if (!strcmp(sv.sound_precache[i], filename))
2046                         return i;
2047         }
2048         Con_Printf("SV_SoundIndex(\"%s\"): i (%i) == MAX_SOUNDS (%i)\n", filename, i, MAX_SOUNDS);
2049         return 0;
2050 }
2051
2052 /*
2053 ================
2054 SV_ParticleEffectIndex
2055
2056 ================
2057 */
2058 int SV_ParticleEffectIndex(const char *name)
2059 {
2060         int i, argc, linenumber, effectnameindex;
2061         fs_offset_t filesize;
2062         unsigned char *filedata;
2063         const char *text, *textstart, *textend;
2064         char argv[16][1024];
2065         if (!sv.particleeffectnamesloaded)
2066         {
2067                 sv.particleeffectnamesloaded = true;
2068                 memset(sv.particleeffectname, 0, sizeof(sv.particleeffectname));
2069                 for (i = 0;i < EFFECT_TOTAL;i++)
2070                         strlcpy(sv.particleeffectname[i], standardeffectnames[i], sizeof(sv.particleeffectname[i]));
2071                 filedata = FS_LoadFile("effectinfo.txt", tempmempool, true, &filesize);
2072                 if (filedata)
2073                 {
2074                         textstart = (const char *)filedata;
2075                         textend = (const char *)filedata + filesize;
2076                         text = textstart;
2077                         for (linenumber = 1;;linenumber++)
2078                         {
2079                                 argc = 0;
2080                                 for (;;)
2081                                 {
2082                                         if (!COM_ParseToken_Simple(&text, true) || !strcmp(com_token, "\n"))
2083                                                 break;
2084                                         if (argc < 16)
2085                                         {
2086                                                 strlcpy(argv[argc], com_token, sizeof(argv[argc]));
2087                                                 argc++;
2088                                         }
2089                                 }
2090                                 if (com_token[0] == 0)
2091                                         break; // if the loop exited and it's not a \n, it's EOF
2092                                 if (argc < 1)
2093                                         continue;
2094                                 if (!strcmp(argv[0], "effect"))
2095                                 {
2096                                         if (argc == 2)
2097                                         {
2098                                                 for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME;effectnameindex++)
2099                                                 {
2100                                                         if (sv.particleeffectname[effectnameindex][0])
2101                                                         {
2102                                                                 if (!strcmp(sv.particleeffectname[effectnameindex], argv[1]))
2103                                                                         break;
2104                                                         }
2105                                                         else
2106                                                         {
2107                                                                 strlcpy(sv.particleeffectname[effectnameindex], argv[1], sizeof(sv.particleeffectname[effectnameindex]));
2108                                                                 break;
2109                                                         }
2110                                                 }
2111                                                 // if we run out of names, abort
2112                                                 if (effectnameindex == SV_MAX_PARTICLEEFFECTNAME)
2113                                                 {
2114                                                         Con_Printf("effectinfo.txt:%i: too many effects!\n", linenumber);
2115                                                         break;
2116                                                 }
2117                                         }
2118                                 }
2119                         }
2120                         Mem_Free(filedata);
2121                 }
2122         }
2123         // search for the name
2124         for (effectnameindex = 1;effectnameindex < SV_MAX_PARTICLEEFFECTNAME && sv.particleeffectname[effectnameindex][0];effectnameindex++)
2125                 if (!strcmp(sv.particleeffectname[effectnameindex], name))
2126                         return effectnameindex;
2127         // return 0 if we couldn't find it
2128         return 0;
2129 }
2130
2131 /*
2132 ================
2133 SV_CreateBaseline
2134
2135 ================
2136 */
2137 static void SV_CreateBaseline (void)
2138 {
2139         int i, entnum, large;
2140         prvm_edict_t *svent;
2141
2142         // LordHavoc: clear *all* states (note just active ones)
2143         for (entnum = 0;entnum < prog->max_edicts;entnum++)
2144         {
2145                 // get the current server version
2146                 svent = PRVM_EDICT_NUM(entnum);
2147
2148                 // LordHavoc: always clear state values, whether the entity is in use or not
2149                 svent->priv.server->baseline = defaultstate;
2150
2151                 if (svent->priv.server->free)
2152                         continue;
2153                 if (entnum > svs.maxclients && !svent->fields.server->modelindex)
2154                         continue;
2155
2156                 // create entity baseline
2157                 VectorCopy (svent->fields.server->origin, svent->priv.server->baseline.origin);
2158                 VectorCopy (svent->fields.server->angles, svent->priv.server->baseline.angles);
2159                 svent->priv.server->baseline.frame = (int)svent->fields.server->frame;
2160                 svent->priv.server->baseline.skin = (int)svent->fields.server->skin;
2161                 if (entnum > 0 && entnum <= svs.maxclients)
2162                 {
2163                         svent->priv.server->baseline.colormap = entnum;
2164                         svent->priv.server->baseline.modelindex = SV_ModelIndex("progs/player.mdl", 1);
2165                 }
2166                 else
2167                 {
2168                         svent->priv.server->baseline.colormap = 0;
2169                         svent->priv.server->baseline.modelindex = (int)svent->fields.server->modelindex;
2170                 }
2171
2172                 large = false;
2173                 if (svent->priv.server->baseline.modelindex & 0xFF00 || svent->priv.server->baseline.frame & 0xFF00)
2174                         large = true;
2175
2176                 // add to the message
2177                 if (large)
2178                         MSG_WriteByte (&sv.signon, svc_spawnbaseline2);
2179                 else
2180                         MSG_WriteByte (&sv.signon, svc_spawnbaseline);
2181                 MSG_WriteShort (&sv.signon, entnum);
2182
2183                 if (large)
2184                 {
2185                         MSG_WriteShort (&sv.signon, svent->priv.server->baseline.modelindex);
2186                         MSG_WriteShort (&sv.signon, svent->priv.server->baseline.frame);
2187                 }
2188                 else
2189                 {
2190                         MSG_WriteByte (&sv.signon, svent->priv.server->baseline.modelindex);
2191                         MSG_WriteByte (&sv.signon, svent->priv.server->baseline.frame);
2192                 }
2193                 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.colormap);
2194                 MSG_WriteByte (&sv.signon, svent->priv.server->baseline.skin);
2195                 for (i=0 ; i<3 ; i++)
2196                 {
2197                         MSG_WriteCoord(&sv.signon, svent->priv.server->baseline.origin[i], sv.protocol);
2198                         MSG_WriteAngle(&sv.signon, svent->priv.server->baseline.angles[i], sv.protocol);
2199                 }
2200         }
2201 }
2202
2203
2204 /*
2205 ================
2206 SV_SaveSpawnparms
2207
2208 Grabs the current state of each client for saving across the
2209 transition to another level
2210 ================
2211 */
2212 void SV_SaveSpawnparms (void)
2213 {
2214         int             i, j;
2215
2216         svs.serverflags = (int)prog->globals.server->serverflags;
2217
2218         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2219         {
2220                 if (!host_client->active)
2221                         continue;
2222
2223         // call the progs to get default spawn parms for the new client
2224                 prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2225                 PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing");
2226                 for (j=0 ; j<NUM_SPAWN_PARMS ; j++)
2227                         host_client->spawn_parms[j] = (&prog->globals.server->parm1)[j];
2228         }
2229 }
2230
2231 /*
2232 ================
2233 SV_SpawnServer
2234
2235 This is called at the start of each level
2236 ================
2237 */
2238
2239 void SV_SpawnServer (const char *server)
2240 {
2241         prvm_edict_t *ent;
2242         int i;
2243         char *entities;
2244         model_t *worldmodel;
2245         char modelname[sizeof(sv.modelname)];
2246
2247         Con_DPrintf("SpawnServer: %s\n", server);
2248
2249         if (cls.state != ca_dedicated)
2250                 SCR_BeginLoadingPlaque();
2251
2252         dpsnprintf (modelname, sizeof(modelname), "maps/%s.bsp", server);
2253         worldmodel = Mod_ForName(modelname, false, true, true);
2254         if (!worldmodel || !worldmodel->TraceBox)
2255         {
2256                 Con_Printf("Couldn't load map %s\n", modelname);
2257                 return;
2258         }
2259
2260         // let's not have any servers with no name
2261         if (hostname.string[0] == 0)
2262                 Cvar_Set ("hostname", "UNNAMED");
2263         scr_centertime_off = 0;
2264
2265         svs.changelevel_issued = false;         // now safe to issue another
2266
2267         // make the map a required file for clients
2268         Curl_ClearRequirements();
2269         Curl_RequireFile(modelname);
2270
2271 //
2272 // tell all connected clients that we are going to a new level
2273 //
2274         if (sv.active)
2275         {
2276                 client_t *client;
2277                 for (i = 0, client = svs.clients;i < svs.maxclients;i++, client++)
2278                 {
2279                         if (client->netconnection)
2280                         {
2281                                 MSG_WriteByte(&client->netconnection->message, svc_stufftext);
2282                                 MSG_WriteString(&client->netconnection->message, "reconnect\n");
2283                         }
2284                 }
2285         }
2286         else
2287         {
2288                 // open server port
2289                 NetConn_OpenServerPorts(true);
2290         }
2291
2292 //
2293 // make cvars consistant
2294 //
2295         if (coop.integer)
2296                 Cvar_SetValue ("deathmatch", 0);
2297         // LordHavoc: it can be useful to have skills outside the range 0-3...
2298         //current_skill = bound(0, (int)(skill.value + 0.5), 3);
2299         //Cvar_SetValue ("skill", (float)current_skill);
2300         current_skill = (int)(skill.value + 0.5);
2301
2302 //
2303 // set up the new server
2304 //
2305         memset (&sv, 0, sizeof(sv));
2306         // if running a local client, make sure it doesn't try to access the last
2307         // level's data which is no longer valiud
2308         cls.signon = 0;
2309
2310         if(*sv_random_seed.string)
2311         {
2312                 srand(sv_random_seed.integer);
2313                 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);
2314         }
2315
2316         SV_VM_Setup();
2317
2318         sv.active = true;
2319
2320         strlcpy (sv.name, server, sizeof (sv.name));
2321
2322         sv.protocol = Protocol_EnumForName(sv_protocolname.string);
2323         if (sv.protocol == PROTOCOL_UNKNOWN)
2324         {
2325                 char buffer[1024];
2326                 Protocol_Names(buffer, sizeof(buffer));
2327                 Con_Printf("Unknown sv_protocolname \"%s\", valid values are:\n%s\n", sv_protocolname.string, buffer);
2328                 sv.protocol = PROTOCOL_QUAKE;
2329         }
2330
2331         SV_VM_Begin();
2332
2333 // load progs to get entity field count
2334         //PR_LoadProgs ( sv_progs.string );
2335
2336         sv.datagram.maxsize = sizeof(sv.datagram_buf);
2337         sv.datagram.cursize = 0;
2338         sv.datagram.data = sv.datagram_buf;
2339
2340         sv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);
2341         sv.reliable_datagram.cursize = 0;
2342         sv.reliable_datagram.data = sv.reliable_datagram_buf;
2343
2344         sv.signon.maxsize = sizeof(sv.signon_buf);
2345         sv.signon.cursize = 0;
2346         sv.signon.data = sv.signon_buf;
2347
2348 // leave slots at start for clients only
2349         //prog->num_edicts = svs.maxclients+1;
2350
2351         sv.state = ss_loading;
2352         prog->allowworldwrites = true;
2353         sv.paused = false;
2354
2355         prog->globals.server->time = sv.time = 1.0;
2356
2357         Mod_ClearUsed();
2358         worldmodel->used = true;
2359
2360         strlcpy (sv.name, server, sizeof (sv.name));
2361         strlcpy(sv.modelname, modelname, sizeof(sv.modelname));
2362         sv.worldmodel = worldmodel;
2363         sv.models[1] = sv.worldmodel;
2364
2365 //
2366 // clear world interaction links
2367 //
2368         VectorCopy(sv.worldmodel->normalmins, sv.world.areagrid_mins);
2369         VectorCopy(sv.worldmodel->normalmaxs, sv.world.areagrid_maxs);
2370         World_Clear(&sv.world);
2371
2372         strlcpy(sv.sound_precache[0], "", sizeof(sv.sound_precache[0]));
2373
2374         strlcpy(sv.model_precache[0], "", sizeof(sv.model_precache[0]));
2375         strlcpy(sv.model_precache[1], sv.modelname, sizeof(sv.model_precache[1]));
2376         for (i = 1;i < sv.worldmodel->brush.numsubmodels;i++)
2377         {
2378                 dpsnprintf(sv.model_precache[i+1], sizeof(sv.model_precache[i+1]), "*%i", i);
2379                 sv.models[i+1] = Mod_ForName (sv.model_precache[i+1], false, false, false);
2380         }
2381
2382 //
2383 // load the rest of the entities
2384 //
2385         // AK possible hack since num_edicts is still 0
2386         ent = PRVM_EDICT_NUM(0);
2387         memset (ent->fields.server, 0, prog->progs->entityfields * 4);
2388         ent->priv.server->free = false;
2389         ent->fields.server->model = PRVM_SetEngineString(sv.modelname);
2390         ent->fields.server->modelindex = 1;             // world model
2391         ent->fields.server->solid = SOLID_BSP;
2392         ent->fields.server->movetype = MOVETYPE_PUSH;
2393         VectorCopy(sv.worldmodel->normalmins, ent->fields.server->mins);
2394         VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->maxs);
2395         VectorCopy(sv.worldmodel->normalmins, ent->fields.server->absmin);
2396         VectorCopy(sv.worldmodel->normalmaxs, ent->fields.server->absmax);
2397
2398         if (coop.value)
2399                 prog->globals.server->coop = coop.integer;
2400         else
2401                 prog->globals.server->deathmatch = deathmatch.integer;
2402
2403         prog->globals.server->mapname = PRVM_SetEngineString(sv.name);
2404
2405 // serverflags are for cross level information (sigils)
2406         prog->globals.server->serverflags = svs.serverflags;
2407
2408         // we need to reset the spawned flag on all connected clients here so that
2409         // their thinks don't run during startup (before PutClientInServer)
2410         // we also need to set up the client entities now
2411         // and we need to set the ->edict pointers to point into the progs edicts
2412         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2413         {
2414                 host_client->spawned = false;
2415                 host_client->edict = PRVM_EDICT_NUM(i + 1);
2416                 PRVM_ED_ClearEdict(host_client->edict);
2417         }
2418
2419         // load replacement entity file if found
2420         if (sv_entpatch.integer && (entities = (char *)FS_LoadFile(va("maps/%s.ent", sv.name), tempmempool, true, NULL)))
2421         {
2422                 Con_Printf("Loaded maps/%s.ent\n", sv.name);
2423                 PRVM_ED_LoadFromFile (entities);
2424                 Mem_Free(entities);
2425         }
2426         else
2427                 PRVM_ED_LoadFromFile (sv.worldmodel->brush.entities);
2428
2429
2430         // LordHavoc: clear world angles (to fix e3m3.bsp)
2431         VectorClear(prog->edicts->fields.server->angles);
2432
2433 // all setup is completed, any further precache statements are errors
2434         sv.state = ss_active;
2435         prog->allowworldwrites = false;
2436
2437 // run two frames to allow everything to settle
2438         for (i = 0;i < 2;i++)
2439         {
2440                 sv.frametime = 0.1;
2441                 SV_Physics ();
2442         }
2443
2444         Mod_PurgeUnused();
2445
2446 // create a baseline for more efficient communications
2447         if (sv.protocol == PROTOCOL_QUAKE || sv.protocol == PROTOCOL_QUAKEDP || sv.protocol == PROTOCOL_NEHAHRAMOVIE)
2448                 SV_CreateBaseline ();
2449
2450 // send serverinfo to all connected clients, and set up botclients coming back from a level change
2451         for (i = 0, host_client = svs.clients;i < svs.maxclients;i++, host_client++)
2452         {
2453                 if (!host_client->active)
2454                         continue;
2455                 if (host_client->netconnection)
2456                         SV_SendServerinfo(host_client);
2457                 else
2458                 {
2459                         int j;
2460                         // if client is a botclient coming from a level change, we need to
2461                         // set up client info that normally requires networking
2462
2463                         // copy spawn parms out of the client_t
2464                         for (j=0 ; j< NUM_SPAWN_PARMS ; j++)
2465                                 (&prog->globals.server->parm1)[j] = host_client->spawn_parms[j];
2466
2467                         // call the spawn function
2468                         host_client->clientconnectcalled = true;
2469                         prog->globals.server->time = sv.time;
2470                         prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
2471                         PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing");
2472                         PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing");
2473                         host_client->spawned = true;
2474                 }
2475         }
2476
2477         Con_DPrint("Server spawned.\n");
2478         NetConn_Heartbeat (2);
2479
2480         SV_VM_End();
2481 }
2482
2483 /////////////////////////////////////////////////////
2484 // SV VM stuff
2485
2486 static void SV_VM_CB_BeginIncreaseEdicts(void)
2487 {
2488         int i;
2489         prvm_edict_t *ent;
2490
2491         // links don't survive the transition, so unlink everything
2492         for (i = 0, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2493         {
2494                 if (!ent->priv.server->free)
2495                         World_UnlinkEdict(prog->edicts + i);
2496                 memset(&ent->priv.server->areagrid, 0, sizeof(ent->priv.server->areagrid));
2497         }
2498         World_Clear(&sv.world);
2499 }
2500
2501 static void SV_VM_CB_EndIncreaseEdicts(void)
2502 {
2503         int i;
2504         prvm_edict_t *ent;
2505
2506         // link every entity except world
2507         for (i = 1, ent = prog->edicts;i < prog->max_edicts;i++, ent++)
2508                 if (!ent->priv.server->free)
2509                         SV_LinkEdict(ent, false);
2510 }
2511
2512 static void SV_VM_CB_InitEdict(prvm_edict_t *e)
2513 {
2514         // LordHavoc: for consistency set these here
2515         int num = PRVM_NUM_FOR_EDICT(e) - 1;
2516
2517         e->priv.server->move = false; // don't move on first frame
2518
2519         if (num >= 0 && num < svs.maxclients)
2520         {
2521                 prvm_eval_t *val;
2522                 // set colormap and team on newly created player entity
2523                 e->fields.server->colormap = num + 1;
2524                 e->fields.server->team = (svs.clients[num].colors & 15) + 1;
2525                 // set netname/clientcolors back to client values so that
2526                 // DP_SV_CLIENTNAME and DP_SV_CLIENTCOLORS will not immediately
2527                 // reset them
2528                 e->fields.server->netname = PRVM_SetEngineString(svs.clients[num].name);
2529                 if ((val = PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.clientcolors)))
2530                         val->_float = svs.clients[num].colors;
2531                 // NEXUIZ_PLAYERMODEL and NEXUIZ_PLAYERSKIN
2532                 if( prog->fieldoffsets.playermodel >= 0 )
2533                         PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playermodel)->string = PRVM_SetEngineString(svs.clients[num].playermodel);
2534                 if( prog->fieldoffsets.playerskin >= 0 )
2535                         PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.playerskin)->string = PRVM_SetEngineString(svs.clients[num].playerskin);
2536                 // Assign netaddress (IP Address, etc)
2537                 if(prog->fieldoffsets.netaddress >= 0)
2538                 { // Valid Field; Process
2539                         if(svs.clients[num].netconnection != NULL)
2540                         {// Valid Address; Assign
2541                                 // Acquire Readable Address
2542                                 LHNETADDRESS_ToString(&svs.clients[num].netconnection->peeraddress, svs.clients[num].netaddress, sizeof(svs.clients[num].netaddress), false);
2543                                 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.netaddress)->string = PRVM_SetEngineString(svs.clients[num].netaddress);
2544                         }
2545                         else
2546                                 // Invalid / Bot
2547                                 PRVM_EDICTFIELDVALUE(e, prog->fieldoffsets.netaddress)->string = PRVM_SetEngineString("null/botclient");
2548                 }
2549         }
2550 }
2551
2552 static void SV_VM_CB_FreeEdict(prvm_edict_t *ed)
2553 {
2554         World_UnlinkEdict(ed);          // unlink from world bsp
2555
2556         ed->fields.server->model = 0;
2557         ed->fields.server->takedamage = 0;
2558         ed->fields.server->modelindex = 0;
2559         ed->fields.server->colormap = 0;
2560         ed->fields.server->skin = 0;
2561         ed->fields.server->frame = 0;
2562         VectorClear(ed->fields.server->origin);
2563         VectorClear(ed->fields.server->angles);
2564         ed->fields.server->nextthink = -1;
2565         ed->fields.server->solid = 0;
2566 }
2567
2568 static void SV_VM_CB_CountEdicts(void)
2569 {
2570         int             i;
2571         prvm_edict_t    *ent;
2572         int             active, models, solid, step;
2573
2574         active = models = solid = step = 0;
2575         for (i=0 ; i<prog->num_edicts ; i++)
2576         {
2577                 ent = PRVM_EDICT_NUM(i);
2578                 if (ent->priv.server->free)
2579                         continue;
2580                 active++;
2581                 if (ent->fields.server->solid)
2582                         solid++;
2583                 if (ent->fields.server->model)
2584                         models++;
2585                 if (ent->fields.server->movetype == MOVETYPE_STEP)
2586                         step++;
2587         }
2588
2589         Con_Printf("num_edicts:%3i\n", prog->num_edicts);
2590         Con_Printf("active    :%3i\n", active);
2591         Con_Printf("view      :%3i\n", models);
2592         Con_Printf("touch     :%3i\n", solid);
2593         Con_Printf("step      :%3i\n", step);
2594 }
2595
2596 static qboolean SV_VM_CB_LoadEdict(prvm_edict_t *ent)
2597 {
2598         // remove things from different skill levels or deathmatch
2599         if (gamemode != GAME_TRANSFUSION) //Transfusion does this in QC
2600         {
2601                 if (deathmatch.integer)
2602                 {
2603                         if (((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_DEATHMATCH))
2604                         {
2605                                 return false;
2606                         }
2607                 }
2608                 else if ((current_skill <= 0 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_EASY  ))
2609                         || (current_skill == 1 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_MEDIUM))
2610                         || (current_skill >= 2 && ((int)ent->fields.server->spawnflags & SPAWNFLAG_NOT_HARD  )))
2611                 {
2612                         return false;
2613                 }
2614         }
2615         return true;
2616 }
2617
2618 static void SV_VM_Setup(void)
2619 {
2620         extern cvar_t csqc_progname;    //[515]: csqc crc check and right csprogs name according to progs.dat
2621         extern cvar_t csqc_progcrc;
2622         extern cvar_t csqc_progsize;
2623         size_t csprogsdatasize;
2624         PRVM_Begin;
2625         PRVM_InitProg( PRVM_SERVERPROG );
2626
2627         // allocate the mempools
2628         // TODO: move the magic numbers/constants into #defines [9/13/2006 Black]
2629         prog->progs_mempool = Mem_AllocPool("Server Progs", 0, NULL);
2630         prog->builtins = vm_sv_builtins;
2631         prog->numbuiltins = vm_sv_numbuiltins;
2632         prog->headercrc = PROGHEADER_CRC;
2633         prog->max_edicts = 512;
2634         prog->limit_edicts = MAX_EDICTS;
2635         prog->reserved_edicts = svs.maxclients;
2636         prog->edictprivate_size = sizeof(edict_engineprivate_t);
2637         prog->name = "server";
2638         prog->extensionstring = vm_sv_extensions;
2639         prog->loadintoworld = true;
2640
2641         prog->begin_increase_edicts = SV_VM_CB_BeginIncreaseEdicts;
2642         prog->end_increase_edicts = SV_VM_CB_EndIncreaseEdicts;
2643         prog->init_edict = SV_VM_CB_InitEdict;
2644         prog->free_edict = SV_VM_CB_FreeEdict;
2645         prog->count_edicts = SV_VM_CB_CountEdicts;
2646         prog->load_edict = SV_VM_CB_LoadEdict;
2647         prog->init_cmd = VM_SV_Cmd_Init;
2648         prog->reset_cmd = VM_SV_Cmd_Reset;
2649         prog->error_cmd = Host_Error;
2650
2651         // TODO: add a requiredfuncs list (ask LH if this is necessary at all)
2652         PRVM_LoadProgs( sv_progs.string, 0, NULL, REQFIELDS, reqfields, 0, NULL );
2653
2654         // some mods compiled with scrambling compilers lack certain critical
2655         // global names and field names such as "self" and "time" and "nextthink"
2656         // so we have to set these offsets manually, matching the entvars_t
2657         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, angles);
2658         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, chain);
2659         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, classname);
2660         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, frame);
2661         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, groundentity);
2662         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, ideal_yaw);
2663         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, nextthink);
2664         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, think);
2665         PRVM_ED_FindFieldOffset_FromStruct(entvars_t, yaw_speed);
2666         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, self);
2667         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, time);
2668         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_forward);
2669         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_right);
2670         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, v_up);
2671         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_allsolid);
2672         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_startsolid);
2673         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_fraction);
2674         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inwater);
2675         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_inopen);
2676         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_endpos);
2677         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_normal);
2678         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_plane_dist);
2679         PRVM_ED_FindGlobalOffset_FromStruct(globalvars_t, trace_ent);
2680         // OP_STATE is always supported on server (due to entvars_t)
2681         prog->flag |= PRVM_OP_STATE;
2682
2683         VM_CustomStats_Clear();//[515]: csqc
2684
2685         PRVM_End;
2686
2687         // 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
2688         sv.csqc_progname[0] = 0;
2689         sv.csqc_progcrc = FS_CRCFile(csqc_progname.string, &csprogsdatasize);
2690         sv.csqc_progsize = csprogsdatasize;
2691         if (sv.csqc_progsize > 0)
2692         {
2693                 strlcpy(sv.csqc_progname, csqc_progname.string, sizeof(sv.csqc_progname));
2694                 Con_DPrintf("server detected csqc progs file \"%s\" with size %i and crc %i\n", sv.csqc_progname, sv.csqc_progsize, sv.csqc_progcrc);
2695         }
2696 }
2697
2698 void SV_VM_Begin(void)
2699 {
2700         PRVM_Begin;
2701         PRVM_SetProg( PRVM_SERVERPROG );
2702
2703         prog->globals.server->time = (float) sv.time;
2704 }
2705
2706 void SV_VM_End(void)
2707 {
2708         PRVM_End;
2709 }