Atrinik Client  4.0
intro.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
32 #include <global.h>
33 #include <toolkit/string.h>
34 #include <toolkit/curl.h>
35 
37 #define EYES_BLINK_TIME (15 * 1000)
38 
39 #define EYES_BLINK_DELAY (200)
40 
46 static size_t last_server_count = 0;
47 
49 static curl_request_t *news_request = NULL;
50 
52 static uint32_t eyes_blink_ticks = 0;
54 static uint8_t eyes_draw = 1;
56 static button_struct button_play, button_refresh, button_server, button_settings, button_update, button_help, button_credits, button_quit;
57 
59 static list_struct *list_news = NULL;
61 static list_struct *list_servers = NULL;
62 
68 static void list_handle_enter(list_struct *list, SDL_Event *event)
69 {
70  /* Servers list? */
71  if (list == list_servers) {
72  char number[16];
73  uint32_t version, i;
74  size_t pos;
75 
76  /* Get selected server. */
78 
79  if (selected_server == NULL) {
80  return;
81  }
82 
83  for (pos = 0, i = 0, version = 0;
84  string_get_word(selected_server->version, &pos, '.', number,
85  sizeof(number), 0); i++) {
86  version += atoi(number) << (i * CHAR_BIT);
87  }
88 
89  if (version != 0 && version < SERVER_VERSION) {
90  draw_info(COLOR_RED, "The server is outdated; "
91  "choose a different one.");
92  return;
93  }
94 
95  login_start();
96  } else if (list == list_news) {
97  if (list->text && list->text[list->row_selected - 1]) {
98  game_news_open(list->text[list->row_selected - 1][0]);
99  }
100  }
101 }
102 
104 static void list_handle_esc(list_struct *list)
105 {
106  (void) list;
107 
108  exit(0);
109 }
110 
112 static void
114  uint32_t row,
115  uint32_t col,
116  const char **color,
117  const char **color_shadow)
118 {
119  server_struct *server = server_get_id(row);
120  SOFT_ASSERT(server != NULL, "Server on row %u is NULL", row);
121 
122  if (!server->is_meta) {
123  return;
124  }
125 
126  /* Default to gray color for the server entry.*/
127  *color = COLOR_GRAY;
128 
129  /* If the server has a crypto port, check its level of trustworthiness. */
130  if (server->port_crypto != -1) {
131  /* Servers with a certificate have a higher level of trust. */
132  if (server->cert_info != NULL) {
133  /* However, check if the certificate has IP addresses; if it
134  * doesn't, we can't be quite sure that we're connecting to the
135  * right host (DNS spoofing is a possibility, albeit an unlikely
136  * one). */
137  if (server->cert_info->ipv4_address == NULL ||
138  server->cert_info->ipv6_address == NULL) {
139  *color = COLOR_YELLOW;
140  } else {
141  *color = COLOR_GREEN;
142  }
143  } else if (server->cert_pubkey != NULL) {
144  *color = COLOR_ORANGE;
145  }
146  }
147 }
148 
152 void intro_deinit(void)
153 {
154  button_destroy(&button_play);
155  button_destroy(&button_refresh);
156  button_destroy(&button_server);
157  button_destroy(&button_settings);
158  button_destroy(&button_update);
159  button_destroy(&button_help);
160  button_destroy(&button_credits);
161  button_destroy(&button_quit);
162 
163  list_remove(list_servers);
164  list_servers = NULL;
165 
166  list_remove(list_news);
167  list_news = NULL;
168 }
169 
174 void intro_show(void)
175 {
176  SDL_Surface *texture;
177  int x, y;
178  size_t server_count;
179  server_struct *node;
180  char buf[MAX_BUF];
181  SDL_Rect box;
182 
184 
185  texture = TEXTURE_CLIENT("intro");
186 
187  /* Background */
188  surface_show(ScreenSurface, 0, 0, NULL, texture);
189  textwin_show(ScreenSurface, texture->w, 1, ScreenSurface->w - texture->w - 2, ScreenSurface->h - 3);
190 
191  /* Calculate whether to show the eyes or not. Blinks every
192  * EYES_BLINK_TIME ticks, then waits EYES_BLINK_DELAY ticks until
193  * showing the eyes again. */
194  if (SDL_GetTicks() - eyes_blink_ticks >= (eyes_draw ? EYES_BLINK_TIME : EYES_BLINK_DELAY)) {
195  eyes_blink_ticks = SDL_GetTicks();
196  eyes_draw++;
197  }
198 
199  if (eyes_draw) {
200  SDL_Rect src_box;
201 
202  src_box.x = 0;
203  src_box.y = eyes_draw - 1;
204  src_box.w = TEXTURE_CLIENT("eyes")->w;
205  src_box.h = TEXTURE_CLIENT("eyes")->h;
206  surface_show(ScreenSurface, texture->w - 90, 310 + src_box.y, &src_box, TEXTURE_CLIENT("eyes"));
207 
208  if (eyes_draw > 1) {
209  eyes_draw++;
210 
211  if (eyes_draw > src_box.h) {
212  eyes_draw = 1;
213  }
214  }
215  }
216 
217  texture = TEXTURE_CLIENT("servers_bg");
218  x = 15;
219  y = ScreenSurface->h - texture->h - 5;
220  surface_show(ScreenSurface, x, y, NULL, texture);
221 
222  server_count = server_get_count();
223 
224  /* Create the buttons. */
225  if (!list_servers) {
226  button_create(&button_play);
227  button_create(&button_refresh);
228  button_create(&button_server);
229  button_create(&button_settings);
230  button_create(&button_update);
231  button_create(&button_help);
232  button_create(&button_credits);
233  button_create(&button_quit);
234  }
235 
236  /* List doesn't exist or the count changed? Create new list. */
237  if (!list_servers || last_server_count != server_count) {
238  size_t i;
239 
240  /* Remove it if it exists already. */
241  if (list_servers) {
242  list_remove(list_servers);
243  }
244 
245  /* Create the servers list. */
246  list_servers = list_create(11, 3, 8);
247  list_servers->handle_enter_func = list_handle_enter;
248  list_servers->handle_esc_func = list_handle_esc;
249  list_servers->text_color_hook = list_text_color;
250  list_scrollbar_enable(list_servers);
251  list_set_column(list_servers, 0, 295, 7, "Server", -1);
252  list_set_column(list_servers, 1, 50, 9, "Port", 1);
253  list_set_column(list_servers, 2, 46, 7, "Players", 1);
254 
255  /* Add the servers to the list. */
256  for (i = 0; i < server_count; i++) {
257  node = server_get_id(i);
258 
259  list_add(list_servers, i, 0, node->name);
260  snprintf(VS(buf),
261  "%d",
262  node->port_crypto == -1 ? node->port : node->port_crypto);
263  list_add(list_servers, i, 1, buf);
264 
265  if (node->player >= 0) {
266  snprintf(buf, sizeof(buf), "%d", node->player);
267  } else {
268  strcpy(buf, "-");
269  }
270 
271  list_add(list_servers, i, 2, buf);
272  }
273 
274  /* Store the new count. */
276  }
277 
278  /* Actually draw the list. */
279  list_show(list_servers, x + 12, y + 8);
280  node = server_get_id(list_servers->row_selected - 1);
281 
282  /* Do we have any selected server? If so, show its version and
283  * description. */
284  if (node) {
285  snprintf(buf, sizeof(buf), "Version: %s", node->version);
286  text_show_shadow(ScreenSurface, FONT_ARIAL10, buf, x + 13, y + 185, COLOR_HGOLD, COLOR_BLACK, 0, NULL);
287 
288  box.w = 410;
289  box.h = 48;
290  text_show(ScreenSurface, FONT_ARIAL10, node->desc, x + 13, y + 197, COLOR_WHITE, TEXT_WORD_WRAP | TEXT_MARKUP, &box);
291  }
292 
293  /* Show whether we are connecting to the metaserver or not. */
294  if (ms_connecting(-1)) {
295  text_show_shadow(ScreenSurface, FONT_ARIAL10, "Connecting to metaserver, please wait...", x + 105, y + 8, COLOR_HGOLD, COLOR_BLACK, 0, NULL);
296  } else {
297  text_show_shadow(ScreenSurface, FONT_ARIAL10, "Select a secure server.", x + 196, y + 8, COLOR_GREEN, COLOR_BLACK, 0, NULL);
298  }
299 
300  texture = TEXTURE_CLIENT("servers_bg_over");
301  surface_show(ScreenSurface, x, y, NULL, texture);
302 
303  x += texture->w + 20;
304  texture = TEXTURE_CLIENT("news_bg");
305  surface_show(ScreenSurface, x, y, NULL, texture);
306 
307  box.w = texture->w;
308  box.h = 0;
309  text_show_shadow(ScreenSurface, FONT_SERIF12, "Game News", x, y + 10, COLOR_HGOLD, COLOR_BLACK, TEXT_ALIGN_CENTER, &box);
310 
311  /* No list yet, make one and start downloading the data. */
312  if (!list_news) {
313  /* Start downloading. */
314  news_request = curl_request_create(clioption_settings.game_news_url,
315  CURL_PKEY_TRUST_ULTIMATE);
316  curl_request_start_get(news_request);
317 
318  list_news = list_create(18, 1, 8);
319  list_news->focus = 0;
321  list_news->handle_esc_func = list_handle_esc;
322  list_set_column(list_news, 0, 150, 7, NULL, -1);
323  list_set_font(list_news, FONT_ARIAL10);
324  }
325 
326  /* Download in progress? */
327  if (news_request != NULL) {
328  curl_state_t state = curl_request_get_state(news_request);
329  /* Finished downloading, parse the data. */
330  if (state == CURL_STATE_OK) {
331  char *body = curl_request_get_body(news_request, NULL);
332  if (body != NULL) {
333  uint32_t i = 0;
334  char *cp = strtok(body, "\n");
335  while (cp != NULL) {
336  list_add(list_news, i++, 0, cp);
337  cp = strtok(NULL, "\n");
338  }
339  }
340  }
341 
342  /* Finished downloading or there was an error: clean up in either
343  * case. */
344  if (state != CURL_STATE_INPROGRESS) {
345  curl_request_free(news_request);
346  news_request = NULL;
347  }
348  }
349 
350  /* Show the news list. */
351  list_show(list_news, x + 13, y + 10);
352 
353  button_play.x = button_refresh.x = button_server.x = button_settings.x = button_update.x = button_help.x = button_credits.x = button_quit.x = 489;
354  y += 2;
355 
356  button_play.y = y + 10;
357  button_show(&button_play, "Play");
358 
359  button_refresh.y = y + 35;
360  button_show(&button_refresh, "Refresh");
361 
362  button_server.y = y + 60;
363  button_show(&button_server, "Server");
364 
365  button_settings.y = y + 86;
366  button_show(&button_settings, "Settings");
367 
368  button_update.y = y + 110;
369  button_show(&button_update, "Update");
370 
371  button_help.y = y + 135;
372  button_show(&button_help, "Help");
373 
374  button_credits.y = y + 160;
375  button_show(&button_credits, "Credits");
376 
377  button_quit.y = y + 224;
378  button_show(&button_quit, "Quit");
379 
380  if (clioption_settings.connect[0] && cpl.state < ST_STARTCONNECT) {
381  size_t i;
382 
383  for (i = 0; i < server_count; i++) {
384  node = server_get_id(i);
385 
386  if (strcasecmp(clioption_settings.connect[0], node->name) == 0) {
387  list_servers->row_selected = i + 1;
388 
389  if (!clioption_settings.reconnect) {
390  efree(clioption_settings.connect[0]);
391  clioption_settings.connect[0] = NULL;
392  }
393 
394  event_push_key_once(SDLK_RETURN, 0);
395  break;
396  }
397  }
398  }
399 }
400 
408 int intro_event(SDL_Event *event)
409 {
410  if (!list_servers) {
411  return 0;
412  }
413 
414  if (event->type == SDL_MOUSEBUTTONDOWN && event->button.button == SDL_BUTTON_LEFT) {
415  if (LIST_MOUSE_OVER(list_news, event->motion.x, event->motion.y)) {
416  list_news->focus = 1;
417  list_servers->focus = 0;
418  } else if (LIST_MOUSE_OVER(list_servers, event->motion.x, event->motion.y)) {
419  list_servers->focus = 1;
420  list_news->focus = 0;
421  }
422  }
423 
424  if (button_event(&button_play, event)) {
425  list_handle_enter(list_servers, event);
426  return 1;
427  } else if (button_event(&button_refresh, event)) {
428  if (!ms_connecting(-1)) {
429  cpl.state = ST_META;
430  }
431 
432  return 1;
433  } else if (button_event(&button_server, event)) {
434  server_add_open();
435  return 1;
436  } else if (button_event(&button_settings, event)) {
437  settings_open();
438  return 1;
439  } else if (button_event(&button_update, event)) {
440  updater_open();
441  return 1;
442  } else if (button_event(&button_help, event)) {
443  help_show("main screen");
444  return 1;
445  } else if (button_event(&button_credits, event)) {
446  credits_show();
447  return 1;
448  } else if (button_event(&button_quit, event)) {
449  exit(0);
450  return 1;
451  } else if (event->type == SDL_KEYDOWN && event->key.keysym.sym == SDLK_TAB && list_news) {
452  int news_focus = 0;
453 
454  if (list_servers->focus) {
455  news_focus = 1;
456  }
457 
458  list_news->focus = news_focus;
459  list_servers->focus = !news_focus;
460  } else if (list_handle_keyboard(list_news && list_news->focus ? list_news : list_servers, event)) {
461  return 1;
462  } else if (list_handle_mouse(list_news, event)) {
463  return 1;
464  } else if (list_handle_mouse(list_servers, event)) {
465  return 1;
466  }
467 
468  return 0;
469 }
static size_t last_server_count
Definition: intro.c:46
list_struct * list_create(uint32_t max_rows, uint32_t cols, int spacing)
Definition: list.c:113
server_struct * selected_server
Definition: main.c:54
#define COLOR_BLACK
Definition: text.h:323
void textwin_show(SDL_Surface *surface, int x, int y, int w, int h)
Definition: textwin.c:523
#define TEXT_WORD_WRAP
Definition: text.h:226
uint8_t focus
Definition: list.h:126
void draw_info(const char *color, const char *str)
Definition: textwin.c:448
void sound_start_bg_music(const char *filename, int volume, int loop)
Definition: sound.c:412
void list_remove(list_struct *list)
Definition: list.c:522
static curl_request_t * news_request
Definition: intro.c:49
int x
Definition: list.h:36
int button_event(button_struct *button, SDL_Event *event)
Definition: button.c:222
char * ipv4_address
IPv4 address. Can be NULL.
Definition: main.h:50
#define EYES_BLINK_TIME
Definition: intro.c:37
void list_set_column(list_struct *list, uint32_t col, int width, int spacing, const char *name, int centered)
Definition: list.c:242
void button_destroy(button_struct *button)
Definition: button.c:94
int list_handle_mouse(list_struct *list, SDL_Event *event)
Definition: list.c:698
void text_show(SDL_Surface *surface, font_struct *font, const char *text, int x, int y, const char *color_notation, uint64_t flags, SDL_Rect *box)
Definition: text.c:1983
void list_add(list_struct *list, uint32_t row, uint32_t col, const char *str)
Definition: list.c:163
void credits_show(void)
Definition: credits.c:81
void intro_show(void)
Definition: intro.c:174
int intro_event(SDL_Event *event)
Definition: intro.c:408
#define COLOR_HGOLD
Definition: text.h:319
char *** text
Definition: list.h:85
SDL_Surface * ScreenSurface
Definition: main.c:47
#define COLOR_ORANGE
Definition: text.h:291
char * cert_pubkey
Definition: main.h:86
#define COLOR_YELLOW
Definition: text.h:309
#define TEXT_MARKUP
Definition: text.h:224
int player
Definition: main.h:77
#define TEXT_ALIGN_CENTER
Definition: text.h:230
void server_add_open(void)
Definition: server_add.c:132
void game_news_open(const char *title)
Definition: game_news.c:231
static button_struct button_play
Definition: intro.c:56
static list_struct * list_servers
Definition: intro.c:61
#define COLOR_RED
Definition: text.h:295
#define COLOR_GREEN
Definition: text.h:297
void help_show(const char *name)
Definition: help.c:219
#define COLOR_GRAY
Definition: text.h:301
char * name
Definition: main.h:65
#define SERVER_VERSION
Definition: config.h:84
Client_Player cpl
Definition: client.c:50
char * version
Definition: main.h:71
void intro_deinit(void)
Definition: intro.c:152
int64_t setting_get_int(int cat, int setting)
Definition: settings.c:414
void button_create(button_struct *button)
Definition: button.c:65
#define EYES_BLINK_DELAY
Definition: intro.c:39
void(* text_color_hook)(struct list_struct *list, uint32_t row, uint32_t col, const char **color, const char **color_shadow)
Definition: list.h:228
void login_start(void)
Definition: login.c:281
void text_show_shadow(SDL_Surface *surface, font_struct *font, const char *text, int x, int y, const char *color_notation, const char *color_shadow_notation, uint64_t flags, SDL_Rect *box)
Definition: text.c:2278
char * desc
Definition: main.h:74
static uint32_t eyes_blink_ticks
Definition: intro.c:52
void settings_open(void)
Definition: settings.c:177
int ms_connecting(int val)
Definition: metaserver.c:678
static void list_handle_esc(list_struct *list)
Definition: intro.c:104
server_struct * server_get_id(size_t num)
Definition: metaserver.c:639
int list_handle_keyboard(list_struct *list, SDL_Event *event)
Definition: list.c:622
size_t server_get_count(void)
Definition: metaserver.c:661
server_cert_info_t * cert_info
Definition: main.h:103
char * ipv6_address
IPv6 address. Can be NULL.
Definition: main.h:51
void list_set_font(list_struct *list, font_struct *font)
Definition: list.c:284
void list_show(list_struct *list, int x, int y)
Definition: list.c:337
Definition: main.h:247
#define LIST_MOUSE_OVER(list, mx, my)
Definition: list.h:278
clioption_settings_struct clioption_settings
Definition: main.c:87
void(* handle_esc_func)(struct list_struct *list)
Definition: list.h:191
void surface_show(SDL_Surface *surface, int x, int y, SDL_Rect *srcrect, SDL_Surface *src)
Definition: sprite.c:761
static uint8_t eyes_draw
Definition: intro.c:54
static void list_handle_enter(list_struct *list, SDL_Event *event)
Definition: intro.c:68
int port
Definition: main.h:80
static void list_text_color(struct list_struct *list, uint32_t row, uint32_t col, const char **color, const char **color_shadow)
Definition: intro.c:113
int port_crypto
Definition: main.h:83
void list_scrollbar_enable(list_struct *list)
Definition: list.c:302
void button_show(button_struct *button, const char *text)
Definition: button.c:161
static size_t server_count
Definition: metaserver.c:69
void(* handle_enter_func)(struct list_struct *list, SDL_Event *event)
Definition: list.h:201
static list_struct * list_news
Definition: intro.c:59
void updater_open(void)
Definition: updater.c:568
uint32_t row_selected
Definition: list.h:109
bool is_meta
Definition: main.h:106
#define COLOR_WHITE
Definition: text.h:289