Atrinik Client 2.5
gui/main.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00030 #include <global.h>
00031 
00033 #define EYES_BLINK_TIME (10 * 1000)
00034 
00035 #define EYES_BLINK_DELAY (200)
00036 
00038 #define NEWS_MAX_WIDTH 455
00039 
00040 #define NEWS_MAX_HEIGHT 260
00041 
00042 #define NEWS_FONT FONT_SANS12
00043 
00048 static size_t last_server_count = 0;
00049 
00051 static curl_data *news_data = NULL;
00052 
00054 static uint32 eyes_blink_ticks = 0;
00056 static uint8 eyes_draw = 1;
00057 
00059 static int char_step = 0;
00061 static uint32 char_race_selected;
00063 static int char_gender_selected;
00065 static int char_points_left;
00067 static int char_points_assigned[7];
00069 const int char_step_max = 2;
00070 
00072 static progress_dots progress;
00073 
00075 static void news_popup_draw_func(popup_struct *popup)
00076 {
00077     /* Got the news yet? */
00078     if (popup->buf)
00079     {
00080         SDL_Rect box;
00081         list_struct *list = list_exists(LIST_NEWS);
00082 
00083         box.w = popup->surface->w;
00084         box.h = 0;
00085         /* Show the news title. */
00086         string_blt(popup->surface, FONT_SERIF12, list ? list->text[list->row_selected - 1][0] : "???", 0, 10, COLOR_HGOLD, TEXT_ALIGN_CENTER, &box);
00087 
00088         box.w = NEWS_MAX_WIDTH;
00089         box.h = NEWS_MAX_HEIGHT;
00090 
00091         /* Calculate number of last displayed lines. */
00092         if (!popup->i[1])
00093         {
00094             string_blt(NULL, NEWS_FONT, popup->buf, 10, 30, COLOR_WHITE, TEXT_WORD_WRAP | TEXT_MARKUP | TEXT_LINES_CALC, &box);
00095             popup->i[1] = box.y;
00096             popup->i[2] = box.h;
00097             box.h = NEWS_MAX_HEIGHT;
00098         }
00099 
00100         /* Skip rows we scrolled past. */
00101         box.y = popup->i[0];
00102         /* Show the news. */
00103         string_blt(popup->surface, NEWS_FONT, popup->buf, 10, 30, COLOR_WHITE, TEXT_WORD_WRAP | TEXT_MARKUP | TEXT_LINES_SKIP, &box);
00104 
00105         box.x = Bitmaps[popup->bitmap_id]->bitmap->w - 30;
00106         box.y = Bitmaps[popup->bitmap_id]->bitmap->h / 2 - 50;
00107         /* Show scroll buttons. */
00108         scroll_buttons_show(popup->surface, ScreenSurface->w / 2 - Bitmaps[popup->bitmap_id]->bitmap->w / 2 + box.x, ScreenSurface->h / 2 - Bitmaps[popup->bitmap_id]->bitmap->h / 2 + box.y, (int *) &popup->i[0], popup->i[2] - popup->i[1], popup->i[1], &box);
00109         return;
00110     }
00111     /* Haven't started downloading yet. */
00112     else if (!popup->custom_data)
00113     {
00114         list_struct *list = list_exists(LIST_NEWS);
00115         char url[MAX_BUF], *id;
00116         CURL *curl;
00117 
00118         /* Shouldn't happen... */
00119         if (!list)
00120         {
00121             popup_destroy_visible();
00122             return;
00123         }
00124 
00125         /* Initialize cURL, escape the selected row's text and construct
00126          * the url to use for downloading. */
00127         curl = curl_easy_init();
00128         id = curl_easy_escape(curl, list->text[list->row_selected - 1][0], 0);
00129         snprintf(url, sizeof(url), "http://www.atrinik.org/client_news.php?news=%s", id);
00130         curl_free(id);
00131         curl_easy_cleanup(curl);
00132 
00133         /* Start downloading. */
00134         popup->custom_data = curl_download_start(url);
00135     }
00136     /* Downloading. */
00137     else
00138     {
00139         /* Check if we finished yet. */
00140         int ret = curl_download_finished(popup->custom_data);
00141 
00142         /* Yes, we finished, store the string we got. */
00143         if (ret == 1)
00144         {
00145             popup->buf = strdup(((curl_data *) popup->custom_data)->memory ? ((curl_data *) popup->custom_data)->memory : "???");
00146         }
00147 
00148         /* Free the cURL data if we finished. */
00149         if (ret != 0)
00150         {
00151             curl_data_free(popup->custom_data);
00152             popup->custom_data = NULL;
00153         }
00154     }
00155 
00156     /* Haven't downloaded the text yet, inform the user. */
00157     string_blt(popup->surface, FONT_SERIF12, "Downloading news, please wait...", 10, 10, COLOR_WHITE, TEXT_ALIGN_CENTER, NULL);
00158 }
00159 
00161 static int news_popup_event_func(popup_struct *popup, SDL_Event *event)
00162 {
00163     int old_i = popup->i[0];
00164 
00165     if (event->type == SDL_KEYDOWN)
00166     {
00167         /* Escape was pressed? */
00168         if (event->key.keysym.sym == SDLK_ESCAPE)
00169         {
00170             /* Free the cURL data, if any. */
00171             if (popup->custom_data)
00172             {
00173                 curl_data_free(popup->custom_data);
00174                 popup->custom_data = NULL;
00175             }
00176         }
00177         /* Scroll the text. */
00178         else if (event->key.keysym.sym == SDLK_DOWN)
00179         {
00180             popup->i[0]++;
00181         }
00182         else if (event->key.keysym.sym == SDLK_UP)
00183         {
00184             popup->i[0]--;
00185         }
00186         else if (event->key.keysym.sym == SDLK_PAGEUP)
00187         {
00188             popup->i[0] -= NEWS_MAX_HEIGHT / FONT_HEIGHT(NEWS_FONT);
00189         }
00190         else if (event->key.keysym.sym == SDLK_PAGEDOWN)
00191         {
00192             popup->i[0] += NEWS_MAX_HEIGHT / FONT_HEIGHT(NEWS_FONT);
00193         }
00194     }
00195     /* Mouse wheel? */
00196     else if (event->type == SDL_MOUSEBUTTONDOWN)
00197     {
00198         if (event->button.button == SDL_BUTTON_WHEELDOWN)
00199         {
00200             popup->i[0]++;
00201         }
00202         else if (event->button.button == SDL_BUTTON_WHEELUP)
00203         {
00204             popup->i[0]--;
00205         }
00206     }
00207 
00208     /* Scroll value was changed, verify it's in range. */
00209     if (old_i != popup->i[0])
00210     {
00211         if (!popup->buf)
00212         {
00213             popup->i[0] = old_i;
00214         }
00215         else if (popup->i[0] < 0)
00216         {
00217             popup->i[0] = 0;
00218         }
00219         else if (popup->i[0] > popup->i[2] - popup->i[1])
00220         {
00221             popup->i[0] = popup->i[2] - popup->i[1];
00222         }
00223     }
00224 
00225     return -1;
00226 }
00227 
00232 static void char_creation_reset(list_struct *list)
00233 {
00234     /* Reset race. */
00235     if (char_step == 0)
00236     {
00237         char_race_selected = 0;
00238     }
00239 
00240     /* Reset gender. */
00241     if (char_step == 0 || char_step == 1)
00242     {
00243         char_gender_selected = 0;
00244     }
00245 
00246     /* Reset assigned points. */
00247     if (char_step == 0 || char_step == 2)
00248     {
00249         memset(&char_points_assigned, 0, sizeof(char_points_assigned));
00250     }
00251 
00252     /* Can we actually go back? */
00253     if (char_step)
00254     {
00255         char_step--;
00256     }
00257 
00258     if (list)
00259     {
00260         list_remove(list);
00261     }
00262 }
00263 
00268 static void char_creation_enter(list_struct *list)
00269 {
00270     char buf[MAX_BUF];
00271 
00272     /* Picked race. */
00273     if (char_step == 0)
00274     {
00275         char_race_selected = list->row_selected - 1;
00276     }
00277     /* Picked gender. */
00278     else if (char_step == 1)
00279     {
00280         /* This is more complicated than the above, because we have to
00281          * change the gender's first letter back to lowercase, and find
00282          * its ID. */
00283         strncpy(buf, list->text[list->row_selected - 1][0], sizeof(buf) - 1);
00284         buf[0] = tolower(buf[0]);
00285         buf[sizeof(buf) - 1] = '\0';
00286         char_gender_selected = gender_to_id(buf);
00287         /* Initialize maximum stat points that can be assigned. */
00288         char_points_left = s_settings->characters[char_race_selected].points_max;
00289     }
00290     /* Selected stats, create the character. */
00291     else if (char_step == 2)
00292     {
00293         if (char_points_left)
00294         {
00295             return;
00296         }
00297 
00298         snprintf(buf, sizeof(buf), "nc %s %d %d %d %d %d %d %d", s_settings->characters[char_race_selected].gender_archetypes[char_gender_selected], s_settings->characters[char_race_selected].stats_base[0] + char_points_assigned[0], s_settings->characters[char_race_selected].stats_base[1] + char_points_assigned[1], s_settings->characters[char_race_selected].stats_base[2] + char_points_assigned[2], s_settings->characters[char_race_selected].stats_base[3] + char_points_assigned[3], s_settings->characters[char_race_selected].stats_base[4] + char_points_assigned[4], s_settings->characters[char_race_selected].stats_base[5] + char_points_assigned[5], s_settings->characters[char_race_selected].stats_base[6] + char_points_assigned[6]);
00299         cs_write_string(buf, strlen(buf));
00300         return;
00301     }
00302 
00303     char_step++;
00304 
00305     if (list)
00306     {
00307         list_remove(list);
00308     }
00309 }
00310 
00317 static void char_stat_change(int stat_id, int adjust)
00318 {
00319     int points = s_settings->characters[char_race_selected].stats_base[stat_id] + char_points_assigned[stat_id];
00320 
00321     /* Add to stat, if possible. */
00322     if (adjust > 0 && char_points_left && points < s_settings->characters[char_race_selected].stats_max[stat_id])
00323     {
00324         char_points_assigned[stat_id]++;
00325         char_points_left--;
00326     }
00327     /* Subtract from stat, if possible. */
00328     else if (adjust < 0 && points > s_settings->characters[char_race_selected].stats_min[stat_id])
00329     {
00330         char_points_assigned[stat_id]--;
00331         char_points_left++;
00332     }
00333 }
00334 
00336 static int char_creation_key(list_struct *list, SDLKey key)
00337 {
00338     switch (key)
00339     {
00340         /* Change selected stats using left/right arrow keys. */
00341         case SDLK_RIGHT:
00342         case SDLK_LEFT:
00343             char_stat_change(list->row_selected - 1, key == SDLK_LEFT ? -1 : 1);
00344             return 1;
00345 
00346         default:
00347             return -1;
00348     }
00349 }
00350 
00352 static void popup_draw_func_post(popup_struct *popup)
00353 {
00354     list_struct *list = NULL;
00355     size_t i;
00356     int face = 0, x, y;
00357     SDL_Rect box;
00358 
00359     x = popup->x;
00360     y = popup->y;
00361 
00362     /* Not creating character, only show the message text window. */
00363     if (GameStatus != GAME_STATUS_NEW_CHAR)
00364     {
00365         textwin_show(x + Bitmaps[popup->bitmap_id]->bitmap->w / 2, y + 30, 220, 132);
00366         return;
00367     }
00368 
00369     list = list_exists(LIST_CREATION);
00370 
00371     y += 50;
00372 
00373     if (char_step == 2)
00374     {
00375         y += 40;
00376     }
00377 
00378     if (!list)
00379     {
00380         /* Create a new list. */
00381         list = list_create(LIST_CREATION, 7, 1, 0);
00382         list_set_focus(list);
00383         list->handle_enter_func = char_creation_enter;
00384 
00385         /* Show list of races. */
00386         if (char_step == 0)
00387         {
00388             list_set_column(list, 0, 250, 7, NULL, -1);
00389 
00390             for (i = 0; i < s_settings->num_characters; i++)
00391             {
00392                 list_add(list, i, 0, s_settings->characters[i].name);
00393             }
00394         }
00395         /* List of genders. */
00396         else if (char_step == 1)
00397         {
00398             char buf[30];
00399             size_t row = 0;
00400 
00401             list_set_column(list, 0, 250, 7, NULL, -1);
00402 
00403             for (i = 0; i < GENDER_MAX; i++)
00404             {
00405                 /* Does the selected race have this gender? */
00406                 if (s_settings->characters[char_race_selected].gender_archetypes[i])
00407                 {
00408                     /* Uppercase the first letter of the gender's name
00409                      * and add it to the list. */
00410                     strncpy(buf, gender_noun[i], sizeof(buf) - 1);
00411                     buf[0] = toupper(buf[0]);
00412                     buf[sizeof(buf) - 1] = '\0';
00413                     list_add(list, row, 0, buf);
00414                     row++;
00415                 }
00416             }
00417         }
00418         /* The stats. */
00419         else if (char_step == 2)
00420         {
00421             list_set_column(list, 0, 30, 7, NULL, -1);
00422             list->y += 2;
00423             list->row_height_adjust = 6;
00424             list->row_color_func = NULL;
00425             list->row_highlight_func = NULL;
00426             list->row_selected_func = NULL;
00427             list->draw_frame_func = NULL;
00428             list->key_event_func = char_creation_key;
00429             list_add(list, 0, 0, "STR:");
00430             list_add(list, 1, 0, "DEX:");
00431             list_add(list, 2, 0, "CON:");
00432             list_add(list, 3, 0, "INT:");
00433             list_add(list, 4, 0, "WIS:");
00434             list_add(list, 5, 0, "POW:");
00435             list_add(list, 6, 0, "CHA:");
00436         }
00437     }
00438 
00439     list_show(list, x + 20, y);
00440 
00441     /* Race picking, pick first possible gender. */
00442     if (char_step == 0)
00443     {
00444         box.w = 460;
00445         box.h = 96;
00446         string_blt(ScreenSurface, FONT_SERIF12, s_settings->characters[list->row_selected - 1].desc, x + 20, y + 125, COLOR_WHITE, TEXT_WORD_WRAP | TEXT_MARKUP, &box);
00447 
00448         for (i = 0; i < GENDER_MAX; i++)
00449         {
00450             /* Does the selected race have this gender? */
00451             if (s_settings->characters[list->row_selected - 1].gender_archetypes[i])
00452             {
00453                 face = get_bmap_id(s_settings->characters[list->row_selected - 1].gender_faces[i]);
00454                 break;
00455             }
00456         }
00457     }
00458     else if (char_step == 1)
00459     {
00460         char buf[MAX_BUF];
00461 
00462         strncpy(buf, list->text[list->row_selected - 1][0], sizeof(buf) - 1);
00463         buf[0] = tolower(buf[0]);
00464         buf[sizeof(buf) - 1] = '\0';
00465         face = get_bmap_id(s_settings->characters[char_race_selected].gender_faces[gender_to_id(buf)]);
00466     }
00467 
00468     if (char_step == 2)
00469     {
00470         box.w = 370;
00471         box.h = 150;
00472         string_blt(ScreenSurface, FONT_ARIAL10, s_settings->text[SERVER_TEXT_STATS], x + 116, y + 10, COLOR_WHITE, TEXT_WORD_WRAP | TEXT_MARKUP, &box);
00473     }
00474     else
00475     {
00476         blit_face(face, x + 300, y + 35);
00477     }
00478 
00479     /* Show the stat values and the range buttons. */
00480     if (char_step == 2)
00481     {
00482         int adjust = 0;
00483 
00484         for (i = 0; i < NUM_STATS; i++)
00485         {
00486             /* Calculate the current stat value and show it. */
00487             string_blt_shadow_format(ScreenSurface, FONT_ARIAL12, x + 60, y + 10 + i * 18 + 4, i == list->row_selected - 1 ? COLOR_GREEN : COLOR_HGOLD, COLOR_BLACK, 0, NULL, "%.2d", s_settings->characters[char_race_selected].stats_base[i] + char_points_assigned[i]);
00488 
00489             /* One of the range buttons clicked? */
00490             if (range_buttons_show(x + 80, y + 10 + i * 18, &adjust, 1))
00491             {
00492                 char_stat_change(i, adjust);
00493             }
00494         }
00495 
00496         string_blt_shadow(ScreenSurface, FONT_SANS12, "Left:", x + 20, y + 150, COLOR_WHITE, COLOR_BLACK, 0, NULL);
00497         string_blt_shadow_format(ScreenSurface, FONT_ARIAL12, x + 60, y + 150, COLOR_HGOLD, COLOR_BLACK, 0, NULL, "%d", char_points_left);
00498     }
00499 
00500     y += 100;
00501 
00502     if (char_step == 2)
00503     {
00504         y += 70;
00505     }
00506 
00507     /* Show previous button if we're not in the first step. */
00508     if (char_step > 0)
00509     {
00510         if (button_show(BITMAP_BUTTON, -1, BITMAP_BUTTON_DOWN, x + 19, y, "Previous", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00511         {
00512             char_creation_reset(list);
00513         }
00514     }
00515 
00516     /* Show the next button, or the play button if we're in the last step. */
00517     if (button_show(BITMAP_BUTTON, -1, BITMAP_BUTTON_DOWN, x + (char_step == char_step_max ? 90 : 220), y, char_step == char_step_max ? "Play" : "Next", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00518     {
00519         char_creation_enter(list);
00520     }
00521 }
00522 
00526 static void popup_draw_func(popup_struct *popup)
00527 {
00528     uint8 downloading;
00529     SDL_Rect box;
00530     char buf[MAX_BUF];
00531     int x, y;
00532 
00533     /* Waiting to log in. */
00534     if (GameStatus == GAME_STATUS_WAITFORPLAY)
00535     {
00536         box.w = Bitmaps[popup->bitmap_id]->bitmap->w;
00537         box.h = Bitmaps[popup->bitmap_id]->bitmap->h;
00538         string_blt_shadow(popup->surface, FONT_SERIF12, "Logging in, please wait...", 0, 0, COLOR_HGOLD, COLOR_BLACK, TEXT_ALIGN_CENTER | TEXT_VALIGN_CENTER, &box);
00539         return;
00540     }
00541     else if (GameStatus == GAME_STATUS_NEW_CHAR)
00542     {
00543         box.w = Bitmaps[popup->bitmap_id]->bitmap->w;
00544         box.h = 0;
00545         string_blt_shadow_format(popup->surface, FONT_SERIF14, 0, 10, COLOR_HGOLD, COLOR_BLACK, TEXT_ALIGN_CENTER, &box, "Welcome, %s!", cpl.name);
00546         box.w = Bitmaps[popup->bitmap_id]->bitmap->w - 40;
00547         box.h = char_step == 2 ? 70 : 30;
00548         string_blt_shadow(popup->surface, FONT_ARIAL12, s_settings->text[SERVER_TEXT_STEP0 + char_step], 20, 30, COLOR_WHITE, COLOR_BLACK, TEXT_MARKUP | TEXT_WORD_WRAP, &box);
00549         return;
00550     }
00551     /* Playing now, so destroy this popup and remove any lists. */
00552     else if (GameStatus == GAME_STATUS_PLAY)
00553     {
00554         popup_destroy_visible();
00555         list_remove_all();
00556         return;
00557     }
00558     /* Connection terminated while we were trying to login. */
00559     else if (GameStatus <= GAME_STATUS_WAITLOOP)
00560     {
00561         popup_destroy_visible();
00562         return;
00563     }
00564 
00565     /* Downloading the files, or updates haven't finished yet? */
00566     downloading = GameStatus < GAME_STATUS_LOGIN || !file_updates_finished();
00567 
00568     progress.done = !downloading;
00569     progress_dots_show(&progress, popup->surface, 75, 30);
00570 
00571     /* Show that we are connecting to the server. */
00572     box.w = Bitmaps[popup->bitmap_id]->bitmap->w;
00573     box.h = 0;
00574     string_blt_shadow(popup->surface, FONT_SERIF12, "Connecting to server, please wait...", 0, 10, COLOR_HGOLD, COLOR_BLACK, TEXT_ALIGN_CENTER, &box);
00575 
00576     if (downloading)
00577     {
00578         return;
00579     }
00580 
00581     box.w = Bitmaps[popup->bitmap_id]->bitmap->w / 2;
00582     x = Bitmaps[popup->bitmap_id]->bitmap->w / 4 - text_input_center_offset();
00583     y = 75;
00584 
00585     /* Player name. */
00586     if (GameStatus == GAME_STATUS_NAME)
00587     {
00588         string_blt(popup->surface, FONT_ARIAL10, "Enter your name", 0, 55, COLOR_HGOLD, TEXT_ALIGN_CENTER, &box);
00589         text_input_string[0] = toupper(text_input_string[0]);
00590         text_input_show(popup->surface, x, y, FONT_ARIAL10, text_input_string, COLOR_WHITE, 0, BITMAP_LOGIN_INP, NULL);
00591     }
00592     else if (cpl.name[0])
00593     {
00594         cpl.name[0] = toupper(cpl.name[0]);
00595         text_input_draw_background(popup->surface, x, y, BITMAP_LOGIN_INP);
00596         text_input_draw_text(popup->surface, x, y, FONT_ARIAL10, cpl.name, COLOR_WHITE, 0, BITMAP_LOGIN_INP, NULL);
00597     }
00598 
00599     y += 35;
00600 
00601     /* Player password. */
00602     if (GameStatus == GAME_STATUS_PSWD || cpl.password[0])
00603     {
00604         char *cp;
00605 
00606         strncpy(buf, GameStatus == GAME_STATUS_PSWD ? text_input_string : cpl.password, sizeof(buf) - 1);
00607 
00608         for (cp = buf; *cp; cp++)
00609         {
00610             *cp = '*';
00611         }
00612 
00613         if (GameStatus == GAME_STATUS_PSWD)
00614         {
00615             string_blt(popup->surface, FONT_ARIAL10, "Enter your password", 0, 95, COLOR_HGOLD, TEXT_ALIGN_CENTER, &box);
00616             text_input_show(popup->surface, x, y, FONT_ARIAL10, buf, COLOR_WHITE, 0, BITMAP_LOGIN_INP, NULL);
00617         }
00618         else
00619         {
00620             text_input_draw_background(popup->surface, x, y, BITMAP_LOGIN_INP);
00621             text_input_draw_text(popup->surface, x, y, FONT_ARIAL10, buf, COLOR_WHITE, 0, BITMAP_LOGIN_INP, NULL);
00622         }
00623     }
00624 
00625     y += 35;
00626 
00627     /* Verify password for character creation. */
00628     if (GameStatus == GAME_STATUS_VERIFYPSWD)
00629     {
00630         char *cp;
00631 
00632         strncpy(buf, text_input_string, sizeof(buf) - 1);
00633 
00634         for (cp = buf; *cp; cp++)
00635         {
00636             *cp = '*';
00637         }
00638 
00639         string_blt(popup->surface, FONT_ARIAL10, "New Character: Verify Password", 0, 130, COLOR_HGOLD, TEXT_ALIGN_CENTER, &box);
00640         text_input_show(popup->surface, x, y, FONT_ARIAL10, buf, COLOR_WHITE, 0, BITMAP_LOGIN_INP, NULL);
00641         char_step = 0;
00642         char_creation_reset(NULL);
00643     }
00644 
00645     y += 20;
00646 
00647     box.w = Bitmaps[popup->bitmap_id]->bitmap->w - 45;
00648     box.h = 120;
00649     string_blt_shadow(popup->surface, FONT_ARIAL12, s_settings->text[SERVER_TEXT_LOGIN], x, y, COLOR_WHITE, COLOR_BLACK, TEXT_MARKUP | TEXT_WORD_WRAP, &box);
00650 }
00651 
00653 static int popup_destroy_callback_func(popup_struct *popup)
00654 {
00655     list_struct *list = list_exists(LIST_CREATION);
00656 
00657     (void) popup;
00658 
00659     if (list)
00660     {
00661         list_remove(list);
00662         list_set_focus(list_exists(LIST_SERVERS));
00663     }
00664 
00665     if (GameStatus != GAME_STATUS_PLAY)
00666     {
00667         GameStatus = GAME_STATUS_START;
00668     }
00669 
00670     return 1;
00671 }
00672 
00674 static int popup_event_func(popup_struct *popup, SDL_Event *event)
00675 {
00676     (void) popup;
00677 
00678     /* Handle events in character creation. */
00679     if (GameStatus == GAME_STATUS_NEW_CHAR)
00680     {
00681         list_struct *list = list_exists(LIST_CREATION);
00682 
00683         /* Handle list events. */
00684         if (list)
00685         {
00686             if (event->type == SDL_KEYDOWN || event->type == SDL_KEYUP)
00687             {
00688                 if (lists_handle_keyboard(&event->key))
00689                 {
00690                     return 1;
00691                 }
00692             }
00693             else
00694             {
00695                 if (list_handle_mouse(list, event->motion.x, event->motion.y, event))
00696                 {
00697                     return 1;
00698                 }
00699             }
00700         }
00701     }
00702 
00703     if (event->type == SDL_KEYDOWN)
00704     {
00705         /* Try to handle text input. */
00706         if (text_input_handle(&event->key))
00707         {
00708             return 1;
00709         }
00710 
00711         /* Ignore. */
00712         return 0;
00713     }
00714 
00715     return -1;
00716 }
00717 
00721 static void list_handle_enter(list_struct *list)
00722 {
00723     /* Servers list? */
00724     if (list->id == LIST_SERVERS)
00725     {
00726         /* Get selected server. */
00727         selected_server = server_get_id(list->row_selected - 1);
00728 
00729         /* Valid server, start connecting. */
00730         if (selected_server)
00731         {
00732             popup_struct *popup = popup_create(BITMAP_POPUP);
00733 
00734             popup->draw_func = popup_draw_func;
00735             popup->draw_func_post = popup_draw_func_post;
00736             popup->event_func = popup_event_func;
00737             popup->destroy_callback_func = popup_destroy_callback_func;
00738             GameStatus = GAME_STATUS_STARTCONNECT;
00739             progress_dots_create(&progress);
00740         }
00741     }
00742     else if (list->id == LIST_NEWS)
00743     {
00744         if (list->text && list->text[list->row_selected - 1])
00745         {
00746             popup_struct *popup = popup_create(BITMAP_POPUP);
00747 
00748             popup->draw_func = news_popup_draw_func;
00749             popup->event_func = news_popup_event_func;
00750         }
00751     }
00752 }
00753 
00755 static void list_handle_esc(list_struct *list)
00756 {
00757     (void) list;
00758 
00759     system_end();
00760     exit(0);
00761 }
00762 
00766 void show_meta_server()
00767 {
00768     int x, y;
00769     list_struct *list;
00770     size_t server_count;
00771     server_struct *node;
00772     char buf[MAX_BUF];
00773     SDL_Rect box;
00774 
00775     /* Active popup, no need to do anything. */
00776     if (popup_get_visible() && !popup_overlay_need_update(popup_get_visible()))
00777     {
00778         return;
00779     }
00780 
00781     x = 15;
00782     y = ScreenSurface->h - Bitmaps[BITMAP_SERVERS_BG]->bitmap->h - 5;
00783 
00784     /* Background */
00785     sprite_blt(Bitmaps[BITMAP_INTRO], 0, 0, NULL, NULL);
00786     textwin_show(Bitmaps[BITMAP_INTRO]->bitmap->w, 1, ScreenSurface->w - Bitmaps[BITMAP_INTRO]->bitmap->w - 2, ScreenSurface->h - 3);
00787     sprite_blt(Bitmaps[BITMAP_SERVERS_BG], x, y, NULL, NULL);
00788 
00789     list = list_exists(LIST_SERVERS);
00790     server_count = server_get_count();
00791 
00792     /* List doesn't exist or the count changed? Create new list. */
00793     if (!list || last_server_count != server_count)
00794     {
00795         size_t i;
00796 
00797         /* Remove it if it exists already. */
00798         if (list)
00799         {
00800             list_remove(list);
00801         }
00802 
00803         /* Create the servers list. */
00804         list = list_create(LIST_SERVERS, 11, 3, 8);
00805         list->handle_enter_func = list_handle_enter;
00806         list->handle_esc_func = list_handle_esc;
00807         list_scrollbar_enable(list);
00808         list_set_column(list, 0, 295, 7, "Server", -1);
00809         list_set_column(list, 1, 50, 9, "Port", 1);
00810         list_set_column(list, 2, 48, 7, "Players", 1);
00811 
00812         /* Add the servers to the list. */
00813         for (i = 0; i < server_count; i++)
00814         {
00815             node = server_get_id(i);
00816 
00817             list_add(list, i, 0, node->name);
00818             snprintf(buf, sizeof(buf), "%d", node->port);
00819             list_add(list, i, 1, buf);
00820 
00821             if (node->player >= 0)
00822             {
00823                 snprintf(buf, sizeof(buf), "%d", node->player);
00824             }
00825             else
00826             {
00827                 strcpy(buf, "-");
00828             }
00829 
00830             list_add(list, i, 2, buf);
00831         }
00832 
00833         /* Update the focus if we re-created the list, since it's no
00834          * longer the first one in the list. */
00835         if (last_server_count != server_count)
00836         {
00837             list_set_focus(list);
00838         }
00839 
00840         /* Store the new count. */
00841         last_server_count = server_count;
00842     }
00843 
00844     /* Actually draw the list. */
00845     list_show(list, x + 12, y + 8);
00846     node = server_get_id(list->row_selected - 1);
00847 
00848     /* Do we have any selected server? If so, show its version and
00849      * description. */
00850     if (node)
00851     {
00852         snprintf(buf, sizeof(buf), "Version: %s", node->version);
00853         string_blt_shadow(ScreenSurface, FONT_ARIAL10, buf, x + 13, y + 185, COLOR_HGOLD, COLOR_BLACK, 0, NULL);
00854 
00855         box.w = 410;
00856         box.h = 48;
00857         string_blt(ScreenSurface, FONT_ARIAL10, node->desc, x + 13, y + 197, COLOR_WHITE, TEXT_WORD_WRAP | TEXT_MARKUP, &box);
00858     }
00859 
00860     /* Show whether we are connecting to the metaserver or not. */
00861     if (ms_connecting(-1))
00862     {
00863         string_blt_shadow(ScreenSurface, FONT_ARIAL10, "Connecting to metaserver, please wait...", x + 105, y + 8, COLOR_HGOLD, COLOR_BLACK, 0, NULL);
00864     }
00865     else
00866     {
00867         string_blt_shadow(ScreenSurface, FONT_ARIAL10, "Select a server.", x + 226, y + 8, COLOR_GREEN, COLOR_BLACK, 0, NULL);
00868     }
00869 
00870     sprite_blt(Bitmaps[BITMAP_SERVERS_BG_OVER], x, y, NULL, NULL);
00871 
00872     x += Bitmaps[BITMAP_SERVERS_BG_OVER]->bitmap->w + 20;
00873     sprite_blt(Bitmaps[BITMAP_NEWS_BG], x, y, NULL, NULL);
00874 
00875     box.w = Bitmaps[BITMAP_NEWS_BG]->bitmap->w;
00876     box.h = 0;
00877     string_blt_shadow(ScreenSurface, FONT_SERIF12, "Game News", x, y + 10, COLOR_HGOLD, COLOR_BLACK, TEXT_ALIGN_CENTER, &box);
00878 
00879     list = list_exists(LIST_NEWS);
00880 
00881     /* No list yet, make one and start downloading the data. */
00882     if (!list)
00883     {
00884         /* Start downloading. */
00885         news_data = curl_download_start("http://www.atrinik.org/client_news.php");
00886 
00887         list = list_create(LIST_NEWS, 18, 1, 8);
00888         list->handle_enter_func = list_handle_enter;
00889         list->handle_esc_func = list_handle_esc;
00890         list_set_column(list, 0, 150, 7, NULL, -1);
00891         list_set_font(list, FONT_ARIAL10);
00892     }
00893 
00894     /* Download in progress? */
00895     if (news_data)
00896     {
00897         /* Get the status. */
00898         int ret = curl_download_finished(news_data);
00899 
00900         /* Finished downloading, parse the data. */
00901         if (ret == 1)
00902         {
00903             char *mem = strdup(news_data->memory ? news_data->memory : "???"), *cp;
00904             size_t i = 0;
00905 
00906             cp = strtok(mem, "\n");
00907 
00908             while (cp)
00909             {
00910                 list_add(list, i, 0, cp);
00911                 i++;
00912                 cp = strtok(NULL, "\n");
00913             }
00914 
00915             free(mem);
00916         }
00917 
00918         /* Finished downloading or there was an error: clean up in either
00919          * case. */
00920         if (ret != 0)
00921         {
00922             curl_data_free(news_data);
00923             news_data = NULL;
00924         }
00925     }
00926 
00927     /* Show the news list. */
00928     list_show(list, x + 13, y + 10);
00929 
00930     /* Calculate whether to show the eyes or not. Blinks every
00931      * EYES_BLINK_TIME ticks, then waits EYES_BLINK_DELAY ticks until
00932      * showing the eyes again. */
00933     if (SDL_GetTicks() - eyes_blink_ticks >= (eyes_draw ? EYES_BLINK_TIME : EYES_BLINK_DELAY))
00934     {
00935         eyes_blink_ticks = SDL_GetTicks();
00936         eyes_draw = !eyes_draw;
00937     }
00938 
00939     if (eyes_draw)
00940     {
00941         sprite_blt(Bitmaps[BITMAP_EYES], Bitmaps[BITMAP_INTRO]->bitmap->w - 90, 310, NULL, NULL);
00942     }
00943 
00944     /* Show the play button. */
00945     if (button_show(BITMAP_BUTTON, -1, BITMAP_BUTTON_DOWN, 489, y + 10, "Play", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00946     {
00947         list_handle_enter(list_exists(LIST_SERVERS));
00948     }
00949 
00950     if (button_show(BITMAP_BUTTON, -1, BITMAP_BUTTON_DOWN, 489, y + 35, "Refresh", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00951     {
00952         if (!ms_connecting(-1))
00953         {
00954             GameStatus = GAME_STATUS_META;
00955         }
00956     }
00957 
00958     if (button_show(BITMAP_BUTTON, -1, BITMAP_BUTTON_DOWN, 489, y + 60, "Settings", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00959     {
00960         settings_open();
00961     }
00962 
00963     if (button_show(BITMAP_BUTTON, -1, BITMAP_BUTTON_DOWN, 489, y + 85, "Update", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00964     {
00965         updater_open();
00966     }
00967 
00968     if (button_show(BITMAP_BUTTON, -1, BITMAP_BUTTON_DOWN, 489, y + 110, "Help", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00969     {
00970         show_help("main screen");
00971     }
00972 
00973     if (button_show(BITMAP_BUTTON, -1, BITMAP_BUTTON_DOWN, 489, y + 228, "Quit", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00974     {
00975         system_end();
00976         exit(0);
00977     }
00978 }