Atrinik Client 2.5
gui/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 
00033 #define MAP_NAME_FONT FONT_SERIF14
00034 
00035 static struct Map the_map;
00036 static SDL_Surface *zoomed = NULL;
00037 
00039 _mapdata MapData;
00040 
00041 static _multi_part_obj MultiArchs[16];
00042 
00044 static int old_map_mouse_x = 0, old_map_mouse_y = 0;
00048 static int right_click_ticks = -1;
00049 
00050 /* Load the multi arch offsets */
00051 void load_mapdef_dat()
00052 {
00053     FILE *stream;
00054     int i, ii, x, y, d[32];
00055     char line[256];
00056 
00057     if (!(stream = fopen_wrapper(ARCHDEF_FILE, "r")))
00058     {
00059         LOG(llevBug, "Can't find file %s\n", ARCHDEF_FILE);
00060         return;
00061     }
00062 
00063     for (i = 0; i < 16; i++)
00064     {
00065         if (!fgets(line, 255, stream))
00066         {
00067             break;
00068         }
00069 
00070         sscanf(line, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", &x, &y, &d[0],&d[1], &d[2], &d[3], &d[4], &d[5], &d[6], &d[7], &d[8], &d[9], &d[10], &d[11], &d[12], &d[13], &d[14], &d[15], &d[16], &d[17], &d[18], &d[19], &d[20], &d[21], &d[22], &d[23], &d[24], &d[25], &d[26], &d[27], &d[28], &d[29], &d[30], &d[31]);
00071         MultiArchs[i].xlen = x;
00072         MultiArchs[i].ylen = y;
00073 
00074         for (ii = 0; ii < 16; ii++)
00075         {
00076             MultiArchs[i].part[ii].xoff = d[ii * 2];
00077             MultiArchs[i].part[ii].yoff = d[ii * 2 + 1];
00078         }
00079     }
00080 
00081     fclose(stream);
00082 }
00083 
00088 void widget_show_mapname(widgetdata *widget)
00089 {
00090     SDL_Rect box;
00091 
00092     box.w = widget->wd;
00093     box.h = 0;
00094     string_blt(ScreenSurface, MAP_NAME_FONT, MapData.name, widget->x1, widget->y1, COLOR_HGOLD, TEXT_MARKUP, &box);
00095 }
00096 
00099 void clear_map()
00100 {
00101     memset(&the_map, 0, sizeof(Map));
00102 }
00103 
00108 void display_mapscroll(int dx, int dy)
00109 {
00110     int x, y;
00111     struct Map newmap;
00112 
00113     for (x = 0; x < setting_get_int(OPT_CAT_MAP, OPT_MAP_WIDTH); x++)
00114     {
00115         for (y = 0; y < setting_get_int(OPT_CAT_MAP, OPT_MAP_HEIGHT); y++)
00116         {
00117             if (x + dx < 0 || x + dx >= setting_get_int(OPT_CAT_MAP, OPT_MAP_WIDTH) || y + dy < 0 || y + dy >= setting_get_int(OPT_CAT_MAP, OPT_MAP_HEIGHT))
00118             {
00119                 memset((char *) &(newmap.cells[x][y]), 0, sizeof(struct MapCell));
00120             }
00121             else
00122             {
00123                 memcpy((char *) &(newmap.cells[x][y]), (char *) &(the_map.cells[x + dx][y + dy]), sizeof(struct MapCell));
00124             }
00125         }
00126     }
00127 
00128     memcpy((char *) &the_map, (char *) & newmap, sizeof(struct Map));
00129 }
00130 
00134 void update_map_name(const char *name)
00135 {
00136     widgetdata *widget;
00137 
00138     strncpy(MapData.name, name, sizeof(MapData.name) - 1);
00139     MapData.name[sizeof(MapData.name) - 1] = '\0';
00140 
00141     /* We need to update all mapname widgets on the screen now.
00142      * Not that there should be more than one at a time, but just in case. */
00143     for (widget = cur_widget[MAPNAME_ID]; widget; widget = widget->type_next)
00144     {
00145         resize_widget(widget, RESIZE_RIGHT, string_get_width(MAP_NAME_FONT, name, TEXT_MARKUP));
00146         resize_widget(widget, RESIZE_BOTTOM, string_get_height(MAP_NAME_FONT, name, TEXT_MARKUP));
00147     }
00148 }
00149 
00153 void update_map_weather(const char *weather)
00154 {
00155     effect_start(weather);
00156 }
00157 
00164 void init_map_data(int xl, int yl, int px, int py)
00165 {
00166     if (xl != -1)
00167     {
00168         MapData.xlen = xl;
00169     }
00170 
00171     if (yl != -1)
00172     {
00173         MapData.ylen = yl;
00174     }
00175 
00176     if (px != -1)
00177     {
00178         MapData.posx = px;
00179     }
00180 
00181     if (py != -1)
00182     {
00183         MapData.posy = py;
00184     }
00185 
00186     if (xl > 0)
00187     {
00188         clear_map();
00189     }
00190 }
00191 
00199 static int calc_map_cell_height(int x, int y)
00200 {
00201     if (x >= 0 && x < setting_get_int(OPT_CAT_MAP, OPT_MAP_WIDTH) && y >= 0 && y < setting_get_int(OPT_CAT_MAP, OPT_MAP_HEIGHT))
00202     {
00203         return the_map.cells[x][y].height[1];
00204     }
00205 
00206     return 0;
00207 }
00208 
00209 #define MAX_STRETCH 8
00210 #define MAX_STRETCH_DIAG 12
00211 
00216 void align_tile_stretch(int x, int y)
00217 {
00218     uint8 top, bottom, right, left, min_ht;
00219     uint32 h;
00220     int nw_height, n_height, ne_height, sw_height, s_height, se_height, w_height, e_height, my_height;
00221 
00222     if (x < 0 || y < 0 || x >= setting_get_int(OPT_CAT_MAP, OPT_MAP_WIDTH) || y >= setting_get_int(OPT_CAT_MAP, OPT_MAP_HEIGHT))
00223     {
00224         return;
00225     }
00226 
00227     nw_height = calc_map_cell_height(x - 1, y - 1);
00228     n_height = calc_map_cell_height(x, y - 1);
00229     ne_height = calc_map_cell_height(x + 1, y - 1);
00230     sw_height = calc_map_cell_height(x - 1, y + 1);
00231     s_height = calc_map_cell_height(x, y + 1);
00232     se_height = calc_map_cell_height(x + 1, y + 1);
00233     w_height = calc_map_cell_height(x - 1, y);
00234     e_height = calc_map_cell_height(x + 1, y);
00235     my_height = calc_map_cell_height(x, y);
00236 
00237     if (abs(my_height - e_height) > MAX_STRETCH)
00238     {
00239         e_height = my_height;
00240     }
00241 
00242     if (abs(my_height - se_height) > MAX_STRETCH_DIAG)
00243     {
00244         se_height = my_height;
00245     }
00246 
00247     if (abs(my_height - s_height) > MAX_STRETCH)
00248     {
00249         s_height = my_height;
00250     }
00251 
00252     if (abs(my_height - sw_height) > MAX_STRETCH_DIAG)
00253     {
00254         sw_height = my_height;
00255     }
00256 
00257     if (abs(my_height - w_height) > MAX_STRETCH)
00258     {
00259         w_height = my_height;
00260     }
00261 
00262     if (abs(my_height - nw_height) > MAX_STRETCH_DIAG)
00263     {
00264         nw_height = my_height;
00265     }
00266 
00267     if (abs(my_height - n_height) > MAX_STRETCH)
00268     {
00269         n_height = my_height;
00270     }
00271 
00272     if (abs(my_height - ne_height) > MAX_STRETCH_DIAG)
00273     {
00274         ne_height = my_height;
00275     }
00276 
00277     top = MAX(w_height, nw_height);
00278     top = MAX(top, n_height);
00279     top = MAX(top, my_height);
00280 
00281     bottom = MAX(s_height, se_height);
00282     bottom = MAX(bottom, e_height);
00283     bottom = MAX(bottom, my_height);
00284 
00285     right = MAX(n_height, ne_height);
00286     right = MAX(right, e_height);
00287     right = MAX(right, my_height);
00288 
00289     left = MAX(w_height, sw_height);
00290     left = MAX(left, s_height);
00291     left = MAX(left, my_height);
00292 
00293     /* Normalize these... */
00294     min_ht = MIN(top, bottom);
00295     min_ht = MIN(min_ht, left);
00296     min_ht = MIN(min_ht, right);
00297     min_ht = MIN(min_ht, my_height);
00298 
00299     top -= min_ht;
00300     bottom -= min_ht;
00301     left -= min_ht;
00302     right -= min_ht;
00303 
00304     h = bottom + (left << 8) + (right << 16) + (top << 24);
00305     the_map.cells[x][y].stretch = h;
00306 }
00307 
00315 void adjust_tile_stretch()
00316 {
00317     int x, y;
00318 
00319     for (x = 0; x < setting_get_int(OPT_CAT_MAP, OPT_MAP_WIDTH); x++)
00320     {
00321         for (y = 0; y < setting_get_int(OPT_CAT_MAP, OPT_MAP_HEIGHT); y++)
00322         {
00323             align_tile_stretch(x - 1, y - 1);
00324             align_tile_stretch(x , y - 1);
00325             align_tile_stretch(x + 1, y - 1);
00326             align_tile_stretch(x + 1, y);
00327 
00328             align_tile_stretch(x + 1, y + 1);
00329             align_tile_stretch(x, y + 1);
00330             align_tile_stretch(x - 1, y + 1);
00331             align_tile_stretch(x - 1, y);
00332 
00333             align_tile_stretch(x, y);
00334         }
00335     }
00336 }
00337 
00354 void map_set_data(int x, int y, int layer, sint16 face, uint8 quick_pos, uint8 obj_flags, const char *name, const char *name_color, sint16 height, uint8 probe, sint16 zoom, sint16 align, uint8 draw_double, uint8 alpha, sint16 rotate, uint8 infravision)
00355 {
00356     the_map.cells[x][y].faces[layer] = face;
00357     the_map.cells[x][y].flags[layer] = obj_flags;
00358 
00359     the_map.cells[x][y].probe[layer] = probe;
00360     the_map.cells[x][y].quick_pos[layer] = quick_pos;
00361 
00362     strncpy(the_map.cells[x][y].pcolor[layer], name_color, sizeof(the_map.cells[x][y].pcolor[layer]) - 1);
00363     the_map.cells[x][y].pcolor[layer][sizeof(the_map.cells[x][y].pcolor[layer]) - 1] = '\0';
00364 
00365     strncpy(the_map.cells[x][y].pname[layer], name, sizeof(the_map.cells[x][y].pname[layer]) - 1);
00366     the_map.cells[x][y].pname[layer][sizeof(the_map.cells[x][y].pname[layer]) - 1] = '\0';
00367 
00368     the_map.cells[x][y].height[layer] = height;
00369     the_map.cells[x][y].zoom[layer] = zoom;
00370     the_map.cells[x][y].align[layer] = align;
00371     the_map.cells[x][y].draw_double[layer] = draw_double;
00372     the_map.cells[x][y].alpha[layer] = alpha;
00373     the_map.cells[x][y].rotate[layer] = rotate;
00374     the_map.cells[x][y].infravision[layer] = infravision;
00375 }
00376 
00381 void map_clear_cell(int x, int y)
00382 {
00383     int i;
00384 
00385     the_map.cells[x][y].darkness = 0;
00386 
00387     for (i = 1; i <= MAX_LAYERS; i++)
00388     {
00389         the_map.cells[x][y].faces[i] = 0;
00390         the_map.cells[x][y].flags[i] = 0;
00391         the_map.cells[x][y].probe[i] = 0;
00392         the_map.cells[x][y].quick_pos[i] = 0;
00393         the_map.cells[x][y].pname[i][0] = '\0';
00394         the_map.cells[x][y].height[i] = 0;
00395         the_map.cells[x][y].zoom[i] = 0;
00396         the_map.cells[x][y].align[i] = 0;
00397         the_map.cells[x][y].rotate[i] = 0;
00398         the_map.cells[x][y].infravision[i] = 0;
00399     }
00400 }
00401 
00407 void map_set_darkness(int x, int y, uint8 darkness)
00408 {
00409     the_map.cells[x][y].darkness = darkness;
00410 }
00411 
00418 static void draw_map_object(int x, int y, int layer, int player_height_offset)
00419 {
00420     struct MapCell *map = &the_map.cells[x][y];
00421     _Sprite *face_sprite;
00422     int ypos, xpos;
00423     int xl, yl, temp;
00424     int xml, xmpos, xtemp = 0;
00425     uint16 face;
00426     int mid, mnr;
00427     uint32 stretch = 0;
00428     _BLTFX bltfx;
00429     int bitmap_h, bitmap_w;
00430 
00431     bltfx.surface = NULL;
00432     xpos = MAP_START_XOFF + x * MAP_TILE_YOFF - y * MAP_TILE_YOFF;
00433     ypos = MAP_START_YOFF + x * MAP_TILE_XOFF + y * MAP_TILE_XOFF;
00434     face = map->faces[layer];
00435 
00436     if (face <= 0 || face >= MAX_FACE_TILES)
00437     {
00438         return;
00439     }
00440 
00441     face_sprite = FaceList[face].sprite;
00442 
00443     if (!face_sprite)
00444     {
00445         return;
00446     }
00447 
00448     bitmap_h = face_sprite->bitmap->h;
00449     bitmap_w = face_sprite->bitmap->w;
00450 
00451     if (map->rotate[layer])
00452     {
00453         rotozoomSurfaceSize(bitmap_w, bitmap_h, map->rotate[layer], map->zoom[layer] ? map->zoom[layer] / 100.0 : 1.0, &bitmap_w, &bitmap_h);
00454     }
00455     else if (map->zoom[layer] && map->zoom[layer] != 100)
00456     {
00457         zoomSurfaceSize(bitmap_w, bitmap_h, map->zoom[layer] / 100.0, map->zoom[layer] / 100.0, &bitmap_w, &bitmap_h);
00458     }
00459 
00460     /* We have a set quick_pos = multi tile */
00461     if (map->quick_pos[layer])
00462     {
00463         mnr = map->quick_pos[layer];
00464         mid = mnr >> 4;
00465         mnr &= 0x0f;
00466         xml = MultiArchs[mid].xlen;
00467         yl = ypos - MultiArchs[mid].part[mnr].yoff + MultiArchs[mid].ylen - bitmap_h;
00468 
00469         /* we allow overlapping x borders - we simply center then */
00470         xl = 0;
00471 
00472         if (bitmap_w > MultiArchs[mid].xlen)
00473         {
00474             xl = (MultiArchs[mid].xlen - bitmap_w) >> 1;
00475         }
00476 
00477         xmpos = xpos - MultiArchs[mid].part[mnr].xoff;
00478         xl += xmpos;
00479     }
00480     /* Single tile... */
00481     else
00482     {
00483         /* First, we calc the shift positions */
00484         xml = MAP_TILE_POS_XOFF;
00485         yl = (ypos + MAP_TILE_POS_YOFF) - bitmap_h;
00486         xmpos = xl = xpos;
00487 
00488         if (bitmap_w > MAP_TILE_POS_XOFF)
00489         {
00490             xl -= (bitmap_w - MAP_TILE_POS_XOFF) / 2;
00491         }
00492     }
00493 
00494     if (map->align[layer])
00495     {
00496         xl += map->align[layer];
00497     }
00498 
00499     /* Blit the face in the darkness level the tile pos has */
00500     temp = map->darkness;
00501 
00502     if (temp == 210)
00503     {
00504         bltfx.dark_level = 0;
00505     }
00506     else if (temp == 180)
00507     {
00508         bltfx.dark_level = 1;
00509     }
00510     else if (temp == 150)
00511     {
00512         bltfx.dark_level = 2;
00513     }
00514     else if (temp == 120)
00515     {
00516         bltfx.dark_level = 3;
00517     }
00518     else if (temp == 90)
00519     {
00520         bltfx.dark_level = 4;
00521     }
00522     else if (temp == 60)
00523     {
00524         bltfx.dark_level = 5;
00525     }
00526     else if (temp == 0)
00527     {
00528         bltfx.dark_level = 7;
00529     }
00530     else
00531     {
00532         bltfx.dark_level = 6;
00533     }
00534 
00535     bltfx.flags = 0;
00536     bltfx.alpha = 0;
00537 
00538     if (map->infravision[layer])
00539     {
00540         bltfx.flags |= BLTFX_FLAG_RED;
00541     }
00542     else
00543     {
00544         bltfx.flags |= BLTFX_FLAG_DARK;
00545     }
00546 
00547     if (map->flags[layer] & FFLAG_INVISIBLE)
00548     {
00549         bltfx.flags &= ~BLTFX_FLAG_DARK;
00550         bltfx.flags |= BLTFX_FLAG_GREY;
00551     }
00552 
00553     if (map->alpha[layer])
00554     {
00555         bltfx.flags &= ~BLTFX_FLAG_DARK;
00556         bltfx.flags |= BLTFX_FLAG_SRCALPHA;
00557         bltfx.alpha = map->alpha[layer];
00558     }
00559 
00560     stretch = 0;
00561 
00562     if (layer <= 2 && map->stretch)
00563     {
00564         bltfx.flags |= BLTFX_FLAG_STRETCH;
00565         stretch = map->stretch;
00566     }
00567 
00568     yl = (yl - map->height[1]) + player_height_offset;
00569 
00570     if (layer > 1)
00571     {
00572         yl -= map->height[layer];
00573     }
00574 
00575     sprite_blt_map(face_sprite, xl, yl, NULL, &bltfx, stretch, map->zoom[layer], map->rotate[layer]);
00576 
00577     /* Double faces are shown twice, one above the other, when not lower
00578      * on the screen than the player. This simulates high walls without
00579      * obscuring the user's view. */
00580     if (map->draw_double[layer])
00581     {
00582         sprite_blt_map(face_sprite, xl, yl - 22, NULL, &bltfx, stretch, map->zoom[layer], map->rotate[layer]);
00583     }
00584 
00585     if (xml == MAP_TILE_POS_XOFF)
00586     {
00587         xtemp = (int) (((double) xml / 100.0) * 25.0);
00588     }
00589     else
00590     {
00591         xtemp = (int) (((double) xml / 100.0) * 20.0);
00592     }
00593 
00594     /* Do we have a playername? Then print it! */
00595     if (setting_get_int(OPT_CAT_MAP, OPT_PLAYER_NAMES) && map->pname[layer][0])
00596     {
00597         if (setting_get_int(OPT_CAT_MAP, OPT_PLAYER_NAMES) == 1 || (setting_get_int(OPT_CAT_MAP, OPT_PLAYER_NAMES) == 2 && strncasecmp(map->pname[layer], cpl.name, strlen(map->pname[layer]))) || (setting_get_int(OPT_CAT_MAP, OPT_PLAYER_NAMES) == 3 && !strncasecmp(map->pname[layer], cpl.name, strlen(map->pname[layer]))))
00598         {
00599             string_blt(cur_widget[MAP_ID]->widgetSF, FONT_SANS9, map->pname[layer], xmpos + xtemp + (xml - xtemp * 2) / 2 - string_get_width(FONT_SANS9, map->pname[layer], 0) / 2 - 2, yl - 24, map->pcolor[layer], TEXT_OUTLINE, NULL);
00600         }
00601     }
00602 
00603     /* Perhaps the object has a marked effect, blit it now */
00604     if (map->flags[layer])
00605     {
00606         if (map->flags[layer] & FFLAG_SLEEP)
00607         {
00608             sprite_blt_map(Bitmaps[BITMAP_SLEEP], xl + bitmap_w / 2, yl - 5, NULL, NULL, 0, map->zoom[layer], map->rotate[layer]);
00609         }
00610 
00611         if (map->flags[layer] & FFLAG_CONFUSED)
00612         {
00613             sprite_blt_map(Bitmaps[BITMAP_CONFUSE], xl + bitmap_w / 2 - 1, yl - 4, NULL, NULL, 0, map->zoom[layer], map->rotate[layer]);
00614         }
00615 
00616         if (map->flags[layer] & FFLAG_SCARED)
00617         {
00618             sprite_blt_map(Bitmaps[BITMAP_SCARED], xl + bitmap_w / 2 + 10, yl - 4, NULL, NULL, 0, map->zoom[layer], map->rotate[layer]);
00619         }
00620 
00621         if (map->flags[layer] & FFLAG_BLINDED)
00622         {
00623             sprite_blt_map(Bitmaps[BITMAP_BLIND], xl + bitmap_w / 2 + 3, yl - 6, NULL, NULL, 0, map->zoom[layer], map->rotate[layer]);
00624         }
00625 
00626         if (map->flags[layer] & FFLAG_PARALYZED)
00627         {
00628             sprite_blt_map(Bitmaps[BITMAP_PARALYZE], xl + bitmap_w / 2 + 2, yl + 3, NULL, NULL, 0, map->zoom[layer], map->rotate[layer]);
00629             sprite_blt_map(Bitmaps[BITMAP_PARALYZE], xl + bitmap_w / 2 + 9, yl + 3, NULL, NULL, 0, map->zoom[layer], map->rotate[layer]);
00630         }
00631     }
00632 
00633     if (map->probe[layer] && cpl.target_code)
00634     {
00635         const char *hp_col;
00636         Uint32 sdl_col;
00637         SDL_Rect rect;
00638         SDL_Color color;
00639 
00640         if (cpl.target_hp > 90)
00641         {
00642             hp_col = COLOR_GREEN;
00643         }
00644         else if (cpl.target_hp > 75)
00645         {
00646             hp_col = COLOR_DGOLD;
00647         }
00648         else if (cpl.target_hp > 50)
00649         {
00650             hp_col = COLOR_HGOLD;
00651         }
00652         else if (cpl.target_hp > 25)
00653         {
00654             hp_col = COLOR_ORANGE;
00655         }
00656         else if (cpl.target_hp > 10)
00657         {
00658             hp_col = COLOR_YELLOW;
00659         }
00660         else
00661         {
00662             hp_col = COLOR_RED;
00663         }
00664 
00665         temp = (xml - xtemp * 2) - 1;
00666 
00667         if (temp <= 0)
00668         {
00669             temp = 1;
00670         }
00671 
00672         if (temp >= 300)
00673         {
00674             temp = 300;
00675         }
00676 
00677         mid = map->probe[layer];
00678 
00679         if (mid <= 0)
00680         {
00681             mid = 1;
00682         }
00683 
00684         if (mid > 100)
00685         {
00686             mid = 100;
00687         }
00688 
00689         temp = (int) (((double) temp / 100.0) * (double) mid);
00690 
00691         rect.h = 2;
00692         rect.w = temp;
00693         rect.x = 0;
00694         rect.y = 0;
00695 
00696         text_color_parse(hp_col, &color);
00697         sdl_col = SDL_MapRGB(cur_widget[MAP_ID]->widgetSF->format, color.r, color.g, color.b);
00698 
00699         /* First draw the bar */
00700         rect.x = xmpos + xtemp - 1;
00701         rect.y = yl - 9;
00702         rect.h = 1;
00703         SDL_FillRect(cur_widget[MAP_ID]->widgetSF, &rect, sdl_col);
00704         /* Horizontal lines of left bracket */
00705         rect.h = 1;
00706         rect.w = 3;
00707         rect.x = xmpos + xtemp - 3;
00708         rect.y = yl - 11;
00709         SDL_FillRect(cur_widget[MAP_ID]->widgetSF, &rect, sdl_col);
00710         rect.y = yl - 7;
00711         SDL_FillRect(cur_widget[MAP_ID]->widgetSF, &rect, sdl_col);
00712         /* Horizontal lines of right bracket */
00713         rect.x = xmpos + xtemp + (xml - xtemp * 2) - 3;
00714         SDL_FillRect(cur_widget[MAP_ID]->widgetSF, &rect, sdl_col);
00715         rect.y = yl - 11;
00716         SDL_FillRect(cur_widget[MAP_ID]->widgetSF, &rect, sdl_col);
00717         /* Vertical lines */
00718         rect.w = 1;
00719         rect.h = 5;
00720         rect.x = xmpos + xtemp - 3;
00721         rect.y = yl - 11;
00722         SDL_FillRect(cur_widget[MAP_ID]->widgetSF, &rect, sdl_col);
00723         rect.x = xmpos + xtemp + (xml - xtemp * 2) - 1;
00724         SDL_FillRect(cur_widget[MAP_ID]->widgetSF, &rect, sdl_col);
00725 
00726         /* Draw the name of target if it's not a player */
00727         if (!(setting_get_int(OPT_CAT_MAP, OPT_PLAYER_NAMES) && map->pname[layer][0]))
00728         {
00729             string_blt(cur_widget[MAP_ID]->widgetSF, FONT_SANS9, cpl.target_name, xmpos + xtemp + (xml - xtemp * 2) / 2 - string_get_width(FONT_SANS9, cpl.target_name, 0) / 2 - 2, yl - 24, cpl.target_color, TEXT_OUTLINE, NULL);
00730         }
00731 
00732         /* Draw HP remaining percent */
00733         if (cpl.target_hp > 0)
00734         {
00735             char hp_text[9];
00736 
00737             snprintf(hp_text, sizeof(hp_text), "HP: %d%%", cpl.target_hp);
00738             string_blt(cur_widget[MAP_ID]->widgetSF, FONT_SANS9, hp_text, xmpos + xtemp + (xml - xtemp * 2) / 2 - string_get_width(FONT_SANS9, hp_text, 0) / 2 - 2, yl - 36, hp_col, TEXT_OUTLINE, NULL);
00739         }
00740     }
00741 }
00742 
00745 void map_draw_map()
00746 {
00747     int player_height_offset;
00748     int x, y, layer;
00749     int tx, ty;
00750 
00751     player_height_offset = the_map.cells[setting_get_int(OPT_CAT_MAP, OPT_MAP_WIDTH) - (setting_get_int(OPT_CAT_MAP, OPT_MAP_WIDTH) / 2) - 1][setting_get_int(OPT_CAT_MAP, OPT_MAP_HEIGHT) - (setting_get_int(OPT_CAT_MAP, OPT_MAP_HEIGHT) / 2) - 1].height[1];
00752 
00753     /* First draw floor and floor masks. */
00754     for (x = 0; x < setting_get_int(OPT_CAT_MAP, OPT_MAP_WIDTH); x++)
00755     {
00756         for (y = 0; y < setting_get_int(OPT_CAT_MAP, OPT_MAP_HEIGHT); y++)
00757         {
00758             for (layer = 1; layer <= 2; layer++)
00759             {
00760                 draw_map_object(x, y, layer, player_height_offset);
00761             }
00762         }
00763     }
00764 
00765     /* Now draw everything else. */
00766     for (x = 0; x < setting_get_int(OPT_CAT_MAP, OPT_MAP_WIDTH); x++)
00767     {
00768         for (y = 0; y < setting_get_int(OPT_CAT_MAP, OPT_MAP_HEIGHT); y++)
00769         {
00770             for (layer = 3; layer <= MAX_LAYERS; layer++)
00771             {
00772                 draw_map_object(x, y, layer, player_height_offset);
00773             }
00774         }
00775     }
00776 
00777     if (cpl.menustatus == MENU_NO && widget_mouse_event.owner == cur_widget[MAP_ID] && mouse_to_tile_coords(x_custom_cursor, y_custom_cursor, &tx, &ty))
00778     {
00779         map_draw_one(tx, ty, Bitmaps[BITMAP_SQUARE_HIGHLIGHT]);
00780     }
00781 }
00782 
00788 void map_draw_one(int x, int y, _Sprite *sprite)
00789 {
00790     int xpos = MAP_START_XOFF + x * MAP_TILE_YOFF - y * MAP_TILE_YOFF;
00791     int ypos = (MAP_START_YOFF + x * MAP_TILE_XOFF + y * MAP_TILE_XOFF) + MAP_TILE_POS_YOFF - sprite->bitmap->h;
00792 
00793     if (sprite->bitmap->w > MAP_TILE_POS_XOFF)
00794     {
00795         xpos -= (sprite->bitmap->w - MAP_TILE_POS_XOFF) / 2;
00796     }
00797 
00798     if (the_map.cells[x][y].faces[1])
00799     {
00800         ypos = (ypos - (the_map.cells[x][y].height[1])) + (the_map.cells[setting_get_int(OPT_CAT_MAP, OPT_MAP_WIDTH) - (setting_get_int(OPT_CAT_MAP, OPT_MAP_WIDTH) / 2) - 1][setting_get_int(OPT_CAT_MAP, OPT_MAP_HEIGHT) - (setting_get_int(OPT_CAT_MAP, OPT_MAP_HEIGHT) / 2) - 1].height[1]);
00801     }
00802 
00803     sprite_blt_map(sprite, xpos, ypos, NULL, NULL, 0, 0, 0);
00804 }
00805 
00810 static void send_move_path(int tx, int ty)
00811 {
00812     SockList sl;
00813     uint8 buf[HUGE_BUF];
00814 
00815     sl.buf = buf;
00816     sl.len = 0;
00817     SockList_AddString(&sl, "mp ");
00818     SockList_AddChar(&sl, tx);
00819     SockList_AddChar(&sl, ty);
00820     send_socklist(sl);
00821 }
00822 
00827 static void send_target(int tx, int ty)
00828 {
00829     char buf[MAX_BUF];
00830 
00831     snprintf(buf, sizeof(buf), "/target !%d %d", tx, ty);
00832     send_command(buf);
00833 }
00834 
00839 void widget_map_mevent(widgetdata *widget, SDL_Event *event)
00840 {
00841     int tx, ty;
00842 
00843     (void) widget;
00844 
00845     /* Check if the mouse is in play field. */
00846     if (!mouse_to_tile_coords(event->motion.x, event->motion.y, &tx, &ty))
00847     {
00848         return;
00849     }
00850 
00851     if (event->type == SDL_MOUSEBUTTONUP)
00852     {
00853         /* Send target command if we released the right button in time;
00854          * otherwise the widget menu will be created. */
00855         if (event->button.button == SDL_BUTTON_RIGHT && SDL_GetTicks() - right_click_ticks < 500)
00856         {
00857             send_target(tx, ty);
00858         }
00859 
00860         right_click_ticks = -1;
00861     }
00862     else if (event->type == SDL_MOUSEBUTTONDOWN)
00863     {
00864         if (event->button.button == SDL_BUTTON_RIGHT)
00865         {
00866             right_click_ticks = SDL_GetTicks();
00867         }
00868         /* Running */
00869         else if (SDL_GetMouseState(NULL, NULL) == SDL_BUTTON_LEFT)
00870         {
00871             if (cpl.fire_on || cpl.run_on)
00872             {
00873                 move_keys(dir_from_tile_coords(tx, ty));
00874             }
00875             else
00876             {
00877                 send_move_path(tx, ty);
00878             }
00879         }
00880     }
00881     else if (event->type == SDL_MOUSEMOTION)
00882     {
00883         if (tx != old_map_mouse_x || ty != old_map_mouse_y)
00884         {
00885             map_redraw_flag = 1;
00886             old_map_mouse_x = tx;
00887             old_map_mouse_y = ty;
00888         }
00889     }
00890 }
00891 
00894 static void menu_map_walk_here(widgetdata *widget, int x, int y)
00895 {
00896     int tx, ty;
00897 
00898     (void) widget;
00899     (void) x;
00900     (void) y;
00901 
00902     if (mouse_to_tile_coords(cur_widget[MENU_ID]->x1, cur_widget[MENU_ID]->y1, &tx, &ty))
00903     {
00904         send_move_path(tx, ty);
00905     }
00906 }
00907 
00910 static void menu_map_talk_to(widgetdata *widget, int x, int y)
00911 {
00912     int tx, ty;
00913 
00914     (void) widget;
00915     (void) x;
00916     (void) y;
00917 
00918     if (mouse_to_tile_coords(cur_widget[MENU_ID]->x1, cur_widget[MENU_ID]->y1, &tx, &ty))
00919     {
00920         send_target(tx, ty);
00921         send_command("/t_tell hi");
00922     }
00923 }
00924 
00928 void widget_map_render(widgetdata *widget)
00929 {
00930     static int gfx_toggle = 0;
00931     SDL_Rect box;
00932     int mx, my;
00933 
00934     if (!widget->widgetSF)
00935     {
00936         widget->widgetSF = SDL_CreateRGBSurface(get_video_flags(), 850, 600, video_get_bpp(), 0, 0, 0, 0);
00937     }
00938 
00939     /* Make sure the map widget is always the last to handle events for. */
00940     SetPriorityWidget_reverse(widget);
00941 
00942     if (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) != 100)
00943     {
00944         int w, h;
00945 
00946         zoomSurfaceSize(widget->widgetSF->w, widget->widgetSF->h, setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0, setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0, &w, &h);
00947         widget->wd = w;
00948         widget->ht = h;
00949     }
00950 
00951     /* We recreate the map only when there is a change. */
00952     if (map_redraw_flag && (!popup_get_visible() || popup_overlay_need_update(popup_get_visible())))
00953     {
00954         SDL_FillRect(widget->widgetSF, NULL, 0);
00955         map_draw_map();
00956         map_redraw_flag = 0;
00957         effect_sprites_play();
00958 
00959         if (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) != 100)
00960         {
00961             if (zoomed)
00962             {
00963                 SDL_FreeSurface(zoomed);
00964             }
00965 
00966             zoomed = zoomSurface(widget->widgetSF, setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0, setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0, setting_get_int(OPT_CAT_MAP, OPT_ZOOM_SMOOTH));
00967         }
00968     }
00969 
00970     box.x = widget->x1;
00971     box.y = widget->y1;
00972 
00973     if (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) == 100)
00974     {
00975         SDL_BlitSurface(widget->widgetSF, NULL, ScreenSurface, &box);
00976     }
00977     else
00978     {
00979         SDL_BlitSurface(zoomed, NULL, ScreenSurface, &box);
00980     }
00981 
00982     /* The damage numbers */
00983     play_anims();
00984 
00985     /* Draw warning icons above player */
00986     if ((gfx_toggle++ & 63) < 25)
00987     {
00988         if (setting_get_int(OPT_CAT_MAP, OPT_HEALTH_WARNING) && ((float) cpl.stats.hp / (float) cpl.stats.maxhp) * 100 <= setting_get_int(OPT_CAT_MAP, OPT_HEALTH_WARNING))
00989         {
00990             sprite_blt(Bitmaps[BITMAP_WARN_HP], widget->x1 + 393 * (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0), widget->y1 + 298 * (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0), NULL, NULL);
00991         }
00992     }
00993     else
00994     {
00995         /* Low food */
00996         if (setting_get_int(OPT_CAT_MAP, OPT_FOOD_WARNING) && ((float) cpl.stats.food / 1000.0f) * 100 <= setting_get_int(OPT_CAT_MAP, OPT_FOOD_WARNING))
00997         {
00998             sprite_blt(Bitmaps[BITMAP_WARN_FOOD], widget->x1 + 390 * (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0), widget->y1 + 294 * (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0), NULL, NULL);
00999         }
01000     }
01001 
01002     /* Process message animations */
01003     if (msg_anim.message[0] != '\0')
01004     {
01005         if ((LastTick - msg_anim.tick) < 3000)
01006         {
01007             int bmoff = (int) ((50.0f / 3.0f) * ((float) (LastTick - msg_anim.tick) / 1000.0f) * ((float) (LastTick - msg_anim.tick) / 1000.0f) + ((int) (150.0f * ((float) (LastTick - msg_anim.tick) / 3000.0f)))), y_offset = 0;
01008             char *msg = strdup(msg_anim.message), *cp;
01009 
01010             cp = strtok(msg, "\n");
01011 
01012             while (cp)
01013             {
01014                 string_blt(ScreenSurface, FONT_SERIF16, cp, widget->x1 + widget->widgetSF->w / 2 - string_get_width(FONT_SERIF16, cp, TEXT_OUTLINE) / 2, widget->y1 + 300 - bmoff + y_offset, msg_anim.color, TEXT_OUTLINE | TEXT_MARKUP, NULL);
01015                 y_offset += FONT_HEIGHT(FONT_SERIF16);
01016                 cp = strtok(NULL, "\n");
01017             }
01018 
01019             free(msg);
01020         }
01021         else
01022         {
01023             msg_anim.message[0] = '\0';
01024         }
01025     }
01026 
01027     /* Holding the right mouse button for some time, create a menu. */
01028     if (SDL_GetMouseState(&mx, &my) == SDL_BUTTON(SDL_BUTTON_RIGHT) && right_click_ticks != -1 && SDL_GetTicks() - right_click_ticks > 500)
01029     {
01030         widgetdata *menu;
01031 
01032         menu = create_menu(mx, my, widget);
01033         add_menuitem(menu, "Walk Here", &menu_map_walk_here, MENU_NORMAL, 0);
01034         add_menuitem(menu, "Talk To NPC", &menu_map_talk_to, MENU_NORMAL, 0);
01035         add_menuitem(menu, "Move Widget", &menu_move_widget, MENU_NORMAL, 0);
01036         menu_finalize(menu);
01037         right_click_ticks = -1;
01038     }
01039 }
01040 
01042 const char tile_off[MAP_TILE_YOFF][MAP_TILE_POS_XOFF] =
01043 {
01044     "000000000000000000000022221111111111111111111111",
01045     "000000000000000000002222222211111111111111111111",
01046     "000000000000000000222222222222111111111111111111",
01047     "000000000000000022222222222222221111111111111111",
01048     "000000000000002222222222222222222211111111111111",
01049     "000000000000222222222222222222222222111111111111",
01050     "000000000022222222222222222222222222221111111111",
01051     "000000002222222222222222222222222222222211111111",
01052     "000000222222222222222222222222222222222222111111",
01053     "000022222222222222222222222222222222222222221111",
01054     "002222222222222222222222222222222222222222222211",
01055     "222222222222222222222222222222222222222222222222",
01056     "332222222222222222222222222222222222222222222244",
01057     "333322222222222222222222222222222222222222224444",
01058     "333333222222222222222222222222222222222222444444",
01059     "333333332222222222222222222222222222222244444444",
01060     "333333333322222222222222222222222222224444444444",
01061     "333333333333222222222222222222222222444444444444",
01062     "333333333333332222222222222222222244444444444444",
01063     "333333333333333322222222222222224444444444444444",
01064     "333333333333333333222222222222444444444444444444",
01065     "333333333333333333332222222244444444444444444444",
01066     "333333333333333333333322224444444444444444444444"
01067 };
01068 
01081 int mouse_to_tile_coords(int mx, int my, int *tx, int *ty)
01082 {
01083     int x, y, xpos, ypos;
01084 
01085     /* Adjust mouse x/y, making it look as if the map was drawn from
01086      * top left corner, in order to simplify comparisons below. */
01087     mx -= (MAP_START_XOFF * (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0)) + cur_widget[MAP_ID]->x1;
01088     my -= (MAP_START_YOFF * (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0)) + cur_widget[MAP_ID]->y1;
01089 
01090     /* Go through all the map squares. */
01091     for (x = setting_get_int(OPT_CAT_MAP, OPT_MAP_WIDTH) - 1; x >= 0; x--)
01092     {
01093         for (y = setting_get_int(OPT_CAT_MAP, OPT_MAP_HEIGHT) - 1; y >= 0; y--)
01094         {
01095             /* X/Y position of the map square. */
01096             xpos = (x * MAP_TILE_YOFF - y * MAP_TILE_YOFF) * (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0);
01097             ypos = (x * MAP_TILE_XOFF + y * MAP_TILE_XOFF) * (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0);
01098 
01099             if (the_map.cells[x][y].faces[1])
01100             {
01101                 ypos = (ypos - (the_map.cells[x][y].height[1]) * (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0)) + (the_map.cells[setting_get_int(OPT_CAT_MAP, OPT_MAP_WIDTH) - (setting_get_int(OPT_CAT_MAP, OPT_MAP_WIDTH) / 2) - 1][setting_get_int(OPT_CAT_MAP, OPT_MAP_HEIGHT) - (setting_get_int(OPT_CAT_MAP, OPT_MAP_HEIGHT) / 2) - 1].height[1]) * (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0);
01102             }
01103 
01104             /* See if this square matches our 48x24 box shape. */
01105             if (mx >= xpos && mx < xpos + (MAP_TILE_POS_XOFF * (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0)) && my >= ypos && my < ypos + (MAP_TILE_YOFF * (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0)))
01106             {
01107                 /* See if the square matches isometric 48x24 tile. */
01108                 if (tile_off[(int) ((my - ypos) / (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0))][(int) ((mx - xpos) / (setting_get_int(OPT_CAT_MAP, OPT_MAP_ZOOM) / 100.0))] == '2')
01109                 {
01110                     if (tx)
01111                     {
01112                         *tx = x;
01113                     }
01114 
01115                     if (ty)
01116                     {
01117                         *ty = y;
01118                     }
01119 
01120                     return 1;
01121                 }
01122             }
01123         }
01124     }
01125 
01126     return 0;
01127 }