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