PageRenderTime 65ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/server_browser.c

https://gitlab.com/fzwoch/fodquake
C | 3209 lines | 2642 code | 495 blank | 72 comment | 799 complexity | c8aa671100c2cfd7acda7afd10b9c70c 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) 2009 Jürgen Legler
  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. #define _GNU_SOURCE
  16. #include <stdarg.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include "quakedef.h"
  20. #include "strl.h"
  21. #include "keys.h"
  22. #include "linked_list.h"
  23. #include "serverscanner.h"
  24. #include "readablechars.h"
  25. #include "server_browser_qtv.h"
  26. #include "utils.h"
  27. #include "tokenize_string.h"
  28. #include "context_sensitive_tab.h"
  29. static void SB_AddMacros(void);
  30. static int Color_For_Map (int m)
  31. {
  32. m = bound(0, m, 13);
  33. return 16 * m + 8;
  34. }
  35. struct server
  36. {
  37. struct linked_list_node node;
  38. char *ip;
  39. int port;
  40. };
  41. struct sb_friend
  42. {
  43. struct sb_friend *next, *prev;
  44. char *name;
  45. };
  46. static struct ServerScanner *serverscanner;
  47. static struct sb_friend *friends;
  48. static int qtv_connect_pending;
  49. static double qtv_connect_time;
  50. static cvar_t sb_masterserver = {"sb_masterserver", "qwmaster.fodquake.net:27000 master.quakeservers.net:27000 satan.idsoftware.com:27000"};
  51. static cvar_t sb_player_drawing = {"sb_player_drawing", "1"};
  52. static cvar_t sb_refresh_on_activate = {"sb_refresh_on_activate", "1"};
  53. static cvar_t sb_color_bg = {"sb_color_bg", "1"};
  54. static cvar_t sb_color_bg_free = {"sb_color_bg_free", "55"};
  55. static cvar_t sb_color_bg_full = {"sb_color_bg_full", "70"};
  56. static cvar_t sb_color_bg_empty = {"sb_color_bg_empty", "1"};
  57. static cvar_t sb_color_bg_specable = {"sb_color_bg_specable", "88"};
  58. static cvar_t sb_qtv_proxy = {"sb_qtv_proxy", "qtv.fodquake.net:27599"};
  59. static cvar_t sb_qtv_lookup = {"sb_qtv_lookup", "qtv.fodquake.net:12000"};
  60. static cvar_t sb_qtv_connect_timeout = {"sb_qtv_connect_timeout", "2"};
  61. static cvar_t sb_highlight_sort_column = {"sb_highlight_sort_column", "1"};
  62. static cvar_t sb_highlight_sort_column_color = {"sb_highlight_sort_column_color", "70"};
  63. static cvar_t sb_highlight_sort_column_alpha = {"sb_highlight_sort_column_alpha", "0.5"};
  64. static char sb_macro_buf[512];
  65. static struct qtvr *qtvr;
  66. static int sb_open = 0;
  67. static int sb_default_settings = 1;
  68. static const struct QWServer **sb_qw_server;
  69. static unsigned int sb_qw_server_count = 0;
  70. static int sb_help_prev = -1;
  71. static int sb_active_help_window = 0;
  72. #define SB_HELP_WINDOWS 4
  73. static int sb_check_serverscanner = 0;
  74. // general display
  75. static int sb_active_window= 0;
  76. static int sb_selected_filter = 0;
  77. static char sb_status_bar[512];
  78. // server display
  79. static int sb_server_insert;
  80. static int sb_server_count_width = 1;
  81. // filter display
  82. static int sb_filter_insert;
  83. static int sb_filter_edit;
  84. static int sb_filter_delete;
  85. // inserting filter
  86. static int sb_filter_insert_selected_key;
  87. static int sb_filter_insert_selected_type;
  88. static char sb_filter_insert_value[512];
  89. static int sb_filter_insert_value_position = 0;
  90. static int sb_filter_insert_selected_box;
  91. // player filter
  92. static int sb_player_filter = 0;
  93. static char sb_player_filter_entry[512];
  94. static int sb_player_filter_entry_position = 0;
  95. static double sb_player_filter_blink_time = 0;
  96. // text filter
  97. static int sb_text_filter = 0;
  98. static char sb_text_filter_entry[512];
  99. static int sb_text_filter_entry_position = 0;
  100. static double sb_text_filter_blink_time = 0;
  101. static int sb_server_insert_selected_box;
  102. static char sb_server_insert_ip[512];
  103. static int sb_server_insert_ip_position;
  104. static char sb_server_insert_port[512];
  105. static int sb_server_insert_port_position;
  106. #define SB_MAX_TABS 10
  107. #define SB_SERVER 0
  108. #define SB_FILTER 1
  109. #define SB_HELP 2
  110. const struct QWServer *current_selected_server;
  111. static int friend_name_max_len = 0;
  112. enum column_type
  113. {
  114. SBCT_PLAYERS,
  115. SBCT_MAP,
  116. SBCT_HOSTNAME,
  117. SBCT_PING
  118. };
  119. #define SB_SORT_MAX 4
  120. struct tab_column_type
  121. {
  122. int length;
  123. enum column_type type;
  124. };
  125. struct tab
  126. {
  127. struct tab *prev, *next;
  128. char *name;
  129. int max_filter_keyword_length;
  130. int server_count;
  131. int player_count;
  132. int max_hostname_length;
  133. int max_map_length;
  134. int sb_position;
  135. int changed;
  136. int sort;
  137. int sort_dir;
  138. struct server **servers;
  139. int *server_index;
  140. char *player_filter;
  141. char *text_filter;
  142. struct linked_list *filters;
  143. int friends;
  144. struct sb_friend **friend_links;
  145. int columns;
  146. struct tab_column_type *column_types;
  147. };
  148. static struct tab *tab_first;
  149. static struct tab *tab_last;
  150. static struct tab *tab_active;
  151. /*
  152. static char *get_column_name (enum column_type type)
  153. {
  154. if (type == SBCT_PLAYERS)
  155. return "players";
  156. else if (type == SBCT_PING)
  157. return "ping";
  158. else if (type == SBCT_MAP)
  159. return "map";
  160. else if (type == SBCT_HOSTNAME)
  161. return "hostname";
  162. else
  163. return "weird!";
  164. }
  165. */
  166. char *column_names[] =
  167. {
  168. "players",
  169. "map",
  170. "hostname",
  171. "ping"
  172. };
  173. struct filter
  174. {
  175. struct linked_list_node node;
  176. int key;
  177. char *keyword;
  178. int type;
  179. char *value;
  180. float fvalue;
  181. };
  182. struct filter_types
  183. {
  184. int type; // 0 - float, 1 - string
  185. char *name;
  186. char *description;
  187. int (*compare_function)(struct QWServer *server, struct filter *filter);
  188. };
  189. const char *filter_num_operators[] =
  190. {
  191. "==",
  192. "<=",
  193. ">="
  194. };
  195. const char *filter_char_operators[] =
  196. {
  197. "isin",
  198. "!isin"
  199. };
  200. static int num_check(float sv, float fv, int type)
  201. {
  202. if (type == 0)
  203. {
  204. if (sv == fv)
  205. return 1;
  206. }
  207. else if (type == 1)
  208. {
  209. if (sv <= fv)
  210. return 1;
  211. }
  212. else if (type == 2)
  213. {
  214. if (sv >= fv)
  215. return 1;
  216. }
  217. return 0;
  218. }
  219. static int char_check(const char *sv, char *fv, int type)
  220. {
  221. if (type == 0)
  222. {
  223. if(strstr(fv, sv) == NULL)
  224. return 0;
  225. else
  226. return 1;
  227. }
  228. else if (type ==1)
  229. {
  230. if(strstr(sv, fv) == NULL)
  231. return 0;
  232. else
  233. return 1;
  234. }
  235. return 0;
  236. }
  237. static int filter_player_check(struct QWServer *server, struct filter *filter)
  238. {
  239. return num_check(server->numplayers, filter->fvalue, filter->type);
  240. }
  241. static int filter_map_check(struct QWServer *server, struct filter *filter)
  242. {
  243. if (server->map)
  244. return char_check(server->map, filter->value, filter->type);
  245. return 0;
  246. }
  247. static int filter_hostname_check(struct QWServer *server, struct filter *filter)
  248. {
  249. if (server->hostname)
  250. return char_check(server->hostname, filter->value, filter->type);
  251. return 0;
  252. }
  253. static int filter_teamplay_check(struct QWServer *server, struct filter *filter)
  254. {
  255. return num_check(server->teamplay, filter->fvalue, filter->type);
  256. }
  257. static int filter_max_clients_check(struct QWServer *server, struct filter *filter)
  258. {
  259. return num_check(server->maxclients, filter->fvalue, filter->type);
  260. }
  261. static int filter_ping_check(struct QWServer *server, struct filter *filter)
  262. {
  263. return num_check(server->pingtime/1000, filter->fvalue, filter->type);
  264. }
  265. #define SB_FILTER_TYPE_MAX 6
  266. struct filter_types filter_types[SB_FILTER_TYPE_MAX] =
  267. {
  268. { 0, "players", "amount of players on the servers", filter_player_check},
  269. { 1, "map", "mapname", filter_map_check},
  270. { 1, "hostname", "hostname", filter_hostname_check},
  271. { 0, "teamplay", "teamplay", filter_teamplay_check},
  272. { 0, "max_clients", "max clients allowed on server", filter_max_clients_check},
  273. { 0, "ping", "ping to the server", filter_ping_check}
  274. };
  275. static keydest_t old_keydest;
  276. //static void SB_Filter_Delete_Handler(int ket);
  277. void SB_Filter_Delete_Filter(void);
  278. static void SB_Filter_Insert_Handler(int key);
  279. static void SB_Server_Insert_Handler(int key);
  280. static void update_tab(struct tab *tab);
  281. static void SB_Proxy_Connect(const struct QWServer *server)
  282. {
  283. if (qtvr)
  284. QTVR_Destroy(qtvr);
  285. qtvr = QTVR_Create(sb_qtv_lookup.string, NET_AdrToString(&server->addr));
  286. if (qtvr == NULL)
  287. {
  288. Com_Printf("QTV Retriever not running.\n");
  289. return;
  290. }
  291. Com_Printf("Retrieving proxy for %s\n", NET_AdrToString(&server->addr));
  292. qtv_connect_pending = 1;
  293. qtv_connect_time = cls.realtime;
  294. }
  295. static char *Filter_Type_String(int type)
  296. {
  297. if (type == 0)
  298. return "==";
  299. else if (type == 1)
  300. return ">=";
  301. else if (type == 2)
  302. return "<=";
  303. else if (type == 3)
  304. return "isin";
  305. else if (type == 4)
  306. return "!isin";
  307. else
  308. return NULL;
  309. }
  310. static struct tab *sb_add_tab(char *name)
  311. {
  312. struct tab *tab;
  313. if (name == NULL)
  314. return NULL;
  315. tab = calloc(1, sizeof(struct tab));
  316. if (tab == NULL)
  317. return NULL;
  318. tab->column_types = calloc(4, sizeof(struct tab_column_type));
  319. if (tab->column_types == NULL)
  320. {
  321. free(tab);
  322. return NULL;
  323. }
  324. tab->filters = List_Add(0, NULL, NULL);
  325. if (tab->filters == NULL)
  326. {
  327. free(tab->column_types);
  328. free(tab);
  329. return NULL;
  330. }
  331. tab->name = strdup(name);
  332. if (tab->name == NULL)
  333. {
  334. free(tab->column_types);
  335. free(tab->filters);
  336. free(tab);
  337. return NULL;
  338. }
  339. if (tab_first == NULL)
  340. tab_first = tab;
  341. if (tab_last == NULL)
  342. {
  343. tab_last = tab;
  344. }
  345. else
  346. {
  347. tab_last->next = tab;
  348. tab->prev = tab_last;
  349. tab_last = tab_last->next;
  350. }
  351. if (tab_active == NULL)
  352. tab_active = tab;
  353. if (strcmp(name, "friends") == 0)
  354. tab->friends = 1;
  355. tab->column_types[0].type = SBCT_PING;
  356. tab->column_types[1].type = SBCT_PLAYERS;
  357. tab->column_types[2].type = SBCT_MAP;
  358. tab->column_types[3].type = SBCT_HOSTNAME;
  359. tab->columns = 4;
  360. tab->sort = 1;
  361. return tab;
  362. }
  363. static void sb_del_tab(struct tab *tab)
  364. {
  365. struct filter *filter;
  366. if (tab->next == NULL && tab->prev == NULL)
  367. {
  368. tab_first = tab_last = tab_active = NULL;
  369. }
  370. else if (tab->next && tab->prev == NULL)
  371. {
  372. tab_first = tab->next;
  373. tab->next->prev = NULL;
  374. if (tab == tab_active)
  375. tab_active = tab->next;
  376. }
  377. else if (tab->next == NULL && tab->prev)
  378. {
  379. tab->prev->next = NULL;
  380. tab_last = tab->prev;
  381. if (tab == tab_active)
  382. tab_active = tab->prev;
  383. }
  384. else
  385. {
  386. tab->prev->next = tab->next;
  387. tab->next->prev = tab->prev;
  388. if (tab == tab_active)
  389. tab_active = tab->next;
  390. }
  391. filter = (struct filter *) List_Get_Node(tab->filters, 0);
  392. while(filter)
  393. {
  394. free(filter->keyword);
  395. free(filter->value);
  396. filter = (struct filter *)filter->node.next;
  397. }
  398. List_Remove(tab->filters);
  399. free(tab->name);
  400. free(tab->column_types);
  401. free(tab->player_filter);
  402. free(tab->text_filter);
  403. free(tab->server_index);
  404. free(tab);
  405. }
  406. static void sb_del_tab_by_name(char *name)
  407. {
  408. struct tab *tab;
  409. tab = tab_first;
  410. while(tab)
  411. {
  412. if (strcmp(tab->name, name) == 0)
  413. {
  414. sb_del_tab(tab);
  415. return;
  416. }
  417. tab = tab->next;
  418. }
  419. Com_Printf("tab \"%s\" not found.\n", name);
  420. }
  421. static void sb_activate_tab(int num)
  422. {
  423. struct tab *tab, *ptab;
  424. int i;
  425. tab = tab_first;
  426. i = 0;
  427. if (!tab)
  428. return;
  429. while (tab && i++ < num)
  430. {
  431. ptab = tab;
  432. tab = tab->next;
  433. }
  434. if (tab)
  435. tab_active = tab;
  436. else
  437. tab_active = ptab;
  438. }
  439. static void SB_Set_Statusbar (const char *format, ...)
  440. {
  441. va_list args;
  442. va_start(args, format);
  443. vsnprintf(sb_status_bar, sizeof(sb_status_bar), format, args);
  444. va_end(args);
  445. }
  446. static void SB_Refresh(void)
  447. {
  448. struct tab *tab;
  449. if (serverscanner)
  450. {
  451. ServerScanner_FreeServers(serverscanner, sb_qw_server);
  452. ServerScanner_Delete(serverscanner);
  453. }
  454. serverscanner = NULL;
  455. sb_qw_server = NULL;
  456. current_selected_server = NULL;
  457. sb_qw_server_count = 0;
  458. serverscanner = ServerScanner_Create(sb_masterserver.string);
  459. if (serverscanner == NULL)
  460. SB_Set_Statusbar("error creating server scanner!");
  461. tab = tab_first;
  462. while (tab)
  463. {
  464. tab->sb_position = 0;
  465. tab->changed = 0;
  466. tab = tab->next;
  467. }
  468. }
  469. static void handle_textbox(int key, char *string, int *position, int size)
  470. {
  471. int i, length;
  472. length = strlen(string);
  473. if (key == K_LEFTARROW)
  474. {
  475. *position -= 1;
  476. if (*position < 0)
  477. *position = 0;
  478. return;
  479. }
  480. if (key == K_RIGHTARROW)
  481. {
  482. *position += 1;
  483. if (*position> length)
  484. *position = length;
  485. return;
  486. }
  487. if (key == K_DEL)
  488. {
  489. i = *position;
  490. if (*position >= length- 1)
  491. return;
  492. while(string[i] != '\0')
  493. {
  494. string[i] = string[i+1];
  495. i++;
  496. }
  497. return;
  498. }
  499. if (key == K_BACKSPACE)
  500. {
  501. i = *position - 1;
  502. if (*position < 1)
  503. return;
  504. while(i<size)
  505. {
  506. string[i] = string[i+1];
  507. i++;
  508. }
  509. *position -= 1;
  510. if (*position < 0)
  511. position = 0;
  512. return;
  513. }
  514. if (key < 32 || key > 127)
  515. return;
  516. if (length == size)
  517. return;
  518. i = length;
  519. while(i>*position)
  520. {
  521. string[i] = string[i-1];
  522. i--;
  523. }
  524. string[*position] = key;
  525. *position += 1;
  526. }
  527. static int Check_Server_Against_Filter(struct tab *tab, const struct QWServer *server)
  528. {
  529. struct filter *fe;
  530. fe = (struct filter *) List_Get_Node(tab->filters, 0);
  531. while (fe)
  532. {
  533. if (filter_types[fe->key].compare_function((struct QWServer *)server, fe) == 0)
  534. return 0;
  535. fe = (struct filter *)fe->node.next;
  536. }
  537. return 1;
  538. }
  539. static char *remove_colors(const char *string, int size)
  540. {
  541. const char *ptr;
  542. char *ptr1, *new_string;
  543. int x = 0;
  544. new_string = calloc(size+1, sizeof(char));
  545. if (new_string == NULL)
  546. return NULL;
  547. ptr = string;
  548. ptr1 = new_string;
  549. while (*ptr != '\0' && x < size)
  550. {
  551. if (*ptr == '&')
  552. {
  553. if (x + 1 < size)
  554. {
  555. if (*(ptr + 1) == 'c')
  556. {
  557. if (x + 5 >= size)
  558. break;
  559. ptr += 5;
  560. x += 5;
  561. }
  562. }
  563. else
  564. {
  565. break;
  566. }
  567. }
  568. *ptr1 = readablechars[(unsigned char)*ptr];
  569. ptr++;
  570. ptr1++;
  571. x++;
  572. }
  573. return new_string;
  574. }
  575. static int check_player_name(char *name, const struct QWServer *server)
  576. {
  577. int i;
  578. char *player;
  579. char *player_uncolored;
  580. player = name;
  581. if (server->numplayers == 0 && server->numspectators == 0)
  582. return 0;
  583. for (i=0; i<server->numplayers; i++)
  584. {
  585. if (server->players[i].name)
  586. {
  587. player_uncolored = remove_colors(server->players[i].name , strlen(server->players[i].name));
  588. if (player_uncolored == NULL)
  589. continue;
  590. if (Util_strcasestr(player_uncolored, player))
  591. {
  592. free(player_uncolored);
  593. return 1;
  594. }
  595. free(player_uncolored);
  596. }
  597. }
  598. for (i=0; i<server->numspectators; i++)
  599. {
  600. if (server->spectators[i].name)
  601. {
  602. player_uncolored = remove_colors(server->spectators[i].name , strlen(server->spectators[i].name));
  603. if (player_uncolored == NULL)
  604. continue;
  605. if (Util_strcasestr(player_uncolored, player))
  606. {
  607. free(player_uncolored);
  608. return 1;
  609. }
  610. free(player_uncolored);
  611. }
  612. }
  613. return 0;
  614. }
  615. static int check_player(struct tab *tab, const struct QWServer *server)
  616. {
  617. return check_player_name(tab->player_filter, server);
  618. }
  619. static int check_text_hm(char *text, const struct QWServer *server)
  620. {
  621. if (server->hostname)
  622. if (Util_strcasestr(server->hostname, text))
  623. return 1;
  624. if (server->map)
  625. if (Util_strcasestr(server->map, text))
  626. return 1;
  627. if (server->gamedir)
  628. if (Util_strcasestr(server->gamedir, text))
  629. return 1;
  630. return 0;
  631. }
  632. static int check_text (struct tab *tab, const struct QWServer *server)
  633. {
  634. return check_text_hm (tab->text_filter, server);
  635. }
  636. static int hostname_compare(const void *a, const void *b);
  637. static int player_count_compare(const void *a, const void *b)
  638. {
  639. struct QWServer *x, *y;
  640. x = (struct QWServer *) sb_qw_server[*(int *)a];
  641. y = (struct QWServer *) sb_qw_server[*(int *)b];
  642. if (y->numplayers == x->numplayers)
  643. {
  644. if (y->numspectators == x->numspectators)
  645. return hostname_compare(a, b);
  646. return y->numspectators - x->numspectators;
  647. }
  648. return (y->numplayers - x->numplayers);
  649. }
  650. static int ping_compare(const void *a, const void *b)
  651. {
  652. struct QWServer *x, *y;
  653. x = (struct QWServer *) sb_qw_server[*(int *)a];
  654. y = (struct QWServer *) sb_qw_server[*(int *)b];
  655. if (x->status == QWSS_FAILED && y->status == QWSS_FAILED)
  656. return 0;
  657. else if (x->status == QWSS_FAILED)
  658. return 1;
  659. else if (y->status == QWSS_FAILED)
  660. return -1;
  661. if (x->pingtime == y->pingtime)
  662. return hostname_compare(a, b);
  663. return (x->pingtime - y->pingtime);
  664. }
  665. static int hostname_compare(const void *a, const void *b)
  666. {
  667. struct QWServer *x, *y;
  668. char buf[64];
  669. x = (struct QWServer *) sb_qw_server[*(int *)a];
  670. y = (struct QWServer *) sb_qw_server[*(int *)b];
  671. if (x->hostname && y->hostname)
  672. {
  673. return strcasecmp(x->hostname, y->hostname);
  674. }
  675. else if (!x->hostname && !y->hostname)
  676. {
  677. strlcpy(buf, NET_AdrToString(&x->addr), sizeof(buf));
  678. return (strcmp(buf, NET_AdrToString(&y->addr)));
  679. }
  680. else
  681. {
  682. if (x->hostname)
  683. return -1;
  684. else
  685. return 1;
  686. }
  687. }
  688. static int map_compare(const void *a, const void *b)
  689. {
  690. struct QWServer *x, *y;
  691. int ret;
  692. x = (struct QWServer *) sb_qw_server[*(int *)a];
  693. y = (struct QWServer *) sb_qw_server[*(int *)b];
  694. if (x->map && y->map)
  695. {
  696. ret = strcasecmp(x->map, y->map);
  697. if (ret == 0)
  698. return hostname_compare(a, b);
  699. return ret;
  700. }
  701. else
  702. {
  703. if (x->map)
  704. return -1;
  705. else
  706. return 1;
  707. }
  708. }
  709. int (* compare_functions[])(const void *a, const void *b) =
  710. {
  711. player_count_compare,
  712. map_compare,
  713. hostname_compare,
  714. ping_compare
  715. };
  716. static void sort_tab(struct tab *tab)
  717. {
  718. qsort(tab->server_index, tab->server_count, sizeof(int), compare_functions[tab->column_types[tab->sort].type]);
  719. }
  720. static int stubby (struct tab *tab, const struct QWServer *server)
  721. {
  722. return 1;
  723. }
  724. static void update_friends_tab(struct tab *tab)
  725. {
  726. int count, i, x;
  727. struct sb_friend *s;
  728. tab->max_hostname_length = 0;
  729. count = 0;
  730. s = friends;
  731. count = 0;
  732. while (s)
  733. {
  734. for (x = 0; x < sb_qw_server_count; x++)
  735. {
  736. if (check_player_name(s->name, sb_qw_server[x]))
  737. count++;
  738. }
  739. s = s->next;
  740. }
  741. if (tab->server_index)
  742. {
  743. free(tab->server_index);
  744. tab->server_index = NULL;
  745. }
  746. if (tab->friend_links)
  747. {
  748. free(tab->friend_links);
  749. tab->friend_links = NULL;
  750. }
  751. if (count > 10000 || count <= 0)
  752. {
  753. tab->server_count = 0;
  754. tab->sb_position = 0;
  755. return;
  756. }
  757. tab->server_index = calloc(count, sizeof(int));
  758. if (tab->server_index == NULL)
  759. {
  760. tab->server_count = 0;
  761. tab->sb_position = 0;
  762. return;
  763. }
  764. tab->friend_links = calloc(count, sizeof(struct sb_friend *));
  765. if (tab->friend_links == NULL)
  766. {
  767. tab->server_count = 0;
  768. tab->sb_position = 0;
  769. free(tab->server_index);
  770. return;
  771. }
  772. tab->server_count = count;
  773. s = friends;
  774. i = 0;
  775. while (s)
  776. {
  777. for (x=0;x<sb_qw_server_count; x++)
  778. {
  779. if (check_player_name(s->name, sb_qw_server[x]))
  780. {
  781. tab->friend_links[i] = s;
  782. tab->server_index[i++] = x;
  783. }
  784. }
  785. s = s->next;
  786. }
  787. }
  788. static void update_tab(struct tab *tab)
  789. {
  790. int count, i, x, temp;
  791. int (*cf)(struct tab *tab, const struct QWServer *server);
  792. tab->max_hostname_length = 0;
  793. count = 0;
  794. if (tab->friends)
  795. {
  796. update_friends_tab(tab);
  797. return;
  798. }
  799. if (List_Node_Count(tab->filters) && tab->player_filter == NULL)
  800. cf = Check_Server_Against_Filter;
  801. else if (tab->player_filter)
  802. cf = check_player;
  803. else if (tab->text_filter)
  804. cf = check_text;
  805. else
  806. cf = stubby;
  807. if (tab->server_index)
  808. {
  809. free(tab->server_index);
  810. tab->server_index = NULL;
  811. }
  812. for (count=0, x=0; x < sb_qw_server_count; x++)
  813. {
  814. if (cf(tab, sb_qw_server[x]))
  815. count++;
  816. }
  817. if (count > 10000 || count <= 0)
  818. {
  819. tab->server_count = 0;
  820. tab->sb_position = 0;
  821. return;
  822. }
  823. tab->server_index = calloc(count, sizeof(int));
  824. if (tab->server_index == NULL)
  825. {
  826. tab->server_count = 0;
  827. tab->sb_position = 0;
  828. return;
  829. }
  830. tab->server_count = count;
  831. for (x=0, i=0;x<sb_qw_server_count; x++)
  832. {
  833. if (cf(tab, sb_qw_server[x]))
  834. tab->server_index[i++] = x;
  835. }
  836. if (tab->sb_position >= tab->server_count)
  837. tab->sb_position = tab->server_count - 1;
  838. if (tab->sb_position < 0)
  839. tab->sb_position = 0;
  840. sort_tab(tab);
  841. for (x=0; x<tab->columns; x++)
  842. {
  843. tab->column_types[x].length = 0;
  844. }
  845. for (i=0; i<tab->server_count; i++)
  846. {
  847. for (x=0; x<tab->columns; x++)
  848. {
  849. if (tab->column_types[x].type == SBCT_PING)
  850. {
  851. temp = snprintf(0, 0, "%d", sb_qw_server[i]->pingtime/1000);
  852. if (temp < 4)
  853. temp = 4;
  854. if (temp > tab->column_types[x].length)
  855. tab->column_types[x].length = temp;
  856. }
  857. else if (tab->column_types[x].type == SBCT_PLAYERS)
  858. {
  859. /*
  860. temp = snprintf(0, 0, "%d", sb_qw_server[i]->numplayers) + snprintf(0, 0, "%d", sb_qw_server[i]->maxclients) + 1;
  861. if (temp > tab->column_types[x].length)
  862. tab->column_types[x].length = temp;
  863. */
  864. tab->column_types[x].length = 7;
  865. }
  866. else if (tab->column_types[x].type == SBCT_MAP)
  867. {
  868. if (sb_qw_server[i]->map)
  869. {
  870. temp = strlen(sb_qw_server[i]->map);
  871. if (temp > tab->column_types[x].length)
  872. tab->column_types[x].length = temp;
  873. }
  874. }
  875. else if (tab->column_types[x].type == SBCT_HOSTNAME)
  876. {
  877. if (sb_qw_server[i]->hostname)
  878. {
  879. temp = strlen(sb_qw_server[i]->hostname);
  880. if (temp > tab->column_types[x].length)
  881. tab->column_types[x].length = temp;
  882. }
  883. }
  884. }
  885. }
  886. if (tab->changed == 0)
  887. return;
  888. if (tab == tab_active)
  889. {
  890. if (current_selected_server)
  891. {
  892. for (i=0; i< tab->server_count; i++)
  893. if (current_selected_server == sb_qw_server[tab->server_index[i]])
  894. break;
  895. if (i == tab->server_count)
  896. {
  897. return;
  898. }
  899. tab->sb_position = i;
  900. }
  901. else
  902. {
  903. i = tab->server_index[tab->sb_position];
  904. current_selected_server = sb_qw_server[i];
  905. }
  906. }
  907. }
  908. static void SB_Update_Tabs(void)
  909. {
  910. struct tab *tab;
  911. tab = tab_first;
  912. while (tab)
  913. {
  914. update_tab(tab);
  915. tab = tab->next;
  916. }
  917. }
  918. static void SB_Help_Handler(int key)
  919. {
  920. if (key == K_ESCAPE)
  921. {
  922. sb_active_window = sb_help_prev;
  923. return;
  924. }
  925. if (key == K_RIGHTARROW)
  926. {
  927. sb_active_help_window++;
  928. if (sb_active_help_window >= SB_HELP_WINDOWS)
  929. sb_active_help_window = 0;
  930. return;
  931. }
  932. if (key == K_LEFTARROW)
  933. {
  934. sb_active_help_window--;
  935. if (sb_active_help_window <= 0)
  936. sb_active_help_window = SB_HELP_WINDOWS - 1;
  937. return;
  938. }
  939. }
  940. static void SB_Close()
  941. {
  942. key_dest = old_keydest;
  943. sb_open = 0;
  944. }
  945. void SB_Key(int key)
  946. {
  947. extern keydest_t key_dest;
  948. int i, update;
  949. const struct QWServer *server;
  950. struct tab *tab;
  951. char cmd[1024];
  952. char *kb;
  953. extern qboolean keyactive[256];
  954. if (key >= K_F1 && key <= K_F12)
  955. {
  956. kb = keybindings[key];
  957. if (kb) {
  958. if (kb[0] == '+'){ // button commands add keynum as a parm
  959. snprintf (cmd, sizeof(cmd), "%s %i\n", kb, key);
  960. Cbuf_AddText (cmd);
  961. keyactive[key] = true;
  962. } else {
  963. Cbuf_AddText (kb);
  964. Cbuf_AddText ("\n");
  965. }
  966. }
  967. return;
  968. }
  969. if (sb_active_window == SB_HELP)
  970. {
  971. SB_Help_Handler(key);
  972. return;
  973. }
  974. if (key == 'h' && keydown[K_CTRL])
  975. {
  976. sb_help_prev = sb_active_window;
  977. sb_active_window = SB_HELP;
  978. return;
  979. }
  980. if (key == K_TAB)
  981. {
  982. if (keydown[K_CTRL])
  983. {
  984. if (tab_active->friends == 1)
  985. return;
  986. if (sb_active_window == SB_SERVER)
  987. {
  988. sb_active_window = SB_FILTER;
  989. }
  990. else
  991. {
  992. sb_active_window = SB_SERVER;
  993. }
  994. return;
  995. }
  996. if (sb_active_window == SB_SERVER)
  997. {
  998. tab = tab_active;
  999. if (keydown[K_SHIFT])
  1000. tab->sort--;
  1001. else
  1002. tab->sort++;
  1003. if (tab->sort >= tab->columns)
  1004. tab->sort = 0;
  1005. if (tab->sort < 0)
  1006. tab->sort = tab->columns - 1;
  1007. sort_tab(tab);
  1008. SB_Set_Statusbar("Sorted by %s\n", column_names[tab->column_types[tab->sort].type]);
  1009. return;
  1010. }
  1011. }
  1012. if (sb_active_window == SB_FILTER)
  1013. {
  1014. if (sb_filter_delete == 1)
  1015. {
  1016. if (key == 'y')
  1017. {
  1018. SB_Filter_Delete_Filter();
  1019. SB_Update_Tabs();
  1020. }
  1021. sb_filter_delete = 0;
  1022. return;
  1023. }
  1024. if (sb_filter_insert == 1)
  1025. {
  1026. SB_Filter_Insert_Handler(key);
  1027. return;
  1028. }
  1029. if (key == K_DOWNARROW)
  1030. {
  1031. sb_selected_filter++;
  1032. if (sb_selected_filter >= List_Node_Count(tab_active->filters))
  1033. sb_selected_filter = 0;
  1034. return;
  1035. }
  1036. if (key == K_UPARROW)
  1037. {
  1038. sb_selected_filter--;
  1039. if (sb_selected_filter < 0)
  1040. sb_selected_filter = List_Node_Count(tab_active->filters);
  1041. return;
  1042. }
  1043. if (key == K_INS)
  1044. {
  1045. sb_filter_insert = 1;
  1046. return;
  1047. }
  1048. if (key == K_ENTER)
  1049. {
  1050. sb_filter_edit = 1;
  1051. return;
  1052. }
  1053. if (key == K_DEL)
  1054. {
  1055. sb_filter_delete = 1;
  1056. return;
  1057. }
  1058. }
  1059. if (sb_active_window == SB_SERVER)
  1060. {
  1061. tab = tab_active;
  1062. if (sb_player_filter == 1)
  1063. {
  1064. tab->changed = 1;
  1065. update = 0;
  1066. if (key == K_ESCAPE)
  1067. {
  1068. sb_player_filter = 0;
  1069. return;
  1070. }
  1071. if (key == K_ENTER)
  1072. sb_player_filter = 0;
  1073. handle_textbox(key, sb_player_filter_entry, &sb_player_filter_entry_position, sizeof(sb_player_filter_entry));
  1074. if (tab->player_filter)
  1075. {
  1076. free(tab->player_filter);
  1077. tab->player_filter = NULL;
  1078. update = 1;
  1079. }
  1080. if (strlen(sb_player_filter_entry) > 0)
  1081. {
  1082. tab->player_filter = strdup(sb_player_filter_entry);
  1083. if (tab->player_filter == NULL)
  1084. Com_Printf("warning: strdup failed in \"%s\", line: %d.\n", __func__, __LINE__);
  1085. update_tab(tab);
  1086. }
  1087. if (update)
  1088. update_tab(tab);
  1089. if (key != K_UPARROW && key != K_DOWNARROW && key != K_ENTER)
  1090. return;
  1091. }
  1092. if (sb_text_filter == 1)
  1093. {
  1094. tab->changed = 1;
  1095. update = 0;
  1096. if (key == K_ESCAPE)
  1097. {
  1098. sb_text_filter = 0;
  1099. return;
  1100. }
  1101. if (key == K_ENTER)
  1102. sb_text_filter = 0;
  1103. handle_textbox(key, sb_text_filter_entry, &sb_text_filter_entry_position, sizeof(sb_text_filter_entry));
  1104. if (tab->text_filter)
  1105. {
  1106. free(tab->text_filter);
  1107. tab->text_filter = NULL;
  1108. update = 1;
  1109. }
  1110. if (strlen(sb_text_filter_entry) > 0)
  1111. {
  1112. tab->text_filter = strdup(sb_text_filter_entry);
  1113. if (tab->text_filter == NULL)
  1114. Com_Printf("warning: strdup failed in \"%s\", line: %d.\n", __func__, __LINE__);
  1115. update_tab(tab);
  1116. }
  1117. if (update)
  1118. update_tab(tab);
  1119. if (key != K_UPARROW && key != K_DOWNARROW && key != K_ENTER)
  1120. return;
  1121. }
  1122. if (sb_server_insert == 1)
  1123. {
  1124. SB_Server_Insert_Handler(key);
  1125. return;
  1126. }
  1127. if (key == K_INS)
  1128. {
  1129. if (tab_active->friends == 1)
  1130. return;
  1131. sb_server_insert = 1;
  1132. }
  1133. if (key == K_UPARROW)
  1134. {
  1135. if (sb_qw_server == NULL)
  1136. return;
  1137. if (keydown[K_SHIFT])
  1138. tab->sb_position -= 10;
  1139. else if (keydown[K_CTRL])
  1140. tab->sb_position -= 20;
  1141. else
  1142. tab->sb_position--;
  1143. if (tab->sb_position < 0)
  1144. {
  1145. tab->sb_position = tab->server_count - 1;
  1146. if (tab->sb_position < 0)
  1147. tab->sb_position = 0;
  1148. }
  1149. if (tab->server_count == 0 || tab->sb_position > tab->server_count)
  1150. {
  1151. current_selected_server = NULL;
  1152. return;
  1153. }
  1154. i = tab->server_index[tab->sb_position];
  1155. current_selected_server = sb_qw_server[i];
  1156. tab->changed = 1;
  1157. return;
  1158. }
  1159. if (key == K_DOWNARROW)
  1160. {
  1161. if (sb_qw_server == NULL)
  1162. return;
  1163. if (keydown[K_SHIFT])
  1164. tab->sb_position += 10;
  1165. else if (keydown[K_CTRL])
  1166. tab->sb_position += 20;
  1167. else
  1168. tab->sb_position++;
  1169. if (tab->sb_position >= tab->server_count)
  1170. tab->sb_position = 0;
  1171. if (tab->server_count == 0 || tab->sb_position > tab->server_count)
  1172. {
  1173. current_selected_server = NULL;
  1174. return;
  1175. }
  1176. i = tab->server_index[tab->sb_position];
  1177. current_selected_server = sb_qw_server[i];
  1178. tab->changed = 1;
  1179. return;
  1180. }
  1181. if (key == K_ENTER)
  1182. {
  1183. if (sb_qw_server == NULL)
  1184. return;
  1185. if (keydown[K_CTRL])
  1186. {
  1187. Cbuf_AddText("spectator 1\n");
  1188. if (tab->server_index)
  1189. {
  1190. i = tab->server_index[tab->sb_position];
  1191. server = sb_qw_server[i];
  1192. }
  1193. else
  1194. {
  1195. server = sb_qw_server[tab->sb_position];
  1196. }
  1197. Cbuf_AddText(va("connect %s\n", NET_AdrToString(&server->addr)));
  1198. SB_Close();
  1199. return;
  1200. }
  1201. if (keydown[K_SHIFT])
  1202. {
  1203. if (tab->server_index)
  1204. {
  1205. i = tab->server_index[tab->sb_position];
  1206. server = sb_qw_server[i];
  1207. }
  1208. else
  1209. {
  1210. server = sb_qw_server[tab->sb_position];
  1211. }
  1212. SB_Proxy_Connect(server);
  1213. SB_Close();
  1214. return;
  1215. }
  1216. if (tab->server_index)
  1217. {
  1218. i = tab->server_index[tab->sb_position];
  1219. server = sb_qw_server[i];
  1220. }
  1221. else
  1222. {
  1223. server = sb_qw_server[tab->sb_position];
  1224. }
  1225. if (server->maxclients == server->numplayers)
  1226. Cbuf_AddText("spectator 1\n");
  1227. else
  1228. Cbuf_AddText("spectator 0\n");
  1229. Cbuf_AddText(va("connect %s\n", NET_AdrToString(&server->addr)));
  1230. SB_Close();
  1231. return;
  1232. }
  1233. if (key == 'f' && keydown[K_CTRL])
  1234. {
  1235. sb_player_filter = 1;
  1236. return;
  1237. }
  1238. if (key == '/')
  1239. {
  1240. sb_text_filter = 1;
  1241. return;
  1242. }
  1243. if (key == 'r')
  1244. {
  1245. if (keydown[K_CTRL])
  1246. {
  1247. SB_Refresh();
  1248. return;
  1249. }
  1250. if (sb_qw_server)
  1251. {
  1252. if (tab->server_index)
  1253. {
  1254. i = tab->server_index[tab->sb_position];
  1255. server = sb_qw_server[i];
  1256. }
  1257. else
  1258. {
  1259. server = sb_qw_server[tab->sb_position];
  1260. }
  1261. ServerScanner_RescanServer(serverscanner, server);
  1262. }
  1263. }
  1264. }
  1265. if (key == K_ESCAPE)
  1266. {
  1267. SB_Close();
  1268. return;
  1269. }
  1270. if (key == K_LEFTARROW)
  1271. {
  1272. if (tab_active->prev)
  1273. tab_active = tab_active->prev;
  1274. else
  1275. tab_active = tab_last;
  1276. return;
  1277. }
  1278. if (key == K_RIGHTARROW)
  1279. {
  1280. if (tab_active->next)
  1281. tab_active = tab_active->next;
  1282. else
  1283. tab_active = tab_first;
  1284. return;
  1285. }
  1286. switch (key)
  1287. {
  1288. case '1':
  1289. sb_activate_tab(0);
  1290. break;
  1291. case '2':
  1292. sb_activate_tab(1);
  1293. break;
  1294. case '3':
  1295. sb_activate_tab(2);
  1296. break;
  1297. case '4':
  1298. sb_activate_tab(3);
  1299. break;
  1300. case '5':
  1301. sb_activate_tab(4);
  1302. break;
  1303. case '6':
  1304. sb_activate_tab(5);
  1305. break;
  1306. case '7':
  1307. sb_activate_tab(6);
  1308. break;
  1309. case '8':
  1310. sb_activate_tab(7);
  1311. break;
  1312. case '9':
  1313. sb_activate_tab(8);
  1314. break;
  1315. case '0':
  1316. sb_activate_tab(9);
  1317. break;
  1318. }
  1319. }
  1320. static void SB_Server_Add(char *ip, int port)
  1321. {
  1322. /*
  1323. struct server *entry;
  1324. entry = List_Get_Node(server, 0);
  1325. while (entry)
  1326. {
  1327. if (strcmp(ip, entry->ip) == 0)
  1328. if (port == entry->port)
  1329. return;
  1330. entry = (struct server *)entry->node.next;
  1331. }
  1332. entry = calloc(1, sizeof(struct server));
  1333. if (!entry)
  1334. return;
  1335. entry->ip = strdup(ip);
  1336. entry->port = port;
  1337. List_Add_Node(server, entry);
  1338. sb_server_count++;
  1339. SB_Update_Tabs();
  1340. */
  1341. }
  1342. static void SB_Add_Filter_To_Tab(struct tab *tab, int key , int type, char *value)
  1343. {
  1344. struct filter *f;
  1345. int i;
  1346. if (!tab)
  1347. return;
  1348. if (strlen(value) == 0)
  1349. return;
  1350. f = calloc(1, sizeof(struct filter));
  1351. if (!f)
  1352. return;
  1353. f->key = key;
  1354. f->keyword = strdup(filter_types[key].name);
  1355. if (f->keyword == NULL)
  1356. {
  1357. Com_Printf("error: strdup failed in \"%s\", line: %d\n.", __func__, __LINE__);
  1358. free(f);
  1359. return;
  1360. }
  1361. f->type = type;
  1362. f->value = strdup(value);
  1363. if (f->value == NULL)
  1364. {
  1365. Com_Printf("error: strdup failed in \"%s\", line: %d\n.", __func__, __LINE__);
  1366. free(f->keyword);
  1367. free(f);
  1368. return;
  1369. }
  1370. if (filter_types[key].type == 0)
  1371. f->fvalue = atof(value);
  1372. List_Add_Node(tab->filters, f);
  1373. i = strlen(f->keyword);
  1374. if (tab->max_filter_keyword_length < i)
  1375. tab->max_filter_keyword_length = i;
  1376. }
  1377. static void sb_default_tabs(void)
  1378. {
  1379. struct tab *tab;
  1380. tab = sb_add_tab("all");
  1381. tab = sb_add_tab("duel");
  1382. SB_Add_Filter_To_Tab(tab, 0, 2, "1");
  1383. SB_Add_Filter_To_Tab(tab, 4, 0, "2");
  1384. tab = sb_add_tab("2on2");
  1385. SB_Add_Filter_To_Tab(tab, 0, 2, "1");
  1386. SB_Add_Filter_To_Tab(tab, 4, 0, "4");
  1387. tab = sb_add_tab("4on4");
  1388. SB_Add_Filter_To_Tab(tab, 0, 2, "1");
  1389. SB_Add_Filter_To_Tab(tab, 4, 0, "8");
  1390. sb_add_tab("friends");
  1391. }
  1392. void SB_Activate_f(void)
  1393. {
  1394. extern keydest_t key_dest;
  1395. if (sb_open)
  1396. return;
  1397. old_keydest = key_dest;
  1398. key_dest = key_serverbrowser;
  1399. sb_open = 1;
  1400. if (tab_first == NULL)
  1401. {
  1402. sb_default_tabs();
  1403. tab_active = tab_first;
  1404. }
  1405. if (sb_refresh_on_activate.value == 1 || serverscanner == NULL)
  1406. {
  1407. SB_Refresh();
  1408. }
  1409. SB_Update_Tabs();
  1410. }
  1411. static int check_selected_type(int type)
  1412. {
  1413. int max;
  1414. if (filter_types[sb_filter_insert_selected_key].type == 0)
  1415. max = 3;
  1416. else
  1417. max = 2;
  1418. if (type < 0)
  1419. type = max - 1;
  1420. if (type >= max )
  1421. type = 0;
  1422. return type;
  1423. }
  1424. static void SB_Filter_Insert_Handler(int key)
  1425. {
  1426. if (key == K_ENTER)
  1427. {
  1428. SB_Add_Filter_To_Tab(tab_active, sb_filter_insert_selected_key, sb_filter_insert_selected_type, sb_filter_insert_value);
  1429. sb_filter_insert = 0;
  1430. sb_filter_insert_value_position = 0;
  1431. update_tab(tab_active);
  1432. sb_default_settings = 0;
  1433. return;
  1434. }
  1435. if (key == K_TAB)
  1436. {
  1437. sb_filter_insert_selected_box++;
  1438. if (sb_filter_insert_selected_box > 2)
  1439. sb_filter_insert_selected_box = 0;
  1440. return;
  1441. }
  1442. if (key == K_ESCAPE)
  1443. {
  1444. sb_filter_insert = 0;
  1445. return;
  1446. }
  1447. if (sb_filter_insert_selected_box== 1)
  1448. {
  1449. if (key == K_DOWNARROW)
  1450. sb_filter_insert_selected_type--;
  1451. else if (key == K_UPARROW)
  1452. sb_filter_insert_selected_type++;
  1453. sb_filter_insert_selected_type = check_selected_type(sb_filter_insert_selected_type);
  1454. return;
  1455. }
  1456. if (sb_filter_insert_selected_box == 2)
  1457. {
  1458. handle_textbox(key, sb_filter_insert_value, &sb_filter_insert_value_position, sizeof(sb_filter_insert_value));
  1459. return;
  1460. }
  1461. if (sb_filter_insert_selected_box == 0)
  1462. {
  1463. if (key == K_DOWNARROW)
  1464. sb_filter_insert_selected_key--;
  1465. else if (key == K_UPARROW)
  1466. sb_filter_insert_selected_key++;
  1467. if (sb_filter_insert_selected_key < 0)
  1468. sb_filter_insert_selected_key = SB_FILTER_TYPE_MAX - 1;
  1469. if (sb_filter_insert_selected_key >= SB_FILTER_TYPE_MAX)
  1470. sb_filter_insert_selected_key = 0;
  1471. sb_filter_insert_selected_type = check_selected_type(sb_filter_insert_selected_type);
  1472. return;
  1473. }
  1474. }
  1475. void SB_Filter_Delete_Filter(void)
  1476. {
  1477. List_Remove_Node(tab_active->filters, sb_selected_filter, 1);
  1478. }
  1479. static void SB_Server_Insert_Handler(int key)
  1480. {
  1481. if (key == K_TAB)
  1482. {
  1483. sb_server_insert_selected_box++;
  1484. if (sb_server_insert_selected_box > 1)
  1485. sb_server_insert_selected_box = 0;
  1486. return;
  1487. }
  1488. if (key == K_ESCAPE)
  1489. {
  1490. sb_server_insert = 0;
  1491. return;
  1492. }
  1493. if (key == K_ENTER)
  1494. {
  1495. SB_Server_Add(sb_server_insert_ip, atoi(sb_server_insert_port));
  1496. sb_server_insert = 0;
  1497. return;
  1498. }
  1499. if (sb_server_insert_selected_box == 0)
  1500. {
  1501. handle_textbox(key, sb_server_insert_ip, &sb_server_insert_ip_position, sizeof(sb_server_insert_ip));
  1502. return;
  1503. }
  1504. if (sb_server_insert_selected_box == 1)
  1505. {
  1506. handle_textbox(key, sb_server_insert_port, &sb_server_insert_port_position, sizeof(sb_server_insert_port));
  1507. return;
  1508. }
  1509. }
  1510. static void SB_Draw_Tabs(void)
  1511. {
  1512. int width, x, l, r, i;
  1513. struct tab *tab;
  1514. width = vid.conwidth/8;
  1515. x = strlen(tab_active->name);
  1516. if (x % 2)
  1517. x++;
  1518. l = x;
  1519. x = x/ 2 + 1;
  1520. Draw_ColoredString((width/2 - x) * 8, 0, va("&cf44<%-*s>",l ,tab_active->name), 1);
  1521. l = width/2 - x - 1;
  1522. r = width/2 + x + 1;
  1523. tab = tab_active->prev;
  1524. i = l;
  1525. while (tab)
  1526. {
  1527. x = strlen(tab->name);
  1528. i -= x;
  1529. Draw_String(i*8, 0, tab->name);
  1530. i--;
  1531. tab = tab->prev;
  1532. }
  1533. tab = tab_active->next;
  1534. i = r;
  1535. while (tab)
  1536. {
  1537. x = strlen(tab->name);
  1538. Draw_String(i*8, 0, tab->name);
  1539. i += x;
  1540. i++;
  1541. tab = tab->next;
  1542. }
  1543. }
  1544. static void SB_Draw_Background(void)
  1545. {
  1546. Draw_Fill(0, 0, vid.conwidth, vid.conheight, 1);
  1547. }
  1548. static void SB_Draw_Filter_Insert(void)
  1549. {
  1550. int i;
  1551. i = 0;
  1552. Draw_String(8,24, filter_types[sb_filter_insert_selected_key].name);
  1553. Draw_String(0, 24 + sb_filter_insert_selected_box * 8, ">");
  1554. Draw_String(8, 48 + 8 * i++, "press arrow up/down to switch trough available options");
  1555. Draw_String(8, 48 + 8 * i++, "tab to switch trough the entry fields");
  1556. Draw_String(8, 48 + 8 * i++, "esc to leave");
  1557. if (sb_filter_insert_selected_box == 0)
  1558. {
  1559. Draw_String(8, 48 + 8 * i++, filter_types[sb_filter_insert_selected_key].description);
  1560. }
  1561. if (sb_filter_insert_selected_box == 1)
  1562. {
  1563. if (filter_types[sb_filter_insert_selected_key].type == 0)
  1564. {
  1565. Draw_String(8, 48 + 8 * i++, (char *)filter_num_operators[sb_filter_insert_selected_type]);
  1566. }
  1567. else
  1568. {
  1569. Draw_String(8, 48 + 8 * i++, (char *)filter_num_operators[sb_filter_insert_selected_type]);
  1570. }
  1571. }
  1572. if (filter_types[sb_filter_insert_selected_key].type == 0)
  1573. Draw_String(8, 32, (char *)filter_num_operators[sb_filter_insert_selected_type]);
  1574. else
  1575. Draw_String(8, 32, (char *)filter_char_operators[sb_filter_insert_selected_type]);
  1576. Draw_String(8, 40, sb_filter_insert_value);
  1577. if (sb_filter_insert_selected_box == 2)
  1578. {
  1579. Draw_String(8 + 8*sb_filter_insert_value_position, 40, "_");
  1580. }
  1581. }
  1582. static void SB_Draw_Filter(void)
  1583. {
  1584. int i;
  1585. struct filter *filter;
  1586. if (sb_filter_insert)
  1587. {
  1588. SB_Draw_Filter_Insert();
  1589. return;
  1590. }
  1591. Draw_String(8, 16, "Filter:");
  1592. filter = List_Get_Node(tab_active->filters, 0);
  1593. i = 0;
  1594. while(filter)
  1595. {
  1596. if (i == sb_selected_filter)
  1597. {
  1598. Draw_String(0, 24+i*8,">");
  1599. }
  1600. Draw_String(8, 24 + i++ * 8, va("%*s %5s %s", tab_active->max_filter_keyword_length, filter->keyword, Filter_Type_String(filter->type), filter->value));
  1601. filter = (struct filter *)filter->node.next;
  1602. }
  1603. }
  1604. static void SB_Draw_Server_Insert(void)
  1605. {
  1606. Draw_String(8, 24, va("ip: %s", sb_server_insert_ip));
  1607. if (sb_server_insert_selected_box == 0)
  1608. Draw_String(8 + 8* (sb_server_insert_ip_position + 3), 24, "_");
  1609. Draw_String(8, 32, va("port: %s", sb_server_insert_port));
  1610. if (sb_server_insert_selected_box == 1)
  1611. Draw_String(8 + 8* (sb_server_insert_port_position + 6), 32, "_");
  1612. }
  1613. static int sort_players_team(const void *a, const void *b)
  1614. {
  1615. struct QWPlayer *x, *y;
  1616. int i;
  1617. x = *(struct QWPlayer **)a;
  1618. y = *(struct QWPlayer **)b;
  1619. if (x->team && y->team)
  1620. {
  1621. if ((i = strcmp(x->team ,y->team)) == 0)
  1622. return (y->frags - x->frags);
  1623. else
  1624. return i;
  1625. }
  1626. return (y->frags - x->frags);
  1627. }
  1628. static int sort_players(const void *a, const void *b)
  1629. {
  1630. struct QWPlayer *x, *y;
  1631. x = *(struct QWPlayer **)a;
  1632. y = *(struct QWPlayer **)b;
  1633. return (y->frags - x->frags);
  1634. }
  1635. static void SB_Draw_Server(void)
  1636. {
  1637. int k, i, x, y, z, header_distance, header_x;
  1638. int tab_type;
  1639. int line_space, player_space;
  1640. int offset;
  1641. struct tab *tab;
  1642. const char *hostname, *map;
  1643. char string[512];
  1644. char *s;
  1645. int position;
  1646. char *friend_name;
  1647. const struct QWPlayer **sorted_players;
  1648. const struct QWServer *server;
  1649. const struct QWPlayer *player;
  1650. const struct QWSpectator *spectator;
  1651. enum column_type sorted_enum;
  1652. if (sb_server_insert)
  1653. {
  1654. SB_Draw_Server_Insert();
  1655. return;
  1656. }
  1657. if (sb_qw_server_count == 0)
  1658. return;
  1659. tab = tab_active;
  1660. if (!tab)
  1661. return;
  1662. player_space = 0;
  1663. // Header
  1664. string[0] = 0;
  1665. sorted_enum = tab->column_types[tab->sort].type;
  1666. k = 0;
  1667. for (x=0; x<tab->columns; x++)
  1668. {
  1669. if (sorted_enum == tab->column_types[x].type)
  1670. k += snprintf(string + k, sizeof(string) - k, "&cf00%-*.*s&cfff ", tab->column_types[x].length, tab->column_types[x].length, column_names[tab->column_types[x].type]);
  1671. else
  1672. k += snprintf(string + k, sizeof(string) - k, "%-*.*s ", tab->column_types[x].length, tab->column_types[x].length, column_names[tab->column_types[x].type]);
  1673. if (k >= sizeof(string))
  1674. break;
  1675. }
  1676. Draw_ColoredString(8, 16, string, 0);
  1677. if (sb_player_filter == 1 || sb_text_filter == 1)
  1678. {
  1679. snprintf(string, 512, "Server: %*i/%*i - %s: ", sb_server_count_width, tab->sb_position + 1, sb_server_count_width, tab->server_count, sb_text_filter ? "text search" : "player search");
  1680. i = strlen(string);
  1681. Draw_String(8, 8,string);
  1682. x = 1;
  1683. if (tab->player_filter || tab->text_filter)
  1684. {
  1685. s = tab->text_filter ? tab->text_filter : tab->player_filter;
  1686. x = strlen(s);
  1687. if (x == 0)
  1688. x = 1;
  1689. else
  1690. x += 1;
  1691. if (sb_player_filter == 1 || sb_text_filter == 1)
  1692. Draw_Fill(8 + i *8, 8, x * 8, 8, 55);
  1693. Draw_String(8 + i *8, 8, s);
  1694. }
  1695. else
  1696. {
  1697. if (sb_player_filter == 1 | sb_text_filter == 1)
  1698. Draw_Fill(8 + i *8, 8, x * 8, 8, 55);
  1699. }
  1700. if (sb_player_filter == 1 && sb_text_filter == 0)
  1701. {
  1702. if (sb_player_filter_blink_time < cls.realtime)
  1703. Draw_Character(8 + i *8 + sb_player_filter_entry_position *8, 8, 11);
  1704. if (sb_player_filter_blink_time + 0.2f < cls.realtime)
  1705. sb_player_filter_blink_time = cls.realtime + 0.2f;
  1706. }
  1707. if (sb_text_filter == 1)
  1708. {
  1709. if (sb_text_filter_blink_time < cls.realtime)
  1710. Draw_Character(8 + i *8 + sb_text_filter_entry_position *8, 8, 11);
  1711. if (sb_text_filter_blink_time + 0.2f < cls.realtime)
  1712. sb_text_filter_blink_time = cls.realtime + 0.2f;
  1713. }
  1714. }
  1715. else
  1716. Draw_String(8, 8,va("Server: %*i/%*i ", sb_server_count_width, tab->sb_position + 1, sb_server_count_width, tab->server_count));
  1717. if (tab->server_count == 0)
  1718. return;
  1719. line_space = vid.conheight/8 - 4;
  1720. if (sb_player_drawing.value == 1)
  1721. {
  1722. if (tab->server_index == NULL)
  1723. {
  1724. z = tab->sb_position;
  1725. }
  1726. else
  1727. {
  1728. z = tab->server_index[tab->sb_position];
  1729. }
  1730. if (sb_qw_server[z]->numplayers || sb_qw_server[z]->numspectators)
  1731. {
  1732. player_space = sb_qw_server[z]->numspectators + sb_qw_server[z]->numplayers + 1;
  1733. z = 0;
  1734. }
  1735. else
  1736. z = 0;
  1737. }
  1738. x = 0;
  1739. if (tab->server_count > line_space)
  1740. {
  1741. x = tab->sb_position - ((float)line_space/2.0f);
  1742. if (x<0)
  1743. {
  1744. x = 0;
  1745. offset = tab->sb_position;
  1746. position = 2;
  1747. }
  1748. else if (x> tab->server_count - line_space)
  1749. {
  1750. x = tab->server_count - line_space;
  1751. offset = line_space - (tab->server_count - tab->sb_position);
  1752. position = 0;
  1753. }
  1754. else
  1755. {
  1756. offset = tab->sb_position - x;
  1757. position = 1;
  1758. }
  1759. }
  1760. else
  1761. {
  1762. offset = tab->sb_position;
  1763. position = 3;
  1764. }
  1765. offset += z;
  1766. //Draw_Fill(0,(offset+3) * 8, vid.conwidth , 9 , 13);
  1767. y = x+1;
  1768. for (i=0;x<tab->server_count && i < line_space ;i++,x++)
  1769. {
  1770. if (tab->server_index == NULL)
  1771. {
  1772. z = x;
  1773. }
  1774. else
  1775. {
  1776. z = tab->server_index[x];
  1777. }
  1778. server = sb_qw_server[z];
  1779. if (server->hostname == NULL)
  1780. hostname = NET_AdrToString(&server->addr);
  1781. else
  1782. hostname = server->hostname;
  1783. if (server->map == NULL)
  1784. map = " ";
  1785. else
  1786. map = server->map;
  1787. if (tab->friends == 0)
  1788. snprintf(string, sizeof(string),"%*i: %3i %2i/%3i %-*.*s %s", sb_server_count_width, y, server->pingtime/1000, server->numplayers, server->maxclients, 8, 8, map, hostname);
  1789. else
  1790. {
  1791. friend_name = tab->friend_links[x]->name;
  1792. snprintf(string, sizeof(string),"%-*s: %2i/%3i %-*.*s %s",friend_name_max_len, friend_name, server->numplayers, server->maxclients, 8, 8, map, hostname);
  1793. }
  1794. if (sb_color_bg.value == 1)
  1795. {
  1796. if (server->maxclients == server->numplayers)
  1797. {
  1798. if (server->maxspectators == server->numspectators)
  1799. Draw_Fill(0, 24 + i * 8, vid.conwidth, 8, sb_color_bg_full.value);
  1800. else
  1801. Draw_Fill(0, 24 + i * 8, vid.conwidth, 8, sb_color_bg_specable.value);
  1802. }
  1803. else if (server->maxclients > server->numplayers && server->numplayers > 0)
  1804. {
  1805. Draw_Fill(0, 24 + i * 8, vid.conwidth, 8, sb_color_bg_free.value);
  1806. }
  1807. else if (server->numplayers == 0)
  1808. Draw_Fill(0, 24 + i * 8, vid.conwidth, 8, sb_color_bg_empty.value);
  1809. }
  1810. if (server == current_selected_server)
  1811. Draw_Fill(0, 24 + i * 8, vid.conwidth , 9 , 13);
  1812. if (sb_highlight_sort_column.value)
  1813. {
  1814. for (header_x=0, header_distance=0; header_x<tab->columns; header_x++)
  1815. {
  1816. if (sorted_enum == tab->column_types[header_x].type)
  1817. {
  1818. Draw_AlphaFill((header_distance + 1)*8, 24 + i *8, 8 * tab->column_types[header_x].length, 8, sb_highlight_sort_column_color.value, sb_highlight_sort_column_alpha.value);
  1819. break;
  1820. }
  1821. else
  1822. header_distance += tab->column_types[header_x].length + 1;
  1823. }
  1824. }
  1825. string[0] = 0;
  1826. k = 0;
  1827. for (tab_type=0; tab_type<tab->columns; tab_type++)
  1828. {
  1829. if (tab->column_types[tab_type].type == SBCT_PING)
  1830. k += snprintf(string + k, sizeof(string) - k, "%*i ", tab->column_types[tab_type].length, server->pingtime/1000);
  1831. else if (tab->column_types[tab_type].type == SBCT_PLAYERS)
  1832. k += snprintf(string + k, sizeof(string) - k, "%*i/%*i ", 3, server->numplayers, 3, server->maxclients);
  1833. else if (tab->column_types[tab_type].type == SBCT_MAP)
  1834. k += snprintf(string + k, sizeof(string) - k, "%-*.*s ", tab->column_types[tab_type].length, tab->column_types[tab_type].length, map);
  1835. else if (tab->column_types[tab_type].type == SBCT_HOSTNAME)
  1836. k += snprintf(string + k, sizeof(string) - k, "%-*.*s ", tab->column_types[tab_type].length, tab->column_types[tab_type].length, hostname);
  1837. if (k >= sizeof(string))
  1838. break;
  1839. }
  1840. Draw_String(8, 24 + i * 8, string);
  1841. y++;
  1842. }
  1843. Draw_String(0,24 + offset * 8,">");
  1844. if (sb_qw_server_count == 0)
  1845. return;
  1846. if (tab->sb_position < 0 || tab->sb_position >= tab->server_count)
  1847. return;
  1848. if (tab->server_index == NULL)
  1849. {
  1850. server = sb_qw_server[tab->sb_position];
  1851. }
  1852. else
  1853. {
  1854. z = tab->server_index[tab->sb_position];
  1855. server = sb_qw_server[z];
  1856. }
  1857. if (tab->server_index != NULL)
  1858. {
  1859. x = tab->sb_position;
  1860. x = tab->server_index[x];
  1861. if (x>sb_qw_server_count)
  1862. return;
  1863. server = sb_qw_server[x];
  1864. }
  1865. else
  1866. {
  1867. if (tab->sb_position > sb_qw_server_count)
  1868. return;
  1869. server = sb_qw_server[tab->sb_position];
  1870. }
  1871. if (!server)
  1872. return;
  1873. if (sb_player_drawing.value == 1)
  1874. {
  1875. if (server->numplayers == 0 && server->numspectators == 0)
  1876. return;
  1877. y = (line_space - player_space) + 3;
  1878. if (y<offset+3)
  1879. y = offset+1+3;
  1880. z = vid.conwidth/8;
  1881. //if (player_space < line_space/2)
  1882. Draw_Fill(0, y*8, vid.conwidth, player_space * 8, 2);
  1883. Draw_Fill(0, y*8, vid.conwidth, 8, 20);
  1884. Draw_String(0, (y++)*8, "ping time frags team");
  1885. player = (struct QWPlayer *)&server->players[0];
  1886. sorted_players = calloc(server->numplayers, sizeof(struct QWPlayer **));
  1887. if (sorted_players == NULL)
  1888. return;
  1889. for(i = 0;i<server->numplayers;i++)
  1890. {
  1891. sorted_players[i] = &server->players[i];
  1892. }
  1893. if (server->teamplay > 0)
  1894. qsort(sorted_players, server->numplayers, sizeof(struct QWPlayer *), sort_players_team);
  1895. else
  1896. qsort(sorted_players, server->numplayers, sizeof(struct QWPlayer *), sort_players);
  1897. for(i = 0;i<server->numplayers;i++)
  1898. {
  1899. player = sorted_players[i];
  1900. if (player->name)
  1901. {
  1902. Draw_Fill((5+5)*8, y*8, 5*8, 4, Color_For_Map(player->topcolor));
  1903. Draw_Fill((5+5)*8, y*8+4, 5*8, 4, Color_For_Map(player->bottomcolor));
  1904. if (player->team)
  1905. Draw_ColoredString(0, y++ * 8, va("%4i %4i %4i %4.4s&cFFF %s", player->ping, player->time, player->frags, player->team, player->name), 0);
  1906. else
  1907. Draw_ColoredString(0, y++ * 8, va("%4i %4i %4i %4.4s&cFFF %s", player->ping, player->time, player->frags, " ", player->name), 0);
  1908. }
  1909. }
  1910. free(sorted_players);
  1911. spectator = &server->spectators[0];
  1912. for(i = 0;i<server->numspectators;i++)
  1913. {
  1914. if (spectator->name)
  1915. Draw_ColoredString(0, y++ * 8, va("%4i %4i &cF20s&cF50p&cF80e&c883c&cA85t&c668a&c55At&c33Bo&c22Dr&cFFF %s", -spectator->ping, -spectator->time, spectator->name), 0);
  1916. spectator++;
  1917. }
  1918. }
  1919. }
  1920. static void SB_Draw_Status_Bar(void)
  1921. {
  1922. Draw_String(0, vid.conheight - 8, sb_status_bar);
  1923. }
  1924. static void SB_Draw_Help(void)
  1925. {
  1926. int i = 0;
  1927. Draw_String(8, 0 + 8 * i++, "press arrow left/right to switch help screens");
  1928. Draw_String(8, 0 + 8 * i++, "esc to quit");
  1929. if (sb_active_help_window == 0)
  1930. {
  1931. Draw_String(8, 8 + 8 * i++, "general controls:");
  1932. Draw_String(8, 8 + 8 * i++, " 1->0, arrow left/right - to switch tabs");
  1933. Draw_String(8, 8 + 8 * i++, " arrow up/down - to scroll, use shift/ctrl to modify jump length");
  1934. Draw_String(8, 8 + 8 * i++, " esc - will quit submenus, browser");
  1935. }
  1936. else if (sb_active_help_window == 1)
  1937. {
  1938. Draw_String(8, 8 + 8 * i++, "server screen:");
  1939. Draw_String(8, 8 + 8 * i++, " ctrl + r - rescan all server");
  1940. Draw_String(8, 8 + 8 * i++, " r - rescan selected server");
  1941. Draw_String(8, 8 + 8 * i++, " enter - to join as player");
  1942. Draw_String(8, 8 + 8 * i++, " ctrl + enter - to join as spectator");
  1943. Draw_String(8, 8 + 8 * i++, " shift + enter - to join via qtv");
  1944. Draw_String(8, 8 + 8 * i++, " ctrl + f - start player search");
  1945. Draw_String(8, 8 + 8 * i++, " tab - to switch through sort mode");
  1946. }
  1947. else if (sb_active_help_window == 2)
  1948. {
  1949. Draw_String(8, 8 + 8 * i++, "filter screen:");
  1950. Draw_String(8, 8 + 8 * i++, " insert - to add filter");
  1951. }
  1952. else if (sb_active_help_window == 3)
  1953. {
  1954. Draw_String(8, 8 + 8 * i++, "insert filter screen:");
  1955. Draw_String(8, 8 + 8 * i++, " tab - to switch through entry boxes");
  1956. Draw_String(8, 8 + 8 * i++, " arrow up/down - to select compare type");
  1957. }
  1958. }
  1959. void SB_Frame(void)
  1960. {
  1961. enum ServerScannerStatus sss;
  1962. int count,todo;
  1963. int x;
  1964. char *proxy_stream = NULL;
  1965. if (qtv_connect_pending)
  1966. {
  1967. if (!QTVR_Waiting(qtvr))
  1968. {
  1969. proxy_stream = QTVR_Get_Retval(qtvr);
  1970. qtv_connect_pending = 0;
  1971. if (proxy_stream)
  1972. Cbuf_AddText(va("alias f_qtv \"say .qtv %s\"; connect %s; echo qtv will buffer for 10 seconds please be patient", proxy_stream, sb_qtv_proxy.string));
  1973. else
  1974. Com_Printf("Sorry could not get a qtv reply.\n");
  1975. QTVR_Destroy(qtvr);
  1976. qtvr = 0;
  1977. }
  1978. if (sb_qtv_connect_timeout.value + qtv_connect_time < cls.realtime)
  1979. {
  1980. Com_Printf("Sorry qtv lookup timed out.\n");
  1981. qtv_connect_pending = 0;
  1982. QTVR_Destroy(qtvr);
  1983. qtvr = 0;
  1984. }
  1985. }
  1986. if (key_dest != key_serverbrowser)
  1987. sb_open = 0;
  1988. if (!sb_open)
  1989. return;
  1990. if (serverscanner)
  1991. ServerScanner_DoStuff(serverscanner);
  1992. if (serverscanner && sb_check_serverscanner)
  1993. {
  1994. sss = ServerScanner_GetStatus(serverscanner);
  1995. if (sss == SSS_IDLE)
  1996. {
  1997. SB_Set_Statusbar("All done. Press \"ctrl + h\" for help.");
  1998. sb_check_serverscanner = 0;
  1999. }
  2000. else if (sss == SSS_SCANNING)
  2001. {
  2002. todo = 0;//ServerScanner_ServersToScan(serverscanner);
  2003. count = 0;//ServerScanner_Servers(serverscanner);
  2004. SB_Set_Statusbar("Scanning servers. Press \"ctrl + h\" for help");
  2005. }
  2006. else if (sss == SSS_PINGING)
  2007. {
  2008. SB_Set_Statusbar("Pinging servers. Press \"ctrl + h\" for help.");
  2009. }
  2010. else if (sss == SSS_ERROR)
  2011. SB_Set_Statusbar("Server scanner error. Press \"ctrl +h\" for help.\n");
  2012. }
  2013. if (serverscanner)
  2014. {
  2015. if(ServerScanner_DataUpdated(serverscanner))
  2016. {
  2017. if (sb_qw_server)
  2018. ServerScanner_FreeServers(serverscanner, sb_qw_server);
  2019. sb_qw_server = ServerScanner_GetServers(serverscanner, &sb_qw_server_count);
  2020. sb_server_count_width = 1;
  2021. x = sb_qw_server_count;
  2022. while((x/=10)) sb_server_count_width++;
  2023. SB_Update_Tabs();
  2024. }
  2025. }
  2026. if (!sb_open)
  2027. return;
  2028. SB_Draw_Background();
  2029. if (sb_active_window != SB_HELP)
  2030. SB_Draw_Tabs();
  2031. if (sb_active_window == SB_SERVER && serverscanner)
  2032. SB_Draw_Server();
  2033. if (sb_active_window == SB_FILTER)
  2034. SB_Draw_Filter();
  2035. if (sb_active_window == SB_HELP)
  2036. SB_Draw_Help();
  2037. SB_Draw_Status_Bar();
  2038. sb_check_serverscanner = 1;
  2039. }
  2040. void SB_Quit(void)
  2041. {
  2042. struct sb_friend *friend;
  2043. struct tab *tab;
  2044. if (serverscanner)
  2045. {
  2046. ServerScanner_FreeServers(serverscanner, sb_qw_server);
  2047. ServerScanner_Delete(serverscanner);
  2048. serverscanner = 0;
  2049. }
  2050. if (qtvr)
  2051. {
  2052. Q

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