PageRenderTime 63ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/cl_main.c

https://gitlab.com/fzwoch/fodquake
C | 2302 lines | 1775 code | 464 blank | 63 comment | 322 complexity | 4597aec798c96b17d5e69439ae56cc16 MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // cl_main.c -- client main loop
  16. #include <ctype.h>
  17. #include <string.h>
  18. #include <stdlib.h>
  19. #include "quakedef.h"
  20. #include "sys_io.h"
  21. #include "filesystem.h"
  22. #include "cdaudio.h"
  23. #include "input.h"
  24. #include "keys.h"
  25. #include "menu.h"
  26. #include "sbar.h"
  27. #include "skin.h"
  28. #include "sound.h"
  29. #include "version.h"
  30. #include "teamplay.h"
  31. #include "image.h"
  32. #include "wad.h"
  33. #include "movie.h"
  34. #include "logging.h"
  35. #include "ignore.h"
  36. #include "fmod.h"
  37. #include "fchecks.h"
  38. #include "modules.h"
  39. #include "config_manager.h"
  40. #include "huffman.h"
  41. #include "config.h"
  42. #include "sleep.h"
  43. #include "mouse.h"
  44. #ifdef NETQW
  45. #include "netqw.h"
  46. #endif
  47. #include "strl.h"
  48. #include "ruleset.h"
  49. #include "tokenize_string.h"
  50. #include "context_sensitive_tab.h"
  51. #include "lua.h"
  52. #ifndef GLQUAKE
  53. #include "d_local.h"
  54. #endif
  55. #ifdef FOD_PPC
  56. int altivec_available;
  57. #endif
  58. int movementkey;
  59. static qboolean net_maxfps_callback(cvar_t *var, char *string);
  60. static qboolean net_lag_callback(cvar_t *var, char *string);
  61. static qboolean net_lag_ezcheat_callback(cvar_t *var, char *string);
  62. #include "pmove.h"
  63. static qboolean cl_imitate_client_callback(cvar_t *var, char *string);
  64. static qboolean cl_imitate_os_callback(cvar_t *var, char *string);
  65. static void R_Draw_Flat(float x_lower_limit, float x_upper_limit, float y_lower_limit, float y_upper_limit, float z_lower_limit, float z_upper_limit, float r, float g, float b, qboolean unset);
  66. static qboolean r_drawflat_enable_callback(cvar_t *var, char *string);
  67. static qboolean r_drawflat_walls_callback(cvar_t *var, char *string);
  68. static qboolean r_drawflat_floors_ceilings_callback(cvar_t *var, char *string);
  69. static qboolean r_drawflat_slopes_callback(cvar_t *var, char *string);
  70. cvar_t rcon_password = {"rcon_password", ""};
  71. cvar_t rcon_address = {"rcon_address", ""};
  72. static cvar_t con_clearnotify = {"con_clearnotify","1"};
  73. cvar_t cl_timeout = {"cl_timeout", "60"};
  74. cvar_t cl_shownet = {"cl_shownet", "0"}; // can be 0, 1, or 2
  75. cvar_t cl_sbar = {"cl_sbar", "0", CVAR_ARCHIVE};
  76. cvar_t cl_hudswap = {"cl_hudswap", "0", CVAR_ARCHIVE};
  77. cvar_t cl_maxfps = {"cl_maxfps", "0", CVAR_ARCHIVE};
  78. cvar_t cl_predictPlayers = {"cl_predictPlayers", "1"};
  79. cvar_t cl_solidPlayers = {"cl_solidPlayers", "1"};
  80. cvar_t localid = {"localid", ""};
  81. static qboolean allowremotecmd = true;
  82. cvar_t cl_deadbodyfilter = {"cl_deadbodyFilter", "0"};
  83. cvar_t cl_gibfilter = {"cl_gibFilter", "0"};
  84. cvar_t cl_muzzleflash = {"cl_muzzleflash", "1"};
  85. cvar_t cl_rocket2grenade = {"cl_r2g", "0"};
  86. cvar_t cl_demospeed = {"cl_demospeed", "1"};
  87. cvar_t cl_staticsounds = {"cl_staticSounds", "1"};
  88. cvar_t cl_trueLightning = {"cl_trueLightning", "0"};
  89. cvar_t cl_parseWhiteText = {"cl_parseWhiteText", "1"};
  90. cvar_t cl_filterdrawviewmodel = {"cl_filterdrawviewmodel", "0"};
  91. cvar_t cl_oldPL = {"cl_oldPL", "0"};
  92. cvar_t cl_demoPingInterval = {"cl_demoPingInterval", "5"};
  93. cvar_t cl_chatsound = {"cl_chatsound", "1"};
  94. cvar_t cl_confirmquit = {"cl_confirmquit", "1"};
  95. cvar_t default_fov = {"default_fov", "0"};
  96. cvar_t qizmo_dir = {"qizmo_dir", "qizmo"};
  97. cvar_t cl_floodprot = {"cl_floodprot", "0"};
  98. cvar_t cl_fp_messages = {"cl_fp_messages", "4"};
  99. cvar_t cl_fp_persecond = {"cl_fp_persecond", "4"};
  100. cvar_t cl_cmdline = {"cl_cmdline", "", CVAR_ROM};
  101. cvar_t cl_useproxy = {"cl_useproxy", "0"};
  102. cvar_t net_maxfps = { "net_maxfps", "0", 0, net_maxfps_callback };
  103. static cvar_t net_lag = { "net_lag", "0", 0, net_lag_callback };
  104. static cvar_t net_lag_ezcheat = { "net_lag_ezcheat", "0", 0, net_lag_ezcheat_callback };
  105. cvar_t cl_imitate_client = { "cl_imitate_client", "none", 0, cl_imitate_client_callback };
  106. cvar_t cl_imitate_os = { "cl_imitate_os", "none", 0, cl_imitate_os_callback };
  107. cvar_t cl_model_bobbing = {"cl_model_bobbing", "1"};
  108. cvar_t cl_nolerp = {"cl_nolerp", "1"};
  109. cvar_t r_rocketlight = {"r_rocketLight", "1"};
  110. cvar_t r_rocketlightcolor = {"r_rocketLightColor", "0"};
  111. cvar_t r_explosionlightcolor = {"r_explosionLightColor", "0"};
  112. cvar_t r_explosionlight = {"r_explosionLight", "1"};
  113. cvar_t r_explosiontype = {"r_explosionType", "0"};
  114. cvar_t r_flagcolor = {"r_flagColor", "0"};
  115. cvar_t r_lightflicker = {"r_lightflicker", "1"};
  116. cvar_t r_rockettrail = {"r_rocketTrail", "1"};
  117. cvar_t r_grenadetrail = {"r_grenadeTrail", "1"};
  118. cvar_t r_powerupglow = {"r_powerupGlow", "1"};
  119. cvar_t r_drawflat_enable = {"r_drawflat_enable", "0", 0, r_drawflat_enable_callback };
  120. cvar_t r_drawflat_walls = {"r_drawflat_walls", "off", 0, r_drawflat_walls_callback};
  121. cvar_t r_drawflat_floors_ceilings = {"r_drawflat_floors_ceilings", "off", 0, r_drawflat_floors_ceilings_callback};
  122. cvar_t r_drawflat_slopes= {"r_drawflat_slopes", "off", 0, r_drawflat_slopes_callback};
  123. // info mirrors
  124. cvar_t password = {"password", "", CVAR_USERINFO};
  125. cvar_t spectator = {"spectator", "", CVAR_USERINFO};
  126. cvar_t name = {"name", "player", CVAR_ARCHIVE|CVAR_USERINFO};
  127. cvar_t team = {"team", "", CVAR_ARCHIVE|CVAR_USERINFO};
  128. cvar_t topcolor = {"topcolor","0", CVAR_ARCHIVE|CVAR_USERINFO};
  129. cvar_t bottomcolor = {"bottomcolor","0", CVAR_ARCHIVE|CVAR_USERINFO};
  130. cvar_t skin = {"skin", "", CVAR_ARCHIVE|CVAR_USERINFO};
  131. cvar_t rate = {"rate", "30000", CVAR_ARCHIVE|CVAR_USERINFO};
  132. cvar_t msg = {"msg", "1", CVAR_ARCHIVE|CVAR_USERINFO};
  133. cvar_t noaim = {"noaim", "0", CVAR_ARCHIVE|CVAR_USERINFO};
  134. cvar_t w_switch = {"w_switch", "", CVAR_ARCHIVE|CVAR_USERINFO};
  135. cvar_t b_switch = {"b_switch", "", CVAR_ARCHIVE|CVAR_USERINFO};
  136. int imitatedclientnum;
  137. int imitatedosnum;
  138. clientPersistent_t cls;
  139. clientState_t cl;
  140. centity_t cl_entities[CL_MAX_EDICTS];
  141. efrag_t cl_efrags[MAX_EFRAGS];
  142. lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
  143. dlight_t cl_dlights[MAX_DLIGHTS];
  144. unsigned int cl_dlight_active[MAX_DLIGHTS/32];
  145. // draw flat globals
  146. static float draw_flat[3][3];
  147. // refresh list
  148. #ifdef GLQUAKE
  149. visentlist_t cl_firstpassents, cl_visents, cl_alphaents;
  150. #else
  151. visentlist_t cl_visents, cl_visbents;
  152. #endif
  153. double connect_time = 0; // for connection retransmits
  154. qboolean host_skipframe; // used in demo playback
  155. byte *host_basepal;
  156. byte *host_colormap;
  157. int fps_count;
  158. static int cl_vidinitialised;
  159. struct netaddr cl_net_from;
  160. sizebuf_t cl_net_message;
  161. static byte cl_net_message_buffer[MAX_MSGLEN*2];
  162. static qboolean net_maxfps_callback(cvar_t *var, char *string)
  163. {
  164. float maxfps;
  165. float value;
  166. #ifdef NETQW
  167. value = Q_atof(string);
  168. maxfps = cl.maxfps;
  169. if (maxfps == 0)
  170. maxfps = 72;
  171. if (value && value < maxfps)
  172. maxfps = value;
  173. if (maxfps < 30)
  174. maxfps = 30;
  175. if (cls.netqw)
  176. NetQW_SetFPS(cls.netqw, maxfps);
  177. #endif
  178. return false;
  179. }
  180. static qboolean net_lag_callback(cvar_t *var, char *string)
  181. {
  182. float value;
  183. #ifdef NETQW
  184. value = Q_atof(string);
  185. if (cls.netqw)
  186. NetQW_SetLag(cls.netqw, value*1000);
  187. #endif
  188. return false;
  189. }
  190. static qboolean net_lag_ezcheat_callback(cvar_t *var, char *string)
  191. {
  192. float value;
  193. #ifdef NETQW
  194. value = Q_atof(string);
  195. if (cls.netqw)
  196. NetQW_SetLagEzcheat(cls.netqw, value!=0);
  197. #endif
  198. return false;
  199. }
  200. static void CL_InitClientVersionInfo(void);
  201. enum
  202. {
  203. CLIENT_FODQUAKE,
  204. CLIENT_EZQUAKE_1144,
  205. CLIENT_EZQUAKE_1517,
  206. CLIENT_EZQUAKE_1_8_2,
  207. CLIENT_FUHQUAKE_0_31_675
  208. };
  209. static char *validclientnames[] =
  210. {
  211. "none",
  212. "ezquake-1144",
  213. "ezquake-1517",
  214. "ezquake-1.8.2",
  215. "FuhQuake-0.31-675"
  216. };
  217. char *fversion_clientnames[] =
  218. {
  219. "Fodquake version "FODQUAKE_VERSION,
  220. "ezQuake version 1144",
  221. "ezQuake version 1517",
  222. "ezQuake 1.8.2 stable (build 2029)",
  223. "FuhQuake version 0.31 (build 675)"
  224. };
  225. char *validosnames[] =
  226. {
  227. "none",
  228. "Cygwin",
  229. "Linux",
  230. "MorphOS",
  231. "Win32"
  232. };
  233. char *fversion_osnames[] =
  234. {
  235. QW_PLATFORM,
  236. "Cygwin",
  237. "Linux",
  238. "MorphOS",
  239. "Win32"
  240. };
  241. static int Point_On_Surface(vec3_t *points, int count, vec3_t point)
  242. {
  243. vec3_t temp3, temp4, p, q;
  244. int i;
  245. VectorSubtract(points[count-1], point, temp3);
  246. VectorSubtract(points[0], point, temp4);
  247. CrossProduct(temp3, temp4, p);
  248. for (i=0;i<count-1;i++)
  249. {
  250. VectorSubtract(points[i], point, temp3);
  251. VectorSubtract(points[i+1], point, temp4);
  252. CrossProduct(temp3, temp4, q);
  253. if (DotProduct(p,q) < 0)
  254. return 0;
  255. }
  256. return 1;
  257. }
  258. static qboolean r_drawflat_enable_callback(cvar_t *var, char *string)
  259. {
  260. #ifndef GLQUAKE
  261. model_t *model;
  262. unsigned int i;
  263. model = cl.worldmodel;
  264. if (model)
  265. {
  266. for (i=0;i<model->numsurfaces;i++)
  267. {
  268. D_UncacheSurface(&model->surfaces[i]);
  269. }
  270. }
  271. #endif
  272. return false;
  273. }
  274. static qboolean r_drawflat_walls_callback(cvar_t *var, char *string)
  275. {
  276. struct tokenized_string *ts;
  277. float r, g, b;
  278. ts = Tokenize_String(string);
  279. if (!ts)
  280. return true;
  281. if (ts->count != 1 && ts->count != 3)
  282. {
  283. Com_Printf("usage: %s [r] [g] [b] or off, colors should be in the range of 0 to 1.\n", var->name);
  284. Tokenize_String_Delete(ts);
  285. return true;
  286. }
  287. if (ts->count == 1)
  288. {
  289. if (strcmp(ts->tokens[0], "off") != 0)
  290. {
  291. Com_Printf("usage: %s [r] [g] [b] or off, colors should be in the range of 0 to 1.\n", var->name);
  292. Tokenize_String_Delete(ts);
  293. return true;
  294. }
  295. R_Draw_Flat(-1, 1, -1, 1, 0, 0, 0, 0, 0, true);
  296. Tokenize_String_Delete(ts);
  297. return false;
  298. }
  299. if (ts->count == 3)
  300. {
  301. r = bound(0, atof(ts->tokens[0]), 1);
  302. g = bound(0, atof(ts->tokens[1]), 1);
  303. b = bound(0, atof(ts->tokens[2]), 1);
  304. draw_flat[0][0] = r;
  305. draw_flat[0][1] = g;
  306. draw_flat[0][2] = b;
  307. R_Draw_Flat(-1, 1, -1, 1, 0, 0, r, g, b, false);
  308. Tokenize_String_Delete(ts);
  309. return false;
  310. }
  311. return true;
  312. }
  313. static qboolean r_drawflat_floors_ceilings_callback(cvar_t *var, char *string)
  314. {
  315. struct tokenized_string *ts;
  316. float r, g, b;
  317. ts = Tokenize_String(string);
  318. if (!ts)
  319. return true;
  320. if (ts->count != 1 && ts->count != 3)
  321. {
  322. Com_Printf("usage: %s [r] [g] [b] or off, colors should be in the range of 0 to 1.\n", var->name);
  323. Tokenize_String_Delete(ts);
  324. return true;
  325. }
  326. if (ts->count == 1)
  327. {
  328. if (strcmp(ts->tokens[0], "off") != 0)
  329. {
  330. Com_Printf("usage: %s [r] [g] [b] or off, colors should be in the range of 0 to 1.\n", var->name);
  331. Tokenize_String_Delete(ts);
  332. return true;
  333. }
  334. R_Draw_Flat(-1, 1, -1, 1, -1, -1, 0, 0, 0, true);
  335. R_Draw_Flat(-1, 1, -1, 1, 1, 1, 0, 0, 0, true);
  336. Tokenize_String_Delete(ts);
  337. return false;
  338. }
  339. if (ts->count == 3)
  340. {
  341. r = bound(0, atof(ts->tokens[0]), 1);
  342. g = bound(0, atof(ts->tokens[1]), 1);
  343. b = bound(0, atof(ts->tokens[2]), 1);
  344. draw_flat[1][0] = r;
  345. draw_flat[1][1] = g;
  346. draw_flat[1][2] = b;
  347. R_Draw_Flat(-1, 1, -1, 1, -1, -1, r, g, b, false);
  348. R_Draw_Flat(-1, 1, -1, 1, 1, 1, r, g, b, false);
  349. Tokenize_String_Delete(ts);
  350. return false;
  351. }
  352. return true;
  353. }
  354. static qboolean r_drawflat_slopes_callback(cvar_t *var, char *string)
  355. {
  356. struct tokenized_string *ts;
  357. float r, g, b;
  358. ts = Tokenize_String(string);
  359. if (!ts)
  360. return true;
  361. if (ts->count != 1 && ts->count != 3)
  362. {
  363. Com_Printf("usage: %s [r] [g] [b] or off, colors should be in the range of 0 to 1.\n", var->name);
  364. Tokenize_String_Delete(ts);
  365. return true;
  366. }
  367. if (ts->count == 1)
  368. {
  369. if (strcmp(ts->tokens[0], "off") != 0)
  370. {
  371. Com_Printf("usage: %s [r] [g] [b] or off, colors should be in the range of 0 to 1.\n", var->name);
  372. Tokenize_String_Delete(ts);
  373. return true;
  374. }
  375. R_Draw_Flat(-1, 1, -1, 1, -0.99999f, -0.00001f, 0, 0, 0, true);
  376. R_Draw_Flat(-1, 1, -1, 1, 0.00001f, 0.99999f, 0, 0, 0, true);
  377. Tokenize_String_Delete(ts);
  378. return false;
  379. }
  380. if (ts->count == 3)
  381. {
  382. r = bound(0, atof(ts->tokens[0]), 1);
  383. g = bound(0, atof(ts->tokens[1]), 1);
  384. b = bound(0, atof(ts->tokens[2]), 1);
  385. draw_flat[2][0] = r;
  386. draw_flat[2][1] = g;
  387. draw_flat[2][2] = b;
  388. R_Draw_Flat(-1, 1, -1, 1, -0.99999f, -0.00001f, r, g, b, false);
  389. R_Draw_Flat(-1, 1, -1, 1, 0.00001f, 0.99999f, r, g, b, false);
  390. Tokenize_String_Delete(ts);
  391. return false;
  392. }
  393. return true;
  394. }
  395. static void R_DrawFlat_UpdateSurface(model_t *model, msurface_t *surface)
  396. {
  397. #ifdef GLQUAKE
  398. unsigned int i;
  399. if (model->vertcolours)
  400. {
  401. if (surface->polys)
  402. {
  403. for(i=surface->polys->firstindex;i<surface->polys->firstindex+surface->polys->numverts;i++)
  404. {
  405. model->vertcolours[i*3+0] = surface->color[0];
  406. model->vertcolours[i*3+1] = surface->color[1];
  407. model->vertcolours[i*3+2] = surface->color[2];
  408. }
  409. model->surface_colours_dirty = 1;
  410. }
  411. }
  412. #else
  413. surface->palcolor = V_LookUpColour(surface->color[0], surface->color[1], surface->color[2]);
  414. if (r_drawflat_enable.value == 1)
  415. D_UncacheSurface(surface);
  416. #endif
  417. }
  418. static void R_DrawFlatShoot_f(void)
  419. {
  420. model_t *model;
  421. vec3_t vec, vec1;
  422. vec3_t *points;
  423. pmtrace_t trace;
  424. mleaf_t *leaf;
  425. msurface_t *surface;
  426. unsigned int marksurface;
  427. mvertex_t *vertex;
  428. int e, x, i;
  429. float color[3];
  430. if (Cmd_Argc() != 4)
  431. {
  432. Com_Printf("Usage: r_drawflat_shoot [r] [g] [b], colors should be in range of 0 to 1\n");
  433. return;
  434. }
  435. if (!cl.worldmodel)
  436. {
  437. Com_Printf("No map loaded, can't set surface color\n");
  438. return;
  439. }
  440. color[0] = bound(0, atof(Cmd_Argv(1)), 1);
  441. color[1] = bound(0, atof(Cmd_Argv(2)), 1);
  442. color[2] = bound(0, atof(Cmd_Argv(3)), 1);
  443. model = cl.worldmodel;
  444. AngleVectors(r_refdef.viewangles, vec1, NULL, NULL);
  445. VectorMA(r_refdef.vieworg, 10000.0f, vec1, vec);
  446. trace = PM_TraceLine (r_refdef.vieworg, vec);
  447. leaf = Mod_PointInLeaf(trace.endpos, model);
  448. if (!leaf)
  449. {
  450. Com_Printf("no leaf returned\n");
  451. return;
  452. }
  453. for (i=0, marksurface = leaf->firstmarksurfacenum; i<leaf->nummarksurfaces; i++, marksurface++)
  454. {
  455. surface = model->surfaces + model->marksurfaces[marksurface];
  456. points = calloc(surface->numedges , sizeof(vec3_t));
  457. if (points == NULL)
  458. {
  459. Com_Printf("alloc error\n");
  460. return;
  461. }
  462. for (x=0;x<surface->numedges;x++)
  463. {
  464. e = model->surfedges[surface->firstedge + x];
  465. if (abs(e) >= model->numedges)
  466. return;
  467. if (e >= 0)
  468. vertex = &model->vertexes[model->edges[e].v[0]];
  469. else
  470. vertex = &model->vertexes[model->edges[-e].v[1]];
  471. points[x][0] = vertex->position[0];
  472. points[x][1] = vertex->position[1];
  473. points[x][2] = vertex->position[2];
  474. }
  475. if (Point_On_Surface(points, surface->numedges, trace.endpos) && trace.draw_plane == surface->plane )
  476. {
  477. surface->is_drawflat = 1;
  478. surface->color[0] = color[0];
  479. surface->color[1] = color[1];
  480. surface->color[2] = color[2];
  481. R_DrawFlat_UpdateSurface(model, surface);
  482. }
  483. free(points);
  484. }
  485. return;
  486. }
  487. static void R_DrawFlatShootUnset_f(void)
  488. {
  489. model_t *model;
  490. vec3_t vec, vec1;
  491. vec3_t *points;
  492. pmtrace_t trace;
  493. mleaf_t *leaf;
  494. msurface_t *surface;
  495. unsigned int marksurface;
  496. mvertex_t *vertex;
  497. int e, x, i;
  498. if (!cl.worldmodel)
  499. {
  500. Com_Printf("No map loaded, can't set surface color\n");
  501. return;
  502. }
  503. model = cl.worldmodel;
  504. AngleVectors(r_refdef.viewangles, vec1, NULL, NULL);
  505. VectorMA(r_refdef.vieworg, 10000.0f, vec1, vec);
  506. trace = PM_TraceLine (r_refdef.vieworg, vec);
  507. leaf = Mod_PointInLeaf(trace.endpos, model);
  508. if (!leaf)
  509. {
  510. Com_Printf("no leaf returned\n");
  511. return;
  512. }
  513. for (i=0, marksurface = leaf->firstmarksurfacenum; i<leaf->nummarksurfaces; i++, marksurface++)
  514. {
  515. surface = model->surfaces + model->marksurfaces[marksurface];
  516. points = calloc(surface->numedges , sizeof(vec3_t));
  517. if (points == NULL)
  518. {
  519. Com_Printf("alloc error\n");
  520. return;
  521. }
  522. for (x=0;x<surface->numedges;x++)
  523. {
  524. e = model->surfedges[surface->firstedge + x];
  525. if (abs(e) >= model->numedges)
  526. return;
  527. if (e >= 0)
  528. vertex = &model->vertexes[model->edges[e].v[0]];
  529. else
  530. vertex = &model->vertexes[model->edges[-e].v[1]];
  531. points[x][0] = vertex->position[0];
  532. points[x][1] = vertex->position[1];
  533. points[x][2] = vertex->position[2];
  534. }
  535. if (Point_On_Surface(points, surface->numedges, trace.endpos) && trace.draw_plane == surface->plane )
  536. {
  537. surface->is_drawflat = 0;
  538. R_DrawFlat_UpdateSurface(model, surface);
  539. }
  540. free(points);
  541. }
  542. return;
  543. }
  544. static void R_Draw_Flat(float x_lower_limit, float x_upper_limit, float y_lower_limit, float y_upper_limit, float z_lower_limit, float z_upper_limit, float r, float g, float b, qboolean unset)
  545. {
  546. model_t *model;
  547. vec3_t vec;
  548. int i;
  549. if (!cl.worldmodel)
  550. return;
  551. model = cl.worldmodel;
  552. for (i=0;i<model->numsurfaces;i++)
  553. {
  554. VectorCopy(model->surfaces[i].plane->normal, vec);
  555. VectorNormalize(vec);
  556. if (vec[2] <= z_upper_limit && vec[2] >= z_lower_limit
  557. && vec[1] <= y_upper_limit && vec[1] >= y_lower_limit
  558. && vec[0] <= x_upper_limit && vec[0] >= x_lower_limit)
  559. {
  560. if (unset == true)
  561. {
  562. model->surfaces[i].is_drawflat = 0;
  563. }
  564. else
  565. {
  566. model->surfaces[i].is_drawflat = 1;
  567. model->surfaces[i].color[0] = r;
  568. model->surfaces[i].color[1] = g;
  569. model->surfaces[i].color[2] = b;
  570. }
  571. R_DrawFlat_UpdateSurface(model, &model->surfaces[i]);
  572. }
  573. }
  574. return;
  575. }
  576. static void R_DrawFlat_f(void)
  577. {
  578. float limit[6], color[3];
  579. if (Cmd_Argc() != 10)
  580. {
  581. Com_Printf("Usage: r_drawflat [x_lower_limit] [x_upper_limit] [y_lower_limit] [y_upper_limit] [z_lower_limit] [z_upper_limit] [r] [g] [b], limits go from -1 to 1, colors should be in the range of 0 to 1.\n");
  582. return;
  583. }
  584. limit[0] = atof(Cmd_Argv(1));
  585. limit[1] = atof(Cmd_Argv(2));
  586. limit[2] = atof(Cmd_Argv(3));
  587. limit[3] = atof(Cmd_Argv(4));
  588. limit[4] = atof(Cmd_Argv(5));
  589. limit[5] = atof(Cmd_Argv(6));
  590. color[0] = bound(0, atof(Cmd_Argv(7)), 1);
  591. color[1] = bound(0, atof(Cmd_Argv(8)), 1);
  592. color[2] = bound(0, atof(Cmd_Argv(9)), 1);
  593. R_Draw_Flat(limit[0], limit[1], limit[2], limit[3], limit[4], limit[5], color[0], color[1], color[2], true);
  594. }
  595. static void R_DrawFlat_Set_f(void)
  596. {
  597. model_t *model;
  598. float r, g, b;
  599. int surface;
  600. if (Cmd_Argc() != 5)
  601. {
  602. Com_Printf("Usage: r_drawflat_set [surface] [r] [g] [b], colors should be in range of 0 to 1\n");
  603. return;
  604. }
  605. if (!cl.worldmodel)
  606. {
  607. Com_Printf("No map loaded, can't set surface color\n");
  608. return;
  609. }
  610. model = cl.worldmodel;
  611. surface = atoi(Cmd_Argv(1));
  612. r = bound(0, atof(Cmd_Argv(2)), 1);
  613. g = bound(0, atof(Cmd_Argv(3)), 1);
  614. b = bound(0, atof(Cmd_Argv(4)), 1);
  615. if (surface < 0 || surface >= model->numsurfaces)
  616. {
  617. Com_Printf("Surface out of range.\n");
  618. return;
  619. }
  620. model->surfaces[surface].is_drawflat = 1;
  621. model->surfaces[surface].color[0] = r;
  622. model->surfaces[surface].color[1] = g;
  623. model->surfaces[surface].color[2] = b;
  624. R_DrawFlat_UpdateSurface(model, &model->surfaces[surface]);
  625. }
  626. static void R_DrawFlat_Unset_f(void)
  627. {
  628. model_t *model;
  629. int surface;
  630. if (!cl.worldmodel)
  631. return;
  632. if (Cmd_Argc() != 2)
  633. {
  634. Com_Printf("Usage: r_drawflat_unset [surface number]\n");
  635. return;
  636. }
  637. model = cl.worldmodel;
  638. surface = atoi(Cmd_Argv(1));
  639. if (surface < 0 || surface >= model->numsurfaces)
  640. {
  641. Com_Printf("Surface out of range.\n");
  642. return;
  643. }
  644. model->surfaces[surface].is_drawflat = 0;
  645. }
  646. static void R_DrawFlat_Write_Config(void)
  647. {
  648. FILE *f;
  649. char *file;
  650. model_t *model;
  651. int i;
  652. if (!cl.worldmodel)
  653. return;
  654. model = cl.worldmodel;
  655. file = va("%s/qw/%s.dfcfg", com_basedir, mapname.string);
  656. f = fopen(file, "r");
  657. if (f)
  658. {
  659. fclose(f);
  660. if (Cmd_Argc() != 2)
  661. {
  662. Com_Printf("File \"%s\" exists. Please use \"r_drawflat_writeconfig overwrite\" to overwrite the old file.\n", mapname.string);
  663. return;
  664. }
  665. else
  666. {
  667. if (strcmp(Cmd_Argv(1), "overwrite") != 0)
  668. {
  669. Com_Printf("If you really want to overwrite please spell overwrite right.\n");
  670. return;
  671. }
  672. }
  673. }
  674. f = fopen(file, "wb");
  675. if (!f)
  676. return;
  677. for (i=0;i<model->numsurfaces;i++)
  678. {
  679. if(model->surfaces[i].is_drawflat == 1)
  680. {
  681. fprintf(f,"r_drawflat_set %i %f %f %f\n",i ,model->surfaces[i].color[0], model->surfaces[i].color[1], model->surfaces[i].color[2]);
  682. }
  683. }
  684. fclose(f);
  685. }
  686. void R_DrawFlat_NewMap (void)
  687. {
  688. if (r_drawflat_enable.value != 1)
  689. return;
  690. if (strcmp(r_drawflat_walls.string, "off") != 0)
  691. {
  692. R_Draw_Flat(-1, 1, -1, 1, 0, 0, draw_flat[0][0], draw_flat[0][1], draw_flat[0][2], false);
  693. }
  694. if (strcmp(r_drawflat_floors_ceilings.string, "off") != 0)
  695. {
  696. R_Draw_Flat(-1, 1, -1, 1, -1, -1, draw_flat[1][0], draw_flat[1][1], draw_flat[1][2], false);
  697. R_Draw_Flat(-1, 1, -1, 1, 1, 1, draw_flat[1][0], draw_flat[1][1], draw_flat[1][2], false);
  698. }
  699. if (strcmp(r_drawflat_slopes.string, "off") != 0)
  700. {
  701. R_Draw_Flat(-1, 1, -1, 1, -0.99999f, -0.00001f, draw_flat[2][0], draw_flat[2][1], draw_flat[2][2], false);
  702. R_Draw_Flat(-1, 1, -1, 1, 0.00001f, 0.99999f, draw_flat[2][0], draw_flat[2][1], draw_flat[2][2], false);
  703. }
  704. Cbuf_AddText(va("exec %s.dfcfg\n", mapname.string));
  705. }
  706. #define NUMVALIDCLIENTNAMES (sizeof(validclientnames)/sizeof(*validclientnames))
  707. #define NUMVALIDOSNAMES (sizeof(validosnames)/sizeof(*validosnames))
  708. static qboolean cl_imitate_client_callback(cvar_t *var, char *string)
  709. {
  710. int i;
  711. for(i=0;i<NUMVALIDCLIENTNAMES;i++)
  712. {
  713. if (Q_strcasecmp(validclientnames[i], string) == 0)
  714. break;
  715. }
  716. if (i == NUMVALIDCLIENTNAMES)
  717. {
  718. Com_Printf("Client name \"%s\" is invalid. Valid client names are:\n", string);
  719. for(i=0;i<NUMVALIDCLIENTNAMES;i++)
  720. Com_Printf(" - %s\n", validclientnames[i]);
  721. return true;
  722. }
  723. if (Q_strcasecmp(string, validclientnames[imitatedclientnum]) == 0)
  724. return false;
  725. imitatedclientnum = i;
  726. CL_InitClientVersionInfo();
  727. Com_Printf("Client information will be updated after (re)connecting to a server.\n");
  728. return false;
  729. }
  730. static qboolean cl_imitate_os_callback(cvar_t *var, char *string)
  731. {
  732. int i;
  733. for(i=0;i<NUMVALIDOSNAMES;i++)
  734. {
  735. if (Q_strcasecmp(validosnames[i], string) == 0)
  736. break;
  737. }
  738. if (i == NUMVALIDOSNAMES)
  739. {
  740. Com_Printf("OS name \"%s\" is invalid. Valid OS names are:\n", string);
  741. for(i=0;i<NUMVALIDOSNAMES;i++)
  742. Com_Printf(" - %s\n", validosnames[i]);
  743. return true;
  744. }
  745. imitatedosnum = i;
  746. return false;
  747. }
  748. char emodel_name[] = "emodel";
  749. char pmodel_name[] = "pmodel";
  750. //============================================================================
  751. const char *CL_Macro_ConnectionType(void)
  752. {
  753. char *s;
  754. static char macrobuf[16];
  755. s = (cls.state < ca_connected) ? "disconnected" : cl.spectator ? "spectator" : "player";
  756. Q_strncpyz(macrobuf, s, sizeof(macrobuf));
  757. return macrobuf;
  758. }
  759. const char *CL_Macro_Demoplayback(void)
  760. {
  761. char *s;
  762. static char macrobuf[16];
  763. s = cls.mvdplayback ? "mvdplayback" : cls.demoplayback ? "qwdplayback" : "0";
  764. Q_strncpyz(macrobuf, s, sizeof(macrobuf));
  765. return macrobuf;
  766. }
  767. const char *CL_Macro_Serverstatus(void)
  768. {
  769. char *s;
  770. static char macrobuf[16];
  771. s = (cls.state < ca_connected) ? "disconnected" : cl.standby ? "standby" : "normal";
  772. Q_strncpyz(macrobuf, s, sizeof(macrobuf));
  773. return macrobuf;
  774. }
  775. int CL_ClientState(void)
  776. {
  777. return cls.state;
  778. }
  779. void CL_MakeActive(void)
  780. {
  781. cls.state = ca_active;
  782. if (cls.demoplayback)
  783. {
  784. host_skipframe = true;
  785. demostarttime = cls.demotime;
  786. }
  787. if (!cls.demoplayback)
  788. VID_SetCaption (va("Fodquake: %s", cls.servername));
  789. Con_ClearNotify();
  790. TP_ExecTrigger("f_spawn");
  791. Ignore_PostNewMap();
  792. if (key_dest == key_game)
  793. VID_SetMouseGrab(1);
  794. }
  795. //Cvar system calls this when a CVAR_USERINFO cvar changes
  796. void CL_UserinfoChanged(char *key, char *string)
  797. {
  798. char *s;
  799. s = TP_ParseFunChars (string, false);
  800. if (strcmp(s, Info_ValueForKey (cls.userinfo, key)))
  801. {
  802. Info_SetValueForKey (cls.userinfo, key, s, MAX_INFO_STRING);
  803. if (cls.state >= ca_connected)
  804. {
  805. #ifdef NETQW
  806. if (cls.netqw)
  807. {
  808. unsigned int i;
  809. char buf[1400];
  810. i = snprintf(buf, sizeof(buf), "%csetinfo \"%s\" \"%s\"\n", clc_stringcmd, key, s);
  811. if (i < sizeof(buf))
  812. {
  813. NetQW_AppendReliableBuffer(cls.netqw, buf, i+1);
  814. }
  815. }
  816. #else
  817. MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
  818. SZ_Print (&cls.netchan.message, va("setinfo \"%s\" \"%s\"\n", key, s));
  819. #endif
  820. }
  821. }
  822. }
  823. #ifndef NETQW
  824. //called by CL_Connect_f and CL_CheckResend
  825. static void CL_SendConnectPacket(void)
  826. {
  827. char data[2048];
  828. int i;
  829. if (cls.state != ca_disconnected)
  830. return;
  831. Ruleset_Activate();
  832. connect_time = cls.realtime; // for retransmit requests
  833. cls.qport = Cvar_VariableValue("qport");
  834. i = Q_snprintfz(data, sizeof(data), "\xff\xff\xff\xff" "connect %i %i %i \"%s\"\n", PROTOCOL_VERSION, cls.qport, cls.challenge, cls.userinfo);
  835. i++;
  836. if (i < sizeof(data) && cls.netchan.huffcontext)
  837. i+= Q_snprintfz(data+i, sizeof(data)-i, "0x%08x 0x%08x\n", QW_PROTOEXT_HUFF, cls.hufftablecrc);
  838. if (i < sizeof(data) && cls.ftexsupported)
  839. i+= Q_snprintfz(data+i, sizeof(data)-i, "0x%08x 0x%08x\n", QW_PROTOEXT_FTEX, cls.ftexsupported);
  840. if (i < sizeof(data))
  841. {
  842. if (data[i-1] == 0)
  843. i--;
  844. NET_SendPacket(NS_CLIENT, i+1, data, &cls.server_adr);
  845. return;
  846. }
  847. Com_Printf("Connection packet size overflow\n");
  848. return;
  849. }
  850. //Resend a connect message if the last one has timed out
  851. static void CL_CheckForResend (void)
  852. {
  853. char data[2048];
  854. if (cls.state == ca_disconnected && com_serveractive)
  855. {
  856. // if the local server is running and we are not, then connect
  857. Q_strncpyz (cls.servername, "local", sizeof(cls.servername));
  858. NET_StringToAdr(0, "local", &cls.server_adr);
  859. CL_SendConnectPacket (); // we don't need a challenge on the local server
  860. // FIXME: cls.state = ca_connecting so that we don't send the packet twice?
  861. return;
  862. }
  863. if (cls.state != ca_disconnected || !connect_time)
  864. return;
  865. if (cls.realtime - connect_time < 5.0)
  866. return;
  867. connect_time = cls.realtime; // for retransmit requests
  868. Com_Printf("Connecting to %s...\n", cls.servername);
  869. Q_snprintfz(data, sizeof(data), "\xff\xff\xff\xff" "getchallenge\n");
  870. NET_SendPacket(NS_CLIENT, strlen(data), data, &cls.server_adr);
  871. }
  872. #endif
  873. static void CL_BeginServerConnect(void)
  874. {
  875. connect_time = 0;
  876. #ifdef NETQW
  877. Ruleset_Activate();
  878. cls.netqw = NetQW_Create(cls.servername, cls.userinfo, rand()&0xffff);
  879. if (cls.netqw)
  880. {
  881. Com_Printf("Connecting to %s...\n", cls.servername);
  882. NetQW_SetLag(cls.netqw, net_lag.value*1000);
  883. NetQW_SetLagEzcheat(cls.netqw, net_lag_ezcheat.value!=0);
  884. }
  885. else
  886. Com_Printf("Unable to create connection\n");
  887. #endif
  888. #if 1
  889. #warning This is currently needed for /packet to work.
  890. if (!NET_StringToAdr(0, cls.servername, &cls.server_adr))
  891. {
  892. Com_Printf("Bad server address\n");
  893. return;
  894. }
  895. if (!NET_OpenSocket(NS_CLIENT, cls.server_adr.type))
  896. {
  897. Com_Printf("Unable to create socket\n");
  898. return;
  899. }
  900. #endif
  901. #ifndef NETQW
  902. connect_time = -999; // CL_CheckForResend() will fire immediately
  903. CL_CheckForResend();
  904. #endif
  905. }
  906. void CL_Connect_f(void)
  907. {
  908. qboolean proxy;
  909. if (Cmd_Argc() != 2)
  910. {
  911. Com_Printf("Usage: %s <server>\n", Cmd_Argv(0));
  912. return;
  913. }
  914. proxy = cl_useproxy.value && CL_ConnectedToProxy();
  915. if (proxy)
  916. {
  917. Cbuf_AddText(va("say ,connect %s", Cmd_Argv(1)));
  918. }
  919. else
  920. {
  921. Host_EndGame();
  922. Q_strncpyz(cls.servername, Cmd_Argv (1), sizeof(cls.servername));
  923. CL_BeginServerConnect();
  924. }
  925. }
  926. qboolean CL_ConnectedToProxy(void)
  927. {
  928. cmd_alias_t *alias = NULL;
  929. char **s, *qizmo_aliases[] = { "ezcomp", "ezcomp2", "ezcomp3", "f_sens", "f_fps", "f_tj", "f_ta", NULL};
  930. if (cls.state < ca_active)
  931. return false;
  932. for (s = qizmo_aliases; *s; s++)
  933. {
  934. if (!(alias = Cmd_FindAlias(*s)) || !(alias->flags & ALIAS_SERVER))
  935. return false;
  936. }
  937. return true;
  938. }
  939. void CL_Join_f(void)
  940. {
  941. qboolean proxy;
  942. if (cls.demoplayback)
  943. {
  944. Com_Printf("Playing a demo, can't join.\n");
  945. return;
  946. }
  947. proxy = cl_useproxy.value && CL_ConnectedToProxy();
  948. if (Cmd_Argc() > 2)
  949. {
  950. Com_Printf ("Usage: %s [server]\n", Cmd_Argv(0));
  951. return;
  952. }
  953. Cvar_Set(&spectator, "");
  954. if (Cmd_Argc() == 2)
  955. Cbuf_AddText(va("%s %s\n", proxy ? "say ,connect" : "connect", Cmd_Argv(1)));
  956. else if (cl.z_ext & Z_EXT_JOIN_OBSERVE)
  957. Cbuf_AddText("cmd join\n");
  958. else
  959. Cbuf_AddText(va("%s\n", proxy ? "say ,reconnect" : "reconnect"));
  960. }
  961. void CL_Observe_f(void)
  962. {
  963. qboolean proxy;
  964. if (cls.demoplayback)
  965. {
  966. Com_Printf("Playing a demo, can't observe.\n");
  967. return;
  968. }
  969. proxy = cl_useproxy.value && CL_ConnectedToProxy();
  970. if (Cmd_Argc() > 2)
  971. {
  972. Com_Printf("Usage: %s [server]\n", Cmd_Argv(0));
  973. return;
  974. }
  975. if (!spectator.string[0] || !strcmp(spectator.string, "0"))
  976. Cvar_SetValue(&spectator, 1);
  977. if (Cmd_Argc() == 2)
  978. Cbuf_AddText(va("%s %s\n", proxy ? "say ,connect" : "connect", Cmd_Argv(1)));
  979. else if (cl.z_ext & Z_EXT_JOIN_OBSERVE)
  980. Cbuf_AddText("cmd observe\n");
  981. else
  982. Cbuf_AddText(va("%s\n", proxy ? "say ,reconnect" : "reconnect"));
  983. }
  984. void CL_QTVPlay_f()
  985. {
  986. char buf[512];
  987. if (Cmd_Argc() != 2)
  988. {
  989. Com_Printf("Usage: %s <stream>\n", Cmd_Argv(0));
  990. return;
  991. }
  992. snprintf(buf, sizeof(buf), "alias f_qtv \"say .qtv %s\"; connect $sb_qtv_proxy\n", Cmd_Argv(1));
  993. Cbuf_AddText(buf);
  994. }
  995. void CL_DNS_f()
  996. {
  997. char address[128];
  998. struct netaddr addr;
  999. qboolean r;
  1000. const char *cname;
  1001. if (Cmd_Argc() != 2)
  1002. {
  1003. Com_Printf("Usage: %s <address>\n", Cmd_Argv(0));
  1004. return;
  1005. }
  1006. strlcpy(address, Cmd_Argv(1), sizeof(address));
  1007. #if 0
  1008. if ((s = strchr(address, ':')))
  1009. *s = 0;
  1010. #endif
  1011. r = NET_StringToAdr(0, address, &addr);
  1012. if (!r)
  1013. {
  1014. Com_Printf("Couldn't look up \"%s\"\n", address);
  1015. }
  1016. else
  1017. {
  1018. Com_Printf("IP: %s\n", NET_BaseAdrToString(&addr));
  1019. cname = NET_GetHostnameForAddress(&addr);
  1020. if (cname)
  1021. Com_Printf("Hostname: %s\n", cname);
  1022. }
  1023. }
  1024. void CL_ClearState(void)
  1025. {
  1026. int i;
  1027. extern float scr_centertime_off;
  1028. S_StopAllSounds(true);
  1029. Com_DPrintf("Clearing memory\n");
  1030. CL_ClearTEnts();
  1031. CL_ClearScene();
  1032. CL_FreeStatics();
  1033. // wipe the entire cl structure
  1034. memset(&cl, 0, sizeof(cl));
  1035. SZ_Clear(&cls.netchan.message);
  1036. // clear other arrays
  1037. memset(cl_efrags, 0, sizeof(cl_efrags));
  1038. memset(cl_dlight_active, 0, sizeof(cl_dlight_active));
  1039. memset(cl_lightstyle, 0, sizeof(cl_lightstyle));
  1040. memset(cl_entities, 0, sizeof(cl_entities));
  1041. // make sure no centerprint messages are left from previous level
  1042. scr_centertime_off = 0;
  1043. // allocate the efrags and chain together into a free list
  1044. cl.free_efrags = cl_efrags;
  1045. for (i = 0; i < MAX_EFRAGS - 1; i++)
  1046. cl.free_efrags[i].entnext = &cl.free_efrags[i + 1];
  1047. cl.free_efrags[i].entnext = NULL;
  1048. }
  1049. //Sends a disconnect message to the server
  1050. //This is also called on Host_Error, so it shouldn't cause any errors
  1051. void CL_Disconnect(void)
  1052. {
  1053. byte final[10];
  1054. connect_time = 0;
  1055. cl.teamfortress = false;
  1056. cls.ftexsupported = 0;
  1057. cls.fte2supported = 0;
  1058. VID_SetCaption("Fodquake");
  1059. // stop sounds (especially looping!)
  1060. S_StopAllSounds(true);
  1061. MT_Disconnect();
  1062. if (cls.demorecording && cls.state != ca_disconnected)
  1063. CL_Stop_f();
  1064. if (cls.demoplayback)
  1065. {
  1066. CL_StopPlayback();
  1067. }
  1068. else if (cls.state != ca_disconnected)
  1069. {
  1070. final[0] = clc_stringcmd;
  1071. strcpy((char *)(final + 1), "drop");
  1072. Netchan_Transmit(&cls.netchan, 6, final);
  1073. Netchan_Transmit(&cls.netchan, 6, final);
  1074. Netchan_Transmit(&cls.netchan, 6, final);
  1075. }
  1076. memset(&cls.netchan, 0, sizeof(cls.netchan));
  1077. memset(&cls.server_adr, 0, sizeof(cls.server_adr));
  1078. cls.state = ca_disconnected;
  1079. VID_SetMouseGrab(0);
  1080. connect_time = 0;
  1081. #ifdef NETQW
  1082. if (cls.netqw)
  1083. {
  1084. NetQW_Delete(cls.netqw);
  1085. cls.netqw = 0;
  1086. }
  1087. #endif
  1088. Cam_Reset();
  1089. if (cls.download)
  1090. {
  1091. fclose(cls.download);
  1092. cls.download = NULL;
  1093. }
  1094. CL_StopUpload();
  1095. DeleteServerAliases();
  1096. /* Restore the rate if it has been overridden by the server */
  1097. if (strcmp(Info_ValueForKey(cls.userinfo, "rate"), rate.string) != 0)
  1098. {
  1099. CL_UserinfoChanged("rate", rate.string);
  1100. }
  1101. }
  1102. void CL_Disconnect_f(void)
  1103. {
  1104. cl.intermission = 0;
  1105. Host_EndGame();
  1106. }
  1107. //The server is changing levels
  1108. void CL_Reconnect_f(void)
  1109. {
  1110. if (cls.download) // don't change when downloading
  1111. return;
  1112. S_StopAllSounds (true);
  1113. if (cls.state == ca_connected)
  1114. {
  1115. char buf[5];
  1116. Com_Printf ("reconnecting...\n");
  1117. #ifdef NETQW
  1118. if (cls.netqw)
  1119. {
  1120. buf[0] = clc_stringcmd;
  1121. strcpy(buf+1, "new");
  1122. NetQW_AppendReliableBuffer(cls.netqw, buf, 5);
  1123. }
  1124. #else
  1125. MSG_WriteChar(&cls.netchan.message, clc_stringcmd);
  1126. MSG_WriteString(&cls.netchan.message, "new");
  1127. #endif
  1128. return;
  1129. }
  1130. if (!*cls.servername)
  1131. {
  1132. Com_Printf("No server to reconnect to.\n");
  1133. return;
  1134. }
  1135. Host_EndGame();
  1136. CL_BeginServerConnect();
  1137. }
  1138. //Responses to broadcasts, etc
  1139. void CL_ConnectionlessPacket(void)
  1140. {
  1141. int c;
  1142. char *s, cmdtext[2048];
  1143. MSG_BeginReading(&cl_net_message);
  1144. MSG_ReadLong(); // skip the -1
  1145. c = MSG_ReadByte();
  1146. if (msg_badread)
  1147. return; // runt packet
  1148. switch(c)
  1149. {
  1150. #ifndef NETQW
  1151. case S2C_CHALLENGE:
  1152. if (!NET_CompareAdr(&cl_net_from, &cls.server_adr))
  1153. return;
  1154. Com_Printf("%s: challenge\n", NET_AdrToString(&cl_net_from));
  1155. cls.challenge = atoi(MSG_ReadString());
  1156. while(1)
  1157. {
  1158. unsigned int extension;
  1159. unsigned int value;
  1160. extension = MSG_ReadLong();
  1161. value = MSG_ReadLong();
  1162. if (msg_badread)
  1163. break;
  1164. if (extension == QW_PROTOEXT_HUFF)
  1165. {
  1166. Com_Printf("Server supports Huffman compression\n");
  1167. cls.hufftablecrc = value;
  1168. cls.netchan.huffcontext = Huff_Init(cls.hufftablecrc);
  1169. if (!cls.netchan.huffcontext)
  1170. Com_Printf("Unknown Huffman table\n");
  1171. }
  1172. else if (extension == QW_PROTOEXT_FTEX)
  1173. {
  1174. cls.ftexsupported = FTEX_SUPPORTED&value;
  1175. Com_Printf("FTE extensions enabled: %08x\n", cls.ftexsupported);
  1176. }
  1177. #if 0
  1178. else
  1179. {
  1180. printf("Unknown extension %08x %08x\n", extension, value);
  1181. }
  1182. #endif
  1183. }
  1184. CL_SendConnectPacket();
  1185. break;
  1186. case S2C_CONNECTION:
  1187. if (!NET_CompareAdr(&cl_net_from, &cls.server_adr))
  1188. return;
  1189. if (!com_serveractive || developer.value)
  1190. Com_Printf("%s: connection\n", NET_AdrToString(&cl_net_from));
  1191. if (cls.state >= ca_connected)
  1192. {
  1193. if (!cls.demoplayback)
  1194. Com_Printf("Dup connect received. Ignored.\n");
  1195. break;
  1196. }
  1197. Netchan_Setup(NS_CLIENT, &cls.netchan, cl_net_from, cls.qport);
  1198. MSG_WriteChar (&cls.netchan.message, clc_stringcmd);
  1199. MSG_WriteString (&cls.netchan.message, "new");
  1200. cls.state = ca_connected;
  1201. if (!com_serveractive || developer.value)
  1202. Com_Printf("Connected.\n");
  1203. allowremotecmd = false; // localid required now for remote cmds
  1204. break;
  1205. #endif
  1206. #warning This is b0rken in so many ways.
  1207. case A2C_CLIENT_COMMAND: // remote command from gui front end
  1208. Com_Printf ("%s: client command\n", NET_AdrToString(&cl_net_from));
  1209. if (!NET_IsLocalAddress(&cl_net_from))
  1210. {
  1211. Com_Printf ("Command packet from remote host. Ignored.\n");
  1212. return;
  1213. }
  1214. #ifdef _WIN32
  1215. #if 0
  1216. ShowWindow (mainwindow, SW_RESTORE);
  1217. SetForegroundWindow (mainwindow);
  1218. #endif
  1219. #endif
  1220. s = MSG_ReadString();
  1221. Q_strncpyz(cmdtext, s, sizeof(cmdtext));
  1222. s = MSG_ReadString();
  1223. while (*s && isspace(*s))
  1224. s++;
  1225. while (*s && isspace(s[strlen(s) - 1]))
  1226. s[strlen(s) - 1] = 0;
  1227. if (!allowremotecmd && (!*localid.string || strcmp(localid.string, s)))
  1228. {
  1229. if (!*localid.string)
  1230. {
  1231. Com_Printf("===========================\n");
  1232. Com_Printf("Command packet received from local host, but no "
  1233. "localid has been set. You may need to upgrade your server "
  1234. "browser.\n");
  1235. Com_Printf("===========================\n");
  1236. }
  1237. else
  1238. {
  1239. Com_Printf("===========================\n");
  1240. Com_Printf("Invalid localid on command packet received from local host. "
  1241. "\n|%s| != |%s|\n"
  1242. "You may need to reload your server browser and FuhQuake.\n",
  1243. s, localid.string);
  1244. Com_Printf("===========================\n");
  1245. Cvar_Set(&localid, "");
  1246. }
  1247. }
  1248. else
  1249. {
  1250. Cbuf_AddText(cmdtext);
  1251. Cbuf_AddText("\n");
  1252. allowremotecmd = false;
  1253. }
  1254. break;
  1255. case A2C_PRINT: // print command from somewhere
  1256. Com_Printf("%s: print\n", NET_AdrToString(&cl_net_from));
  1257. Com_Printf("%s", MSG_ReadString());
  1258. break;
  1259. case svc_disconnect:
  1260. if (cls.demoplayback)
  1261. {
  1262. Com_Printf("\n======== End of demo ========\n\n");
  1263. Host_EndGame();
  1264. Host_Abort();
  1265. }
  1266. break;
  1267. }
  1268. }
  1269. #ifdef NETQW
  1270. void CL_DoNetQWStuff()
  1271. {
  1272. unsigned int startframe, numframes;
  1273. NetQW_GenerateFrames(cls.netqw);
  1274. NetQW_CopyFrames(cls.netqw, cl.frames, (unsigned int *)&cls.netchan.outgoing_sequence, &startframe, &numframes);
  1275. while(numframes)
  1276. {
  1277. Cam_FinishMove(&cl.frames[startframe].cmd);
  1278. if (cls.demorecording)
  1279. CL_WriteDemoCmd(&cl.frames[startframe].cmd);
  1280. startframe++;
  1281. startframe &= UPDATE_MASK;
  1282. numframes--;
  1283. }
  1284. }
  1285. #endif
  1286. //Handles playback of demos, on top of NET_ code
  1287. qboolean CL_GetMessage(void)
  1288. {
  1289. #ifdef _WIN32
  1290. CL_CheckQizmoCompletion();
  1291. #endif
  1292. if (cls.demoplayback)
  1293. return CL_GetDemoMessage();
  1294. #ifndef NETQW
  1295. while(NET_GetPacket(NS_CLIENT, &cl_net_message, &cl_net_from))
  1296. {
  1297. if ((*(int *)cl_net_message.data != -1) && !NET_CompareAdr(&cl_net_from, &cls.netchan.remote_address))
  1298. {
  1299. Com_DPrintf ("%s: sequenced packet without connection\n", NET_AdrToString(&cl_net_from));
  1300. }
  1301. else
  1302. return true;
  1303. }
  1304. #endif
  1305. #ifdef NETQW
  1306. if (cls.netqw)
  1307. {
  1308. unsigned int size;
  1309. void *p;
  1310. size = NetQW_GetPacketLength(cls.netqw);
  1311. if (size)
  1312. {
  1313. if (size > sizeof(cl_net_message_buffer))
  1314. size = sizeof(cl_net_message_buffer);
  1315. p = NetQW_GetPacketData(cls.netqw);
  1316. memcpy(cl_net_message_buffer, p, size);
  1317. NetQW_FreePacket(cls.netqw);
  1318. SZ_Init(&cl_net_message, cl_net_message_buffer, sizeof(cl_net_message_buffer));
  1319. cl_net_message.cursize = size;
  1320. if (cls.state == ca_disconnected)
  1321. cls.state = ca_connected;
  1322. CL_DoNetQWStuff();
  1323. return true;
  1324. }
  1325. }
  1326. #endif
  1327. return false;
  1328. }
  1329. void CL_ReadPackets(void)
  1330. {
  1331. #ifdef NETQW
  1332. /* Check connectionless messages (such as rcon) over the non-game socket */
  1333. while(NET_GetPacket(NS_CLIENT, &cl_net_message, &cl_net_from))
  1334. {
  1335. if (*(int *)cl_net_message.data == -1)
  1336. {
  1337. CL_ConnectionlessPacket();
  1338. }
  1339. }
  1340. #endif
  1341. while (CL_GetMessage())
  1342. {
  1343. // remote command packet
  1344. if (*(int *)cl_net_message.data == -1)
  1345. {
  1346. CL_ConnectionlessPacket();
  1347. continue;
  1348. }
  1349. if (cl_net_message.cursize < 8 && !cls.mvdplayback)
  1350. {
  1351. Com_DPrintf ("%s: Runt packet\n", NET_AdrToString(&cl_net_from));
  1352. continue;
  1353. }
  1354. if (cls.mvdplayback)
  1355. {
  1356. MSG_BeginReading(&cl_net_message);
  1357. }
  1358. else
  1359. {
  1360. #ifdef NETQW
  1361. MSG_BeginReading(&cl_net_message);
  1362. cls.netchan.incoming_sequence = MSG_ReadLong() & 0x7fffffff;
  1363. cls.netchan.incoming_acknowledged = MSG_ReadLong() & 0x7fffffff;
  1364. #else
  1365. if (!Netchan_Process(&cls.netchan, &cl_net_message))
  1366. continue; // wasn't accepted for some reason
  1367. #endif
  1368. }
  1369. CL_ParseServerMessage ();
  1370. }
  1371. #ifndef NETQW
  1372. // check timeout
  1373. if (!cls.demoplayback && cls.state >= ca_connected)
  1374. {
  1375. if (curtime - cls.netchan.last_received > (cl_timeout.value > 0 ? cl_timeout.value : 60))
  1376. {
  1377. Com_Printf("\nServer connection timed out.\n");
  1378. Host_EndGame();
  1379. return;
  1380. }
  1381. }
  1382. #endif
  1383. }
  1384. #ifndef NETQW
  1385. void CL_SendToServer(void)
  1386. {
  1387. // when recording demos, request new ping times every cl_demoPingInterval.value seconds
  1388. if (cls.demorecording && !cls.demoplayback && cls.state == ca_active && cl_demoPingInterval.value > 0)
  1389. {
  1390. if (cls.realtime - cl.last_ping_request > cl_demoPingInterval.value)
  1391. {
  1392. cl.last_ping_request = cls.realtime;
  1393. MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
  1394. SZ_Print (&cls.netchan.message, "pings");
  1395. }
  1396. }
  1397. // send intentions now
  1398. // resend a connection request if necessary
  1399. if (cls.state == ca_disconnected)
  1400. CL_CheckForResend ();
  1401. else
  1402. CL_SendCmd ();
  1403. }
  1404. #endif
  1405. #define MAXCMDLINE 256
  1406. extern char key_lines[32][MAXCMDLINE];
  1407. void ToggleConsole_f(void)
  1408. {
  1409. Key_ClearTyping();
  1410. if (key_dest == key_console)
  1411. {
  1412. if (!SCR_NEED_CONSOLE_BACKGROUND)
  1413. {
  1414. key_dest = key_game;
  1415. VID_SetMouseGrab(1);
  1416. }
  1417. }
  1418. else
  1419. {
  1420. key_dest = key_console;
  1421. VID_SetMouseGrab(0);
  1422. }
  1423. CSTC_Console_Close();
  1424. if (con_clearnotify.value)
  1425. Con_ClearNotify();
  1426. }
  1427. //=============================================================================
  1428. void CL_SaveArgv(int argc, char **argv)
  1429. {
  1430. char saved_args[512];
  1431. int i, total_length, length;
  1432. qboolean first = true;
  1433. total_length = saved_args[0] = 0;
  1434. for (i = 0; i < argc; i++)
  1435. {
  1436. if (!argv[i][0])
  1437. continue;
  1438. if (!first && total_length + 1 < sizeof(saved_args))
  1439. {
  1440. strcat(saved_args, " ");
  1441. total_length++;
  1442. }
  1443. first = false;
  1444. length = strlen(argv[i]);
  1445. if (total_length + length < sizeof(saved_args))
  1446. {
  1447. strcat(saved_args, argv[i]);
  1448. total_length += length;
  1449. }
  1450. }
  1451. Cvar_ForceSet(&cl_cmdline, saved_args);
  1452. }
  1453. #if HUFFTEST
  1454. void huff_load_f(void)
  1455. {
  1456. if (Cmd_Argc() != 2)
  1457. {
  1458. Com_Printf("Blah!\n");
  1459. return;
  1460. }
  1461. huff_loadfile(Cmd_Argv(1));
  1462. }
  1463. void huff_save_f(void)
  1464. {
  1465. if (Cmd_Argc() != 2)
  1466. {
  1467. Com_Printf("Blah!\n");
  1468. return;
  1469. }
  1470. huff_savefile(Cmd_Argv(1));
  1471. }
  1472. #endif
  1473. void CL_CvarInit(void)
  1474. {
  1475. Cvar_SetCurrentGroup(CVAR_GROUP_CHAT);
  1476. Cvar_Register(&cl_parseWhiteText);
  1477. Cvar_Register(&cl_chatsound);
  1478. Cvar_Register(&cl_floodprot);
  1479. Cvar_Register(&cl_fp_messages );
  1480. Cvar_Register(&cl_fp_persecond);
  1481. Cvar_SetCurrentGroup(CVAR_GROUP_SCREEN);
  1482. Cvar_Register (&cl_shownet);
  1483. Cvar_SetCurrentGroup(CVAR_GROUP_SBAR);
  1484. Cvar_Register(&cl_sbar);
  1485. Cvar_Register(&cl_hudswap);
  1486. Cvar_SetCurrentGroup(CVAR_GROUP_VIEWMODEL);
  1487. Cvar_Register(&cl_filterdrawviewmodel);
  1488. Cvar_SetCurrentGroup(CVAR_GROUP_EYECANDY);
  1489. Cvar_Register(&cl_model_bobbing);
  1490. Cvar_Register(&cl_nolerp);
  1491. Cvar_Register(&cl_maxfps);
  1492. Cvar_Register(&cl_deadbodyfilter);
  1493. Cvar_Register(&cl_gibfilter);
  1494. Cvar_Register(&cl_muzzleflash);
  1495. Cvar_Register(&cl_rocket2grenade);
  1496. Cvar_Register(&r_explosiontype);
  1497. Cvar_Register(&r_lightflicker);
  1498. Cvar_Register(&r_rockettrail);
  1499. Cvar_Register(&r_grenadetrail);
  1500. Cvar_Register(&r_powerupglow);
  1501. Cvar_Register(&r_rocketlight);
  1502. Cvar_Register(&r_explosionlight);
  1503. Cvar_Register(&r_rocketlightcolor);
  1504. Cvar_Register(&r_explosionlightcolor);
  1505. Cvar_Register(&r_flagcolor);
  1506. Cvar_Register(&cl_trueLightning);
  1507. Cvar_SetCurrentGroup(CVAR_GROUP_DEMO);
  1508. Cvar_Register(&cl_demospeed);
  1509. Cvar_Register(&cl_demoPingInterval);
  1510. Cvar_Register(&qizmo_dir);
  1511. Cvar_SetCurrentGroup(CVAR_GROUP_SOUND);
  1512. Cvar_Register(&cl_staticsounds);
  1513. Cvar_SetCurrentGroup(CVAR_GROUP_USERINFO);
  1514. Cvar_Register(&team);
  1515. Cvar_Register(&spectator);
  1516. Cvar_Register(&skin);
  1517. Cvar_Register(&rate);
  1518. Cvar_Register(&noaim);
  1519. Cvar_Register(&name);
  1520. Cvar_Register(&msg);
  1521. Cvar_Register(&topcolor);
  1522. Cvar_Register(&bottomcolor);
  1523. Cvar_Register(&w_switch);
  1524. Cvar_Register(&b_switch);
  1525. Cvar_SetCurrentGroup(CVAR_GROUP_VIEW);
  1526. Cvar_Register(&default_fov);
  1527. Cvar_SetCurrentGroup(CVAR_GROUP_NETWORK);
  1528. Cvar_Register(&cl_predictPlayers);
  1529. Cvar_Register(&cl_solidPlayers);
  1530. Cvar_Register(&cl_oldPL);
  1531. Cvar_Register(&cl_timeout);
  1532. Cvar_Register(&cl_useproxy);
  1533. Cvar_Register(&net_maxfps);
  1534. Cvar_Register(&net_lag);
  1535. Cvar_Register(&net_lag_ezcheat);
  1536. Cvar_SetCurrentGroup(CVAR_GROUP_CONSOLE);
  1537. Cvar_Register(&con_clearnotify);
  1538. Cvar_SetCurrentGroup(CVAR_GROUP_NO_GROUP);
  1539. Cvar_Register(&password);
  1540. Cvar_Register(&rcon_password);
  1541. Cvar_Register(&rcon_address);
  1542. Cvar_Register(&localid);
  1543. Cvar_Register(&cl_warncmd);
  1544. Cvar_Register(&cl_cmdline);
  1545. Cvar_ResetCurrentGroup();
  1546. Cvar_Register(&cl_confirmquit);
  1547. Cvar_Register(&cl_imitate_client);
  1548. Cvar_Register(&cl_imitate_os);
  1549. Cvar_Register(&r_drawflat_enable);
  1550. Cvar_Register(&r_drawflat_floors_ceilings);
  1551. Cvar_Register(&r_drawflat_slopes);
  1552. Cvar_Register(&r_drawflat_walls);
  1553. Cmd_AddLegacyCommand("demotimescale", "cl_demospeed");
  1554. CL_InitCommands();
  1555. #if HUFFTEST
  1556. Cmd_AddCommand("huff_load", huff_load_f);
  1557. Cmd_AddCommand("huff_save", huff_save_f);
  1558. #endif
  1559. Cmd_AddCommand("r_drawflat", R_DrawFlat_f);
  1560. Cmd_AddCommand("r_drawflat_shoot", R_DrawFlatShoot_f);
  1561. Cmd_AddCommand("r_drawflat_shoot_unset", R_DrawFlatShootUnset_f);
  1562. Cmd_AddCommand("r_drawflat_set", R_DrawFlat_Set_f);
  1563. Cmd_AddCommand("r_drawflat_unset", R_DrawFlat_Unset_f);
  1564. Cmd_AddCommand("r_drawflat_writeconfig", R_DrawFlat_Write_Config);
  1565. Cmd_AddCommand("disconnect", CL_Disconnect_f);
  1566. Cmd_AddCommand("connect", CL_Connect_f);
  1567. Cmd_AddCommand("join", CL_Join_f);
  1568. Cmd_AddCommand("observe", CL_Observe_f);
  1569. Cmd_AddCommand("qtvplay", CL_QTVPlay_f);
  1570. Cmd_AddCommand("dns", CL_DNS_f);
  1571. Cmd_AddCommand("reconnect", CL_Reconnect_f);
  1572. Cmd_AddMacro("connectiontype", CL_Macro_ConnectionType);
  1573. Cmd_AddMacro("demoplayback", CL_Macro_Demoplayback);
  1574. Cmd_AddMacro("matchstatus", CL_Macro_Serverstatus);
  1575. Cmd_AddCommand("toggleconsole", ToggleConsole_f);
  1576. }
  1577. static void CL_InitClientVersionInfo()
  1578. {
  1579. Info_RemoveKey(cls.userinfo, "*FuhQuake");
  1580. Info_RemoveKey(cls.userinfo, "*client");
  1581. Info_RemoveKey(cls.userinfo, "*Fodquake");
  1582. if (imitatedclientnum == CLIENT_EZQUAKE_1144)
  1583. {
  1584. Info_SetValueForStarKey (cls.userinfo, "*client", "ezQuake 1144", MAX_INFO_STRING);
  1585. }
  1586. else if (imitatedclientnum == CLIENT_EZQUAKE_1517)
  1587. {
  1588. Info_SetValueForStarKey (cls.userinfo, "*client", "ezQuake 1517", MAX_INFO_STRING);
  1589. }
  1590. else if (imitatedclientnum == CLIENT_EZQUAKE_1_8_2)
  1591. {
  1592. Info_SetValueForStarKey (cls.userinfo, "*client", "ezQuake 2029", MAX_INFO_STRING);
  1593. }
  1594. else if (imitatedclientnum == CLIENT_FUHQUAKE_0_31_675)
  1595. {
  1596. Info_SetValueForStarKey (cls.userinfo, "*FuhQuake", "0.31", MAX_INFO_STRING);
  1597. }
  1598. else
  1599. Info_SetValueForStarKey (cls.userinfo, "*Fodquake", FODQUAKE_VERSION, MAX_INFO_STRING);
  1600. }
  1601. void CL_Init (void)
  1602. {
  1603. if (dedicated)
  1604. return;
  1605. SZ_Init(&cl_net_message, cl_net_message_buffer, sizeof(cl_net_message_buffer));
  1606. cls.state = ca_disconnected;
  1607. strcpy(cls.gamedirfile, com_gamedirfile);
  1608. strcpy(cls.gamedir, com_gamedir);
  1609. W_LoadWadFile("gfx.wad");
  1610. FChecks_Init();
  1611. host_basepal = (byte *) FS_LoadMallocFile("gfx/palette.lmp");
  1612. if (!host_basepal)
  1613. Sys_Error("Couldn't load gfx/palette.lmp");
  1614. FMod_CheckModel("gfx/palette.lmp", host_basepal, com_filesize);
  1615. host_colormap = (byte *) FS_LoadMallocFile ("gfx/colormap.lmp");
  1616. if (!host_colormap)
  1617. Sys_Error("Couldn't load gfx/colormap.lmp");
  1618. FMod_CheckModel("gfx/colormap.lmp", host_colormap, com_filesize);
  1619. Sys_IO_Create_Directory(va("%s/qw", com_basedir));
  1620. Sys_IO_Create_Directory(va("%s/fodquake", com_basedir));
  1621. Key_Init();
  1622. V_Init();
  1623. VID_Init(host_basepal);
  1624. cl_vidinitialised = 1;
  1625. Image_Init();
  1626. S_Init();
  1627. CDAudio_Init();
  1628. Info_SetValueForStarKey(cls.userinfo, "*z_ext", va("%i", SUPPORTED_EXTENSIONS), MAX_SERVERINFO_STRING);
  1629. CL_InitClientVersionInfo();
  1630. if (!CL_InitEnts())
  1631. Sys_Error("CL_InitEnts() failed\n");
  1632. CL_InitTEnts();
  1633. #warning If I want to keep compatibility with Win32 server browsers, I need to open a socket on port 27001 here.
  1634. MT_Init();
  1635. CL_Demo_Init();
  1636. Ignore_Init();
  1637. Stats_Init();
  1638. Sleep_Init();
  1639. M_Init();
  1640. }
  1641. //============================================================================
  1642. void CL_BeginLocalConnection(void)
  1643. {
  1644. S_StopAllSounds(true);
  1645. // make sure we're not connected to an external server,
  1646. // and demo playback is stopped
  1647. if (!com_serveractive)
  1648. CL_Disconnect();
  1649. cl.worldmodel = NULL;
  1650. if (cls.state == ca_active)
  1651. cls.state = ca_connected;
  1652. }
  1653. static double CL_MinFrameTime(void)
  1654. {
  1655. double fps;
  1656. if (cls.timedemo || Movie_IsCapturing())
  1657. return 0;
  1658. if (cls.demoplayback)
  1659. {
  1660. if (!cl_maxfps.value)
  1661. return 0;
  1662. fps = max(30.0, cl_maxfps.value);
  1663. }
  1664. else
  1665. {
  1666. #ifdef NETQW
  1667. #warning This needs updating for in sync net/video.
  1668. if (!cl_maxfps.value)
  1669. return 0;
  1670. fps = max(30.0, cl_maxfps.value);
  1671. #else
  1672. double fpscap;
  1673. fpscap = cl.maxfps ? max(30.0, cl.maxfps) : 72;
  1674. fps = cl_maxfps.value ? bound(30.0, cl_maxfps.value, fpscap) : com_serveractive ? fpscap : bound(30.0, rate.value / 80.0, fpscap);
  1675. #endif
  1676. }
  1677. return 1 / fps;
  1678. }
  1679. void CL_Frame (double time)
  1680. {
  1681. keynum_t key;
  1682. qboolean down;
  1683. int focuschanged;
  1684. static double extratime = 0.001;
  1685. double minframetime;
  1686. extratime += time;
  1687. minframetime = CL_MinFrameTime();
  1688. if (extratime < minframetime)
  1689. {
  1690. Sleep_Sleep((unsigned int)((minframetime-extratime)*1000000));
  1691. return;
  1692. }
  1693. #if 0
  1694. cls.trueframetime = extratime - 0.001;
  1695. cls.trueframetime = max(cls.trueframetime, minframetime);
  1696. extratime -= cls.trueframetime;
  1697. #else
  1698. cls.trueframetime = minframetime;
  1699. extratime -= minframetime;
  1700. if (extratime > minframetime)
  1701. {
  1702. /* Com_Printf("Dropping frame: %.4f\n", extratime);*/
  1703. cls.trueframetime+= extratime-minframetime;
  1704. extratime = minframetime;
  1705. }
  1706. #endif
  1707. cls.framedev = extratime;
  1708. /* Ugliest hack ever */
  1709. movementkey = rand();
  1710. if (Movie_IsCapturing())
  1711. cls.frametime = Movie_StartFrame();
  1712. else
  1713. cls.frametime = min(0.2, cls.trueframetime);
  1714. if (cls.demoplayback) {
  1715. if (cl.paused & PAUSED_DEMO)
  1716. cls.frametime = 0;
  1717. else if (!cls.timedemo)
  1718. cls.frametime *= bound(0, cl_demospeed.value, 20);
  1719. if (!host_skipframe)
  1720. cls.demotime += cls.frametime;
  1721. host_skipframe = false;
  1722. }
  1723. #ifdef NETQW
  1724. cls.realtime = Sys_DoubleTime();
  1725. #else
  1726. cls.realtime += cls.frametime;
  1727. #endif
  1728. if (!cl.paused) {
  1729. cl.time += cls.frametime;
  1730. cl.servertime += cls.frametime;
  1731. cl.stats[STAT_TIME] = (int) (cl.servertime * 1000);
  1732. cl.gametime += cls.frametime;
  1733. }
  1734. if (cls.demoplayback)
  1735. {
  1736. cl.gametime = cls.realactualdemotime - cls.demotimeoffset;
  1737. }
  1738. focuschanged = VID_FocusChanged();
  1739. M_PerFramePreRender();
  1740. while(VID_GetKeyEvent(&key, &down))
  1741. Key_Event(key, down);
  1742. if (focuschanged)
  1743. Key_ClearStates();
  1744. // process console commands
  1745. Cbuf_Execute();
  1746. #ifndef CLIENTONLY
  1747. if (com_serveractive)
  1748. SV_Frame(cls.frametime);
  1749. #endif
  1750. // fetch results from server
  1751. CL_ReadPackets();
  1752. if (cls.mvdplayback)
  1753. MVD_Interpolate();
  1754. // process stuffed commands
  1755. Cbuf_ExecuteEx(cbuf_svc);
  1756. if (!cls.demoplayback || cls.mvdplayback)
  1757. Mouse_GetViewAngles(cl.viewangles);
  1758. #ifdef NETQW
  1759. if (cls.netqw)
  1760. {
  1761. CL_DoNetQWStuff();
  1762. if (cl.spectator)
  1763. {
  1764. usercmd_t cmd;
  1765. #warning Get rid of the cmd arg.
  1766. Cam_Track(&cmd);
  1767. }
  1768. }
  1769. else if (cls.mvdplayback)
  1770. {
  1771. usercmd_t *cmd;
  1772. cmd = &cl.frames[cls.netchan.outgoing_sequence & UPDATE_MASK].cmd;
  1773. cl.frames[cls.netchan.outgoing_sequence & UPDATE_MASK].senttime = cls.realtime;
  1774. cl.frames[cls.netchan.outgoing_sequence & UPDATE_MASK].receivedtime = -1;
  1775. CL_BaseMove(cmd);
  1776. // if we are spectator, try a…

Large files files are truncated, but you can click here to view the full file