Atrinik Client 2.5
gui/region_map.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 #include <region_map.h>
00032 
00034 static curl_data *data_png = NULL;
00036 static curl_data *data_def = NULL;
00038 static SDL_Surface *region_map_png = NULL;
00043 static SDL_Surface *region_map_png_orig;
00045 static region_map_def *rm_def = NULL;
00047 static char current_map[MAX_BUF];
00049 static sint16 current_x;
00051 static sint16 current_y;
00053 static char **cmd_labels = NULL;
00055 static size_t num_cmd_labels = 0;
00057 static char **cmd_tooltips = NULL;
00059 static size_t num_cmd_tooltips = 0;
00061 static int region_map_zoom;
00063 static SDL_Rect region_map_pos;
00065 static uint32 region_mouse_ticks = 0;
00066 
00068 #define RM_TOOLTIP_HEIGHT 150
00069 
00074 static region_map_struct *rm_def_get_map(const char *path)
00075 {
00076     size_t i;
00077 
00078     for (i = 0; i < rm_def->num_maps; i++)
00079     {
00080         if (!strcmp(rm_def->maps[i].path, path))
00081         {
00082             return &rm_def->maps[i];
00083         }
00084     }
00085 
00086     return NULL;
00087 }
00088 
00093 static region_label_struct *rm_find_label(const char *name)
00094 {
00095     size_t i;
00096 
00097     for (i = 0; i < rm_def->num_labels; i++)
00098     {
00099         if (!strcmp(rm_def->labels[i].name, name))
00100         {
00101             return &rm_def->labels[i];
00102         }
00103     }
00104 
00105     return NULL;
00106 }
00107 
00112 static region_map_tooltip *rm_find_tooltip(const char *name)
00113 {
00114     size_t i;
00115 
00116     for (i = 0; i < rm_def->num_tooltips; i++)
00117     {
00118         if (!strcmp(rm_def->tooltips[i].name, name))
00119         {
00120             return &rm_def->tooltips[i];
00121         }
00122     }
00123 
00124     return NULL;
00125 }
00126 
00130 static void rm_def_create(char *str)
00131 {
00132     char *cp;
00133     size_t i;
00134     region_label_struct *label;
00135 
00136     rm_def = calloc(1, sizeof(region_map_def));
00137     rm_def->pixel_size = 1;
00138     rm_def->map_size_x = 24;
00139     rm_def->map_size_y = 24;
00140 
00141     cp = strtok(str, "\n");
00142 
00143     while (cp)
00144     {
00145         if (!strncmp(cp, "pixel_size ", 11))
00146         {
00147             rm_def->pixel_size = atoi(cp + 11);
00148         }
00149         else if (!strncmp(cp, "map_size_x ", 11))
00150         {
00151             rm_def->map_size_x = atoi(cp + 11);
00152         }
00153         else if (!strncmp(cp, "map_size_y ", 11))
00154         {
00155             rm_def->map_size_y = atoi(cp + 11);
00156         }
00157         /* Map command, add it to the list of maps. */
00158         else if (!strncmp(cp, "map ", 4))
00159         {
00160             uint32 x, y;
00161             char path[HUGE_BUF * 4];
00162 
00163             rm_def->maps = realloc(rm_def->maps, sizeof(*rm_def->maps) * (rm_def->num_maps + 1));
00164 
00165             if (sscanf(cp + 4, "%x %x %s", &x, &y, path) == 3)
00166             {
00167                 rm_def->maps[rm_def->num_maps].xpos = x;
00168                 rm_def->maps[rm_def->num_maps].ypos = y;
00169                 rm_def->maps[rm_def->num_maps].path = strdup(path);
00170             }
00171 
00172             rm_def->num_maps++;
00173         }
00174         /* Add label. */
00175         else if (!strncmp(cp, "label ", 6))
00176         {
00177             uint32 x, y;
00178             char label_name[MAX_BUF], label_text[HUGE_BUF * 2];
00179 
00180             if (sscanf(cp + 6, "%x %x %s %8191[^\n]", &x, &y, label_name, label_text) == 4)
00181             {
00182                 rm_def->labels = realloc(rm_def->labels, sizeof(*rm_def->labels) * (rm_def->num_labels + 1));
00183                 rm_def->labels[rm_def->num_labels].hidden = -1;
00184                 rm_def->labels[rm_def->num_labels].x = x;
00185                 rm_def->labels[rm_def->num_labels].y = y;
00186                 convert_newline(label_text);
00187                 rm_def->labels[rm_def->num_labels].name = strdup(label_name);
00188                 rm_def->labels[rm_def->num_labels].text = strdup(label_text);
00189                 rm_def->num_labels++;
00190             }
00191         }
00192         /* Hide the previously added label. */
00193         else if (!strncmp(cp, "label_hide", 10))
00194         {
00195             rm_def->labels[rm_def->num_labels - 1].hidden = 1;
00196         }
00197         /* Add tooltip. */
00198         else if (!strncmp(cp, "tooltip ", 8))
00199         {
00200             uint32 x, y, w, h;
00201             char tooltip_name[MAX_BUF], tooltip[HUGE_BUF * 2];
00202 
00203             if (sscanf(cp + 8, "%x %x %x %x %s %8191[^\n]", &x, &y, &w, &h, tooltip_name, tooltip) == 6)
00204             {
00205                 rm_def->tooltips = realloc(rm_def->tooltips, sizeof(*rm_def->tooltips) * (rm_def->num_tooltips + 1));
00206                 rm_def->tooltips[rm_def->num_tooltips].hidden = -1;
00207                 rm_def->tooltips[rm_def->num_tooltips].outline = 0;
00208                 rm_def->tooltips[rm_def->num_tooltips].x = x;
00209                 rm_def->tooltips[rm_def->num_tooltips].y = y;
00210                 rm_def->tooltips[rm_def->num_tooltips].w = w;
00211                 rm_def->tooltips[rm_def->num_tooltips].h = h;
00212                 convert_newline(tooltip);
00213 
00214                 rm_def->tooltips[rm_def->num_tooltips].text = strdup(tooltip);
00215                 rm_def->tooltips[rm_def->num_tooltips].name = strdup(tooltip_name);
00216                 rm_def->num_tooltips++;
00217             }
00218         }
00219         else if (!strncmp(cp, "tooltip_hide", 12))
00220         {
00221             rm_def->tooltips[rm_def->num_tooltips - 1].hidden = 1;
00222         }
00223         else if (!strncmp(cp, "t_outline ", 10))
00224         {
00225             uint32 r, g, b;
00226             int outline_size = 1;
00227 
00228             if (sscanf(cp + 10, "#%2X%2X%2X %d", &r, &g, &b, &outline_size) >= 3)
00229             {
00230                 rm_def->tooltips[rm_def->num_tooltips - 1].outline = 1;
00231                 rm_def->tooltips[rm_def->num_tooltips - 1].outline_color.r = r;
00232                 rm_def->tooltips[rm_def->num_tooltips - 1].outline_color.g = g;
00233                 rm_def->tooltips[rm_def->num_tooltips - 1].outline_color.b = b;
00234                 rm_def->tooltips[rm_def->num_tooltips - 1].outline_size = outline_size;
00235             }
00236         }
00237         else if (!strncmp(cp, "t_outline", 9))
00238         {
00239             rm_def->tooltips[rm_def->num_tooltips - 1].outline = 1;
00240             rm_def->tooltips[rm_def->num_tooltips - 1].outline_size = 1;
00241             rm_def->tooltips[rm_def->num_tooltips - 1].outline_color.r = 255;
00242             rm_def->tooltips[rm_def->num_tooltips - 1].outline_color.g = 0;
00243             rm_def->tooltips[rm_def->num_tooltips - 1].outline_color.b = 0;
00244         }
00245 
00246         cp = strtok(NULL, "\n");
00247     }
00248 
00249     /* Parse the labels from the server command. */
00250     for (i = 0; i < num_cmd_labels; i++)
00251     {
00252         label = rm_find_label(cmd_labels[i]);
00253 
00254         /* Unhide the label if we found it. */
00255         if (label)
00256         {
00257             label->hidden = 0;
00258         }
00259 
00260         free(cmd_labels[i]);
00261     }
00262 
00263     /* Don't need the labels from the command anymore, free them. */
00264     if (cmd_labels)
00265     {
00266         free(cmd_labels);
00267         cmd_labels = NULL;
00268     }
00269 
00270     num_cmd_labels = 0;
00271 
00272     /* Parse the tooltips from the server command. */
00273     for (i = 0; i < num_cmd_tooltips; i++)
00274     {
00275         region_map_tooltip *tooltip = rm_find_tooltip(cmd_tooltips[i]);
00276 
00277         /* Unhide the tooltip if we found it. */
00278         if (tooltip)
00279         {
00280             tooltip->hidden = 0;
00281         }
00282 
00283         free(cmd_tooltips[i]);
00284     }
00285 
00286     /* Don't need the tooltip from the command anymore, free them. */
00287     if (cmd_tooltips)
00288     {
00289         free(cmd_tooltips);
00290         cmd_tooltips = NULL;
00291     }
00292 
00293     num_cmd_tooltips = 0;
00294 }
00295 
00298 static void rm_def_free()
00299 {
00300     size_t i;
00301 
00302     if (!rm_def)
00303     {
00304         return;
00305     }
00306 
00307     /* Free all maps. */
00308     for (i = 0; i < rm_def->num_maps; i++)
00309     {
00310         free(rm_def->maps[i].path);
00311     }
00312 
00313     free(rm_def->maps);
00314 
00315     /* Free labels. */
00316     for (i = 0; i < rm_def->num_labels; i++)
00317     {
00318         free(rm_def->labels[i].name);
00319         free(rm_def->labels[i].text);
00320     }
00321 
00322     if (rm_def->labels)
00323     {
00324         free(rm_def->labels);
00325     }
00326 
00327     /* Free tooltips. */
00328     for (i = 0; i < rm_def->num_tooltips; i++)
00329     {
00330         free(rm_def->tooltips[i].name);
00331         free(rm_def->tooltips[i].text);
00332     }
00333 
00334     if (rm_def->tooltips)
00335     {
00336         free(rm_def->tooltips);
00337     }
00338 
00339     free(rm_def);
00340     rm_def = NULL;
00341 }
00342 
00347 static int rm_label_in_cmd(const char *name)
00348 {
00349     size_t i;
00350 
00351     for (i = 0; i < num_cmd_labels; i++)
00352     {
00353         if (!strcmp(cmd_labels[i], name))
00354         {
00355             return 1;
00356         }
00357     }
00358 
00359     return 0;
00360 }
00361 
00366 static int rm_tooltip_in_cmd(const char *name)
00367 {
00368     size_t i;
00369 
00370     for (i = 0; i < num_cmd_tooltips; i++)
00371     {
00372         if (!strcmp(cmd_tooltips[i], name))
00373         {
00374             return 1;
00375         }
00376     }
00377 
00378     return 0;
00379 }
00380 
00386 static int region_map_is_same(const char *url)
00387 {
00388     if (setting_get_int(OPT_CAT_DEVEL, OPT_DISABLE_RM_CACHE))
00389     {
00390         return 0;
00391     }
00392 
00393     /* Try to check labels from definitions. */
00394     if (rm_def)
00395     {
00396         size_t i;
00397         uint8 in_cmd;
00398 
00399         for (i = 0; i < rm_def->num_labels; i++)
00400         {
00401             in_cmd = rm_label_in_cmd(rm_def->labels[i].name);
00402 
00403             /* Not the same if the label should be shown or
00404              * re-hidden. */
00405             if ((rm_def->labels[i].hidden == 1 && in_cmd) || (rm_def->labels[i].hidden == 0 && !in_cmd))
00406             {
00407                 return 0;
00408             }
00409         }
00410 
00411         for (i = 0; i < rm_def->num_tooltips; i++)
00412         {
00413             in_cmd = rm_tooltip_in_cmd(rm_def->tooltips[i].name);
00414 
00415             /* Not the same if the tooltip should be shown or
00416              * re-hidden. */
00417             if ((rm_def->tooltips[i].hidden == 1 && in_cmd) || (rm_def->tooltips[i].hidden == 0 && !in_cmd))
00418             {
00419                 return 0;
00420             }
00421         }
00422     }
00423 
00424     /* Is the image URL the same? */
00425     if (data_png && !strcmp(url, data_png->url) && curl_download_finished(data_png) == 1 && curl_download_finished(data_def) == 1)
00426     {
00427         return 1;
00428     }
00429 
00430     return 0;
00431 }
00432 
00437 void RegionMapCmd(uint8 *data, int len)
00438 {
00439     char region[MAX_BUF], url_base[HUGE_BUF], url[HUGE_BUF], text[HUGE_BUF];
00440     int pos = 0;
00441 
00442     /* Get the player's map, X and Y. */
00443     GetString_String(data, &pos, current_map, sizeof(current_map));
00444     current_x = GetShort_String(data + pos);
00445     pos += 2;
00446     current_y = GetShort_String(data + pos);
00447     pos += 2;
00448     /* Get the region and the URL base for the maps. */
00449     GetString_String(data, &pos, region, sizeof(region));
00450     GetString_String(data, &pos, url_base, sizeof(url_base));
00451 
00452     /* Rest of the data packet may be labels/tooltips/etc. */
00453     while (pos < len)
00454     {
00455         uint8 type = data[pos++];
00456 
00457         GetString_String(data, &pos, text, sizeof(text));
00458 
00459         if (type == RM_TYPE_LABEL)
00460         {
00461             cmd_labels = realloc(cmd_labels, sizeof(*cmd_labels) * (num_cmd_labels + 1));
00462             cmd_labels[num_cmd_labels] = strdup(text);
00463             num_cmd_labels++;
00464         }
00465         else if (type == RM_TYPE_TOOLTIP)
00466         {
00467             cmd_tooltips = realloc(cmd_tooltips, sizeof(*cmd_tooltips) * (num_cmd_tooltips + 1));
00468             cmd_tooltips[num_cmd_tooltips] = strdup(text);
00469             num_cmd_tooltips++;
00470         }
00471     }
00472 
00473     cpl.menustatus = MENU_REGION_MAP;
00474 
00475     /* Construct URL for the image. */
00476     snprintf(url, sizeof(url), "%s/%s.png", url_base, region);
00477 
00478     /* Free old map surface. */
00479     if (region_map_png)
00480     {
00481         /* If zoom was used, we have to free both. */
00482         if (region_map_png != region_map_png_orig)
00483         {
00484             SDL_FreeSurface(region_map_png);
00485         }
00486 
00487         SDL_FreeSurface(region_map_png_orig);
00488         region_map_png = NULL;
00489         region_map_png_orig = NULL;
00490     }
00491 
00492     /* Default zoom. */
00493     region_map_zoom = RM_ZOOM_DEFAULT;
00494 
00495     region_map_pos.x = 0;
00496     region_map_pos.y = 0;
00497     region_map_pos.w = Bitmaps[BITMAP_REGION_MAP]->bitmap->w - RM_BORDER_SIZE * 2;
00498     region_map_pos.h = Bitmaps[BITMAP_REGION_MAP]->bitmap->h - RM_BORDER_SIZE * 2 -RM_TOOLTIP_HEIGHT;
00499 
00500     /* The map is the same, no downloading needed. */
00501     if (region_map_is_same(url))
00502     {
00503         if (cmd_labels)
00504         {
00505             free(cmd_labels);
00506             cmd_labels = NULL;
00507         }
00508 
00509         if (cmd_tooltips)
00510         {
00511             free(cmd_tooltips);
00512             cmd_tooltips = NULL;
00513         }
00514 
00515         num_cmd_labels = 0;
00516         num_cmd_tooltips = 0;
00517         return;
00518     }
00519 
00520     region_map_clear();
00521 
00522     /* Start the downloads. */
00523     data_png = curl_download_start(url);
00524     snprintf(url, sizeof(url), "%s/%s.def", url_base, region);
00525     data_def = curl_download_start(url);
00526 }
00527 
00530 void region_map_clear()
00531 {
00532     /* Free old cURL data and the parsed definitions. */
00533     if (data_png)
00534     {
00535         curl_data_free(data_png);
00536         data_png = NULL;
00537     }
00538 
00539     if (data_def)
00540     {
00541         curl_data_free(data_def);
00542         data_def = NULL;
00543     }
00544 
00545     rm_def_free();
00546 }
00547 
00551 static void region_map_resize(int adjust)
00552 {
00553     float delta;
00554 
00555     region_map_zoom += adjust;
00556 
00557     /* Free old zoomed surface if applicable. */
00558     if (region_map_png != region_map_png_orig)
00559     {
00560         SDL_FreeSurface(region_map_png);
00561     }
00562 
00563     /* Zoom the surface. */
00564     region_map_png = zoomSurface(region_map_png_orig, region_map_zoom / 100.0, region_map_zoom / 100.0, setting_get_int(OPT_CAT_MAP, OPT_ZOOM_SMOOTH));
00565 
00566     if (adjust > 0)
00567     {
00568         delta = (region_map_zoom / 100.0 - 0.1f);
00569     }
00570     else
00571     {
00572         delta = (region_map_zoom / 100.0 + 0.1f);
00573     }
00574 
00575     region_map_pos.x += region_map_pos.x / delta * (adjust / 100.0) + region_map_pos.w / delta * (adjust / 100.0) / 2;
00576     region_map_pos.y += region_map_pos.y / delta * (adjust / 100.0) + region_map_pos.h / delta * (adjust / 100.0) / 2;
00577 
00578     surface_pan(region_map_png, &region_map_pos);
00579 }
00580 
00584 void region_map_handle_key(SDLKey key)
00585 {
00586     int pos = RM_SCROLL;
00587 
00588     if (!region_map_png)
00589     {
00590         return;
00591     }
00592 
00593     /* Shift is held, increase the scrolling 'speed'. */
00594     if (SDL_GetModState() & KMOD_SHIFT)
00595     {
00596         pos = RM_SCROLL_SHIFT;
00597     }
00598 
00599     if (key == SDLK_UP)
00600     {
00601         region_map_pos.y -= pos;
00602     }
00603     else if (key == SDLK_DOWN)
00604     {
00605         region_map_pos.y += pos;
00606     }
00607     else if (key == SDLK_LEFT)
00608     {
00609         region_map_pos.x -= pos;
00610     }
00611     else if (key == SDLK_RIGHT)
00612     {
00613         region_map_pos.x += pos;
00614     }
00615     else if (key == SDLK_PAGEUP)
00616     {
00617         if (region_map_zoom < RM_ZOOM_MAX)
00618         {
00619             region_map_resize(RM_ZOOM_PROGRESS);
00620         }
00621     }
00622     else if (key == SDLK_PAGEDOWN)
00623     {
00624         if (region_map_zoom > RM_ZOOM_MIN)
00625         {
00626             region_map_resize(-RM_ZOOM_PROGRESS);
00627         }
00628     }
00629     else
00630     {
00631         return;
00632     }
00633 
00634     surface_pan(region_map_png, &region_map_pos);
00635 }
00636 
00640 void region_map_handle_event(SDL_Event *event)
00641 {
00642     if (!region_map_png)
00643     {
00644         return;
00645     }
00646 
00647     if (event->type == SDL_MOUSEBUTTONDOWN)
00648     {
00649         /* Zoom in. */
00650         if (event->button.button == SDL_BUTTON_WHEELUP)
00651         {
00652             if (region_map_zoom < RM_ZOOM_MAX)
00653             {
00654                 region_map_resize(RM_ZOOM_PROGRESS);
00655             }
00656         }
00657         /* Zoom out. */
00658         else if (event->button.button == SDL_BUTTON_WHEELDOWN)
00659         {
00660             if (region_map_zoom > RM_ZOOM_MIN)
00661             {
00662                 region_map_resize(-RM_ZOOM_PROGRESS);
00663             }
00664         }
00665     }
00666 }
00667 
00670 void region_map_show()
00671 {
00672     int x, y, ret_png, ret_def;
00673     SDL_Rect box, dest;
00674     int state, mx, my;
00675     size_t i;
00676 
00677     /* Show the background. */
00678     x = (ScreenSurface->w / 2 - Bitmaps[BITMAP_REGION_MAP]->bitmap->w / 2);
00679     y = (ScreenSurface->h / 2 - Bitmaps[BITMAP_REGION_MAP]->bitmap->h / 2);
00680     sprite_blt(Bitmaps[BITMAP_REGION_MAP], x, y, NULL, NULL);
00681 
00682     box.x = x + RM_BORDER_SIZE;
00683     box.y = y + RM_BORDER_SIZE;
00684     box.w = region_map_pos.w;
00685     box.h = region_map_pos.h;
00686 
00687     /* Show a close button. */
00688     if (button_show(BITMAP_BUTTON_ROUND, -1, BITMAP_BUTTON_ROUND_DOWN, box.x + box.w, y + 10, "X", FONT_ARIAL10, COLOR_WHITE, COLOR_BLACK, COLOR_HGOLD, COLOR_BLACK, 0))
00689     {
00690         cpl.menustatus = MENU_NO;
00691         map_udate_flag = 2;
00692         reset_keys();
00693     }
00694 
00695     /* Show direction markers. */
00696     string_blt(ScreenSurface, FONT_SERIF14, "N", box.x, y + RM_BORDER_SIZE / 2 - FONT_HEIGHT(FONT_SERIF14) / 2, COLOR_HGOLD, TEXT_ALIGN_CENTER | TEXT_OUTLINE, &box);
00697     string_blt(ScreenSurface, FONT_SERIF14, "E", x + Bitmaps[BITMAP_REGION_MAP]->bitmap->w - RM_BORDER_SIZE / 2 - string_get_width(FONT_SERIF14, "E", 0) / 2, y + (Bitmaps[BITMAP_REGION_MAP]->bitmap->h - RM_TOOLTIP_HEIGHT) / 2 - FONT_HEIGHT(FONT_SERIF14), COLOR_HGOLD, TEXT_OUTLINE, &box);
00698     string_blt(ScreenSurface, FONT_SERIF14, "S", box.x, y + Bitmaps[BITMAP_REGION_MAP]->bitmap->h - RM_BORDER_SIZE / 2 - FONT_HEIGHT(FONT_SERIF14) / 2 - RM_TOOLTIP_HEIGHT, COLOR_HGOLD, TEXT_ALIGN_CENTER | TEXT_OUTLINE, &box);
00699     string_blt(ScreenSurface, FONT_SERIF14, "W", x + RM_BORDER_SIZE / 2 - string_get_width(FONT_SERIF14, "W", 0) / 2, y + (Bitmaps[BITMAP_REGION_MAP]->bitmap->h - RM_TOOLTIP_HEIGHT) / 2 - FONT_HEIGHT(FONT_SERIF14), COLOR_HGOLD, TEXT_OUTLINE, &box);
00700 
00701     /* Check the status of the downloads. */
00702     ret_png = curl_download_finished(data_png);
00703     ret_def = curl_download_finished(data_def);
00704 
00705     /* We failed. */
00706     if (ret_png == -1 || ret_def == -1)
00707     {
00708         string_blt(ScreenSurface, FONT_SERIF14, "Connection timed out.", box.x, box.y, COLOR_WHITE, TEXT_ALIGN_CENTER | TEXT_VALIGN_CENTER | TEXT_OUTLINE, &box);
00709         return;
00710     }
00711 
00712     /* Still in progress. */
00713     if (ret_png == 0 || ret_def == 0)
00714     {
00715         string_blt(ScreenSurface, FONT_SERIF14, "Downloading the map, please wait...", box.x, box.y, COLOR_WHITE, TEXT_ALIGN_CENTER | TEXT_VALIGN_CENTER | TEXT_OUTLINE, &box);
00716         return;
00717     }
00718 
00719     /* Parse the definitions. */
00720     if (!rm_def)
00721     {
00722         rm_def_create(data_def->memory);
00723     }
00724 
00725     /* Create the map surface. */
00726     if (!region_map_png)
00727     {
00728         SDL_Rect marker;
00729         region_map_struct *map;
00730         SDL_Surface *img;
00731 
00732         /* Create the surface from downloaded data. */
00733         img = IMG_Load_RW(SDL_RWFromMem(data_png->memory, data_png->size), 1);
00734         region_map_png = region_map_png_orig = SDL_DisplayFormat(img);
00735         SDL_FreeSurface(img);
00736 
00737         map = rm_def_get_map(current_map);
00738 
00739         /* Valid map? */
00740         if (map)
00741         {
00742             /* Calculate the player's marker position. */
00743             marker.x = map->xpos + current_x * rm_def->pixel_size - Bitmaps[BITMAP_MAP_MARKER]->bitmap->w / 2 + rm_def->pixel_size / 2;
00744             marker.y = map->ypos + current_y * rm_def->pixel_size - Bitmaps[BITMAP_MAP_MARKER]->bitmap->h + rm_def->pixel_size;
00745             SDL_BlitSurface(Bitmaps[BITMAP_MAP_MARKER]->bitmap, NULL, region_map_png, &marker);
00746 
00747             /* Center the map on the player. */
00748             region_map_pos.x = (map->xpos + current_x * rm_def->pixel_size) - region_map_pos.w / 2;
00749             region_map_pos.y = (map->ypos + current_y * rm_def->pixel_size) - region_map_pos.h / 2;
00750         }
00751         else
00752         {
00753             region_map_pos.x = region_map_png->w / 2 - region_map_pos.w / 2;
00754             region_map_pos.y = region_map_png->h / 2 - region_map_pos.h / 2;
00755             surface_pan(region_map_png, &region_map_pos);
00756         }
00757 
00758         surface_pan(region_map_png, &region_map_pos);
00759 
00760         /* Blit the labels. */
00761         for (i = 0; i < rm_def->num_labels; i++)
00762         {
00763             if (rm_def->labels[i].hidden < 1)
00764             {
00765                 string_blt(region_map_png, FONT_SERIF20, rm_def->labels[i].text, rm_def->labels[i].x, rm_def->labels[i].y, COLOR_HGOLD, TEXT_MARKUP | TEXT_OUTLINE, NULL);
00766             }
00767         }
00768 
00769         for (i = 0; i < rm_def->num_tooltips; i++)
00770         {
00771             if (rm_def->tooltips[i].hidden < 1 && rm_def->tooltips[i].outline)
00772             {
00773                 border_create(region_map_png, rm_def->tooltips[i].x, rm_def->tooltips[i].y, rm_def->tooltips[i].w, rm_def->tooltips[i].h, SDL_MapRGB(region_map_png->format, rm_def->tooltips[i].outline_color.r, rm_def->tooltips[i].outline_color.g, rm_def->tooltips[i].outline_color.b), rm_def->tooltips[i].outline_size);
00774             }
00775         }
00776     }
00777 
00778     state = SDL_GetMouseState(&mx, &my);
00779 
00780     /* Move the map around with the mouse. */
00781     if ((state == SDL_BUTTON(SDL_BUTTON_LEFT) || state == SDL_BUTTON(SDL_BUTTON_MIDDLE)) && mx > box.x && my < box.x + box.w && my > box.y && my < box.y + box.h && (!region_mouse_ticks || state == SDL_BUTTON(SDL_BUTTON_MIDDLE) || SDL_GetTicks() - region_mouse_ticks > 125))
00782     {
00783         region_mouse_ticks = SDL_GetTicks();
00784 
00785         if (state == SDL_BUTTON(SDL_BUTTON_LEFT))
00786         {
00787             /* The clicked position will become centered, unless it's too
00788              * close to an edge of the map, of course. */
00789             region_map_pos.x += mx - box.x - region_map_pos.w / 2;
00790             region_map_pos.y += my - box.y - region_map_pos.h / 2;
00791             surface_pan(region_map_png, &region_map_pos);
00792         }
00793         else if (state == SDL_BUTTON(SDL_BUTTON_MIDDLE) && setting_get_int(OPT_CAT_DEVEL, OPT_QUICKPORT))
00794         {
00795             int xpos, ypos;
00796 
00797             xpos = region_map_pos.x + mx - box.x;
00798             ypos = region_map_pos.y + my - box.y;
00799 
00800             for (i = 0; i < rm_def->num_maps; i++)
00801             {
00802                 if (xpos >= rm_def->maps[i].xpos * (region_map_zoom / 100.0) && xpos <= (rm_def->maps[i].xpos + (rm_def->map_size_x * rm_def->pixel_size)) * (region_map_zoom / 100.0) && ypos >= rm_def->maps[i].ypos * (region_map_zoom / 100.0) && ypos <= (rm_def->maps[i].ypos + (rm_def->map_size_y * rm_def->pixel_size)) * (region_map_zoom / 100.0))
00803                 {
00804                     char buf[HUGE_BUF];
00805 
00806                     xpos = (xpos - rm_def->maps[i].xpos * (region_map_zoom / 100.0)) / (rm_def->pixel_size * (region_map_zoom / 100.0));
00807                     ypos = (ypos - rm_def->maps[i].ypos * (region_map_zoom / 100.0)) / (rm_def->pixel_size * (region_map_zoom / 100.0));
00808                     snprintf(buf, sizeof(buf), "/goto %s %d %d", rm_def->maps[i].path, xpos, ypos);
00809                     send_command(buf);
00810 
00811                     cpl.menustatus = MENU_NO;
00812                     map_udate_flag = 2;
00813                     reset_keys();
00814                     /* Workaround so the middle click doesn't also trigger a
00815                      * fire action. */
00816                     cpl.action_timer = 0.0001f;
00817                     break;
00818                 }
00819             }
00820         }
00821     }
00822 
00823     dest.x = box.x;
00824     dest.y = box.y;
00825 
00826     /* Actually blit the map. */
00827     SDL_BlitSurface(region_map_png, &region_map_pos, ScreenSurface, &dest);
00828 
00829     string_blt(ScreenSurface, FONT_ARIAL11, "Move the mouse cursor over buildings to see additional information about them, if any. Scroll the map by pressing left mouse click.", box.x + 3, y + Bitmaps[BITMAP_REGION_MAP]->bitmap->h - RM_BORDER_SIZE - FONT_HEIGHT(FONT_ARIAL11) - 3, COLOR_WHITE, TEXT_OUTLINE, NULL);
00830 
00831     if (mx >= box.x && mx <= box.x + box.w && my >= box.y && my <= box.y + box.h)
00832     {
00833         SDL_Rect tooltip_box;
00834 
00835         tooltip_box.x = box.x + 3;
00836         tooltip_box.y = box.y + box.h + RM_BORDER_SIZE + 3;
00837         tooltip_box.w = box.w;
00838         tooltip_box.h = RM_TOOLTIP_HEIGHT - RM_BORDER_SIZE * 2;
00839 
00840         for (i = 0; i < rm_def->num_tooltips; i++)
00841         {
00842             if (rm_def->tooltips[i].hidden < 1 && region_map_pos.x + mx - box.x >= rm_def->tooltips[i].x * (region_map_zoom / 100.0) && region_map_pos.x + mx - box.x <= (rm_def->tooltips[i].x + rm_def->tooltips[i].w) * (region_map_zoom / 100.0) && region_map_pos.y + my - box.y >= rm_def->tooltips[i].y * (region_map_zoom / 100.0) && region_map_pos.y + my - box.y <= (rm_def->tooltips[i].y + rm_def->tooltips[i].h) * (region_map_zoom / 100.0))
00843             {
00844                 string_blt(ScreenSurface, FONT_ARIAL11, rm_def->tooltips[i].text, tooltip_box.x, tooltip_box.y, COLOR_WHITE, TEXT_MARKUP | TEXT_WORD_WRAP | TEXT_OUTLINE, &tooltip_box);
00845                 break;
00846             }
00847         }
00848     }
00849 }