Complete.Org: Mailing Lists: Archives: freeciv-dev: March 2004:
[Freeciv-Dev] Re: (PR#7481) meta-ticket for hex maps
Home

[Freeciv-Dev] Re: (PR#7481) meta-ticket for hex maps

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: jdorje@xxxxxxxxxxxxxxxxxxxxx
Subject: [Freeciv-Dev] Re: (PR#7481) meta-ticket for hex maps
From: "rwetmore@xxxxxxxxxxxx" <rwetmore@xxxxxxxxxxxx>
Date: Wed, 31 Mar 2004 13:40:08 -0800
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=7481 >

Excellent stuff ...

I think this hits all the right spots and done things in
the way that generalizing topologies suggested would make
ongoing improvement rapid and incremental rather than big
bang and one-off.

There is of course still a lot of work, but it is clearly
just work and not a minefield of unexpected problems.

Congratulations to all involved in getting things to this stage.

Cheers
RossW
=====

Jason Short wrote:
> <URL: http://rt.freeciv.org/Ticket/Display.html?id=7481 >
> 
> Jason Short wrote:
> 
>><URL: http://rt.freeciv.org/Ticket/Display.html?id=7481 >
>>
>>A hex map is a map with hexagonal tiles.  These tiles can come in two forms:
>>
>>   ____       /\
>>  /    \     /  \
>> /      \    |  |
>> \      /    |  |
>>  \____/     \  /
>>              \/
> 
> 
> OK, throw out everything I said before, except the above.  I will 
> henceforth rename these iso-hex (on the left) and hex (on the right).
> 
> All of the following has been tested for iso-hex.  I haven't tested hex 
> at all, since I don't have a hex tileset.
> 
> Hex, iso, and non-iso view are all compatible.  They can all use the 
> same map coordinate representation.  However if the view doesn't match 
> up with the map you'll get a bad interface.
> 
> So, we have two separate tasks: implementing hex maps, and implementing 
> a hex view.
> 
> 
> We'll start with hex view.  Hex view can be done in almost exactly the 
> same way as iso-view!  A while ago Andreas Rosdal made an iso-hex view 
> tileset as an extension of iso-view.  You can see a screenshot at
> 
>    http://www.freeciv.org/screenshots/1.14.1/index.phtml?only=isophex
> 
> and download the tileset at
> 
>    ftp://ftp.freeciv.org/freeciv/contrib/tilesets/isophex/
> 
> Since iso-view is typically tilted this means the cartesian (map) 
> coordinate system for a hex map should be tilted with reference to the 
> mapview.  In other words the native and cartesian coordinate systems for 
> iso-hex-maps should be the same as for iso-maps (this comes into play 
> later).
> 
> Only a very few changes are needed to iso-view to support hex maps. 
> I've implemented this by setting
> 
>    is_isometric = 1
>    hex_side = 16
> 
> in the tileset.  The hex side specifies how long the "extra" side (in he 
> iso-hex-view case, top and bottom) of the hexagon is.  A small amount of 
> extra code is needed to support hex-view:
> 
>    hex_isometric = 1
> 
> the representation of these in the tileset fairly inconsequential. 
> What's significant is that both types of hex maps should have 
> is_isometric set.
> 
> A little bit of extra code is needed in the drawing.  The only thing I 
> could find that didn't work solely by changing the tileset sprites is 
> the map grid.  Here we need to draw the extra side, which is where the 
> hex_side (and potentially hex_isometric) variables come into play.
> 
> 
> Now for hex maps.  Both hex and iso-hex will use the same cartesian 
> representation; however, this representation is only an approximation. 
> We have to filter out certain directions.  This amounts to changing 
> is_valid_dir so that southeast and northwest are excluded for a hex-map 
> and northeast and southwest excluded for an iso-hex-map.  This change is 
> made direclty in is_valid_dir; then we just need to use is_valid_dir in 
> a few more places (basically every where DIRSTEP is used).
> 
> The topology_id needs an extra bit.  Now there are 16 possible 
> topologies.  Marcelo's suggestion of simplifying the list of choices 
> becomes more attractive.
> 
> The next change is to the map_distance functions.  map_distance_vector 
> remains the same but isn't quite as useful.  map_distance, 
> real_map_distance, and sq_map_distance should all be the same.  They can 
> call map_distance_vector but must interpret the vector a bit to get 
> their return values.
> 
> There are some mapgen changes needed.  These are fairly non-critical; 
> things like make_polar and make_passable need tweaking to get the right 
> combinations.
> 
> Probably the hardest part is changing the citymap.  In a hex map of 
> course the citymap should just be a hex circle.  Changing this will 
> probably be fairly hard; something along the lines of Remi's city radius 
> work will probably do it.  But this isn't critical for an initial 
> implementation.
> 
> And that's it!  With these changes, things pretty much work.
> 
> Try the attached patch (gtk2 only) with /set topology 13 and the isophex 
> tileset from above.  See
> 
>    http://freeciv.org/~jdorje/hex.png
>    http://freeciv.org/~jdorje/iso.png
>    http://freeciv.org/~jdorje/non-iso.png
> 
> These screenshots all show an iso-hex map (topology 13) with different 
> tilesets.  The hex tileset is obviously the best since it shows the tile 
> relations properly.  With the other two, moves in certain directions 
> will fail.  Of course you won't see this in a screenshot; you'll only 
> see it if you play the game.
> 
> jason
> 
> P.S.  Much thanks to Andreas Rosdal for creating the isophex tileset! 
> Now we just need a hex tileset tilted the other way...
> 
> 
> 
> 
> ------------------------------------------------------------------------
> 
> ? cma_weirdness
> ? data/civ3
> ? data/womoks
> Index: client/mapview_common.c
> ===================================================================
> RCS file: /home/freeciv/CVS/freeciv/client/mapview_common.c,v
> retrieving revision 1.98
> diff -u -r1.98 mapview_common.c
> --- client/mapview_common.c   29 Mar 2004 19:17:06 -0000      1.98
> +++ client/mapview_common.c   31 Mar 2004 21:09:35 -0000
> @@ -1467,6 +1467,7 @@
>    }
>    canvas_src_x += NORMAL_TILE_WIDTH/2;
>    canvas_src_y += NORMAL_TILE_HEIGHT/2;
> +  assert(is_valid_dir(dir));
>    DIRSTEP(canvas_dest_x, canvas_dest_y, dir);
>    canvas_dest_x = canvas_src_x + (NORMAL_TILE_WIDTH * canvas_dest_x) / 2;
>    canvas_dest_y = canvas_src_y + (NORMAL_TILE_WIDTH * canvas_dest_y) / 2;
> Index: client/tilespec.c
> ===================================================================
> RCS file: /home/freeciv/CVS/freeciv/client/tilespec.c,v
> retrieving revision 1.155
> diff -u -r1.155 tilespec.c
> --- client/tilespec.c 30 Mar 2004 19:07:31 -0000      1.155
> +++ client/tilespec.c 31 Mar 2004 21:09:35 -0000
> @@ -76,6 +76,7 @@
>  int OVERVIEW_TILE_HEIGHT = 2;
>  
>  bool is_isometric;
> +int hex_side;
>  
>  char *city_names_font;
>  char *city_productions_font_name;
> @@ -662,6 +663,7 @@
>      free(fname);
>      return tilespec_read_toplevel(NULL);
>    }
> +  hex_side = secfile_lookup_int_default(file, 0, "tilespec.hex_side");
>  
>    NORMAL_TILE_WIDTH = secfile_lookup_int(file, "tilespec.normal_tile_width");
>    NORMAL_TILE_HEIGHT = secfile_lookup_int(file, 
> "tilespec.normal_tile_height");
> Index: client/tilespec.h
> ===================================================================
> RCS file: /home/freeciv/CVS/freeciv/client/tilespec.h,v
> retrieving revision 1.59
> diff -u -r1.59 tilespec.h
> --- client/tilespec.h 30 Mar 2004 19:07:32 -0000      1.59
> +++ client/tilespec.h 31 Mar 2004 21:09:35 -0000
> @@ -270,6 +270,7 @@
>  extern int OVERVIEW_TILE_HEIGHT;
>  
>  extern bool is_isometric;
> +extern int hex_side;
>  
>  /* name of font to use to draw city names on main map */
>  
> Index: client/gui-gtk-2.0/mapview.c
> ===================================================================
> RCS file: /home/freeciv/CVS/freeciv/client/gui-gtk-2.0/mapview.c,v
> retrieving revision 1.112
> diff -u -r1.112 mapview.c
> --- client/gui-gtk-2.0/mapview.c      31 Mar 2004 18:42:45 -0000      1.112
> +++ client/gui-gtk-2.0/mapview.c      31 Mar 2004 21:09:36 -0000
> @@ -1204,15 +1204,15 @@
>  
>    /*** Map grid ***/
>    if (draw_map_grid && !tile_hilited) {
> -    /* we draw the 2 lines on top of the tile; the buttom lines will be
> +    /* we draw the 3 lines on top of the tile; the buttom lines will be
>         drawn by the tiles underneath. */
>      if (draw & D_M_R) {
>        gdk_gc_set_foreground(thin_line_gc,
>                           colors_standard[get_grid_color
>                                           (x, y, x, y - 1)]);
>        gdk_draw_line(pm, thin_line_gc,
> -                 canvas_x + NORMAL_TILE_WIDTH / 2, canvas_y,
> -                 canvas_x + NORMAL_TILE_WIDTH,
> +                 canvas_x + (NORMAL_TILE_WIDTH + hex_side) / 2, canvas_y,
> +                 canvas_x + NORMAL_TILE_WIDTH - hex_side / 2,
>                   canvas_y + NORMAL_TILE_HEIGHT / 2);
>      }
>  
> @@ -1221,8 +1221,18 @@
>                           colors_standard[get_grid_color
>                                           (x, y, x - 1, y)]);
>        gdk_draw_line(pm, thin_line_gc,
> -                 canvas_x, canvas_y + NORMAL_TILE_HEIGHT / 2,
> -                 canvas_x + NORMAL_TILE_WIDTH / 2, canvas_y);
> +                 canvas_x + hex_side / 2,
> +                 canvas_y + NORMAL_TILE_HEIGHT / 2,
> +                 canvas_x + (NORMAL_TILE_WIDTH - hex_side) / 2, canvas_y);
> +    }
> +
> +    if (hex_side > 0 && (draw & D_M_LR)) {
> +      gdk_gc_set_foreground(thin_line_gc,
> +                         colors_standard[get_grid_color
> +                                         (x, y, x - 1, y - 1)]);
> +      gdk_draw_line(pm, thin_line_gc,
> +                 canvas_x + (NORMAL_TILE_WIDTH - hex_side) / 2, canvas_y,
> +                 canvas_x + (NORMAL_TILE_WIDTH + hex_side) / 2, canvas_y);
>      }
>    }
>  
> Index: common/map.c
> ===================================================================
> RCS file: /home/freeciv/CVS/freeciv/common/map.c,v
> retrieving revision 1.163
> diff -u -r1.163 map.c
> --- common/map.c      26 Feb 2004 13:19:47 -0000      1.163
> +++ common/map.c      31 Mar 2004 21:09:36 -0000
> @@ -323,11 +323,15 @@
>  ***************************************************************/
>  int real_map_distance(int x0, int y0, int x1, int y1)
>  {
> -  int dx, dy;
> +  if (topo_has_flag(TF_HEX)) {
> +    return map_distance(x0, y0, x1, y1);
> +  } else {
> +    int dx, dy;
>  
> -  map_distance_vector(&dx, &dy, x0, y0, x1, y1);
> +    map_distance_vector(&dx, &dy, x0, y0, x1, y1);
>  
> -  return MAX(abs(dx), abs(dy));
> +    return MAX(abs(dx), abs(dy));
> +  }
>  }
>  
>  /***************************************************************
> @@ -335,13 +339,22 @@
>  ***************************************************************/
>  int sq_map_distance(int x0, int y0, int x1, int y1)
>  {
> -  /* We assume map_distance_vector gives us the vector with the
> -     minimum squared distance. Right now this is true. */
> -  int dx, dy;
> +  if (topo_has_flag(TF_HEX)) {
> +    int dist = map_distance(x0, y0, x1, y1);
>  
> -  map_distance_vector(&dx, &dy, x0, y0, x1, y1);
> +    /* In a hex map the pythagorean distance is not significantly different
> +     * from the map distance.  If you think about what the value's used
> +     * for it becomes apparent the two should be the same. */
> +    return dist * dist;
> +  } else {
> +    /* We assume map_distance_vector gives us the vector with the
> +     * minimum squared distance. Right now this is true. */
> +    int dx, dy;
>  
> -  return (dx*dx + dy*dy);
> +    map_distance_vector(&dx, &dy, x0, y0, x1, y1);
> +
> +    return dx * dx + dy * dy;
> +  }
>  }
>  
>  /***************************************************************
> @@ -355,7 +368,33 @@
>  
>    map_distance_vector(&dx, &dy, x0, y0, x1, y1);
>  
> -  return abs(dx) + abs(dy);
> +  if (topo_has_flag(TF_HEX)) {
> +    if (topo_has_flag(TF_ISO)) {
> +      /* Iso-hex: you can't move NE or SW. */
> +      if ((dx < 0 && dy > 0)
> +       || (dx > 0 && dy < 0)) {
> +     /* Diagonal moves in this direction aren't allowed, so it will take
> +      * the full number of moves. */
> +     return abs(dx) + abs(dy);
> +      } else {
> +     /* Diagonal moves in this direction *are* allowed. */
> +     return MAX(abs(dx), abs(dy));
> +      }
> +    } else {
> +      /* Hex: you can't move SE or NW. */
> +      if ((dx > 0 && dy > 0)
> +       || (dx < 0 && dy < 0)) {
> +     /* Diagonal moves in this direction aren't allowed, so it will take
> +      * the full number of moves. */
> +     return abs(dx) + abs(dy);
> +      } else {
> +     /* Diagonal moves in this direction *are* allowed. */
> +     return MAX(abs(dx), abs(dy));
> +      }
> +    }
> +  } else {
> +    return abs(dx) + abs(dy);
> +  }
>  }
>  
>  /***************************************************************
> @@ -1520,14 +1559,16 @@
>  bool is_valid_dir(enum direction8 dir)
>  {
>    switch (dir) {
> -  case DIR8_NORTH:
> +  case DIR8_SOUTHEAST:
> +  case DIR8_NORTHWEST:
> +    return !(topo_has_flag(TF_HEX) && !topo_has_flag(TF_ISO));
>    case DIR8_NORTHEAST:
> +  case DIR8_SOUTHWEST:
> +    return !(topo_has_flag(TF_HEX) && topo_has_flag(TF_ISO));
> +  case DIR8_NORTH:
>    case DIR8_EAST:
> -  case DIR8_SOUTHEAST:
>    case DIR8_SOUTH:
> -  case DIR8_SOUTHWEST:
>    case DIR8_WEST:
> -  case DIR8_NORTHWEST:
>      return TRUE;
>    default:
>      return FALSE;
> Index: common/map.h
> ===================================================================
> RCS file: /home/freeciv/CVS/freeciv/common/map.h,v
> retrieving revision 1.177
> diff -u -r1.177 map.h
> --- common/map.h      26 Feb 2004 13:19:47 -0000      1.177
> +++ common/map.h      31 Mar 2004 21:09:36 -0000
> @@ -150,7 +150,8 @@
>    /* Bit-values. */
>    TF_WRAPX = 1,
>    TF_WRAPY = 2,
> -  TF_ISO = 4
> +  TF_ISO = 4,
> +  TF_HEX = 8
>  };
>  
>  #define CURRENT_TOPOLOGY (map.topology_id)
> @@ -199,13 +200,13 @@
>  
>  /* Obscure math.  See explanation in doc/HACKING. */
>  #define native_to_map_pos(pmap_x, pmap_y, nat_x, nat_y)                     \
> -  (topo_has_flag(TF_ISO)                                                    \
> +  ((topo_has_flag(TF_ISO) || topo_has_flag(TF_HEX))                         \
>     ? (*(pmap_x) = ((nat_y) + ((nat_y) & 1)) / 2 + (nat_x),                  \
>        *(pmap_y) = (nat_y) - *(pmap_x) + map.xsize)                          \
>     : (*(pmap_x) = (nat_x), *(pmap_y) = (nat_y)))
>  
>  #define map_to_native_pos(pnat_x, pnat_y, map_x, map_y)                     \
> -  (topo_has_flag(TF_ISO)                                                    \
> +  ((topo_has_flag(TF_ISO) || topo_has_flag(TF_HEX))                      \
>     ? (*(pnat_y) = (map_x) + (map_y) - map.xsize,                            \
>        *(pnat_x) = (2 * (map_x) - *(pnat_y) - (*(pnat_y) & 1)) / 2)          \
>     : (*(pnat_x) = (map_x), *(pnat_y) = (map_y)))
> @@ -232,9 +233,10 @@
>   * we bend this rule here.
>   */
>  #define MAPSTEP(dest_x, dest_y, src_x, src_y, dir)   \
> -(    (dest_x) = (src_x) + DIR_DX[(dir)],             \
> -     (dest_y) = (src_y) + DIR_DY[(dir)],             \
> -     normalize_map_pos(&(dest_x), &(dest_y)))
> +  (is_valid_dir(dir)                                    \
> +   && ((dest_x) = (src_x) + DIR_DX[(dir)],           \
> +       (dest_y) = (src_y) + DIR_DY[(dir)],           \
> +       normalize_map_pos(&(dest_x), &(dest_y))))
>  
>  struct player *map_get_owner(int x, int y);
>  void map_set_owner(int x, int y, struct player *pplayer);
> @@ -269,7 +271,7 @@
>   * TODO: implement this for iso-maps.
>   */
>  #define IS_BORDER_MAP_POS(x, y, dist)                         \
> -  (topo_has_flag(TF_ISO)                                      \
> +  (topo_has_flag(TF_ISO) || topo_has_flag(TF_HEX)          \
>     || (x) < (dist) || (x) >= map.xsize - (dist)               \
>     || (y) < (dist) || (y) >= map.ysize - (dist))
>  
> @@ -488,6 +490,9 @@
>    int MACRO_center_y = (center_y);                                           
>  \
>    CHECK_MAP_POS(MACRO_center_x, MACRO_center_y);                             
>  \
>    for (dir_itr = 0; dir_itr < 8; dir_itr++) {                                
>  \
> +    if (!is_valid_dir(dir_itr)) {                                          \
> +      continue;                                                              
>       \
> +    }                                                                        
>       \
>      DIRSTEP(x_itr, y_itr, dir_itr);                                          
>  \
>      x_itr += MACRO_center_x;                                                 
>  \
>      y_itr += MACRO_center_y;                                                 
>  \
> @@ -577,6 +582,7 @@
>    bool _is_border = IS_BORDER_MAP_POS(x, y, 1);                              
>  \
>    CHECK_MAP_POS(x, y);                                                       
>  \
>    for (IAC_i = 0; IAC_i < 4; IAC_i++) {                                      
>  \
> +    /* All cardinal directions are valid. */                               \
>      IAC_x = x + CAR_DIR_DX[IAC_i];                                           
>  \
>      IAC_y = y + CAR_DIR_DY[IAC_i];                                           
>  \
>                                                                               
>  \
> @@ -606,7 +612,7 @@
>  #define MAP_ORIGINAL_TOPO        TF_WRAPX
>  #define MAP_DEFAULT_TOPO         TF_WRAPX
>  #define MAP_MIN_TOPO             0
> -#define MAP_MAX_TOPO             7
> +#define MAP_MAX_TOPO             15
>  
>  #define MAP_DEFAULT_SEED         0
>  #define MAP_MIN_SEED             0
> Index: server/mapgen.c
> ===================================================================
> RCS file: /home/freeciv/CVS/freeciv/server/mapgen.c,v
> retrieving revision 1.131
> diff -u -r1.131 mapgen.c
> --- server/mapgen.c   12 Mar 2004 05:50:48 -0000      1.131
> +++ server/mapgen.c   31 Mar 2004 21:09:37 -0000
> @@ -813,7 +813,7 @@
>      nat_set_terrain(x, 2, T_OCEAN);
>  
>      /* Iso-maps need two lines of ocean. */
> -    if (myrand(2) != 0 || topo_has_flag(TF_ISO)) {
> +    if (myrand(2) != 0 || (topo_has_flag(TF_ISO) && !topo_has_flag(TF_HEX))) 
> {
>        nat_set_terrain(x, 1, T_OCEAN);
>      }
>  
> @@ -823,7 +823,7 @@
>  
>      nat_set_terrain(x, map.ysize - 3, T_OCEAN);
>  
> -    if (myrand(2) != 0 || topo_has_flag(TF_ISO)) {
> +    if (myrand(2) != 0 || (topo_has_flag(TF_ISO) && topo_has_flag(TF_HEX))) {
>        nat_set_terrain(x, map.ysize - 2, T_OCEAN);
>      }
>      if (myrand(2) != 0) {
> Index: server/srv_main.c
> ===================================================================
> RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
> retrieving revision 1.157
> diff -u -r1.157 srv_main.c
> --- server/srv_main.c 26 Mar 2004 18:11:32 -0000      1.157
> +++ server/srv_main.c 31 Mar 2004 21:09:37 -0000
> @@ -1603,7 +1603,7 @@
>    test_random1(200000);
>  #endif
>      
> -  if (topo_has_flag(TF_ISO) && topo_has_flag(TF_WRAPY)
> +  if ((topo_has_flag(TF_ISO) || topo_has_flag(TF_HEX)) && 
> topo_has_flag(TF_WRAPY)
>        && (map.ysize % 2 == 1)) {
>      /* To wrap north-south an iso-map must have even Y dimension.  Since the
>       * X dimension is compressed this isn't an issue for east-west
> Index: server/stdinhand.c
> ===================================================================
> RCS file: /home/freeciv/CVS/freeciv/server/stdinhand.c,v
> retrieving revision 1.311
> diff -u -r1.311 stdinhand.c
> --- server/stdinhand.c        26 Mar 2004 16:45:13 -0000      1.311
> +++ server/stdinhand.c        31 Mar 2004 21:09:38 -0000
> @@ -249,10 +249,14 @@
>         N_("Two-dimensional maps can wrap at the north-south or \n"
>            "east-west edges, and use a cartesian or isometric \n"
>            "rectangular grid.  See the manual for further explanation.\n"
> -             "  0 Flat Earth (unwrapped)          4 Flat Earth (isometric)\n"
> -             "  1 Earth (wraps E-W)               5 Earth (isometric)\n"
> -             "  2 Uranus (wraps N-S)              6 Uranus (isometric)\n"
> -             "  3 Donut World (wraps N-S, E-W)    7 Donut World (isometric)"
> +             "  0 Flat Earth (unwrapped)\n"
> +          "    4 => isometric, 8 => hexagonal; 12 => iso-hex\n"
> +             "  1 Earth (wraps E-W)\n"
> +          "    5 => isometric, 9 => hexagonal; 13 => iso-hex\n"
> +             "  2 Uranus (wraps N-S)\n"
> +          "    6 => isometric, 10 => hexagonal; 14 => iso-hex\n"
> +             "  3 Donut World (wraps N-S, E-W)\n"
> +          "    7 => isometric, 11 => hexagonal; 15 => iso-hex"
>            ), NULL, 
>         MAP_MIN_TOPO, MAP_MAX_TOPO, MAP_DEFAULT_TOPO)
>  




[Prev in Thread] Current Thread [Next in Thread]