smallmap_gui.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "clear_map.h"
00014 #include "industry.h"
00015 #include "station_map.h"
00016 #include "landscape.h"
00017 #include "window_gui.h"
00018 #include "tree_map.h"
00019 #include "viewport_func.h"
00020 #include "town.h"
00021 #include "blitter/factory.hpp"
00022 #include "tunnelbridge_map.h"
00023 #include "strings_func.h"
00024 #include "core/endian_func.hpp"
00025 #include "vehicle_base.h"
00026 #include "sound_func.h"
00027 #include "window_func.h"
00028 #include "company_base.h"
00029 //#include "cargotype.h"
00030 //#include "openttd.h"
00031 #include "company_func.h"
00032 #include "station_base.h"
00033 
00034 #include "table/strings.h"
00035 
00036 //#include <cmath>
00037 #include <vector>
00038 
00040 enum SmallMapWindowWidgets {
00041   SM_WIDGET_CAPTION,           
00042   SM_WIDGET_MAP_BORDER,        
00043   SM_WIDGET_MAP,               
00044   SM_WIDGET_LEGEND,            
00045   SM_WIDGET_BLANK,             
00046   SM_WIDGET_ZOOM_IN,           
00047   SM_WIDGET_ZOOM_OUT,          
00048   SM_WIDGET_CONTOUR,           
00049   SM_WIDGET_VEHICLES,          
00050   SM_WIDGET_INDUSTRIES,        
00051   SM_WIDGET_LINKSTATS,         
00052   SM_WIDGET_ROUTES,            
00053   SM_WIDGET_VEGETATION,        
00054   SM_WIDGET_OWNERS,            
00055   SM_WIDGET_CENTERMAP,         
00056   SM_WIDGET_TOGGLETOWNNAME,    
00057   SM_WIDGET_SELECT_BUTTONS,    
00058   SM_WIDGET_ENABLE_ALL,        
00059   SM_WIDGET_DISABLE_ALL,       
00060   SM_WIDGET_SHOW_HEIGHT,       
00061 };
00062 
00063 static int _smallmap_industry_count;         
00064 static int _smallmap_company_count;          
00065 static const int NUM_NO_COMPANY_ENTRIES = 4; 
00066 static int _smallmap_cargo_count;            
00067 
00068 static const uint8 PC_ROUGH_LAND      = 0x52; 
00069 static const uint8 PC_GRASS_LAND      = 0x54; 
00070 static const uint8 PC_BARE_LAND       = 0x37; 
00071 static const uint8 PC_FIELDS          = 0x25; 
00072 static const uint8 PC_TREES           = 0x57; 
00073 static const uint8 PC_WATER           = 0xCA; 
00074 
00075 enum SmallMapStats {
00076   STAT_CAPACITY,
00077   STAT_BEGIN = STAT_CAPACITY,
00078   STAT_USAGE,
00079   STAT_PLANNED,
00080   STAT_SENT,
00081   STAT_TEXT,
00082   STAT_GRAPH,
00083   STAT_END,
00084   NUM_STATS = STAT_END,
00085 };
00086 
00088 #define MK(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, false}
00089 
00091 #define MC(height)  {0, STR_TINY_BLACK_HEIGHT, INVALID_INDUSTRYTYPE, height, INVALID_COMPANY, true, false, false}
00092 
00097 #define MS(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, true}
00098 
00100 #define MCS(height)  {0, STR_TINY_BLACK_HEIGHT, INVALID_INDUSTRYTYPE, height, INVALID_COMPANY, true, false, true}
00101 
00103 #define MO(a, b) {a, b, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, false, false}
00104 
00106 #define MOEND() {0, 0, INVALID_INDUSTRYTYPE, 0, OWNER_NONE, true, true, false}
00107 
00109 #define MKEND() {0, STR_NULL, INVALID_INDUSTRYTYPE, 0, INVALID_COMPANY, true, true, false}
00110 
00112 struct LegendAndColour {
00113   uint8 colour;              
00114   StringID legend;           
00115   IndustryType type;         
00116   uint8 height;              
00117   CompanyID company;         
00118   bool show_on_map;          
00119   bool end;                  
00120   bool col_break;            
00121 };
00122 
00124 static LegendAndColour _legend_land_contours_old[] = {
00125   /* The colours for the following values are set at BuildLandLegend() based on each colour scheme when the more height levels patch is off. */
00126   MC(1),
00127   MC(5),
00128   MC(9),
00129   MC(13),
00130   MC(15),
00131 
00132   MS(PC_BLACK,           STR_SMALLMAP_LEGENDA_ROADS),
00133   MK(PC_GREY,            STR_SMALLMAP_LEGENDA_RAILROADS),
00134   MK(PC_LIGHT_BLUE,      STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS),
00135   MK(PC_DARK_RED,        STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00136   MK(PC_WHITE,           STR_SMALLMAP_LEGENDA_VEHICLES),
00137   MKEND()
00138 };
00139 
00141 static LegendAndColour _legend_land_contours_extended[] = {
00142   /* The colours for the following values are set at BuildLandLegend() based on each colour scheme when the more height levels patch is on. */
00143   MC(1),
00144   MC(16),
00145   MC(32),
00146   MC(48),
00147   MC(64),
00148   MC(80),
00149 
00150   MCS(96),
00151   MC(112),
00152   MC(128),
00153   MC(144),
00154   MC(160),
00155   MC(176),
00156 
00157   MCS(192),
00158   MC(208),
00159   MC(224),
00160   MC(240),
00161   MC(255),
00162 
00163   MS(PC_BLACK,      STR_SMALLMAP_LEGENDA_ROADS),
00164   MK(PC_GREY,       STR_SMALLMAP_LEGENDA_RAILROADS),
00165   MK(PC_LIGHT_BLUE, STR_SMALLMAP_LEGENDA_STATIONS_AIRPORTS_DOCKS),
00166   MK(PC_DARK_RED,   STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00167   MK(PC_WHITE,      STR_SMALLMAP_LEGENDA_VEHICLES),
00168   MKEND()
00169 };
00170 
00171 static const LegendAndColour _legend_vehicles[] = {
00172   MK(PC_RED,             STR_SMALLMAP_LEGENDA_TRAINS),
00173   MK(PC_YELLOW,          STR_SMALLMAP_LEGENDA_ROAD_VEHICLES),
00174   MK(PC_LIGHT_BLUE,      STR_SMALLMAP_LEGENDA_SHIPS),
00175   MK(PC_WHITE,           STR_SMALLMAP_LEGENDA_AIRCRAFT),
00176 
00177   MS(PC_BLACK,           STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES),
00178   MK(PC_DARK_RED,        STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00179   MKEND()
00180 };
00181 
00182 static const LegendAndColour _legend_routes[] = {
00183   MK(PC_BLACK,           STR_SMALLMAP_LEGENDA_ROADS),
00184   MK(PC_GREY,            STR_SMALLMAP_LEGENDA_RAILROADS),
00185   MK(PC_DARK_RED,        STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00186 
00187   MS(PC_VERY_DARK_BROWN, STR_SMALLMAP_LEGENDA_RAILROAD_STATION),
00188   MK(PC_ORANGE,          STR_SMALLMAP_LEGENDA_TRUCK_LOADING_BAY),
00189   MK(PC_YELLOW,          STR_SMALLMAP_LEGENDA_BUS_STATION),
00190   MK(PC_RED,             STR_SMALLMAP_LEGENDA_AIRPORT_HELIPORT),
00191   MK(PC_LIGHT_BLUE,      STR_SMALLMAP_LEGENDA_DOCK),
00192   MKEND()
00193 };
00194 
00195 static const LegendAndColour _legend_vegetation[] = {
00196   MK(PC_ROUGH_LAND,      STR_SMALLMAP_LEGENDA_ROUGH_LAND),
00197   MK(PC_GRASS_LAND,      STR_SMALLMAP_LEGENDA_GRASS_LAND),
00198   MK(PC_BARE_LAND,       STR_SMALLMAP_LEGENDA_BARE_LAND),
00199   MK(PC_FIELDS,          STR_SMALLMAP_LEGENDA_FIELDS),
00200   MK(PC_TREES,           STR_SMALLMAP_LEGENDA_TREES),
00201   MK(PC_GREEN,           STR_SMALLMAP_LEGENDA_FOREST),
00202 
00203   MS(PC_GREY,            STR_SMALLMAP_LEGENDA_ROCKS),
00204   MK(PC_ORANGE,          STR_SMALLMAP_LEGENDA_DESERT),
00205   MK(PC_LIGHT_BLUE,      STR_SMALLMAP_LEGENDA_SNOW),
00206   MK(PC_BLACK,           STR_SMALLMAP_LEGENDA_TRANSPORT_ROUTES),
00207   MK(PC_DARK_RED,        STR_SMALLMAP_LEGENDA_BUILDINGS_INDUSTRIES),
00208   MKEND()
00209 };
00210 
00211 static LegendAndColour _legend_land_owners[NUM_NO_COMPANY_ENTRIES + MAX_COMPANIES + 1] = {
00212   MO(PC_WATER,           STR_SMALLMAP_LEGENDA_WATER),
00213   MO(0x00,               STR_SMALLMAP_LEGENDA_NO_OWNER), // This colour will vary depending on settings.
00214   MO(PC_DARK_RED,        STR_SMALLMAP_LEGENDA_TOWNS),
00215   MO(PC_DARK_GREY,       STR_SMALLMAP_LEGENDA_INDUSTRIES),
00216   /* The legend will be terminated the first time it is used. */
00217   MOEND(),
00218 };
00219 
00220 #undef MK
00221 #undef MC
00222 #undef MS
00223 #undef MCS
00224 #undef MO
00225 #undef MOEND
00226 #undef MKEND
00227 
00232 static LegendAndColour _legend_from_industries[NUM_INDUSTRYTYPES + 1];
00234 static uint _industry_to_list_pos[NUM_INDUSTRYTYPES];
00236 static bool _smallmap_show_heightmap = false;
00238 static uint _company_to_list_pos[MAX_COMPANIES];
00239 
00243 void BuildIndustriesLegend()
00244 {
00245   uint j = 0;
00246 
00247   /* Add each name */
00248   for (uint8 i = 0; i < NUM_INDUSTRYTYPES; i++) {
00249     IndustryType ind = _sorted_industry_types[i];
00250     const IndustrySpec *indsp = GetIndustrySpec(ind);
00251     if (indsp->enabled) {
00252       _legend_from_industries[j].legend = indsp->name;
00253       _legend_from_industries[j].colour = indsp->map_colour;
00254       _legend_from_industries[j].type = ind;
00255       _legend_from_industries[j].show_on_map = true;
00256       _legend_from_industries[j].col_break = false;
00257       _legend_from_industries[j].end = false;
00258 
00259       /* Store widget number for this industry type. */
00260       _industry_to_list_pos[ind] = j;
00261       j++;
00262     }
00263   }
00264   /* Terminate the list */
00265   _legend_from_industries[j].end = true;
00266 
00267   /* Store number of enabled industries */
00268   _smallmap_industry_count = j;
00269 }
00270 
00271 static LegendAndColour _legend_linkstats[NUM_CARGO + NUM_STATS + 1];
00272 
00276 void BuildLinkStatsLegend()
00277 {
00278   /* Clear the legend */
00279   memset(_legend_linkstats, 0, sizeof(_legend_linkstats));
00280 
00281   uint i = 0;
00282   for (; i < _sorted_cargo_specs_size; ++i) {
00283     const CargoSpec *cs = _sorted_cargo_specs[i];
00284 
00285     _legend_linkstats[i].legend = cs->name;
00286     _legend_linkstats[i].colour = cs->legend_colour;
00287     _legend_linkstats[i].type = cs->Index();
00288     _legend_linkstats[i].show_on_map = true;
00289   }
00290 
00291   _legend_linkstats[i].col_break = true;
00292 
00293   _smallmap_cargo_count = i;
00294 
00295   /* the colours cannot be resolved before the gfx system is initialized.
00296    * So we have to build the legend when creating the window.
00297    */
00298   for (uint st = 0; st < NUM_STATS; ++st) {
00299     LegendAndColour & legend_entry = _legend_linkstats[i + st];
00300     switch(st) {
00301     case STAT_CAPACITY:
00302       legend_entry.colour = _colour_gradient[COLOUR_WHITE][7];
00303       legend_entry.legend = STR_SMALLMAP_LEGENDA_CAPACITY;
00304       legend_entry.show_on_map = true;
00305       break;
00306     case STAT_USAGE:
00307       legend_entry.colour = _colour_gradient[COLOUR_GREY][1];
00308       legend_entry.legend = STR_SMALLMAP_LEGENDA_USAGE;
00309       legend_entry.show_on_map = false;
00310       break;
00311     case STAT_PLANNED:
00312       legend_entry.colour = _colour_gradient[COLOUR_RED][5];
00313       legend_entry.legend = STR_SMALLMAP_LEGENDA_PLANNED;
00314       legend_entry.show_on_map = true;
00315       break;
00316     case STAT_SENT:
00317       legend_entry.colour = _colour_gradient[COLOUR_YELLOW][5];
00318       legend_entry.legend = STR_SMALLMAP_LEGENDA_SENT;
00319       legend_entry.show_on_map = false;
00320       break;
00321     case STAT_TEXT:
00322       legend_entry.colour = _colour_gradient[COLOUR_GREY][7];
00323       legend_entry.legend = STR_SMALLMAP_LEGENDA_SHOW_TEXT;
00324       legend_entry.show_on_map = false;
00325       break;
00326     case STAT_GRAPH:
00327       legend_entry.colour = _colour_gradient[COLOUR_GREY][7];
00328       legend_entry.legend = STR_SMALLMAP_LEGENDA_SHOW_GRAPH;
00329       legend_entry.show_on_map = true;
00330       break;
00331     }
00332   }
00333 
00334   _legend_linkstats[i + NUM_STATS].end = true;
00335 }
00336 
00337 static const LegendAndColour * const _legend_table_old[] = {
00338   _legend_land_contours_old,
00339   _legend_vehicles,
00340   _legend_from_industries,
00341   _legend_linkstats,
00342   _legend_routes,
00343   _legend_vegetation,
00344   _legend_land_owners,
00345 };
00346 
00347 static const LegendAndColour * const _legend_table_extended[] = {
00348   _legend_land_contours_extended,
00349   _legend_vehicles,
00350   _legend_from_industries,
00351   _legend_linkstats,
00352   _legend_routes,
00353   _legend_vegetation,
00354   _legend_land_owners,
00355 };
00356 
00357 #define MKCOLOUR(x)         TO_LE32X(x)
00358 
00359 #define MKCOLOUR_XXXX(x)    (MKCOLOUR(0x01010101) * (uint)(x))
00360 #define MKCOLOUR_X0X0(x)    (MKCOLOUR(0x01000100) * (uint)(x))
00361 #define MKCOLOUR_0X0X(x)    (MKCOLOUR(0x00010001) * (uint)(x))
00362 #define MKCOLOUR_0XX0(x)    (MKCOLOUR(0x00010100) * (uint)(x))
00363 #define MKCOLOUR_X00X(x)    (MKCOLOUR(0x01000001) * (uint)(x))
00364 
00365 #define MKCOLOUR_XYXY(x, y) (MKCOLOUR_X0X0(x) | MKCOLOUR_0X0X(y))
00366 #define MKCOLOUR_XYYX(x, y) (MKCOLOUR_X00X(x) | MKCOLOUR_0XX0(y))
00367 
00368 #define MKCOLOUR_0000       MKCOLOUR_XXXX(0x00)
00369 #define MKCOLOUR_0FF0       MKCOLOUR_0XX0(0xFF)
00370 #define MKCOLOUR_F00F       MKCOLOUR_X00X(0xFF)
00371 #define MKCOLOUR_FFFF       MKCOLOUR_XXXX(0xFF)
00372 
00377 static const uint32 _green_map_heights_old[] = {
00378   MKCOLOUR(0x04dcdcdc), // Action colour, flashing purple. This is for level zero(Not flooded) !! Flooding danger !! Not yet water. (When level -1 will be possible: Will provide for a nice flooding_danger_area_border_flash in combination witch previous colour, similar to the waves at water borders.)
00379   MKCOLOUR_XXXX(0x5A),
00380   MKCOLOUR_XYXY(0x5A, 0x5B),
00381   MKCOLOUR_XXXX(0x5B),
00382   MKCOLOUR_XYXY(0x5B, 0x5C),
00383   MKCOLOUR_XXXX(0x5C),
00384   MKCOLOUR_XYXY(0x5C, 0x5D),
00385   MKCOLOUR_XXXX(0x5D),
00386   MKCOLOUR_XYXY(0x5D, 0x5E),
00387   MKCOLOUR_XXXX(0x5E),
00388   MKCOLOUR_XYXY(0x5E, 0x5F),
00389   MKCOLOUR_XXXX(0x5F),
00390   MKCOLOUR_XYXY(0x5F, 0x1F),
00391   MKCOLOUR_XXXX(0x1F),
00392   MKCOLOUR_XYXY(0x1F, 0x27),
00393   MKCOLOUR_XXXX(0x27),
00394   MKCOLOUR_XXXX(0x27),
00395 };
00396 assert_compile(lengthof(_green_map_heights_old) == MAX_TILE_HEIGHT_OLD + 2);
00397 
00403 static const uint32 _green_map_heights_extended[] = {
00404   /* First two colours are action colours.(First commented out, first we need level -1 (and underwater tunnels)) */
00405   //MKCOLOUR(0xdcdcdcdc), // Nice flashy colour, darkblue. (Do not use above level 1. (second colour)) (I keep it here to become level -1 ground tile (not flooded) (For now: To see its full effect, use this as second color.Then imagine at level -1.))
00406   MKCOLOUR(0x04dcdcdc), // Action colour, flashing purple. This is for level zero(Not flooded) !! Flooding danger !! Not yet water. (When level -1 will be possible: Will provide for a nice flooding_danger_area_border_flash in combination witch previous colour, similar to the waves at water borders.)
00407   MKCOLOUR(0x59595958), // height 1
00408   MKCOLOUR(0x59595958), // height 2
00409   MKCOLOUR(0X59595959), // height 3
00410   MKCOLOUR(0X59595959), // height 4
00411   MKCOLOUR(0X5959595A), // height 5
00412   MKCOLOUR(0X5959595A), // height 6
00413   MKCOLOUR(0X59595A59), // height 7
00414   MKCOLOUR(0X59595A59), // height 8
00415   MKCOLOUR(0X59595A5A), // height 9
00416   MKCOLOUR(0X59595A5A), // height 10
00417   MKCOLOUR(0X595A5959), // height 11
00418   MKCOLOUR(0X595A5959), // height 12
00419   MKCOLOUR(0X595A595A), // height 13
00420   MKCOLOUR(0X595A595A), // height 14
00421   MKCOLOUR(0X595A5A59), // height 15
00422   MKCOLOUR(0X595A5A59), // height 16
00423   MKCOLOUR(0X595A5A5A), // height 17
00424   MKCOLOUR(0X595A5A5A), // height 18
00425   MKCOLOUR(0X5A595959), // height 19
00426   MKCOLOUR(0X5A595959), // height 20
00427   MKCOLOUR(0X5A59595A), // height 21
00428   MKCOLOUR(0X5A59595A), // height 22
00429   MKCOLOUR(0X5A595A59), // height 23
00430   MKCOLOUR(0X5A595A59), // height 24
00431   MKCOLOUR(0X5A595A5A), // height 25
00432   MKCOLOUR(0X5A595A5A), // height 26
00433   MKCOLOUR(0X5A5A5959), // height 27
00434   MKCOLOUR(0X5A5A5959), // height 28
00435   MKCOLOUR(0X5A5A595A), // height 29
00436   MKCOLOUR(0X5A5A595A), // height 30
00437   MKCOLOUR(0X5A5A5A59), // height 31
00438   MKCOLOUR(0X5A5A5A59), // height 32
00439   MKCOLOUR(0x5A5A5A5A), // height 33 // original smallmap color do not modify
00440   MKCOLOUR(0x5A5A5A5A), // height 34 // original smallmap color do not modify
00441   MKCOLOUR(0x5A5A5A5B), // height 35
00442   MKCOLOUR(0x5A5A5A5B), // height 36
00443   MKCOLOUR(0x5A5A5B5A), // height 37
00444   MKCOLOUR(0x5A5A5B5A), // height 38
00445   MKCOLOUR(0x5A5A5B5B), // height 39
00446   MKCOLOUR(0x5A5A5B5B), // height 40
00447   MKCOLOUR(0x5A5B5A5A), // height 41
00448   MKCOLOUR(0x5A5B5A5A), // height 42
00449   MKCOLOUR(0x5A5B5A5B), // height 43 // original smallmap color do not modify
00450   MKCOLOUR(0x5A5B5A5B), // height 44 // original smallmap color do not modify
00451   MKCOLOUR(0x5A5B5B5A), // height 45
00452   MKCOLOUR(0x5A5B5B5A), // height 46
00453   MKCOLOUR(0x5A5B5B5B), // height 47
00454   MKCOLOUR(0x5A5B5B5B), // height 48
00455   MKCOLOUR(0x5B5A5A5A), // height 49
00456   MKCOLOUR(0x5B5A5A5A), // height 50
00457   MKCOLOUR(0x5B5A5A5B), // height 51
00458   MKCOLOUR(0x5B5A5A5B), // height 52
00459   MKCOLOUR(0x5B5A5B5A), // height 53
00460   MKCOLOUR(0x5B5A5B5A), // height 54
00461   MKCOLOUR(0x5B5A5B5B), // height 55
00462   MKCOLOUR(0x5B5A5B5B), // height 56
00463   MKCOLOUR(0x5B5B5A5A), // height 57
00464   MKCOLOUR(0x5B5B5A5A), // height 58
00465   MKCOLOUR(0x5B5B5A5B), // height 59
00466   MKCOLOUR(0x5B5B5A5B), // height 60
00467   MKCOLOUR(0x5B5B5B5B), // height 61 // original smallmap color do not modify
00468   MKCOLOUR(0x5B5B5B5B), // height 62 // original smallmap color do not modify
00469   MKCOLOUR(0x5B5B5B5C), // height 63
00470   MKCOLOUR(0x5B5B5B5C), // height 64
00471   MKCOLOUR(0x5B5B5C5B), // height 65
00472   MKCOLOUR(0x5B5B5C5B), // height 66
00473   MKCOLOUR(0x5B5B5C5C), // height 67
00474   MKCOLOUR(0x5B5B5C5C), // height 68
00475   MKCOLOUR(0x5B5C5B5B), // height 69
00476   MKCOLOUR(0x5B5C5B5B), // height 70
00477   MKCOLOUR(0x5B5C5B5C), // height 71 // original smallmap color do not modify
00478   MKCOLOUR(0x5B5C5B5C), // height 72 // original smallmap color do not modify
00479   MKCOLOUR(0x5B5C5C5B), // height 73
00480   MKCOLOUR(0x5B5C5C5B), // height 74
00481   MKCOLOUR(0x5B5C5C5C), // height 75
00482   MKCOLOUR(0x5B5C5C5C), // height 76
00483   MKCOLOUR(0x5C5B5B5B), // height 77
00484   MKCOLOUR(0x5C5B5B5B), // height 78
00485   MKCOLOUR(0x5C5B5B5C), // height 79
00486   MKCOLOUR(0x5C5B5B5C), // height 80
00487   MKCOLOUR(0x5C5B5C5B), // height 81
00488   MKCOLOUR(0x5C5B5C5B), // height 82
00489   MKCOLOUR(0x5C5B5C5C), // height 83
00490   MKCOLOUR(0x5C5B5C5C), // height 84
00491   MKCOLOUR(0x5C5C5B5B), // height 85
00492   MKCOLOUR(0x5C5C5B5B), // height 86
00493   MKCOLOUR(0x5C5C5B5C), // height 87
00494   MKCOLOUR(0x5C5C5B5C), // height 88
00495   MKCOLOUR(0x5C5C5C5C), // height 89 // original smallmap color do not modify
00496   MKCOLOUR(0x5C5C5C5C), // height 90 // original smallmap color do not modify
00497   MKCOLOUR(0x5C5C5C5D), // height 91
00498   MKCOLOUR(0x5C5C5C5D), // height 92
00499   MKCOLOUR(0x5C5C5D5C), // height 93
00500   MKCOLOUR(0x5C5C5D5C), // height 94
00501   MKCOLOUR(0x5C5C5D5D), // height 95
00502   MKCOLOUR(0x5C5C5D5D), // height 96
00503   MKCOLOUR(0x5C5D5C5C), // height 97
00504   MKCOLOUR(0x5C5D5C5C), // height 98
00505   MKCOLOUR(0x5C5D5C5D), // height 99 // original smallmap color do not modify
00506   MKCOLOUR(0x5C5D5C5D), // height 100 // original smallmap color do not modify
00507   MKCOLOUR(0x5C5D5D5C), // height 101
00508   MKCOLOUR(0x5C5D5D5C), // height 102
00509   MKCOLOUR(0x5C5D5D5D), // height 103
00510   MKCOLOUR(0x5C5D5D5D), // height 104
00511   MKCOLOUR(0x5D5C5C5C), // height 105
00512   MKCOLOUR(0x5D5C5C5C), // height 106
00513   MKCOLOUR(0x5D5C5C5D), // height 107
00514   MKCOLOUR(0x5D5C5C5D), // height 108
00515   MKCOLOUR(0x5D5C5D5C), // height 109
00516   MKCOLOUR(0x5D5C5D5C), // height 110
00517   MKCOLOUR(0x5D5C5D5D), // height 111
00518   MKCOLOUR(0x5D5C5D5D), // height 112
00519   MKCOLOUR(0x5D5D5C5C), // height 113
00520   MKCOLOUR(0x5D5D5C5C), // height 114
00521   MKCOLOUR(0x5D5D5C5D), // height 115
00522   MKCOLOUR(0x5D5D5C5D), // height 116
00523   MKCOLOUR(0x5D5D5D5D), // height 117 // original smallmap color do not modify
00524   MKCOLOUR(0x5D5D5D5D), // height 118 // original smallmap color do not modify
00525   MKCOLOUR(0x5D5D5D5E), // height 119
00526   MKCOLOUR(0x5D5D5D5E), // height 120
00527   MKCOLOUR(0x5D5D5E5D), // height 121
00528   MKCOLOUR(0x5D5D5E5D), // height 122
00529   MKCOLOUR(0x5D5D5E5E), // height 123
00530   MKCOLOUR(0x5D5D5E5E), // height 124
00531   MKCOLOUR(0x5D5E5D5D), // height 125
00532   MKCOLOUR(0x5D5E5D5D), // height 126
00533   MKCOLOUR(0x5D5E5D5E), // height 127 // original smallmap color do not modify
00534   MKCOLOUR(0x5D5E5D5E), // height 128 // original smallmap color do not modify
00535   MKCOLOUR(0x5D5E5E5D), // height 129
00536   MKCOLOUR(0x5D5E5E5D), // height 130
00537   MKCOLOUR(0x5D5E5E5E), // height 131
00538   MKCOLOUR(0x5D5E5E5E), // height 132
00539   MKCOLOUR(0x5E5D5D5D), // height 133
00540   MKCOLOUR(0x5E5D5D5D), // height 134
00541   MKCOLOUR(0x5E5D5D5E), // height 135
00542   MKCOLOUR(0x5E5D5D5E), // height 136
00543   MKCOLOUR(0x5E5D5E5D), // height 137
00544   MKCOLOUR(0x5E5D5E5D), // height 138
00545   MKCOLOUR(0x5E5D5E5E), // height 139
00546   MKCOLOUR(0x5E5D5E5E), // height 140
00547   MKCOLOUR(0x5E5D5D5D), // height 141
00548   MKCOLOUR(0x5E5D5D5D), // height 142
00549   MKCOLOUR(0x5E5D5D5E), // height 143
00550   MKCOLOUR(0x5E5D5D5E), // height 144
00551   MKCOLOUR(0x5E5E5E5E), // height 145 // original smallmap color do not modify
00552   MKCOLOUR(0x5E5E5E5E), // height 146 // original smallmap color do not modify
00553   MKCOLOUR(0x5E5E5E5F), // height 147
00554   MKCOLOUR(0x5E5E5E5F), // height 148
00555   MKCOLOUR(0x5E5E5F5E), // height 149
00556   MKCOLOUR(0x5E5E5F5E), // height 150
00557   MKCOLOUR(0x5E5E5F5F), // height 151
00558   MKCOLOUR(0x5E5E5F5F), // height 152
00559   MKCOLOUR(0x5E5F5E5E), // height 153
00560   MKCOLOUR(0x5E5F5E5E), // height 154
00561   MKCOLOUR(0x5E5F5E5F), // height 155 // original smallmap color do not modify
00562   MKCOLOUR(0x5E5F5E5F), // height 156 // original smallmap color do not modify
00563   MKCOLOUR(0x5E5F5F5E), // height 157
00564   MKCOLOUR(0x5E5F5F5E), // height 158
00565   MKCOLOUR(0x5E5F5F5F), // height 159
00566   MKCOLOUR(0x5E5F5F5F), // height 160
00567   MKCOLOUR(0x5F5E5E5E), // height 161
00568   MKCOLOUR(0x5F5E5E5E), // height 162
00569   MKCOLOUR(0x5F5E5E5F), // height 163
00570   MKCOLOUR(0x5F5E5E5F), // height 164
00571   MKCOLOUR(0x5F5E5F5E), // height 165
00572   MKCOLOUR(0x5F5E5F5E), // height 166
00573   MKCOLOUR(0x5F5E5F5F), // height 167
00574   MKCOLOUR(0x5F5E5F5F), // height 168
00575   MKCOLOUR(0x5F5F5E5E), // height 169
00576   MKCOLOUR(0x5F5F5E5E), // height 170
00577   MKCOLOUR(0x5F5F5E5F), // height 171
00578   MKCOLOUR(0x5F5F5E5F), // height 172
00579   MKCOLOUR(0x5F5F5F5F), // height 173 // original smallmap color do not modify
00580   MKCOLOUR(0x5F5F5F5F), // height 174 // original smallmap color do not modify
00581   MKCOLOUR(0x5F5F5F1F), // height 175
00582   MKCOLOUR(0x5F5F5F1F), // height 176
00583   MKCOLOUR(0x5F5F1F5F), // height 177
00584   MKCOLOUR(0x5F5F1F5F), // height 178
00585   MKCOLOUR(0x5F5F1F1F), // height 179
00586   MKCOLOUR(0x5F5F1F1F), // height 180
00587   MKCOLOUR(0x5F1F5F1F), // height 181 // original smallmap color do not modify
00588   MKCOLOUR(0x5F1F5F1F), // height 182 // original smallmap color do not modify
00589 // pale greens need finetuning ?
00590   MKCOLOUR(0x5F1F1F1F), // height 183
00591   MKCOLOUR(0x5F1F1F1F), // height 184
00592   MKCOLOUR(0x1F5F5F5F), // height 185
00593   MKCOLOUR(0x1F5F5F5F), // height 186
00594   MKCOLOUR(0x1F5F5F1F), // height 187
00595   MKCOLOUR(0x1F5F5F1F), // height 188
00596   MKCOLOUR(0x1F5F1F5F), // height 189
00597   MKCOLOUR(0x1F5F1F5F), // height 190
00598   MKCOLOUR(0x1F5F1F1F), // height 191
00599   MKCOLOUR(0x1F5F1F1F), // height 192
00600   MKCOLOUR(0x1F1F5F5F), // height 193
00601   MKCOLOUR(0x1F1F5F5F), // height 194
00602   MKCOLOUR(0x1F1F5F1F), // height 195
00603   MKCOLOUR(0x1F1F5F1F), // height 196
00604   MKCOLOUR(0x1F1F1F5F), // height 197
00605   MKCOLOUR(0x1F1F1F5F), // height 198
00606 //fine tune pale greens untill here ?
00607   MKCOLOUR(0x1F1F1F1F), // height 199 // original smallmap color do not modify
00608   MKCOLOUR(0x1F1F1F1F), // height 200 // original smallmap color do not modify
00609   MKCOLOUR(0x1F1F1F27), // height 201
00610   MKCOLOUR(0x1F1F1F27), // height 202
00611   MKCOLOUR(0x1F1F271F), // height 203
00612   MKCOLOUR(0x1F1F271F), // height 204
00613   MKCOLOUR(0x1F1F2727), // height 205
00614   MKCOLOUR(0x1F1F2727), // height 206
00615   MKCOLOUR(0x1F271F1F), // height 207
00616   MKCOLOUR(0x1F271F1F), // height 208
00617   MKCOLOUR(0x1F271F27), // height 209 // original smallmap color do not modify
00618   MKCOLOUR(0x1F271F27), // height 210 // original smallmap color do not modify
00619   MKCOLOUR(0x1F272727), // height 211
00620   MKCOLOUR(0x1F272727), // height 212
00621   MKCOLOUR(0x271F1F1F), // height 213
00622   MKCOLOUR(0x271F1F1F), // height 214
00623   MKCOLOUR(0x271F1F27), // height 215
00624   MKCOLOUR(0x271F1F27), // height 216
00625   MKCOLOUR(0x271F271F), // height 217
00626   MKCOLOUR(0x271F271F), // height 218
00627   MKCOLOUR(0x271F2727), // height 219
00628   MKCOLOUR(0x271F2727), // height 220
00629   MKCOLOUR(0x27271F1F), // height 221
00630   MKCOLOUR(0x27271F1F), // height 222
00631   MKCOLOUR(0x27271F27), // height 223
00632   MKCOLOUR(0x27271F27), // height 224
00633   MKCOLOUR(0x2727271F), // height 225
00634   MKCOLOUR(0x2727271F), // height 226
00635   MKCOLOUR(0x27272727), // height 227 // original smallmap color do not modify
00636   MKCOLOUR(0x27272727), // height 228 // original smallmap color do not modify
00637     /* Above and below the same color. I know. It was like that before I arrived. I prefer extending over modifying, it stays. */
00638   MKCOLOUR(0x27272727), // height 229 // original smallmap color do not modify
00639   MKCOLOUR(0x27272727), // height 230 // original smallmap color do not modify
00640   /* Purple top */
00641   MKCOLOUR(0x1F27AF27), // height 231
00642   MKCOLOUR(0x1F27AF27), // height 232
00643   MKCOLOUR(0x1F274FAF), // height 233
00644   MKCOLOUR(0x1F274FAF), // height 234
00645   MKCOLOUR(0x4F274FAF), // height 235
00646   MKCOLOUR(0x4F274FAF), // height 236
00647   MKCOLOUR(0x4FAF1FAF), // height 237
00648   MKCOLOUR(0x4FAF1FAF), // height 238
00649   MKCOLOUR(0x4F2727AF), // height 239
00650   MKCOLOUR(0x4F2727AF), // height 240
00651   MKCOLOUR(0x4F27AF27), // height 241
00652   MKCOLOUR(0x4F27AF27), // height 242
00653   MKCOLOUR(0x4F27AFAF), // height 243
00654   MKCOLOUR(0x4F27AFAF), // height 244
00655   MKCOLOUR(0x4FAF2727), // height 245
00656   MKCOLOUR(0x4FAF2727), // height 246
00657   MKCOLOUR(0x4FAF27AF), // height 247
00658   MKCOLOUR(0x4FAF27AF), // height 248
00659   MKCOLOUR(0x4FAFAF27), // height 249
00660   MKCOLOUR(0x4FAFAF27), // height 250
00661   MKCOLOUR(0x4FAFAFAF), // height 251
00662   MKCOLOUR(0x4FAFAFAF), // height 252
00663   MKCOLOUR(0x4FAFAFCF), // height 253
00664   MKCOLOUR(0x4FAFAFCF), // height 254
00665   MKCOLOUR(0x4FAFCFAF), // height 255
00666   MKCOLOUR(0x4FCFAFAF), /* 1 extra color for people not liking the flood_warning feature. */
00667   /* Flashing test with current parameters no longer needed. */
00668   //MKCOLOUR(0x04dcdcdc), /* FLASHING TEST (You can use this when going for 512 colours.) */
00669 };
00670 assert_compile(lengthof(_green_map_heights_extended) == MAX_TILE_HEIGHT_EXTENDED + 2);
00671 
00676 static const uint32 _dark_green_map_heights_old[] = {
00677   MKCOLOUR(0x04dcdcdc), // Action colour, flashing purple. This is for level zero(Not flooded) !! Flooding danger !! Not yet water. (When level -1 will be possible: Will provide for a nice flooding_danger_area_border_flash in combination witch previous colour, similar to the waves at water borders.)
00678   MKCOLOUR_XXXX(0x60),
00679   MKCOLOUR_XYXY(0x60, 0x61),
00680   MKCOLOUR_XXXX(0x61),
00681   MKCOLOUR_XYXY(0x61, 0x62),
00682   MKCOLOUR_XXXX(0x62),
00683   MKCOLOUR_XYXY(0x62, 0x63),
00684   MKCOLOUR_XXXX(0x63),
00685   MKCOLOUR_XYXY(0x63, 0x64),
00686   MKCOLOUR_XXXX(0x64),
00687   MKCOLOUR_XYXY(0x64, 0x65),
00688   MKCOLOUR_XXXX(0x65),
00689   MKCOLOUR_XYXY(0x65, 0x66),
00690   MKCOLOUR_XXXX(0x66),
00691   MKCOLOUR_XYXY(0x66, 0x67),
00692   MKCOLOUR_XXXX(0x67),
00693   MKCOLOUR_XXXX(0x67),
00694 };
00695 assert_compile(lengthof(_dark_green_map_heights_old) == MAX_TILE_HEIGHT_OLD + 2);
00696 
00702 static const uint32 _dark_green_map_heights_extended[] = {
00703   /* First two colours are action colours.(First commented out, first we need level -1 (and underwater tunnels)) */
00704   //MKCOLOUR(0xdcdcdcdc), // Nice flashy colour, darkblue. (Do not use above level 1. (second colour)) (I keep it here to become level -1 ground tile (not flooded) (For now: To see its full effect, use this as second color.Then imagine at level -1.))
00705   MKCOLOUR(0x04dcdcdc), // Action colour, flashing purple. This is for level zero(Not flooded) !! Flooding danger !! Not yet water. (When level -1 will be possible: Will provide for a nice flooding_danger_area_border_flash in combination witch previous colour, similar to the waves at water borders.)
00706   MKCOLOUR(0x60606060), // height 1 // original smallmap color do not modify
00707   MKCOLOUR(0x60606060),
00708   MKCOLOUR(0x60606061), // height 3
00709   MKCOLOUR(0x60606061),
00710   MKCOLOUR(0x60606160), // height 5
00711   MKCOLOUR(0x60606160),
00712   MKCOLOUR(0x60606161), // height 7
00713   MKCOLOUR(0x60606161),
00714   MKCOLOUR(0x60616060), // height 9
00715   MKCOLOUR(0x60616060),
00716   MKCOLOUR(0x60616061), // height 11 // original smallmap color do not modify
00717   MKCOLOUR(0x60616061),
00718   MKCOLOUR(0x60616160), // height 13
00719   MKCOLOUR(0x60616160),
00720   MKCOLOUR(0x60616161), // height 15
00721   MKCOLOUR(0x60616161),
00722   MKCOLOUR(0x61606060), // height 17
00723   MKCOLOUR(0x61606060),
00724   MKCOLOUR(0x61606061), // height 19
00725   MKCOLOUR(0x61606061),
00726   MKCOLOUR(0x61606160), // height 21
00727   MKCOLOUR(0x61606160),
00728   MKCOLOUR(0x61606161), // height 23
00729   MKCOLOUR(0x61606161),
00730   MKCOLOUR(0x61616060), // height 25
00731   MKCOLOUR(0x61616060),
00732   MKCOLOUR(0x61616061), // height 27
00733   MKCOLOUR(0x61616061),
00734   MKCOLOUR(0x61616160), // height 29
00735   MKCOLOUR(0x61616160),
00736   MKCOLOUR(0x61616161), // height 31 // original smallmap color do not modify
00737   MKCOLOUR(0x61616161),
00738   MKCOLOUR(0x61616162), // height 33
00739   MKCOLOUR(0x61616162),
00740   MKCOLOUR(0x61616261), // height 35
00741   MKCOLOUR(0x61616261),
00742   MKCOLOUR(0x61616262), // height 37
00743   MKCOLOUR(0x61616262),
00744   MKCOLOUR(0x61626161), // height 39
00745   MKCOLOUR(0x61626161),
00746   MKCOLOUR(0x61626162), // height 41 // original smallmap color do not modify
00747   MKCOLOUR(0x61626162),
00748   MKCOLOUR(0x61626261), // height 43
00749   MKCOLOUR(0x61626261),
00750   MKCOLOUR(0x61626262), // height 45
00751   MKCOLOUR(0x61626262),
00752   MKCOLOUR(0x62616161), // height 47
00753   MKCOLOUR(0x62616161),
00754   MKCOLOUR(0x62616162), // height 49
00755   MKCOLOUR(0x62616162),
00756   MKCOLOUR(0x62616261), // height 51
00757   MKCOLOUR(0x62616261),
00758   MKCOLOUR(0x62616262), // height 53
00759   MKCOLOUR(0x62616262),
00760   MKCOLOUR(0x62626161), // height 55
00761   MKCOLOUR(0x62626161),
00762   MKCOLOUR(0x62626162), // height 57
00763   MKCOLOUR(0x62626162),
00764   MKCOLOUR(0x62626261), // height 59
00765   MKCOLOUR(0x62626261),
00766   MKCOLOUR(0x62626262), // height 61 // original smallmap color do not modify
00767   MKCOLOUR(0x62626262),
00768   MKCOLOUR(0x62626263), // height 63
00769   MKCOLOUR(0x62626263),
00770   MKCOLOUR(0x62626362), // height 65
00771   MKCOLOUR(0x62626362),
00772   MKCOLOUR(0x62626363), // height 67
00773   MKCOLOUR(0x62626363),
00774   MKCOLOUR(0x62636262), // height 69
00775   MKCOLOUR(0x62636262),
00776   MKCOLOUR(0x62636263), // height 71 // original smallmap color do not modify
00777   MKCOLOUR(0x62636263),
00778   MKCOLOUR(0x62636362), // height 73
00779   MKCOLOUR(0x62636362),
00780   MKCOLOUR(0x62636363), // height 75
00781   MKCOLOUR(0x62636363),
00782   MKCOLOUR(0x63626262), // height 77
00783   MKCOLOUR(0x63626262),
00784   MKCOLOUR(0x63626263), // height 79
00785   MKCOLOUR(0x63626263),
00786   MKCOLOUR(0x63626362), // height 81
00787   MKCOLOUR(0x63626362),
00788   MKCOLOUR(0x63626363), // height 83
00789   MKCOLOUR(0x63626363),
00790   MKCOLOUR(0x63636262), // height 85
00791   MKCOLOUR(0x63636262),
00792   MKCOLOUR(0x63636263), // height 87
00793   MKCOLOUR(0x63636263),
00794   MKCOLOUR(0x63636362), // height 89
00795   MKCOLOUR(0x63636362),
00796   MKCOLOUR(0x63636363), // height 91 // original smallmap color do not modify
00797   MKCOLOUR(0x63636363),
00798   MKCOLOUR(0x63636364), // height 93
00799   MKCOLOUR(0x63636364),
00800   MKCOLOUR(0x63636463), // height 95
00801   MKCOLOUR(0x63636463),
00802   MKCOLOUR(0x63636464), // height 97
00803   MKCOLOUR(0x63636464),
00804   MKCOLOUR(0x63646363), // height 99
00805   MKCOLOUR(0x63646363),
00806   MKCOLOUR(0x63646364), // height 101 // original smallmap color do not modify
00807   MKCOLOUR(0x63646364),
00808   MKCOLOUR(0x63646463), // height 103
00809   MKCOLOUR(0x63646463),
00810   MKCOLOUR(0x63646464), // height 105
00811   MKCOLOUR(0x63646464),
00812   MKCOLOUR(0x64636363), // height 107
00813   MKCOLOUR(0x64636363),
00814   MKCOLOUR(0x64636364), // height 109
00815   MKCOLOUR(0x64636364),
00816   MKCOLOUR(0x64636463), // height 111
00817   MKCOLOUR(0x64636463),
00818   MKCOLOUR(0x64636464), // height 113
00819   MKCOLOUR(0x64636464),
00820   MKCOLOUR(0x64646363), // height 115
00821   MKCOLOUR(0x64646363),
00822   MKCOLOUR(0x64646364), // height 117
00823   MKCOLOUR(0x64646364),
00824   MKCOLOUR(0x64646463), // height 119
00825   MKCOLOUR(0x64646463),
00826   MKCOLOUR(0x64646464), // height 121 // original smallmap color do not modify
00827   MKCOLOUR(0x64646464),
00828   MKCOLOUR(0x64646465), // height 123
00829   MKCOLOUR(0x64646465),
00830   MKCOLOUR(0x64646564), // height 125
00831   MKCOLOUR(0x64646564),
00832   MKCOLOUR(0x64646565), // height 127
00833   MKCOLOUR(0x64646565),
00834   MKCOLOUR(0x64656464), // height 129
00835   MKCOLOUR(0x64656464),
00836   MKCOLOUR(0x64656465), // height 131 // original smallmap color do not modify
00837   MKCOLOUR(0x64656465),
00838   MKCOLOUR(0x64656564), // height 133
00839   MKCOLOUR(0x64656564),
00840   MKCOLOUR(0x64656565), // height 135
00841   MKCOLOUR(0x64656565),
00842   MKCOLOUR(0x65646464), // height 137
00843   MKCOLOUR(0x65646464),
00844   MKCOLOUR(0x65646465), // height 139
00845   MKCOLOUR(0x65646465),
00846   MKCOLOUR(0x65646564), // height 141
00847   MKCOLOUR(0x65646564),
00848   MKCOLOUR(0x65646565), // height 143
00849   MKCOLOUR(0x65646565),
00850   MKCOLOUR(0x65656464), // height 145
00851   MKCOLOUR(0x65656464),
00852   MKCOLOUR(0x65656465), // height 147
00853   MKCOLOUR(0x65656465),
00854   MKCOLOUR(0x65656564), // height 149
00855   MKCOLOUR(0x65656564),
00856   MKCOLOUR(0x65656565), // height 151 // original smallmap color do not modify
00857   MKCOLOUR(0x65656565),
00858   MKCOLOUR(0x65656566), // height 153
00859   MKCOLOUR(0x65656566),
00860   MKCOLOUR(0x65656665), // height 155
00861   MKCOLOUR(0x65656665),
00862   MKCOLOUR(0x65656666), // height 157
00863   MKCOLOUR(0x65656666),
00864   MKCOLOUR(0x65666565), // height 159
00865   MKCOLOUR(0x65666565),
00866   MKCOLOUR(0x65666566), // height 161 // original smallmap color do not modify
00867   MKCOLOUR(0x65666566),
00868   MKCOLOUR(0x65666665), // height 163
00869   MKCOLOUR(0x65666665),
00870   MKCOLOUR(0x65666666), // height 165
00871   MKCOLOUR(0x65666666),
00872   MKCOLOUR(0x66656565), // height 167
00873   MKCOLOUR(0x66656565),
00874   MKCOLOUR(0x66656566), // height 169
00875   MKCOLOUR(0x66656566),
00876   MKCOLOUR(0x66656665), // height 171
00877   MKCOLOUR(0x66656665),
00878   MKCOLOUR(0x66656666), // height 173
00879   MKCOLOUR(0x66656666),
00880   MKCOLOUR(0x66666565), // height 175
00881   MKCOLOUR(0x66666565),
00882   MKCOLOUR(0x66666566), // height 177
00883   MKCOLOUR(0x66666566),
00884   MKCOLOUR(0x66666665), // height 179
00885   MKCOLOUR(0x66666665),
00886   MKCOLOUR(0x66666666), // height 181 // original smallmap color do not modify
00887   MKCOLOUR(0x66666666),
00888   MKCOLOUR(0x66666667), // height 183
00889   MKCOLOUR(0x66666667),
00890   MKCOLOUR(0x66666766), // height 185
00891   MKCOLOUR(0x66666766),
00892   MKCOLOUR(0x66666767), // height 187
00893   MKCOLOUR(0x66666767),
00894   MKCOLOUR(0x66676666), // height 189
00895   MKCOLOUR(0x66676666),
00896   MKCOLOUR(0x66676667), // height 191 // original smallmap color do not modify
00897   MKCOLOUR(0x66676667),
00898   MKCOLOUR(0x66676766), // height 193
00899   MKCOLOUR(0x66676766),
00900   MKCOLOUR(0x66676767), // height 195
00901   MKCOLOUR(0x66676767),
00902   MKCOLOUR(0x67676767), // height 197 // original smallmap color do not modify
00903   MKCOLOUR(0x67676767),
00904 
00905 // TODO: Extend. read: replace dummy (copied) colurs below
00906 
00907 //  MKCOLOUR(0x67676768), // browns or something do not use untill ...
00908 //  MKCOLOUR(0x67676868),
00909 //  MKCOLOUR(0x67686868),
00910 //  MKCOLOUR(0x68686868),
00911 //  MKCOLOUR(0x68686869),
00912 //  MKCOLOUR(0x69686869),
00913 //  MKCOLOUR(0x68686969),
00914 //  MKCOLOUR(0x68696969),
00915 //  MKCOLOUR(0x69696969),
00916 //  MKCOLOUR(0x6969696A),
00917 //  MKCOLOUR(0x69A96A6A),
00918 //  MKCOLOUR(0x6A6A6A6A),
00919 //  MKCOLOUR(0x6A6A6A6B),
00920 //  MKCOLOUR(0x6A6A6B6B),
00921 //  MKCOLOUR(0x6A6B6B6B),
00922 //  MKCOLOUR(0x6B6B6B6B), // ... here and probably a little further.
00923 
00924   MKCOLOUR(0x67676767), // height 199
00925   MKCOLOUR(0x67676767),
00926   MKCOLOUR(0x67676767), // height 201
00927   MKCOLOUR(0x67676767),
00928   MKCOLOUR(0x67676767), // height 203
00929   MKCOLOUR(0x67676767),
00930   MKCOLOUR(0x67676767), // height 205
00931   MKCOLOUR(0x67676767),
00932   MKCOLOUR(0x67676767), // height 207
00933   MKCOLOUR(0x67676767),
00934   MKCOLOUR(0x67676767), // height 209
00935   MKCOLOUR(0x67676767),
00936   MKCOLOUR(0x67676767), // height 211
00937   MKCOLOUR(0x67676767),
00938   MKCOLOUR(0x67676767), // height 213
00939   MKCOLOUR(0x67676767),
00940   MKCOLOUR(0x67676767), // height 215
00941   MKCOLOUR(0x67676767),
00942   MKCOLOUR(0x67676767), // height 217
00943   MKCOLOUR(0x67676767),
00944   MKCOLOUR(0x67676767), // height 219
00945   MKCOLOUR(0x67676767),
00946   MKCOLOUR(0x67676767), // height 221
00947   MKCOLOUR(0x67676767),
00948   MKCOLOUR(0x67676767), // height 223
00949   MKCOLOUR(0x67676767),
00950   MKCOLOUR(0x67676767), // height 225
00951   MKCOLOUR(0x67676767),
00952   MKCOLOUR(0x67676767), // height 227
00953   MKCOLOUR(0x67676767),
00954   MKCOLOUR(0x67676767), // height 229
00955   MKCOLOUR(0x67676767),
00956 
00957 // TODO: extend untill here
00958 
00959   /* purple top */
00960   MKCOLOUR(0x1F27AF27), // height 231
00961   MKCOLOUR(0x1F27AF27), // height 232
00962   MKCOLOUR(0x1F274FAF), // height 233
00963   MKCOLOUR(0x1F274FAF), // height 234
00964   MKCOLOUR(0x4F274FAF), // height 235
00965   MKCOLOUR(0x4F274FAF), // height 236
00966   MKCOLOUR(0x4FAF1FAF), // height 237
00967   MKCOLOUR(0x4FAF1FAF), // height 238
00968   MKCOLOUR(0x4F2727AF), // height 239
00969   MKCOLOUR(0x4F2727AF), // height 240
00970   MKCOLOUR(0x4F27AF27), // height 241
00971   MKCOLOUR(0x4F27AF27), // height 242
00972   MKCOLOUR(0x4F27AFAF), // height 243
00973   MKCOLOUR(0x4F27AFAF), // height 244
00974   MKCOLOUR(0x4FAF2727), // height 245
00975   MKCOLOUR(0x4FAF2727), // height 246
00976   MKCOLOUR(0x4FAF27AF), // height 247
00977   MKCOLOUR(0x4FAF27AF), // height 248
00978   MKCOLOUR(0x4FAFAF27), // height 249
00979   MKCOLOUR(0x4FAFAF27), // height 250
00980   MKCOLOUR(0x4FAFAFAF), // height 251
00981   MKCOLOUR(0x4FAFAFAF), // height 252
00982   MKCOLOUR(0x4FAFAFCF), // height 253
00983   MKCOLOUR(0x4FAFAFCF), // height 254
00984   MKCOLOUR(0x4FAFCFAF), // height 255
00985   MKCOLOUR(0x4FCFAFAF), /* 1 extra color for people not liking the flood_warning feature. */
00986   /* Flashing test with current parameters no longer needed. */
00987   //MKCOLOUR(0x04dcdcdc), /* FLASHING TEST (You can use this when going for 512 colours.) */
00988 };
00989 assert_compile(lengthof(_dark_green_map_heights_extended) == MAX_TILE_HEIGHT_EXTENDED + 2);
00990 
00995 static const uint32 _violet_map_heights_old[] = {
00996   MKCOLOUR(0x04dcdcdc), // Action colour, flashing purple. This is for level zero(Not flooded) !! Flooding danger !! Not yet water. (When level -1 will be possible: Will provide for a nice flooding_danger_area_border_flash in combination witch previous colour, similar to the waves at water borders.)
00997   MKCOLOUR_XXXX(0x80),
00998   MKCOLOUR_XYXY(0x80, 0x81),
00999   MKCOLOUR_XXXX(0x81),
01000   MKCOLOUR_XYXY(0x81, 0x82),
01001   MKCOLOUR_XXXX(0x82),
01002   MKCOLOUR_XYXY(0x82, 0x83),
01003   MKCOLOUR_XXXX(0x83),
01004   MKCOLOUR_XYXY(0x83, 0x84),
01005   MKCOLOUR_XXXX(0x84),
01006   MKCOLOUR_XYXY(0x84, 0x85),
01007   MKCOLOUR_XXXX(0x85),
01008   MKCOLOUR_XYXY(0x85, 0x86),
01009   MKCOLOUR_XXXX(0x86),
01010   MKCOLOUR_XYXY(0x86, 0x87),
01011   MKCOLOUR_XXXX(0x87),
01012   MKCOLOUR_XXXX(0x87),
01013 };
01014 assert_compile(lengthof(_violet_map_heights_old) == MAX_TILE_HEIGHT_OLD + 2);
01015 
01021 static const uint32 _violet_map_heights_extended[] = {
01022   /* First two colours are action colours.(First commented out, first we need level -1 (and underwater tunnels)) */
01023   //MKCOLOUR(0xdcdcdcdc), // Nice flashy colour, darkblue. (Do not use above level 1. (second colour)) (I keep it here to become level -1 ground tile (not flooded) (For now: To see its full effect, use this as second color.Then imagine at level -1.))
01024   MKCOLOUR(0x04dcdcdc), // Action colour, flashing purple. This is for level zero(Not flooded) !! Flooding danger !! Not yet water. (When level -1 will be possible: Will provide for a nice flooding_danger_area_border_flash in combination witch previous colour, similar to the waves at water borders.)
01025   MKCOLOUR(0x80808080), // height 1 // original smallmap color do not modify
01026   MKCOLOUR(0x80808080),
01027   MKCOLOUR(0x80808081), // height 3
01028   MKCOLOUR(0x80808081),
01029   MKCOLOUR(0x80808180), // height 5
01030   MKCOLOUR(0x80808180),
01031   MKCOLOUR(0x80808181), // height 7
01032   MKCOLOUR(0x80808181),
01033   MKCOLOUR(0x80818080), // height 9
01034   MKCOLOUR(0x80818080),
01035   MKCOLOUR(0x80818081), // height 11 // original smallmap color do not modify
01036   MKCOLOUR(0x80818081),
01037   MKCOLOUR(0x80818180), // height 13
01038   MKCOLOUR(0x80818180),
01039   MKCOLOUR(0x80818181), // height 15
01040   MKCOLOUR(0x80818181),
01041   MKCOLOUR(0x81808080), // height 17
01042   MKCOLOUR(0x81808080),
01043   MKCOLOUR(0x81808081), // height 19
01044   MKCOLOUR(0x81808081),
01045   MKCOLOUR(0x81808180), // height 21
01046   MKCOLOUR(0x81808180),
01047   MKCOLOUR(0x81808181), // height 23
01048   MKCOLOUR(0x81808181),
01049   MKCOLOUR(0x81818080), // height 25
01050   MKCOLOUR(0x81818080),
01051   MKCOLOUR(0x81818081), // height 27
01052   MKCOLOUR(0x81818081),
01053   MKCOLOUR(0x81818180), // height 29
01054   MKCOLOUR(0x81818180),
01055   MKCOLOUR(0x81818181), // height 31 // original smallmap color do not modify
01056   MKCOLOUR(0x81818181),
01057   MKCOLOUR(0x81818182), // height 33
01058   MKCOLOUR(0x81818182),
01059   MKCOLOUR(0x81818281), // height 35
01060   MKCOLOUR(0x81818281),
01061   MKCOLOUR(0x81818282), // height 37
01062   MKCOLOUR(0x81818282),
01063   MKCOLOUR(0x81828181), // height 39
01064   MKCOLOUR(0x81828181),
01065   MKCOLOUR(0x81828182), // height 41 // original smallmap color do not modify
01066   MKCOLOUR(0x81828182),
01067   MKCOLOUR(0x81828281), // height 43
01068   MKCOLOUR(0x81828281),
01069   MKCOLOUR(0x81828282), // height 45
01070   MKCOLOUR(0x81828282),
01071   MKCOLOUR(0x82818181), // height 47
01072   MKCOLOUR(0x82818181),
01073   MKCOLOUR(0x82818182), // height 49
01074   MKCOLOUR(0x82818182),
01075   MKCOLOUR(0x82818281), // height 51
01076   MKCOLOUR(0x82818281),
01077   MKCOLOUR(0x82818282), // height 53
01078   MKCOLOUR(0x82818282),
01079   MKCOLOUR(0x82828181), // height 55
01080   MKCOLOUR(0x82828181),
01081   MKCOLOUR(0x82828182), // height 57
01082   MKCOLOUR(0x82828182),
01083   MKCOLOUR(0x82828281), // height 59
01084   MKCOLOUR(0x82828281),
01085   MKCOLOUR(0x82828282), // height 61 // original smallmap color do not modify
01086   MKCOLOUR(0x82828282),
01087   MKCOLOUR(0x82828283), // height 63
01088   MKCOLOUR(0x82828283),
01089   MKCOLOUR(0x82828382), // height 65
01090   MKCOLOUR(0x82828382),
01091   MKCOLOUR(0x82828383), // height 67
01092   MKCOLOUR(0x82828383),
01093   MKCOLOUR(0x82838282), // height 69
01094   MKCOLOUR(0x82838282),
01095   MKCOLOUR(0x82838283), // height 71 // original smallmap color do not modify
01096   MKCOLOUR(0x82838283),
01097   MKCOLOUR(0x82838382), // height 73
01098   MKCOLOUR(0x82838382),
01099   MKCOLOUR(0x82838383), // height 75
01100   MKCOLOUR(0x82838383),
01101   MKCOLOUR(0x83828282), // height 77
01102   MKCOLOUR(0x83828282),
01103   MKCOLOUR(0x83828283), // height 79
01104   MKCOLOUR(0x83828283),
01105   MKCOLOUR(0x83828382), // height 81
01106   MKCOLOUR(0x83828382),
01107   MKCOLOUR(0x83828383), // height 83
01108   MKCOLOUR(0x83828383),
01109   MKCOLOUR(0x83838282), // height 85
01110   MKCOLOUR(0x83838282),
01111   MKCOLOUR(0x83838283), // height 87
01112   MKCOLOUR(0x83838283),
01113   MKCOLOUR(0x83838382), // height 89
01114   MKCOLOUR(0x83838382),
01115   MKCOLOUR(0x83838383), // height 91 // original smallmap color do not modify
01116   MKCOLOUR(0x83838383),
01117   MKCOLOUR(0x83838384), // height 93
01118   MKCOLOUR(0x83838384),
01119   MKCOLOUR(0x83838483), // height 95
01120   MKCOLOUR(0x83838483),
01121   MKCOLOUR(0x83838484), // height 97
01122   MKCOLOUR(0x83838484),
01123   MKCOLOUR(0x83848383), // height 99
01124   MKCOLOUR(0x83848383),
01125   MKCOLOUR(0x83848384), // height 101 // original smallmap color do not modify
01126   MKCOLOUR(0x83848384),
01127   MKCOLOUR(0x83848483), // height 103
01128   MKCOLOUR(0x83848483),
01129   MKCOLOUR(0x83848484), // height 105
01130   MKCOLOUR(0x83848484),
01131   MKCOLOUR(0x84838383), // height 107
01132   MKCOLOUR(0x84838383),
01133   MKCOLOUR(0x84838384), // height 109
01134   MKCOLOUR(0x84838384),
01135   MKCOLOUR(0x84838483), // height 111
01136   MKCOLOUR(0x84838483),
01137   MKCOLOUR(0x84838484), // height 113
01138   MKCOLOUR(0x84838484),
01139   MKCOLOUR(0x84848383), // height 115
01140   MKCOLOUR(0x84848383),
01141   MKCOLOUR(0x84848384), // height 117
01142   MKCOLOUR(0x84848384),
01143   MKCOLOUR(0x84848483), // height 119
01144   MKCOLOUR(0x84848483),
01145   MKCOLOUR(0x84848484), // height 121 // original smallmap color do not modify
01146   MKCOLOUR(0x84848484),
01147   MKCOLOUR(0x84848485), // height 123
01148   MKCOLOUR(0x84848485),
01149   MKCOLOUR(0x84848584), // height 125
01150   MKCOLOUR(0x84848584),
01151   MKCOLOUR(0x84848585), // height 127
01152   MKCOLOUR(0x84848585),
01153   MKCOLOUR(0x84858484), // height 129
01154   MKCOLOUR(0x84858484),
01155   MKCOLOUR(0x84858485), // height 131 // original smallmap color do not modify
01156   MKCOLOUR(0x84858485),
01157   MKCOLOUR(0x84858584), // height 133
01158   MKCOLOUR(0x84858584),
01159   MKCOLOUR(0x84858585), // height 135
01160   MKCOLOUR(0x84858585),
01161   MKCOLOUR(0x85848484), // height 137
01162   MKCOLOUR(0x85848484),
01163   MKCOLOUR(0x85848485), // height 139
01164   MKCOLOUR(0x85848485),
01165   MKCOLOUR(0x85848584), // height 141
01166   MKCOLOUR(0x85848584),
01167   MKCOLOUR(0x85848585), // height 143
01168   MKCOLOUR(0x85848585),
01169   MKCOLOUR(0x85858484), // height 145
01170   MKCOLOUR(0x85858484),
01171   MKCOLOUR(0x85858485), // height 147
01172   MKCOLOUR(0x85858485),
01173   MKCOLOUR(0x85858584), // height 149
01174   MKCOLOUR(0x85858584),
01175   MKCOLOUR(0x85858585), // height 151 // original smallmap color do not modify
01176   MKCOLOUR(0x85858585),
01177   MKCOLOUR(0x85858586), // height 153
01178   MKCOLOUR(0x85858586),
01179   MKCOLOUR(0x85858685), // height 155
01180   MKCOLOUR(0x85858685),
01181   MKCOLOUR(0x85858686), // height 157
01182   MKCOLOUR(0x85858686),
01183   MKCOLOUR(0x85868585), // height 159
01184   MKCOLOUR(0x85868585),
01185   MKCOLOUR(0x85868586), // height 161 // original smallmap color do not modify
01186   MKCOLOUR(0x85868586),
01187   MKCOLOUR(0x85868685), // height 163
01188   MKCOLOUR(0x85868685),
01189   MKCOLOUR(0x85868686), // height 165
01190   MKCOLOUR(0x85868686),
01191   MKCOLOUR(0x85868585), // height 167
01192   MKCOLOUR(0x85868585),
01193   MKCOLOUR(0x85868586), // height 169
01194   MKCOLOUR(0x85868586),
01195   MKCOLOUR(0x85868685), // height 171
01196   MKCOLOUR(0x85868685),
01197   MKCOLOUR(0x85868686), // height 173
01198   MKCOLOUR(0x85868686),
01199   MKCOLOUR(0x86868585), // height 175
01200   MKCOLOUR(0x86868585),
01201   MKCOLOUR(0x86868586), // height 177
01202   MKCOLOUR(0x86868586),
01203   MKCOLOUR(0x86868685), // height 179
01204   MKCOLOUR(0x86868685),
01205   MKCOLOUR(0x86868686), // height 181 // original smallmap color do not modify
01206   MKCOLOUR(0x86868686),
01207   MKCOLOUR(0x86868687), // height 183
01208   MKCOLOUR(0x86868687),
01209   MKCOLOUR(0x86868786), // height 185
01210   MKCOLOUR(0x86868786),
01211   MKCOLOUR(0x86868787), // height 187
01212   MKCOLOUR(0x86868787),
01213   MKCOLOUR(0x86878686), // height 189
01214   MKCOLOUR(0x86878686),
01215   MKCOLOUR(0x86878687), // height 191 // original smallmap color do not modify
01216   MKCOLOUR(0x86878687),
01217   MKCOLOUR(0x86878786), // height 193
01218   MKCOLOUR(0x86878786),
01219   MKCOLOUR(0x86878787), // height 195
01220   MKCOLOUR(0x86878787),
01221   MKCOLOUR(0x87868686), // height 197
01222   MKCOLOUR(0x87868686),
01223   MKCOLOUR(0x87868687), // height 199
01224   MKCOLOUR(0x87868687),
01225   MKCOLOUR(0x87868786), // height 201
01226   MKCOLOUR(0x87868786),
01227   MKCOLOUR(0x87868787), // height 203
01228   MKCOLOUR(0x87868787),
01229   MKCOLOUR(0x87878686), // height 205
01230   MKCOLOUR(0x87878686),
01231   MKCOLOUR(0x87878687), // height 207
01232   MKCOLOUR(0x87878687),
01233   MKCOLOUR(0x87878786), // height 209
01234   MKCOLOUR(0x87878786),
01235   MKCOLOUR(0x87878787), // height 211 // original smallmap color do not modify
01236   MKCOLOUR(0x87878787),
01237   MKCOLOUR(0x87878787), // height 213 // original smallmap color do not modify
01238   MKCOLOUR(0x87878787),
01239 
01240 // TODO: Extend. read: replace dummy (copied) colurs below
01241 
01242 //  MKCOLOUR(0x87878788), // don't use greys/blacks
01243 //  MKCOLOUR(0x87878788),
01244 //  MKCOLOUR(0x87878887),
01245 //  MKCOLOUR(0x87878887),
01246 //  MKCOLOUR(0x87878888),
01247 //  MKCOLOUR(0x87878888),
01248 //  MKCOLOUR(0x87888787),
01249 //  MKCOLOUR(0x87888787),
01250 //  MKCOLOUR(0x87888788),
01251 //  MKCOLOUR(0x87888788),
01252 //  MKCOLOUR(0x87888887),
01253 //  MKCOLOUR(0x87888887),
01254 //  MKCOLOUR(0x87888888),
01255 //  MKCOLOUR(0x87888888),
01256 //  MKCOLOUR(0x88878787),
01257 //  MKCOLOUR(0x88878788),
01258 //  MKCOLOUR(0x88878887),
01259 //  MKCOLOUR(0x88878888),
01260 //  MKCOLOUR(0x88888787),
01261 //  MKCOLOUR(0x88888788),
01262 //  MKCOLOUR(0x88888887),
01263 //  MKCOLOUR(0x88888888), // dont't use untill here probaby a little further too
01264 
01265   MKCOLOUR(0x87878787), // height 215
01266   MKCOLOUR(0x87878787),
01267   MKCOLOUR(0x87878787), // height 217
01268   MKCOLOUR(0x87878787),
01269   MKCOLOUR(0x87878787), // height 219
01270   MKCOLOUR(0x87878787),
01271   MKCOLOUR(0x87878787), // height 221
01272   MKCOLOUR(0x87878787),
01273   MKCOLOUR(0x87878787), // height 223
01274   MKCOLOUR(0x87878787),
01275   MKCOLOUR(0x87878787), // height 225
01276   MKCOLOUR(0x87878787),
01277   MKCOLOUR(0x87878787), // height 227
01278   MKCOLOUR(0x87878787),
01279   MKCOLOUR(0x87878787), // height 229
01280   MKCOLOUR(0x87878787),
01281 
01282 // TODO: extend untill here
01283 
01284   /* purple top */
01285   MKCOLOUR(0x1F27AF27), // height 231
01286   MKCOLOUR(0x1F27AF27), // height 232
01287   MKCOLOUR(0x1F274FAF), // height 233
01288   MKCOLOUR(0x1F274FAF), // height 234
01289   MKCOLOUR(0x4F274FAF), // height 235
01290   MKCOLOUR(0x4F274FAF), // height 236
01291   MKCOLOUR(0x4FAF1FAF), // height 237
01292   MKCOLOUR(0x4FAF1FAF), // height 238
01293   MKCOLOUR(0x4F2727AF), // height 239
01294   MKCOLOUR(0x4F2727AF), // height 240
01295   MKCOLOUR(0x4F27AF27), // height 241
01296   MKCOLOUR(0x4F27AF27), // height 242
01297   MKCOLOUR(0x4F27AFAF), // height 243
01298   MKCOLOUR(0x4F27AFAF), // height 244
01299   MKCOLOUR(0x4FAF2727), // height 245
01300   MKCOLOUR(0x4FAF2727), // height 246
01301   MKCOLOUR(0x4FAF27AF), // height 247
01302   MKCOLOUR(0x4FAF27AF), // height 248
01303   MKCOLOUR(0x4FAFAF27), // height 249
01304   MKCOLOUR(0x4FAFAF27), // height 250
01305   MKCOLOUR(0x4FAFAFAF), // height 251
01306   MKCOLOUR(0x4FAFAFAF), // height 252
01307   MKCOLOUR(0x4FAFAFCF), // height 253
01308   MKCOLOUR(0x4FAFAFCF), // height 254
01309   MKCOLOUR(0x4FAFCFAF), // height 255
01310   MKCOLOUR(0x4FCFAFAF), /* 1 extra color for people not liking the flood_warning feature. */
01311   /* Flashing test with current parameters no longer needed. */
01312   //MKCOLOUR(0x04dcdcdc), /* FLASHING TEST (You can use this when going for 512 colours.) */
01313 };
01314 assert_compile(lengthof(_violet_map_heights_extended) == MAX_TILE_HEIGHT_EXTENDED + 2);
01315 
01319 static const uint32 _stuck_counter_colours[] = {
01320   MKCOLOUR(0xD0D0D0D0),
01321   MKCOLOUR(0xCECECECE),
01322   MKCOLOUR(0xBFBFBFBF),
01323   MKCOLOUR(0xBDBDBDBD),
01324   MKCOLOUR(0xBABABABA),
01325   MKCOLOUR(0xB8B8B8B8),
01326   MKCOLOUR(0xB6B6B6B6),
01327   MKCOLOUR(0xB4B4B4B4),
01328 };
01329 assert_compile(lengthof(_stuck_counter_colours) == 8);
01330 
01332 struct SmallMapColourScheme {
01333   const uint32 *height_colours; 
01334   uint32 default_colour;        
01335 };
01336 
01338 static const SmallMapColourScheme _heightmap_schemes_old[] = {
01339   {_green_map_heights_old,      MKCOLOUR_XXXX(0x54)}, 
01340   {_dark_green_map_heights_old, MKCOLOUR_XXXX(0x62)}, 
01341   {_violet_map_heights_old,     MKCOLOUR_XXXX(0x82)}, 
01342 };
01343 
01345 static const SmallMapColourScheme _heightmap_schemes_extended[] = {
01346   {_green_map_heights_extended,      MKCOLOUR(0x54545454)}, 
01347   {_dark_green_map_heights_extended, MKCOLOUR(0x62626262)}, 
01348   {_violet_map_heights_extended,     MKCOLOUR(0x82828282)}, 
01349 };
01350 
01354 void BuildLandLegend()
01355 {
01356   if (AllowMoreHeightlevels()) {
01357     for (LegendAndColour *lc = _legend_land_contours_extended; lc->legend == STR_TINY_BLACK_HEIGHT; lc++) {
01358       lc->colour = _heightmap_schemes_extended[_settings_client.gui.smallmap_land_colour].height_colours[lc->height];
01359     }
01360   } else {
01361     for (LegendAndColour *lc = _legend_land_contours_old; lc->legend == STR_TINY_BLACK_HEIGHT; lc++) {
01362       lc->colour = _heightmap_schemes_old[_settings_client.gui.smallmap_land_colour].height_colours[lc->height];
01363     }
01364   }
01365 }
01366 
01370 void BuildOwnerLegend()
01371 {
01372   if (AllowMoreHeightlevels()) {
01373     _legend_land_owners[1].colour = _heightmap_schemes_extended[_settings_client.gui.smallmap_land_colour].default_colour;
01374   } else {
01375     _legend_land_owners[1].colour = _heightmap_schemes_old[_settings_client.gui.smallmap_land_colour].default_colour;
01376   }
01377 
01378   int i = NUM_NO_COMPANY_ENTRIES;
01379   const Company *c;
01380   FOR_ALL_COMPANIES(c) {
01381     _legend_land_owners[i].colour = _colour_gradient[c->colour][5];
01382     _legend_land_owners[i].company = c->index;
01383     _legend_land_owners[i].show_on_map = true;
01384     _legend_land_owners[i].col_break = false;
01385     _legend_land_owners[i].end = false;
01386     _company_to_list_pos[c->index] = i;
01387     i++;
01388   }
01389 
01390   /* Terminate the list */
01391   _legend_land_owners[i].end = true;
01392 
01393   /* Store maximum amount of owner legend entries. */
01394   _smallmap_company_count = i;
01395 }
01396 
01397 struct AndOr {
01398   uint32 mor;
01399   uint32 mand;
01400 };
01401 
01402 static inline uint32 ApplyMask(uint32 colour, const AndOr *mask)
01403 {
01404   return (colour & mask->mand) | mask->mor;
01405 }
01406 
01408 static const AndOr _smallmap_contours_andor[] = {
01409   {MKCOLOUR_0000               , MKCOLOUR_FFFF}, // MP_CLEAR
01410   {MKCOLOUR_0XX0(PC_GREY      ), MKCOLOUR_F00F}, // MP_RAILWAY
01411   {MKCOLOUR_0XX0(PC_BLACK     ), MKCOLOUR_F00F}, // MP_ROAD
01412   {MKCOLOUR_0XX0(PC_DARK_RED  ), MKCOLOUR_F00F}, // MP_HOUSE
01413   {MKCOLOUR_0000               , MKCOLOUR_FFFF}, // MP_TREES
01414   {MKCOLOUR_XXXX(PC_LIGHT_BLUE), MKCOLOUR_0000}, // MP_STATION
01415   {MKCOLOUR_XXXX(PC_WATER     ), MKCOLOUR_0000}, // MP_WATER
01416   {MKCOLOUR_0000               , MKCOLOUR_FFFF}, // MP_VOID
01417   {MKCOLOUR_XXXX(PC_DARK_RED  ), MKCOLOUR_0000}, // MP_INDUSTRY
01418   {MKCOLOUR_0000               , MKCOLOUR_FFFF}, // MP_TUNNELBRIDGE
01419   {MKCOLOUR_0XX0(PC_DARK_RED  ), MKCOLOUR_F00F}, // MP_OBJECT
01420   {MKCOLOUR_0XX0(PC_GREY      ), MKCOLOUR_F00F},
01421 };
01422 
01424 static const AndOr _smallmap_vehicles_andor[] = {
01425   {MKCOLOUR_0000               , MKCOLOUR_FFFF}, // MP_CLEAR
01426   {MKCOLOUR_0XX0(PC_BLACK     ), MKCOLOUR_F00F}, // MP_RAILWAY
01427   {MKCOLOUR_0XX0(PC_BLACK     ), MKCOLOUR_F00F}, // MP_ROAD
01428   {MKCOLOUR_0XX0(PC_DARK_RED  ), MKCOLOUR_F00F}, // MP_HOUSE
01429   {MKCOLOUR_0000               , MKCOLOUR_FFFF}, // MP_TREES
01430   {MKCOLOUR_0XX0(PC_BLACK     ), MKCOLOUR_F00F}, // MP_STATION
01431   {MKCOLOUR_XXXX(PC_WATER     ), MKCOLOUR_0000}, // MP_WATER
01432   {MKCOLOUR_0000               , MKCOLOUR_FFFF}, // MP_VOID
01433   {MKCOLOUR_XXXX(PC_DARK_RED  ), MKCOLOUR_0000}, // MP_INDUSTRY
01434   {MKCOLOUR_0000               , MKCOLOUR_FFFF}, // MP_TUNNELBRIDGE
01435   {MKCOLOUR_0XX0(PC_DARK_RED  ), MKCOLOUR_F00F}, // MP_OBJECT
01436   {MKCOLOUR_0XX0(PC_BLACK     ), MKCOLOUR_F00F},
01437 };
01438 
01440 static const byte _tiletype_importance[] = {
01441   2, // MP_CLEAR
01442   8, // MP_RAILWAY
01443   7, // MP_ROAD
01444   5, // MP_HOUSE
01445   2, // MP_TREES
01446   9, // MP_STATION
01447   2, // MP_WATER
01448   1, // MP_VOID
01449   6, // MP_INDUSTRY
01450   8, // MP_TUNNELBRIDGE
01451   2, // MP_OBJECT
01452   0,
01453 };
01454 
01455 
01456 static inline TileType GetEffectiveTileType(TileIndex tile)
01457 {
01458   TileType t = GetTileType(tile);
01459 
01460   if (t == MP_TUNNELBRIDGE) {
01461     TransportType tt = GetTunnelBridgeTransportType(tile);
01462 
01463     switch (tt) {
01464       case TRANSPORT_RAIL: t = MP_RAILWAY; break;
01465       case TRANSPORT_ROAD: t = MP_ROAD;    break;
01466       default:             t = MP_WATER;   break;
01467     }
01468   }
01469   return t;
01470 }
01471 
01478 static inline uint32 GetSmallMapContoursPixels(TileIndex tile, TileType t)
01479 {
01480   uint tile_height = TileHeight(tile);
01481 
01482   if (_settings_client.gui.smallmap_land_colour == 0) {
01483     if (AllowMoreHeightlevels()) {
01484       if(_settings_client.gui.smallmap_flood_warning) {
01485         return ApplyMask(_green_map_heights_extended[tile_height], &_smallmap_contours_andor[t]);
01486       } else {
01487         return ApplyMask(_green_map_heights_extended[tile_height + 1], &_smallmap_contours_andor[t]);
01488       }
01489     } else {
01490       if(_settings_client.gui.smallmap_flood_warning) {
01491         return ApplyMask(_green_map_heights_old[tile_height], &_smallmap_contours_andor[t]);
01492       } else {
01493         return ApplyMask(_green_map_heights_old[tile_height + 1], &_smallmap_contours_andor[t]);
01494       }
01495     }
01496   } else if (_settings_client.gui.smallmap_land_colour == 1) {
01497     if (AllowMoreHeightlevels()) {
01498       if(_settings_client.gui.smallmap_flood_warning) {
01499         return ApplyMask(_dark_green_map_heights_extended[tile_height], &_smallmap_contours_andor[t]);
01500       } else {
01501         return ApplyMask(_dark_green_map_heights_extended[tile_height + 1], &_smallmap_contours_andor[t]);
01502       }
01503     } else {
01504       if(_settings_client.gui.smallmap_flood_warning) {
01505         return ApplyMask(_dark_green_map_heights_old[tile_height], &_smallmap_contours_andor[t]);
01506       } else {
01507         return ApplyMask(_dark_green_map_heights_old[tile_height + 1], &_smallmap_contours_andor[t]);
01508       }
01509     }
01510   } else {
01511     if (AllowMoreHeightlevels()) {
01512       if(_settings_client.gui.smallmap_flood_warning) {
01513         return ApplyMask(_violet_map_heights_extended[tile_height], &_smallmap_contours_andor[t]);
01514       } else {
01515         return ApplyMask(_violet_map_heights_extended[tile_height + 1], &_smallmap_contours_andor[t]);
01516       }
01517     } else {
01518       if(_settings_client.gui.smallmap_flood_warning) {
01519         return ApplyMask(_violet_map_heights_old[tile_height], &_smallmap_contours_andor[t]);
01520       } else {
01521         return ApplyMask(_violet_map_heights_old[tile_height + 1], &_smallmap_contours_andor[t]);
01522       }
01523     }
01524   }
01525 }
01526 
01534 static inline uint32 GetSmallMapVehiclesPixels(TileIndex tile, TileType t)
01535 {
01536   if (AllowMoreHeightlevels()) {
01537     const SmallMapColourScheme *cs = &_heightmap_schemes_extended[_settings_client.gui.smallmap_land_colour];
01538     return ApplyMask(cs->default_colour, &_smallmap_vehicles_andor[t]);
01539   } else {
01540     const SmallMapColourScheme *cs = &_heightmap_schemes_old[_settings_client.gui.smallmap_land_colour];
01541     return ApplyMask(cs->default_colour, &_smallmap_vehicles_andor[t]);
01542   }
01543 }
01544 
01552 static inline uint32 GetSmallMapIndustriesPixels(TileIndex tile, TileType t)
01553 {
01554   if (t == MP_INDUSTRY) {
01555     /* If industry is allowed to be seen, use its colour on the map */
01556     if (_legend_from_industries[_industry_to_list_pos[Industry::GetByTile(tile)->type]].show_on_map) {
01557       return GetIndustrySpec(Industry::GetByTile(tile)->type)->map_colour * 0x01010101;
01558     } else {
01559       /* Otherwise, return the colour which will make it disappear */
01560       t = (IsTileOnWater(tile) ? MP_WATER : MP_CLEAR);
01561     }
01562   }
01563 
01564   if (_settings_client.gui.smallmap_land_colour == 0) {
01565     if (AllowMoreHeightlevels()) {
01566       if(_settings_client.gui.smallmap_flood_warning) {
01567         return ApplyMask(_smallmap_show_heightmap ? _green_map_heights_extended[TileHeight(tile)] : MKCOLOUR(0x54545454), &_smallmap_vehicles_andor[t]);
01568       } else {
01569         return ApplyMask(_smallmap_show_heightmap ? _green_map_heights_extended[TileHeight(tile) + 1] : MKCOLOUR(0x54545454), &_smallmap_vehicles_andor[t]);
01570       }
01571     } else {
01572       if(_settings_client.gui.smallmap_flood_warning) {
01573         return ApplyMask(_smallmap_show_heightmap ? _green_map_heights_old[TileHeight(tile)] : MKCOLOUR(0x54545454), &_smallmap_vehicles_andor[t]);
01574       } else {
01575         return ApplyMask(_smallmap_show_heightmap ? _green_map_heights_old[TileHeight(tile) + 1] : MKCOLOUR(0x54545454), &_smallmap_vehicles_andor[t]);
01576       }
01577     }
01578   } else if (_settings_client.gui.smallmap_land_colour == 1) {
01579     if (AllowMoreHeightlevels()) {
01580       if(_settings_client.gui.smallmap_flood_warning) {
01581         return ApplyMask(_smallmap_show_heightmap ? _dark_green_map_heights_extended[TileHeight(tile)] : MKCOLOUR(0x62626262), &_smallmap_vehicles_andor[t]);
01582       } else {
01583         return ApplyMask(_smallmap_show_heightmap ? _dark_green_map_heights_extended[TileHeight(tile) + 1] : MKCOLOUR(0x62626262), &_smallmap_vehicles_andor[t]);
01584       }
01585     } else {
01586       if(_settings_client.gui.smallmap_flood_warning) {
01587         return ApplyMask(_smallmap_show_heightmap ? _dark_green_map_heights_old[TileHeight(tile)] : MKCOLOUR(0x62626262), &_smallmap_vehicles_andor[t]);
01588       } else {
01589         return ApplyMask(_smallmap_show_heightmap ? _dark_green_map_heights_old[TileHeight(tile) + 1] : MKCOLOUR(0x62626262), &_smallmap_vehicles_andor[t]);
01590       }
01591     }
01592   } else {
01593     if (AllowMoreHeightlevels()) {
01594       if(_settings_client.gui.smallmap_flood_warning) {
01595         return ApplyMask(_smallmap_show_heightmap ? _violet_map_heights_extended[TileHeight(tile)] : MKCOLOUR(0x82828282), &_smallmap_vehicles_andor[t]);
01596       } else {
01597         return ApplyMask(_smallmap_show_heightmap ? _violet_map_heights_extended[TileHeight(tile) + 1] : MKCOLOUR(0x82828282), &_smallmap_vehicles_andor[t]);
01598       }
01599     } else {
01600       if(_settings_client.gui.smallmap_flood_warning) {
01601         return ApplyMask(_smallmap_show_heightmap ? _violet_map_heights_old[TileHeight(tile)] : MKCOLOUR(0x82828282), &_smallmap_vehicles_andor[t]);
01602       } else {
01603         return ApplyMask(_smallmap_show_heightmap ? _violet_map_heights_old[TileHeight(tile) + 1] : MKCOLOUR(0x82828282), &_smallmap_vehicles_andor[t]);
01604       }
01605     }
01606   }
01607 }
01608 
01616 static inline uint32 GetSmallMapStuckRoutesPixels(TileIndex tile, TileType t)
01617 {
01618   if (t == MP_STATION) {
01619     switch (GetStationType(tile)) {
01620       case STATION_RAIL:    return MKCOLOUR(0x56565656);
01621       case STATION_AIRPORT: return MKCOLOUR(0xB8B8B8B8);
01622       case STATION_TRUCK:   return MKCOLOUR(0xC2C2C2C2);
01623       case STATION_BUS:     return MKCOLOUR(0xBFBFBFBF);
01624       case STATION_DOCK:    return MKCOLOUR(0x98989898);
01625       default:              return MKCOLOUR(0xFFFFFFFF);
01626     }
01627   } else if (t == MP_RAILWAY) {
01628     byte c = GetStuckCounter(tile);
01629     if (c==0) return 0;
01630     return _stuck_counter_colours[c/32];
01631   }
01632 
01633   /* Ground colour */
01634   if (AllowMoreHeightlevels()) {
01635     const SmallMapColourScheme *cs = &_heightmap_schemes_extended[_settings_client.gui.smallmap_land_colour];
01636     return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]);
01637   } else {
01638     const SmallMapColourScheme *cs = &_heightmap_schemes_old[_settings_client.gui.smallmap_land_colour];
01639     return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]);
01640   }
01641 }
01642 
01650 static inline uint32 GetSmallMapRoutesPixels(TileIndex tile, TileType t)
01651 {
01652   if (t == MP_STATION) {
01653     switch (GetStationType(tile)) {
01654       case STATION_RAIL:    return MKCOLOUR_XXXX(PC_VERY_DARK_BROWN);
01655       case STATION_AIRPORT: return MKCOLOUR_XXXX(PC_RED);
01656       case STATION_TRUCK:   return MKCOLOUR_XXXX(PC_ORANGE);
01657       case STATION_BUS:     return MKCOLOUR_XXXX(PC_YELLOW);
01658       case STATION_DOCK:    return MKCOLOUR_XXXX(PC_LIGHT_BLUE);
01659       default:              return MKCOLOUR_FFFF;
01660     }
01661   } else if (t == MP_RAILWAY) {
01662     AndOr andor = {
01663       MKCOLOUR_0XX0(GetRailTypeInfo(GetRailType(tile))->map_colour),
01664       _smallmap_contours_andor[t].mand
01665     };
01666 
01667     if (AllowMoreHeightlevels()) {
01668       const SmallMapColourScheme *cs = &_heightmap_schemes_extended[_settings_client.gui.smallmap_land_colour];
01669       return ApplyMask(cs->default_colour, &andor);
01670     } else {
01671       const SmallMapColourScheme *cs = &_heightmap_schemes_old[_settings_client.gui.smallmap_land_colour];
01672       return ApplyMask(cs->default_colour, &andor);
01673     }
01674   }
01675 
01676   /* Ground colour */
01677   if (AllowMoreHeightlevels()) {
01678     const SmallMapColourScheme *cs = &_heightmap_schemes_extended[_settings_client.gui.smallmap_land_colour];
01679     return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]);
01680   } else {
01681     const SmallMapColourScheme *cs = &_heightmap_schemes_old[_settings_client.gui.smallmap_land_colour];
01682     return ApplyMask(cs->default_colour, &_smallmap_contours_andor[t]);
01683   }
01684 }
01685 
01693 static inline uint32 GetSmallMapLinkStatsPixels(TileIndex tile, TileType t)
01694 {
01695   return _smallmap_show_heightmap ? GetSmallMapContoursPixels(tile, t) : GetSmallMapRoutesPixels(tile, t);
01696 }
01697 
01698 static const uint32 _vegetation_clear_bits[] = {
01699   MKCOLOUR_XXXX(PC_GRASS_LAND), 
01700   MKCOLOUR_XXXX(PC_ROUGH_LAND), 
01701   MKCOLOUR_XXXX(PC_GREY),       
01702   MKCOLOUR_XXXX(PC_FIELDS),     
01703   MKCOLOUR_XXXX(PC_LIGHT_BLUE), 
01704   MKCOLOUR_XXXX(PC_ORANGE),     
01705   MKCOLOUR_XXXX(PC_GRASS_LAND), 
01706   MKCOLOUR_XXXX(PC_GRASS_LAND), 
01707 };
01708 
01716 static inline uint32 GetSmallMapVegetationPixels(TileIndex tile, TileType t)
01717 {
01718   switch (t) {
01719     case MP_CLEAR:
01720       return (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) < 3) ? MKCOLOUR_XXXX(PC_BARE_LAND) : _vegetation_clear_bits[GetClearGround(tile)];
01721 
01722     case MP_INDUSTRY:
01723       return GetIndustrySpec(Industry::GetByTile(tile)->type)->check_proc == CHECK_FOREST ? MKCOLOUR_XXXX(PC_GREEN) : MKCOLOUR_XXXX(PC_DARK_RED);
01724 
01725     case MP_TREES:
01726       if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT || GetTreeGround(tile) == TREE_GROUND_ROUGH_SNOW) {
01727         return (_settings_game.game_creation.landscape == LT_ARCTIC) ? MKCOLOUR_XYYX(PC_LIGHT_BLUE, PC_TREES) : MKCOLOUR_XYYX(PC_ORANGE, PC_TREES);
01728       }
01729       return MKCOLOUR_XYYX(PC_GRASS_LAND, PC_TREES);
01730 
01731     default:
01732       return ApplyMask(MKCOLOUR_XXXX(PC_GRASS_LAND), &_smallmap_vehicles_andor[t]);
01733   }
01734 }
01735 
01743 static inline uint32 GetSmallMapOwnerPixels(TileIndex tile, TileType t)
01744 {
01745   Owner o;
01746 
01747   switch (t) {
01748     case MP_INDUSTRY: return MKCOLOUR_XXXX(PC_DARK_GREY);
01749     case MP_HOUSE:    return MKCOLOUR_XXXX(PC_DARK_RED);
01750     default:          o = GetTileOwner(tile); break;
01751     /* FIXME: For MP_ROAD there are multiple owners.
01752      * GetTileOwner returns the rail owner (level crossing) resp. the owner of ROADTYPE_ROAD (normal road),
01753      * even if there are no ROADTYPE_ROAD bits on the tile.
01754      */
01755   }
01756 
01757   if ((o < MAX_COMPANIES && !_legend_land_owners[_company_to_list_pos[o]].show_on_map) || o == OWNER_NONE || o == OWNER_WATER) {
01758     if (t == MP_WATER) return MKCOLOUR_XXXX(PC_WATER);
01759     if (AllowMoreHeightlevels()) {
01760       const SmallMapColourScheme *cs = &_heightmap_schemes_extended[_settings_client.gui.smallmap_land_colour];
01761       if(_settings_client.gui.smallmap_flood_warning) {
01762         return _smallmap_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour;
01763       } else {
01764         return _smallmap_show_heightmap ? cs->height_colours[TileHeight(tile) + 1] : cs->default_colour;
01765 
01766       }
01767     } else {
01768       const SmallMapColourScheme *cs = &_heightmap_schemes_old[_settings_client.gui.smallmap_land_colour];
01769       if(_settings_client.gui.smallmap_flood_warning) {
01770         return _smallmap_show_heightmap ? cs->height_colours[TileHeight(tile)] : cs->default_colour;
01771       } else {
01772         return _smallmap_show_heightmap ? cs->height_colours[TileHeight(tile) + 1] : cs->default_colour;
01773       }
01774     }
01775   } else if (o == OWNER_TOWN) {
01776     return MKCOLOUR_XXXX(PC_DARK_RED);
01777   }
01778 
01779   return MKCOLOUR_XXXX(_legend_land_owners[_company_to_list_pos[o]].colour);
01780 }
01781 
01782 static Point TileCoordFromScreenCoord(int x, int y)
01783 {
01784   /*  What we calculate here is the inverse function of RemapCoords,
01785    *  assuming z = 0 in RemapCoords.
01786    */
01787   Point pt;
01788   pt.x = (2 * y - x) / 4;
01789   pt.y = (x + 2 * y) / 4;
01790   return pt;
01791 }
01792 
01794 static const byte _vehicle_type_colours[6] = {
01795   PC_RED, PC_YELLOW, PC_LIGHT_BLUE, PC_WHITE, PC_BLACK, PC_RED
01796 };
01797 
01806 void DrawVertex(int x, int y, int size, int colour, int border_colour)
01807 {
01808   size--;
01809   int w1 = size / 2;
01810   int w2 = size / 2 + size % 2;
01811 
01812   GfxFillRect(x - w1, y - w1, x + w2, y + w2, colour);
01813 
01814   w1++;
01815   w2++;
01816   GfxDrawLine(x - w1, y - w1, x + w2, y - w1, border_colour);
01817   GfxDrawLine(x - w1, y + w2, x + w2, y + w2, border_colour);
01818   GfxDrawLine(x - w1, y - w1, x - w1, y + w2, border_colour);
01819   GfxDrawLine(x + w2, y - w1, x + w2, y + w2, border_colour);
01820 }
01821 
01823 class SmallMapWindow : public Window {
01825   enum SmallMapType {
01826     SMT_CONTOUR,
01827     SMT_VEHICLES,
01828     SMT_INDUSTRY,
01829     SMT_LINKSTATS,
01830     SMT_ROUTES,
01831     SMT_VEGETATION,
01832     SMT_OWNER,
01833   };
01834 
01842   struct VehicleAndPosition {
01843     VehicleAndPosition(const Vehicle *v) : vehicle(v->index)
01844     {
01845       this->position.x = v->x_pos;
01846       this->position.y = v->y_pos;
01847     }
01848 
01849     Point position;
01850     VehicleID vehicle;
01851   };
01852 
01853   typedef std::list<VehicleAndPosition> VehicleList;
01854   VehicleList vehicles_on_map; 
01855   
01857   enum ZoomLevelChange {
01858     ZLC_INITIALIZE, 
01859     ZLC_ZOOM_OUT,   
01860     ZLC_ZOOM_IN,    
01861   };
01862 
01863   static SmallMapType map_type; 
01864   static bool show_towns;       
01865 
01866   static const uint LEGEND_BLOB_WIDTH = 8;              
01867   static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2; 
01868   uint min_number_of_fixed_rows; 
01869   uint column_width;             
01870 
01871   bool HasButtons()
01872   {
01873     return this->map_type == SMT_INDUSTRY || this->map_type == SMT_LINKSTATS || this->map_type == SMT_OWNER;
01874   }
01875 
01876   Point cursor;
01877 
01878   struct BaseCargoDetail {
01879     BaseCargoDetail()
01880     {
01881       this->Clear();
01882     }
01883 
01884     void AddLink(const LinkStat & orig_link, const FlowStat & orig_flow)
01885     {
01886       this->capacity += orig_link.Capacity();
01887       this->usage += orig_link.Usage();
01888       this->planned += orig_flow.Planned();
01889       this->sent += orig_flow.Sent();
01890     }
01891 
01892     void Clear()
01893     {
01894       this->capacity = this->usage = this->planned = this->sent = 0;
01895     }
01896 
01897     uint capacity;
01898     uint usage;
01899     uint planned;
01900     uint sent;
01901   };
01902 
01903   struct CargoDetail : public BaseCargoDetail {
01904     CargoDetail(const LegendAndColour * c, const LinkStat &ls, const FlowStat &fs) : legend(c)
01905     {
01906       this->AddLink(ls, fs);
01907     }
01908 
01909     const LegendAndColour *legend;
01910   };
01911 
01912   typedef std::vector<CargoDetail> StatVector;
01913 
01914   struct LinkDetails {
01915     LinkDetails() {this->Clear();}
01916 
01917     StationID sta;
01918     StationID stb;
01919     StatVector a_to_b;
01920     StatVector b_to_a;
01921 
01922     void Clear()
01923     {
01924       this->sta = INVALID_STATION;
01925       this->stb = INVALID_STATION;
01926       this->a_to_b.clear();
01927       this->b_to_a.clear();
01928     }
01929 
01930     bool Empty() const
01931     {
01932       return this->sta == INVALID_STATION;
01933     }
01934   };
01935 
01940   mutable LinkDetails link_details;
01941   mutable StationID supply_details;
01942 
01943   int32 scroll_x;  
01944   int32 scroll_y;  
01945   int32 subscroll; 
01946   int zoom;        
01947 
01948   static const uint8 FORCE_REFRESH_PERIOD = 0x1F; 
01949   static const uint8 REFRESH_NEXT_TICK = 1;       
01950   uint8 refresh; 
01951 
01958   FORCEINLINE Point RemapTile(int tile_x, int tile_y) const
01959   {
01960     if (this->zoom > 0) {
01961       int x_offset = tile_x - this->scroll_x / (int)TILE_SIZE;
01962       int y_offset = tile_y - this->scroll_y / (int)TILE_SIZE;
01963 
01964       /* For negative offsets, round towards -inf. */
01965       if (x_offset < 0) x_offset -= this->zoom - 1;
01966       if (y_offset < 0) y_offset -= this->zoom - 1;
01967 
01968       return RemapCoords(x_offset / this->zoom, y_offset / this->zoom, 0);
01969     } else {
01970       int x_offset = tile_x * (-this->zoom) - this->scroll_x * (-this->zoom) / (int)TILE_SIZE;
01971       int y_offset = tile_y * (-this->zoom) - this->scroll_y * (-this->zoom) / (int)TILE_SIZE;
01972 
01973       return RemapCoords(x_offset, y_offset, 0);
01974     }
01975   }
01976 
01987   FORCEINLINE Point PixelToWorld(int px, int py, int *sub, bool add_sub = true) const
01988   {
01989     if (add_sub) px += this->subscroll;  // Total horizontal offset.
01990 
01991     /* For each two rows down, add a x and a y tile, and
01992      * For each four pixels to the right, move a tile to the right. */
01993     Point pt = {
01994       ((py >> 1) - (px >> 2)) * TILE_SIZE,
01995       ((py >> 1) + (px >> 2)) * TILE_SIZE
01996     };
01997 
01998     if (this->zoom > 0) {
01999       pt.x *= this->zoom;
02000       pt.y *= this->zoom;
02001     } else {
02002       pt.x /= (-this->zoom);
02003       pt.y /= (-this->zoom);
02004     }
02005 
02006     px &= 3;
02007 
02008     if (py & 1) { // Odd number of rows, handle the 2 pixel shift.
02009       int offset = this->zoom > 0 ? this->zoom * TILE_SIZE : TILE_SIZE / (-this->zoom);
02010       if (px < 2) {
02011         pt.x += offset;
02012         px += 2;
02013       } else {
02014         pt.y += offset;
02015         px -= 2;
02016       }
02017     }
02018 
02019     *sub = px;
02020     return pt;
02021   }
02022 
02032   Point ComputeScroll(int tx, int ty, int x, int y, int *sub)
02033   {
02034     assert(x >= 0 && y >= 0);
02035 
02036     int new_sub;
02037     Point tile_xy = PixelToWorld(x, y, &new_sub, false);
02038     tx -= tile_xy.x;
02039     ty -= tile_xy.y;
02040 
02041     int offset = this->zoom < 0 ? TILE_SIZE / (-this->zoom) : this->zoom * TILE_SIZE;
02042 
02043     Point scroll;
02044     if (new_sub == 0) {
02045       *sub = 0;
02046       scroll.x = tx + offset;
02047       scroll.y = ty - offset;
02048     } else {
02049       *sub = 4 - new_sub;
02050       scroll.x = tx + 2 * offset;
02051       scroll.y = ty - 2 * offset;
02052     }
02053     return scroll;
02054   }
02055 
02062   void SetZoomLevel(ZoomLevelChange change, const Point *zoom_pt)
02063   {
02064     static const int zoomlevels[] = {-4, -2, 1, 2, 4, 6, 8}; // Available zoom levels. Bigger number means more zoom-out (further away).
02065     static const int MIN_ZOOM_INDEX = 0;
02066     static const int DEFAULT_ZOOM_INDEX = 2;
02067     static const int MAX_ZOOM_INDEX = lengthof(zoomlevels) - 1;
02068 
02069     int new_index, cur_index, sub;
02070     Point position;
02071     switch (change) {
02072       case ZLC_INITIALIZE:
02073         cur_index = - 1; // Definitely different from new_index.
02074         new_index = DEFAULT_ZOOM_INDEX;
02075         break;
02076 
02077       case ZLC_ZOOM_IN:
02078       case ZLC_ZOOM_OUT:
02079         for (cur_index = MIN_ZOOM_INDEX; cur_index <= MAX_ZOOM_INDEX; cur_index++) {
02080           if (this->zoom == zoomlevels[cur_index]) break;
02081         }
02082         assert(cur_index <= MAX_ZOOM_INDEX);
02083 
02084         position = this->PixelToWorld(zoom_pt->x, zoom_pt->y, &sub);
02085         new_index = Clamp(cur_index + ((change == ZLC_ZOOM_IN) ? -1 : 1), MIN_ZOOM_INDEX, MAX_ZOOM_INDEX);
02086         break;
02087 
02088       default: NOT_REACHED();
02089     }
02090 
02091     if (new_index != cur_index) {
02092       this->zoom = zoomlevels[new_index];
02093       if (cur_index >= 0) {
02094         Point new_pos = this->PixelToWorld(zoom_pt->x, zoom_pt->y, &sub);
02095         this->SetNewScroll(this->scroll_x + position.x - new_pos.x,
02096             this->scroll_y + position.y - new_pos.y, sub);
02097       }
02098       this->SetWidgetDisabledState(SM_WIDGET_ZOOM_IN,  this->zoom == zoomlevels[MIN_ZOOM_INDEX]);
02099       this->SetWidgetDisabledState(SM_WIDGET_ZOOM_OUT, this->zoom == zoomlevels[MAX_ZOOM_INDEX]);
02100       this->SetDirty();
02101     }
02102   }
02103 
02109   inline uint32 GetTileColours(const TileArea &ta) const
02110   {
02111     int importance = 0;
02112     TileIndex tile = INVALID_TILE; // Position of the most important tile.
02113     TileType et = MP_VOID;         // Effective tile type at that position.
02114 
02115     TILE_AREA_LOOP(ti, ta) {
02116       TileType ttype = GetEffectiveTileType(ti);
02117       if (_tiletype_importance[ttype] > importance) {
02118         importance = _tiletype_importance[ttype];
02119         tile = ti;
02120         et = ttype;
02121       }
02122     }
02123 
02124     switch (this->map_type) {
02125       case SMT_CONTOUR:
02126         return GetSmallMapContoursPixels(tile, et);
02127 
02128       case SMT_VEHICLES:
02129         return GetSmallMapVehiclesPixels(tile, et);
02130 
02131       case SMT_INDUSTRY:
02132         return GetSmallMapIndustriesPixels(tile, et);
02133 
02134       case SMT_ROUTES:
02135         return GetSmallMapStuckRoutesPixels(tile, et);
02136 
02137       case SMT_VEGETATION:
02138         return GetSmallMapVegetationPixels(tile, et);
02139 
02140       case SMT_OWNER:
02141         return GetSmallMapOwnerPixels(tile, et);
02142 
02143       case SMT_LINKSTATS:
02144         return GetSmallMapLinkStatsPixels(tile, et);
02145 
02146       default: NOT_REACHED();
02147     }
02148   }
02149 
02164   void DrawSmallMapColumn(void *dst, uint xc, uint yc, int pitch, int reps, int start_pos, int end_pos, Blitter *blitter) const
02165   {
02166     void *dst_ptr_abs_end = blitter->MoveTo(_screen.dst_ptr, 0, _screen.height);
02167     uint min_xy = _settings_game.construction.freeform_edges ? 1 : 0;
02168 
02169     int increment = this->zoom > 0 ? this->zoom * TILE_SIZE : TILE_SIZE / (-this->zoom);
02170     int extent = this->zoom > 0 ? this->zoom : 1;
02171 
02172     do {
02173       /* Check if the tile (xc,yc) is within the map range */
02174       if (xc / TILE_SIZE >= MapMaxX() || yc / TILE_SIZE >= MapMaxY()) continue;
02175 
02176       /* Check if the dst pointer points to a pixel inside the screen buffer */
02177       if (dst < _screen.dst_ptr) continue;
02178       if (dst >= dst_ptr_abs_end) continue;
02179 
02180       /* Construct tilearea covered by (xc, yc, xc + this->zoom, yc + this->zoom) such that it is within min_xy limits. */
02181       TileArea ta;
02182       if (min_xy == 1 && (xc < TILE_SIZE || yc < TILE_SIZE)) {
02183         if (this->zoom <= 1) continue; // The tile area is empty, don't draw anything.
02184 
02185         ta = TileArea(TileXY(max(min_xy, xc / TILE_SIZE), max(min_xy, yc / TILE_SIZE)), this->zoom - (xc < TILE_SIZE), this->zoom - (yc < TILE_SIZE));
02186       } else {
02187         ta = TileArea(TileXY(xc / TILE_SIZE, yc / TILE_SIZE), extent, extent);
02188       }
02189       ta.ClampToMap(); // Clamp to map boundaries (may contain MP_VOID tiles!).
02190 
02191       uint32 val = this->GetTileColours(ta);
02192       uint8 *val8 = (uint8 *)&val;
02193       int idx = max(0, -start_pos);
02194       for (int pos = max(0, start_pos); pos < end_pos; pos++) {
02195         blitter->SetPixel(dst, idx, 0, val8[idx]);
02196         idx++;
02197       }
02198     /* Switch to next tile in the column */
02199     } while (xc += increment, yc += increment, dst = blitter->MoveTo(dst, pitch, 0), --reps != 0);
02200   }
02201 
02207   void DrawVehicles(const DrawPixelInfo *dpi, Blitter *blitter) const
02208   {
02209     for(VehicleList::const_iterator i = this->vehicles_on_map.begin(); i != this->vehicles_on_map.end(); ++i) {
02210       const Vehicle *v = Vehicle::GetIfValid(i->vehicle);
02211       if (v == NULL) continue;
02212 
02213       /* Remap into flat coordinates. */
02214       Point pt = RemapTile(i->position.x / (int)TILE_SIZE, i->position.y / (int)TILE_SIZE);
02215 
02216       int y = pt.y - dpi->top;
02217       int x = pt.x - this->subscroll - 3 - dpi->left; // Offset X coordinate.
02218 
02219       int scale = this->zoom < 0 ? -this->zoom : 1;
02220 
02221       /* Calculate pointer to pixel and the colour */
02222       byte colour = (this->map_type == SMT_VEHICLES) ? _vehicle_type_colours[v->type] : PC_WHITE;
02223 
02224       /* Draw rhombus */
02225       for (int dy = 0; dy < scale; dy++) {
02226         for (int dx = 0; dx < scale; dx++) {
02227           Point pt = RemapCoords(dx, dy, 0);
02228           if (IsInsideMM(y + pt.y, 0, dpi->height)) {
02229             if (IsInsideMM(x + pt.x, 0, dpi->width)) {
02230               blitter->SetPixel(dpi->dst_ptr, x + pt.x, y + pt.y, colour);
02231             }
02232             if (IsInsideMM(x + pt.x + 1, 0, dpi->width)) {
02233               blitter->SetPixel(dpi->dst_ptr, x + pt.x + 1, y + pt.y, colour);
02234             }
02235           }
02236         }
02237       }
02238     }
02239   }
02240 
02241   FORCEINLINE Point GetStationMiddle(const Station *st) const
02242   {
02243     int x = (st->rect.right + st->rect.left + 1) / 2;
02244     int y = (st->rect.bottom + st->rect.top + 1) / 2;
02245     Point ret = this->RemapTile(x, y);
02246     ret.x -= 3 + this->subscroll;
02247     if (this->zoom < 0) {
02248       /* add half a tile if width or height is odd */
02249       if (((st->rect.bottom - st->rect.top) & 1) == 0) {
02250         Point offset = RemapCoords(0, -this->zoom / 2, 0);
02251         ret.x += offset.x;
02252         ret.y += offset.y;
02253       }
02254       if (((st->rect.right - st->rect.left) & 1) == 0) {
02255         Point offset = RemapCoords(-this->zoom / 2, 0, 0);
02256         ret.x += offset.x;
02257         ret.y += offset.y;
02258       }
02259     }
02260     return ret;
02261   }
02262 
02263   StationID DrawStationDots() const
02264   {
02265     const Station *supply_details = NULL;
02266 
02267     const Station *st;
02268     FOR_ALL_STATIONS(st) {
02269       if (((st->owner != _local_company && Company::IsValidID(st->owner)) ||
02270           st->rect.IsEmpty()) && _settings_client.gui.linkgraph_companies == 0) continue; // test show all companies links
02271 
02272       Point pt = GetStationMiddle(st);
02273 
02274       if (supply_details == NULL && CheckStationSelected(&pt)) {
02275         supply_details = st;
02276       }
02277 
02278       /* Add up cargo supplied for each selected cargo type */
02279       uint q = 0;
02280       int colour = 0;
02281       int numCargos = 0;
02282 
02283       if (AllowMoreHeightlevels()) {
02284         for (int i = 0; i < _smallmap_cargo_count; ++i) {
02285           const LegendAndColour &tbl = _legend_table_extended[this->map_type][i];
02286           if (!tbl.show_on_map && supply_details != st) continue;
02287           uint supply = st->goods[tbl.type].supply;
02288           if (supply > 0) {
02289             q += supply;
02290             colour += tbl.colour;
02291             numCargos++;
02292           }
02293         }
02294 
02295       } else {
02296         for (int i = 0; i < _smallmap_cargo_count; ++i) {
02297           const LegendAndColour &tbl = _legend_table_old[this->map_type][i];
02298           if (!tbl.show_on_map && supply_details != st) continue;
02299           uint supply = st->goods[tbl.type].supply;
02300           if (supply > 0) {
02301             q += supply;
02302             colour += tbl.colour;
02303             numCargos++;
02304           }
02305         }
02306       }
02307 
02308       if (numCargos > 1) colour /= numCargos;
02309 
02310       uint r = 2;
02311       if (q >= 10) r++;
02312       if (q >= 20) r++;
02313       if (q >= 40) r++;
02314       if (q >= 80) r++;
02315       if (q >= 160) r++;
02316 
02317       DrawVertex(pt.x, pt.y, r, colour, _colour_gradient[COLOUR_GREY][supply_details == st ? 3 : 1]);
02318     }
02319     return (supply_details == NULL) ? INVALID_STATION : supply_details->index;
02320   }
02321 
02322   class LinkDrawer {
02323 
02324   protected:
02325     virtual void DrawContent() = 0;
02326     virtual void Highlight() {}
02327     virtual void AddLink(const LinkStat &orig_link, const FlowStat &orig_flow, const LegendAndColour &cargo_entry) = 0;
02328 
02329     FORCEINLINE bool IsLinkVisible()
02330     {
02331       const NWidgetBase *wi = this->window->GetWidget<NWidgetCore>(SM_WIDGET_MAP);
02332       return !((this->pta.x < 0 && this->ptb.x < 0) ||
02333           (this->pta.y < 0 && this->ptb.y < 0) ||
02334           (this->pta.x > (int)wi->current_x && this->ptb.x > (int)wi->current_x) ||
02335           (this->pta.y > (int)wi->current_y && this->ptb.y > (int)wi->current_y));
02336     }
02337 
02338     Point pta, ptb;
02339     bool search_link_details;
02340     LinkDetails link_details;
02341     const SmallMapWindow *window;
02342 
02343     void DrawLink(StationID sta, StationID stb)
02344     {
02345       bool highlight_empty = this->search_link_details && this->link_details.Empty();
02346       bool highlight =
02347           (sta == this->link_details.sta && stb == this->link_details.stb) ||
02348           (highlight_empty && window->CheckLinkSelected(&this->pta, &this->ptb));
02349       bool reverse_empty = this->link_details.b_to_a.empty();
02350       bool reverse_highlight = (sta == this->link_details.stb && stb == this->link_details.sta);
02351       if (highlight_empty && highlight) {
02352         this->link_details.sta = sta;
02353         this->link_details.stb = stb;
02354       }
02355 
02356       if (highlight || reverse_highlight) {
02357         this->Highlight();
02358       }
02359 
02360       if (AllowMoreHeightlevels()) {
02361         for (int i = 0; i < _smallmap_cargo_count; ++i) {
02362           const LegendAndColour &cargo_entry = _legend_table_extended[window->map_type][i];
02363           CargoID cargo = cargo_entry.type;
02364           if (cargo_entry.show_on_map || highlight || reverse_highlight) {
02365             GoodsEntry &ge = Station::Get(sta)->goods[cargo];
02366             FlowStat sum_flows = ge.GetSumFlowVia(stb);
02367             const LinkStatMap &ls_map = ge.link_stats;
02368             LinkStatMap::const_iterator i = ls_map.find(stb);
02369             if (i != ls_map.end()) {
02370               const LinkStat &link_stat = i->second;
02371               this->AddLink(link_stat, sum_flows, cargo_entry);
02372               if (highlight_empty && highlight) {
02373                 this->link_details.a_to_b.push_back(CargoDetail(&cargo_entry, link_stat, sum_flows));
02374               } else if (reverse_empty && reverse_highlight) {
02375                 this->link_details.b_to_a.push_back(CargoDetail(&cargo_entry, link_stat, sum_flows));
02376               }
02377             }
02378           }
02379         }
02380 
02381       } else {
02382         for (int i = 0; i < _smallmap_cargo_count; ++i) {
02383           const LegendAndColour &cargo_entry = _legend_table_old[window->map_type][i];
02384           CargoID cargo = cargo_entry.type;
02385           if (cargo_entry.show_on_map || highlight || reverse_highlight) {
02386             GoodsEntry &ge = Station::Get(sta)->goods[cargo];
02387             FlowStat sum_flows = ge.GetSumFlowVia(stb);
02388             const LinkStatMap &ls_map = ge.link_stats;
02389             LinkStatMap::const_iterator i = ls_map.find(stb);
02390             if (i != ls_map.end()) {
02391               const LinkStat &link_stat = i->second;
02392               this->AddLink(link_stat, sum_flows, cargo_entry);
02393               if (highlight_empty && highlight) {
02394                 this->link_details.a_to_b.push_back(CargoDetail(&cargo_entry, link_stat, sum_flows));
02395               } else if (reverse_empty && reverse_highlight) {
02396                 this->link_details.b_to_a.push_back(CargoDetail(&cargo_entry, link_stat, sum_flows));
02397               }
02398             }
02399           }
02400         }
02401       }
02402     }
02403 
02404     virtual void DrawForwBackLinks(StationID sta, StationID stb)
02405     {
02406       this->DrawLink(sta, stb);
02407       this->DrawContent();
02408       Swap(this->pta, this->ptb);
02409       this->DrawLink(stb, sta);
02410       this->DrawContent();
02411     }
02412 
02413   public:
02414     virtual ~LinkDrawer() {}
02415 
02416     LinkDetails DrawLinks(const SmallMapWindow * w, bool search)
02417     {
02418       this->link_details.Clear();
02419       this->window = w;
02420       this->search_link_details = search;
02421       std::set<StationID> seen_stations;
02422       std::set<std::pair<StationID, StationID> > seen_links;
02423 
02424       const Station *sta;
02425       if (AllowMoreHeightlevels()) {
02426         FOR_ALL_STATIONS(sta) {
02427           if (sta->owner != _local_company && Company::IsValidID(sta->owner) && _settings_client.gui.linkgraph_companies == 0) continue; // test show all companies links
02428 
02429           for (int i = 0; i < _smallmap_cargo_count; ++i) {
02430             const LegendAndColour &tbl = _legend_table_extended[window->map_type][i];
02431             if (!tbl.show_on_map) continue;
02432 
02433             CargoID c = tbl.type;
02434             const LinkStatMap &links = sta->goods[c].link_stats;
02435             for (LinkStatMap::const_iterator i = links.begin(); i != links.end(); ++i) {
02436               StationID from = sta->index;
02437               StationID to = i->first;
02438               if (Station::IsValidID(to) && seen_stations.find(to) == seen_stations.end()) {
02439                 const Station *stb = Station::Get(to);
02440 
02441                 if (stb->owner != _local_company && Company::IsValidID(stb->owner) && _settings_client.gui.linkgraph_companies == 0) continue; // test show all companies links
02442                 if (sta->rect.IsEmpty() || stb->rect.IsEmpty()) continue;
02443                 if (seen_links.find(std::make_pair(to, from)) != seen_links.end()) continue;
02444 
02445                 this->pta = this->window->GetStationMiddle(sta);
02446                 this->ptb = this->window->GetStationMiddle(stb);
02447                 if (!this->IsLinkVisible()) continue;
02448 
02449                 this->DrawForwBackLinks(sta->index, stb->index);
02450                 seen_stations.insert(to);
02451               }
02452               seen_links.insert(std::make_pair(from, to));
02453             }
02454           }
02455           seen_stations.clear();
02456         }
02457 
02458       } else {
02459         FOR_ALL_STATIONS(sta) {
02460           if (sta->owner != _local_company && Company::IsValidID(sta->owner) && _settings_client.gui.linkgraph_companies == 0) continue; // test show all companies links
02461 
02462           for (int i = 0; i < _smallmap_cargo_count; ++i) {
02463             const LegendAndColour &tbl = _legend_table_old[window->map_type][i];
02464             if (!tbl.show_on_map) continue;
02465 
02466             CargoID c = tbl.type;
02467             const LinkStatMap &links = sta->goods[c].link_stats;
02468             for (LinkStatMap::const_iterator i = links.begin(); i != links.end(); ++i) {
02469               StationID from = sta->index;
02470               StationID to = i->first;
02471               if (Station::IsValidID(to) && seen_stations.find(to) == seen_stations.end()) {
02472                 const Station *stb = Station::Get(to);
02473 
02474                 if (stb->owner != _local_company && Company::IsValidID(stb->owner) && _settings_client.gui.linkgraph_companies == 0) continue; // test show all companies links
02475                 if (sta->rect.IsEmpty() || stb->rect.IsEmpty()) continue;
02476                 if (seen_links.find(std::make_pair(to, from)) != seen_links.end()) continue;
02477 
02478                 this->pta = this->window->GetStationMiddle(sta);
02479                 this->ptb = this->window->GetStationMiddle(stb);
02480                 if (!this->IsLinkVisible()) continue;
02481 
02482                 this->DrawForwBackLinks(sta->index, stb->index);
02483                 seen_stations.insert(to);
02484               }
02485               seen_links.insert(std::make_pair(from, to));
02486             }
02487           }
02488         
02489           seen_stations.clear();
02490         }
02491       }
02492       return this->link_details;
02493     }
02494 
02495   };
02496 
02497   class LinkLineDrawer : public LinkDrawer {
02498   public:
02499     LinkLineDrawer() : highlight(false) {}
02500 
02501   protected:
02502     typedef std::set<uint16> ColourSet;
02503     ColourSet colours;
02504     bool highlight;
02505 
02506     virtual void DrawForwBackLinks(StationID sta, StationID stb)
02507     {
02508       this->DrawLink(sta, stb);
02509       this->DrawLink(stb, sta);
02510       this->DrawContent();
02511     }
02512 
02513     virtual void AddLink(const LinkStat & orig_link, const FlowStat & orig_flow, const LegendAndColour &cargo_entry)
02514     {
02515       this->colours.insert(cargo_entry.colour);
02516     }
02517 
02518     virtual void Highlight()
02519     {
02520       this->highlight = true;
02521     }
02522 
02523     virtual void DrawContent()
02524     {
02525       uint colour = 0;
02526       uint num_colours = 0;
02527       for (ColourSet::iterator i = colours.begin(); i != colours.end(); ++i) {
02528         colour += *i;
02529         num_colours++;
02530       }
02531       colour /= num_colours;
02532       byte border_colour = _colour_gradient[COLOUR_GREY][highlight ? 3 : 1];
02533       GfxDrawLine(this->pta.x - 1, this->pta.y, this->ptb.x - 1, this->ptb.y, border_colour);
02534       GfxDrawLine(this->pta.x + 1, this->pta.y, this->ptb.x + 1, this->ptb.y, border_colour);
02535       GfxDrawLine(this->pta.x, this->pta.y - 1, this->ptb.x, this->ptb.y - 1, border_colour);
02536       GfxDrawLine(this->pta.x, this->pta.y + 1, this->ptb.x, this->ptb.y + 1, border_colour);
02537       GfxDrawLine(this->pta.x, this->pta.y, this->ptb.x, this->ptb.y, colour);
02538       this->colours.clear();
02539       this->highlight = false;
02540     }
02541   };
02542 
02543   class LinkValueDrawer : public LinkDrawer, public BaseCargoDetail {
02544   protected:
02545 
02546     virtual void AddLink(const LinkStat & orig_link, const FlowStat & orig_flow, const LegendAndColour &cargo_entry)
02547     {
02548       this->BaseCargoDetail::AddLink(orig_link, orig_flow);
02549     }
02550   };
02551 
02552   class LinkTextDrawer : public LinkValueDrawer {
02553   protected:
02554     virtual void DrawContent()
02555     {
02556       Point ptm;
02557       ptm.x = (this->pta.x + 2*this->ptb.x) / 3;
02558       ptm.y = (this->pta.y + 2*this->ptb.y) / 3;
02559       int nums = 0;
02560       if (_legend_linkstats[_smallmap_cargo_count + STAT_CAPACITY].show_on_map) {
02561         SetDParam(nums++, this->capacity);
02562       }
02563       if (_legend_linkstats[_smallmap_cargo_count + STAT_USAGE].show_on_map) {
02564         SetDParam(nums++, this->usage);
02565       }
02566       if (_legend_linkstats[_smallmap_cargo_count + STAT_PLANNED].show_on_map) {
02567         SetDParam(nums++, this->planned);
02568       }
02569       if (_legend_linkstats[_smallmap_cargo_count + STAT_SENT].show_on_map) {
02570         SetDParam(nums++, this->sent);
02571       }
02572       StringID str;
02573       switch (nums) {
02574       case 0:
02575         str = STR_EMPTY; break;
02576       case 1:
02577         str = STR_NUM; break;
02578       case 2:
02579         str = STR_NUM_RELATION_2; break;
02580       case 3:
02581         str = STR_NUM_RELATION_3; break;
02582       case 4:
02583         str = STR_NUM_RELATION_4; break;
02584       default:
02585         NOT_REACHED();
02586       }
02587       DrawString(ptm.x, ptm.x + this->window->ColumnWidth(), ptm.y, str, TC_WHITE);
02588       this->Clear();
02589     }
02590   };
02591 
02592   class LinkGraphDrawer : public LinkValueDrawer {
02593     typedef std::multimap<uint, byte, std::greater<uint> > SizeMap;
02594   protected:
02595     virtual void DrawContent()
02596     {
02597       Point ptm;
02598       SizeMap sizes;
02599       /* these floats only serve to calculate the size of the coloured boxes for capacity, usage, planned, sent
02600        * they are not reused anywhere, so it's network safe.
02601        */
02602       const LegendAndColour *legend_entry = _legend_linkstats + _smallmap_cargo_count + STAT_USAGE;
02603       if (legend_entry->show_on_map && this->usage > 0) {
02604         sizes.insert(std::make_pair((uint)sqrt((float)this->usage), legend_entry->colour));
02605       }
02606       legend_entry = _legend_linkstats + _smallmap_cargo_count + STAT_CAPACITY;
02607       if (legend_entry->show_on_map && this->capacity > 0) {
02608         sizes.insert(std::make_pair((uint)sqrt((float)this->capacity), legend_entry->colour));
02609       }
02610       legend_entry = _legend_linkstats + _smallmap_cargo_count + STAT_PLANNED;
02611       if (legend_entry->show_on_map && this->planned > 0) {
02612         sizes.insert(std::make_pair((uint)sqrt((float)this->planned),  legend_entry->colour));
02613       }
02614       legend_entry = _legend_linkstats + _smallmap_cargo_count + STAT_SENT;
02615       if (legend_entry->show_on_map && this->sent > 0) {
02616         sizes.insert(std::make_pair((uint)sqrt((float)this->sent), legend_entry->colour));
02617       }
02618 
02619       ptm.x = (this->pta.x + this->ptb.x) / 2;
02620       ptm.y = (this->pta.y + this->ptb.y) / 2;
02621 
02622       for (SizeMap::iterator i = sizes.begin(); i != sizes.end(); ++i) {
02623         if (this->pta.x > this->ptb.x) {
02624           ptm.x -= 1;
02625           GfxFillRect(ptm.x - i->first / 2, ptm.y - i->first * 2, ptm.x, ptm.y, i->second);
02626         } else {
02627           ptm.x += 1;
02628           GfxFillRect(ptm.x, ptm.y - i->first * 2, ptm.x + i->first / 2, ptm.y, i->second);
02629         }
02630       }
02631       this->Clear();
02632     }
02633   };
02634 
02635   static const uint MORE_SPACE_NEEDED = 0x1000;
02636 
02637   uint DrawLinkDetails(StatVector &details, uint x, uint y, uint right, uint bottom) const
02638   {
02639     uint x_orig = x;
02640     SetDParam(0, 9999);
02641     static uint entry_width = LEGEND_BLOB_WIDTH +
02642         GetStringBoundingBox(STR_ABBREV_PASSENGERS).width +
02643         GetStringBoundingBox(STR_SMALLMAP_LINK_CAPACITY).width +
02644         GetStringBoundingBox(STR_SMALLMAP_LINK_USAGE).width +
02645         GetStringBoundingBox(STR_SMALLMAP_LINK_PLANNED).width +
02646         GetStringBoundingBox(STR_SMALLMAP_LINK_SENT).width;
02647     uint entries_per_row = (right - x_orig) / entry_width;
02648     if (details.empty()) {
02649       DrawString(x, x + entry_width, y, STR_TINY_NOTHING, TC_BLACK);
02650       return y + FONT_HEIGHT_SMALL;
02651     }
02652     for (uint i = 0; i < details.size(); ++i) {
02653       CargoDetail &detail = details[i];
02654       if (x + entry_width >= right) {
02655         x = x_orig;
02656         y += FONT_HEIGHT_SMALL;
02657         if (y + 2 * FONT_HEIGHT_SMALL > bottom && details.size() - i > entries_per_row) {
02658           return y | MORE_SPACE_NEEDED;
02659         }
02660       }
02661       uint x_next = x + entry_width;
02662       if (detail.legend->show_on_map) {
02663         GfxFillRect(x, y + 1, x + LEGEND_BLOB_WIDTH, y + FONT_HEIGHT_SMALL - 1, PC_BLACK); // outer border of the legend colour
02664       }
02665       GfxFillRect(x + 1, y + 2, x + LEGEND_BLOB_WIDTH - 1, y + FONT_HEIGHT_SMALL - 2, detail.legend->colour); // legend colour
02666       x += LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT;
02667       TextColour textcol[4];
02668       for (int stat = STAT_CAPACITY; stat <= STAT_SENT; ++stat) {
02669         textcol[stat] = (detail.legend->show_on_map && _legend_linkstats[_smallmap_cargo_count + stat].show_on_map) ?
02670             TC_BLACK : TC_GREY;
02671       }
02672 
02673       SetDParam(0, CargoSpec::Get(detail.legend->type)->abbrev);
02674       x = DrawString(x, x_next - 1, y, STR_SMALLMAP_LINK, detail.legend->show_on_map ? TC_BLACK : TC_GREY);
02675       SetDParam(0, detail.capacity);
02676       x = DrawString(x, x_next - 1, y, STR_SMALLMAP_LINK_CAPACITY, textcol[STAT_CAPACITY]);
02677       SetDParam(0, detail.usage);
02678       x = DrawString(x, x_next - 1, y, STR_SMALLMAP_LINK_USAGE, textcol[STAT_USAGE]);
02679       SetDParam(0, detail.planned);
02680       x = DrawString(x, x_next - 1, y, STR_SMALLMAP_LINK_PLANNED, textcol[STAT_PLANNED]);
02681       SetDParam(0, detail.sent);
02682       x = DrawString(x, x_next - 1, y, STR_SMALLMAP_LINK_SENT, textcol[STAT_SENT]);
02683       x = x_next;
02684     }
02685     return y + FONT_HEIGHT_SMALL;
02686   }
02687 
02688   uint DrawLinkDetailCaption(uint x, uint y, uint right, StationID sta, StationID stb) const
02689   {
02690     SetDParam(0, sta);
02691     SetDParam(1, stb);
02692     static uint height = GetStringBoundingBox(STR_SMALLMAP_LINK_CAPTION).height;
02693     DrawString(x, right - 1, y, STR_SMALLMAP_LINK_CAPTION, TC_BLACK);
02694     y += height;
02695     return y;
02696   }
02697 
02698   void DrawLinkDetails(uint x, uint y, uint right, uint bottom) const
02699   {
02700     y = DrawLinkDetailCaption(x, y, right, this->link_details.sta, this->link_details.stb);
02701     if (y + 2 * FONT_HEIGHT_SMALL > bottom) {
02702       DrawString(x, right, y, "...", TC_BLACK);
02703       return;
02704     }
02705     y = DrawLinkDetails(this->link_details.a_to_b, x, y, right, bottom);
02706     if (y + 3 * FONT_HEIGHT_SMALL > bottom) {
02707       /* caption takes more space -> 3 * row height */
02708       DrawString(x, right, y, "...", TC_BLACK);
02709       return;
02710     }
02711     y = DrawLinkDetailCaption(x, y + 2, right, this->link_details.stb, this->link_details.sta);
02712     if (y + 2 * FONT_HEIGHT_SMALL > bottom) {
02713       DrawString(x, right, y, "...", TC_BLACK);
02714       return;
02715     }
02716     y = DrawLinkDetails(this->link_details.b_to_a, x, y, right, bottom);
02717     if (y & MORE_SPACE_NEEDED) {
02718       /* only draw "..." if more entries would have been drawn */
02719       DrawString(x, right, y ^ MORE_SPACE_NEEDED, "...", TC_BLACK);
02720       return;
02721     }
02722   }
02723 
02724   void DrawSupplyDetails(uint x, uint y_org, uint bottom) const
02725   {
02726     const Station *st = Station::GetIfValid(this->supply_details);
02727     if (st == NULL) return;
02728     SetDParam(0, this->supply_details);
02729     static uint height = GetStringBoundingBox(STR_SMALLMAP_SUPPLY_CAPTION).height;
02730     DrawString(x, x + 2 * this->column_width - 1, y_org, STR_SMALLMAP_SUPPLY_CAPTION, TC_BLACK);
02731     y_org += height;
02732     uint y = y_org;
02733     if (AllowMoreHeightlevels()) {
02734       for (int i = 0; i < _smallmap_cargo_count; ++i) {
02735         if (y + FONT_HEIGHT_SMALL - 1 >= bottom) {
02736           /* Column break needed, continue at top, SD_LEGEND_COLUMN_WIDTH pixels
02737            * (one "row") to the right. */
02738           x += this->column_width;
02739           y = y_org;
02740         }
02741 
02742         const LegendAndColour &tbl = _legend_table_extended[this->map_type][i];
02743 
02744         CargoID c = tbl.type;
02745         uint supply = st->goods[c].supply;
02746         if (supply > 0) {
02747           TextColour textcol = TC_BLACK;
02748           if (tbl.show_on_map) {
02749             GfxFillRect(x, y + 1, x + LEGEND_BLOB_WIDTH, y + FONT_HEIGHT_SMALL - 1, PC_BLACK); // outer border of the legend colour
02750           } else {
02751             textcol = TC_GREY;
02752           }
02753           SetDParam(0, c);
02754           SetDParam(1, supply);
02755           DrawString(x + LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT, x + this->column_width - 1, y, STR_SMALLMAP_SUPPLY, textcol);
02756           GfxFillRect(x + 1, y + 2, x + LEGEND_BLOB_WIDTH - 1, y + FONT_HEIGHT_SMALL - 2, tbl.colour); // legend colour
02757           y += FONT_HEIGHT_SMALL;
02758         }
02759       }
02760 
02761     } else {
02762       for (int i = 0; i < _smallmap_cargo_count; ++i) {
02763         if (y + FONT_HEIGHT_SMALL - 1 >= bottom) {
02764           /* Column break needed, continue at top, SD_LEGEND_COLUMN_WIDTH pixels
02765            * (one "row") to the right. */
02766           x += this->column_width;
02767           y = y_org;
02768         }
02769 
02770         const LegendAndColour &tbl = _legend_table_old[this->map_type][i];
02771 
02772         CargoID c = tbl.type;
02773         uint supply = st->goods[c].supply;
02774         if (supply > 0) {
02775           TextColour textcol = TC_BLACK;
02776           if (tbl.show_on_map) {
02777             GfxFillRect(x, y + 1, x + LEGEND_BLOB_WIDTH, y + FONT_HEIGHT_SMALL - 1, PC_BLACK); // outer border of the legend colour
02778           } else {
02779             textcol = TC_GREY;
02780           }
02781           SetDParam(0, c);
02782           SetDParam(1, supply);
02783           DrawString(x + LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT, x + this->column_width - 1, y, STR_SMALLMAP_SUPPLY, textcol);
02784           GfxFillRect(x + 1, y + 2, x + LEGEND_BLOB_WIDTH - 1, y + FONT_HEIGHT_SMALL - 2, tbl.colour); // legend colour
02785           y += FONT_HEIGHT_SMALL;
02786         }
02787       }
02788     }
02789   }
02790 
02795   void DrawTowns(const DrawPixelInfo *dpi) const
02796   {
02797     const Town *t;
02798     FOR_ALL_TOWNS(t) {
02799       /* Remap the town coordinate */
02800       Point pt = this->RemapTile(TileX(t->xy), TileY(t->xy));
02801       int x = pt.x - this->subscroll - (t->sign.width_small >> 1);
02802       int y = pt.y;
02803 
02804       /* Check if the town sign is within bounds */
02805       if (x + t->sign.width_small > dpi->left &&
02806           x < dpi->left + dpi->width &&
02807           y + FONT_HEIGHT_SMALL > dpi->top &&
02808           y < dpi->top + dpi->height) {
02809         /* And draw it. */
02810         SetDParam(0, t->index);
02811         DrawString(x, x + t->sign.width_small, y, STR_SMALLMAP_TOWN);
02812       }
02813     }
02814   }
02815 
02822   static inline void DrawVertMapIndicator(int x, int y, int y2)
02823   {
02824     GfxFillRect(x, y,      x, y + 3, PC_VERY_LIGHT_YELLOW);
02825     GfxFillRect(x, y2 - 3, x, y2,    PC_VERY_LIGHT_YELLOW);
02826   }
02827 
02834   static inline void DrawHorizMapIndicator(int x, int x2, int y)
02835   {
02836     GfxFillRect(x,      y, x + 3, y, PC_VERY_LIGHT_YELLOW);
02837     GfxFillRect(x2 - 3, y, x2,    y, PC_VERY_LIGHT_YELLOW);
02838   }
02839 
02843   void DrawMapIndicators() const
02844   {
02845     /* Find main viewport. */
02846     const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
02847 
02848     Point tile = InverseRemapCoords(vp->virtual_left, vp->virtual_top);
02849     Point tl = this->RemapTile(tile.x >> 4, tile.y >> 4);
02850     tl.x -= this->subscroll;
02851 
02852     tile = InverseRemapCoords(vp->virtual_left + vp->virtual_width, vp->virtual_top + vp->virtual_height);
02853     Point br = this->RemapTile(tile.x >> 4, tile.y >> 4);
02854     br.x -= this->subscroll;
02855 
02856     SmallMapWindow::DrawVertMapIndicator(tl.x, tl.y, br.y);
02857     SmallMapWindow::DrawVertMapIndicator(br.x, tl.y, br.y);
02858 
02859     SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, tl.y);
02860     SmallMapWindow::DrawHorizMapIndicator(tl.x, br.x, br.y);
02861   }
02862 
02874   void DrawSmallMap(DrawPixelInfo *dpi) const
02875   {
02876     Blitter *blitter = BlitterFactoryBase::GetCurrentBlitter();
02877     DrawPixelInfo *old_dpi;
02878 
02879     old_dpi = _cur_dpi;
02880     _cur_dpi = dpi;
02881 
02882     /* Clear it */
02883     GfxFillRect(dpi->left, dpi->top, dpi->left + dpi->width - 1, dpi->top + dpi->height - 1, PC_BLACK);
02884 
02885     /* Which tile is displayed at (dpi->left, dpi->top)? */
02886     int dx;
02887     Point position = this->PixelToWorld(dpi->left, dpi->top, &dx);
02888     int pos_x = this->scroll_x + position.x;
02889     int pos_y = this->scroll_y + position.y;
02890 
02891     void *ptr = blitter->MoveTo(dpi->dst_ptr, -dx - 4, 0);
02892     int x = - dx - 4;
02893     int y = 0;
02894     int increment = this->zoom > 0 ? this->zoom * TILE_SIZE : TILE_SIZE / (-this->zoom); 
02895 
02896     for (;;) {
02897       /* Distance from left edge */
02898       if (x >= -3) {
02899         if (x >= dpi->width) break; // Exit the loop.
02900 
02901         int end_pos = min(dpi->width, x + 4);
02902         int reps = (dpi->height - y + 1) / 2; // Number of lines.
02903         if (reps > 0) {
02904           this->DrawSmallMapColumn(ptr, pos_x, pos_y, dpi->pitch * 2, reps, x, end_pos, blitter);
02905         }
02906       }
02907 
02908       if (y == 0) {
02909         pos_y += increment;
02910         y++;
02911         ptr = blitter->MoveTo(ptr, 0, 1);
02912       } else {
02913         pos_x -= increment;
02914         y--;
02915         ptr = blitter->MoveTo(ptr, 0, -1);
02916       }
02917       ptr = blitter->MoveTo(ptr, 2, 0);
02918       x += 2;
02919     }
02920 
02921     /* Draw vehicles */
02922     if (this->map_type == SMT_CONTOUR || this->map_type == SMT_VEHICLES) this->DrawVehicles(dpi, blitter);
02923 
02924     /* Draw the cargo linkgraphs */
02925     if (this->map_type == SMT_LINKSTATS && _game_mode == GM_NORMAL) {
02926       LinkLineDrawer lines;
02927       this->link_details = lines.DrawLinks(this, true);
02928 
02929       this->supply_details = DrawStationDots();
02930 
02931       if (_legend_linkstats[_smallmap_cargo_count + STAT_TEXT].show_on_map) {
02932         LinkTextDrawer text;
02933         text.DrawLinks(this, false);
02934       }
02935       if (_legend_linkstats[_smallmap_cargo_count + STAT_GRAPH].show_on_map) {
02936         LinkGraphDrawer graph;
02937         graph.DrawLinks(this, false);
02938       }
02939     }
02940 
02941     /* Draw town names */
02942     if (this->show_towns) this->DrawTowns(dpi);
02943 
02944     /* Draw map indicators */
02945     this->DrawMapIndicators();
02946 
02947     _cur_dpi = old_dpi;
02948   }
02949 
02950   bool CheckStationSelected(Point *pt) const
02951   {
02952     return abs(this->cursor.x - pt->x) < 7 && abs(this->cursor.y - pt->y) < 7;
02953   }
02954 
02955   bool CheckLinkSelected(Point *pta, Point *ptb) const
02956   {
02957     if (this->cursor.x == -1 && this->cursor.y == -1) return false;
02958     if (CheckStationSelected(pta) || CheckStationSelected(ptb)) return false;
02959     if (pta->x > ptb->x) Swap(pta, ptb);
02960     int minx = min(pta->x, ptb->x);
02961     int maxx = max(pta->x, ptb->x);
02962     int miny = min(pta->y, ptb->y);
02963     int maxy = max(pta->y, ptb->y);
02964     if (!IsInsideMM(cursor.x, minx - 3, maxx + 3) || !IsInsideMM(cursor.y, miny - 3, maxy + 3)) {
02965       return false;
02966     }
02967 
02968     if (pta->x == ptb->x || ptb->y == pta->y) {
02969       return true;
02970     } else {
02971       int incliney = (ptb->y - pta->y);
02972       int inclinex = (ptb->x - pta->x);
02973       int diff = (cursor.x - minx) * incliney / inclinex - (cursor.y - miny);
02974       if (incliney < 0) {
02975         diff += maxy - miny;
02976       }
02977       return abs(diff) < 4;
02978     }
02979   }
02980 
02984   void RecalcVehiclePositions()
02985   {
02986     this->vehicles_on_map.clear();
02987     const Vehicle *v;
02988     const NWidgetCore *wi = this->GetWidget<NWidgetCore>(SM_WIDGET_MAP);
02989     int scale = this->zoom < 0 ? -this->zoom : 1;
02990 
02991     FOR_ALL_VEHICLES(v) {
02992       if (v->type == VEH_EFFECT) continue;
02993       if (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) continue;
02994 
02995       /* Remap into flat coordinates. We have to do that again in DrawVehicles to account for scrolling. */
02996       Point pos = RemapTile(v->x_pos / (int)TILE_SIZE, v->y_pos / (int)TILE_SIZE);
02997 
02998       /* Check if rhombus is inside bounds */
02999       if (IsInsideMM(pos.x, -2 * scale, wi->current_x + 2 * scale) &&
03000         IsInsideMM(pos.y, -2 * scale, wi->current_y + 2 * scale)) {
03001 
03002         this->vehicles_on_map.push_back(VehicleAndPosition(v));
03003       }
03004     }
03005   }
03006 
03010   void SetupWidgetData()
03011   {
03012     StringID legend_tooltip;
03013     StringID enable_all_tooltip;
03014     StringID disable_all_tooltip;
03015     int plane;
03016     switch (this->map_type) {
03017       case SMT_INDUSTRY:
03018         legend_tooltip = STR_SMALLMAP_TOOLTIP_INDUSTRY_SELECTION;
03019         enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_INDUSTRIES;
03020         disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_INDUSTRIES;
03021         plane = 0;
03022         break;
03023 
03024       case SMT_LINKSTATS:
03025         legend_tooltip = STR_SMALLMAP_TOOLTIP_LINK_STATS_SELECTION;
03026         enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_LINK_STATS;
03027         disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_LINK_STATS;
03028         plane = 0;
03029         break;
03030 
03031       case SMT_OWNER:
03032         legend_tooltip = STR_SMALLMAP_TOOLTIP_COMPANY_SELECTION;
03033         enable_all_tooltip = STR_SMALLMAP_TOOLTIP_ENABLE_ALL_COMPANIES;
03034         disable_all_tooltip = STR_SMALLMAP_TOOLTIP_DISABLE_ALL_COMPANIES;
03035         plane = 0;
03036         break;
03037 
03038       default:
03039         legend_tooltip = STR_NULL;
03040         enable_all_tooltip = STR_NULL;
03041         disable_all_tooltip = STR_NULL;
03042         plane = 1;
03043         break;
03044     }
03045 
03046     this->GetWidget<NWidgetCore>(SM_WIDGET_LEGEND)->SetDataTip(STR_NULL, legend_tooltip);
03047     this->GetWidget<NWidgetCore>(SM_WIDGET_ENABLE_ALL)->SetDataTip(STR_SMALLMAP_ENABLE_ALL, enable_all_tooltip);
03048     this->GetWidget<NWidgetCore>(SM_WIDGET_DISABLE_ALL)->SetDataTip(STR_SMALLMAP_DISABLE_ALL, disable_all_tooltip);
03049     this->GetWidget<NWidgetStacked>(SM_WIDGET_SELECT_BUTTONS)->SetDisplayedPlane(plane);
03050   }
03051 
03052 public:
03053   uint min_number_of_columns;    
03054 
03055   SmallMapWindow(const WindowDesc *desc, int window_number) : Window(), supply_details(INVALID_STATION), refresh(FORCE_REFRESH_PERIOD)
03056   {
03057     this->cursor.x = -1;
03058     this->cursor.y = -1;
03059     this->InitNested(desc, window_number);
03060     if (_smallmap_cargo_count == 0) {
03061       this->DisableWidget(SM_WIDGET_LINKSTATS);
03062       if (this->map_type == SMT_LINKSTATS) this->map_type = SMT_CONTOUR;
03063     }
03064 
03065     this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
03066 
03067     BuildLandLegend();
03068     this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_show_heightmap);
03069 
03070     this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
03071 
03072     this->SetupWidgetData();
03073 
03074     this->SetZoomLevel(ZLC_INITIALIZE, NULL);
03075     this->SmallMapCenterOnCurrentPos();
03076   }
03077 
03078 //  /**
03079 //   * Compute maximal required height of the legends. // TODO: remove and fix
03080 //   * @return Maximally needed height for displaying the smallmap legends in pixels.
03081 //   */
03082 //  inline uint GetMaxLegendHeight() const
03083 //  {
03084 //    return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + this->GetMaxNumberRowsLegend(this->min_number_of_columns) * FONT_HEIGHT_SMALL;
03085 //  }
03086 
03091   inline uint GetMinLegendWidth() const
03092   {
03093     return WD_FRAMERECT_LEFT + this->min_number_of_columns * this->column_width;
03094   }
03095 
03100   inline uint GetNumberColumnsLegend(uint width) const
03101   {
03102     return width / this->column_width;
03103   }
03104 
03111   uint GetLegendHeight(uint num_columns) const
03112 //  uint GetLegendHeight(uint width) const
03113   {
03114 //    uint num_rows = max(this->min_number_of_fixed_rows, CeilDiv(max(_smallmap_company_count, _smallmap_industry_count), num_columns));
03115 //    return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + num_rows * FONT_HEIGHT_SMALL;
03116 //    uint num_columns = this->GetNumberColumnsLegend(width);
03117     return WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + this->GetNumberRowsLegend(num_columns) * FONT_HEIGHT_SMALL;
03118   }
03119 
03120   virtual void SetStringParameters(int widget) const
03121   {
03122     switch (widget) {
03123       case SM_WIDGET_CAPTION:
03124         SetDParam(0, STR_SMALLMAP_TYPE_CONTOURS + this->map_type);
03125         break;
03126     }
03127   }
03128 
03129   virtual void OnInit()
03130   {
03131     uint min_width = 0;
03132     this->min_number_of_columns = INDUSTRY_MIN_NUMBER_OF_COLUMNS;
03133 //    this->min_number_of_fixed_rows = 0;
03134     this->min_number_of_fixed_rows = lengthof(_legend_linkstats) / 2 + 1;
03135     if (AllowMoreHeightlevels()) {
03136       for (uint i = 0; i < lengthof(_legend_table_extended); i++) {
03137         uint height = 0;
03138         uint num_columns = 1;
03139         for (const LegendAndColour *tbl = _legend_table_extended[i]; !tbl->end; ++tbl) {
03140           StringID str;
03141           if (i == SMT_INDUSTRY) {
03142             SetDParam(0, tbl->legend);
03143             SetDParam(1, IndustryPool::MAX_SIZE);
03144             str = STR_SMALLMAP_INDUSTRY;
03145           } else if (i == SMT_LINKSTATS) {
03146             SetDParam(0, tbl->legend);
03147             str = STR_SMALLMAP_LINKSTATS;
03148           } else if (i == SMT_OWNER) {
03149             if (tbl->company != INVALID_COMPANY) {
03150               if (!Company::IsValidID(tbl->company)) {
03151                 /* Rebuild the owner legend. */
03152                 BuildOwnerLegend();
03153                 this->OnInit();
03154                 return;
03155               }
03156               /* Non-fixed legend entries for the owner view. */
03157               SetDParam(0, tbl->company);
03158               str = STR_SMALLMAP_COMPANY;
03159             } else {
03160               str = tbl->legend;
03161             }
03162           } else {
03163             if (tbl->col_break) {
03164               this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
03165               height = 0;
03166               num_columns++;
03167             }
03168             height++;
03169             str = tbl->legend;
03170           }
03171           min_width = max(GetStringBoundingBox(str).width, min_width);
03172         }
03173         this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
03174         this->min_number_of_columns = max(this->min_number_of_columns, num_columns);
03175       }
03176 
03177     } else {
03178       for (uint i = 0; i < lengthof(_legend_table_old); i++) {
03179         uint height = 0;
03180         uint num_columns = 1;
03181         for (const LegendAndColour *tbl = _legend_table_old[i]; !tbl->end; ++tbl) {
03182           StringID str;
03183           if (i == SMT_INDUSTRY) {
03184             SetDParam(0, tbl->legend);
03185             SetDParam(1, IndustryPool::MAX_SIZE);
03186             str = STR_SMALLMAP_INDUSTRY;
03187           } else if (i == SMT_LINKSTATS) {
03188             SetDParam(0, tbl->legend);
03189             str = STR_SMALLMAP_LINKSTATS;
03190           } else if (i == SMT_OWNER) {
03191             if (tbl->company != INVALID_COMPANY) {
03192               if (!Company::IsValidID(tbl->company)) {
03193                 /* Rebuild the owner legend. */
03194                 BuildOwnerLegend();
03195                 this->OnInit();
03196                 return;
03197               }
03198               /* Non-fixed legend entries for the owner view. */
03199               SetDParam(0, tbl->company);
03200               str = STR_SMALLMAP_COMPANY;
03201             } else {
03202               str = tbl->legend;
03203             }
03204           } else {
03205             if (tbl->col_break) {
03206               this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
03207               height = 0;
03208               num_columns++;
03209             }
03210             height++;
03211             str = tbl->legend;
03212           }
03213           min_width = max(GetStringBoundingBox(str).width, min_width);
03214         }
03215         this->min_number_of_fixed_rows = max(this->min_number_of_fixed_rows, height);
03216         this->min_number_of_columns = max(this->min_number_of_columns, num_columns);
03217       }
03218     }
03219 
03220     /* The width of a column is the minimum width of all texts + the size of the blob + some spacing */
03221     this->column_width = min_width + LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
03222   }
03223 
03224   virtual void OnPaint()
03225   {
03226     if (this->map_type == SMT_OWNER) {
03227       if (AllowMoreHeightlevels()) {
03228         for (const LegendAndColour *tbl = _legend_table_extended[this->map_type]; !tbl->end; ++tbl) {
03229           if (tbl->company != INVALID_COMPANY && !Company::IsValidID(tbl->company)) {
03230             /* Rebuild the owner legend. */
03231             BuildOwnerLegend();
03232             this->InvalidateData(1);
03233             break;
03234           }
03235         }
03236       } else {
03237         for (const LegendAndColour *tbl = _legend_table_old[this->map_type]; !tbl->end; ++tbl) {
03238           if (tbl->company != INVALID_COMPANY && !Company::IsValidID(tbl->company)) {
03239             /* Rebuild the owner legend. */
03240             BuildOwnerLegend();
03241             this->InvalidateData(1);
03242             break;
03243           }
03244         }
03245       }
03246     }
03247 
03248     this->DrawWidgets();
03249   }
03250 
03251   virtual void DrawWidget(const Rect &r, int widget) const
03252   {
03253     switch (widget) {
03254       case SM_WIDGET_MAP: {
03255         DrawPixelInfo new_dpi;
03256         if (!FillDrawPixelInfo(&new_dpi, r.left + 1, r.top + 1, r.right - r.left - 1, r.bottom - r.top - 1)) return;
03257         this->DrawSmallMap(&new_dpi);
03258         break;
03259       }
03260 
03261       case SM_WIDGET_LEGEND: {
03262         uint y_org = r.top + WD_FRAMERECT_TOP;
03263         uint x = r.left + WD_FRAMERECT_LEFT;
03264         if (this->supply_details != INVALID_STATION) {
03265           this->DrawSupplyDetails(x, y_org, r.bottom - WD_FRAMERECT_BOTTOM);
03266         } else if (!this->link_details.Empty()) {
03267           this->DrawLinkDetails(x, y_org, r.right - WD_FRAMERECT_RIGHT, r.bottom - WD_FRAMERECT_BOTTOM);
03268         } else {
03269           uint columns = this->GetNumberColumnsLegend(r.right - r.left + 1);
03270           uint number_of_rows = this->GetNumberRowsLegend(columns);
03271           bool rtl = _current_text_dir == TD_RTL;
03272           uint y_org = r.top + WD_FRAMERECT_TOP;
03273           uint x = rtl ? r.right - this->column_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT;
03274           uint y = y_org;
03275           uint i = 0; // Row counter for industry legend.
03276           uint row_height = FONT_HEIGHT_SMALL;
03277 
03278           uint text_left  = rtl ? 0 : LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT;
03279           uint text_right = this->column_width - 1 - (rtl ? LEGEND_BLOB_WIDTH + WD_FRAMERECT_RIGHT : 0);
03280           uint blob_left  = rtl ? this->column_width - 1 - LEGEND_BLOB_WIDTH : 0;
03281           uint blob_right = rtl ? this->column_width - 1 : LEGEND_BLOB_WIDTH;
03282 
03283           StringID string = STR_NULL;
03284           switch (this->map_type) {
03285             case SMT_INDUSTRY:
03286               string = STR_SMALLMAP_INDUSTRY;
03287               break;
03288             case SMT_LINKSTATS:
03289               string = STR_SMALLMAP_LINKSTATS;
03290               break;
03291             case SMT_OWNER:
03292               string = STR_SMALLMAP_COMPANY;
03293               break;
03294             default:
03295               break;
03296           }
03297 
03298           if (AllowMoreHeightlevels()) {
03299             for (const LegendAndColour *tbl = _legend_table_extended[this->map_type]; !tbl->end; ++tbl) {
03300               if (tbl->col_break || ((this->map_type == SMT_INDUSTRY || this->map_type == SMT_LINKSTATS || this->map_type == SMT_OWNER) && i++ >= number_of_rows)) {
03301                 /* Column break needed, continue at top, COLUMN_WIDTH pixels
03302                  * (one "row") to the right. */
03303                 x += rtl ? -(int)this->column_width : this->column_width;
03304                 y = y_org;
03305                 i = 1;
03306               }
03307 
03308               switch(this->map_type) {
03309                 case SMT_INDUSTRY:
03310                   /* Industry name must be formatted, since it's not in tiny font in the specs.
03311                    * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font. */
03312                   SetDParam(1, Industry::GetIndustryTypeCount(tbl->type));
03313                 case SMT_LINKSTATS:
03314                   SetDParam(0, tbl->legend);
03315                 case SMT_OWNER:
03316                   if (this->map_type != SMT_OWNER || tbl->company != INVALID_COMPANY) {
03317                     if (this->map_type == SMT_OWNER) SetDParam(0, tbl->company);
03318                     if (!tbl->show_on_map) {
03319                       /* Simply draw the string, not the black border of the legend colour.
03320                       * This will enforce the idea of the disabled item */
03321                       DrawString(x + text_left, x + text_right, y, string, TC_GREY);
03322                     } else {
03323                       DrawString(x + text_left, x + text_right, y, string, TC_BLACK);
03324                       GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK); // Outer border of the legend colour
03325                     }
03326                   break;
03327                   } // else fall through
03328                 default:
03329                   if (this->map_type == SMT_CONTOUR) SetDParam(0, tbl->height * TILE_HEIGHT_STEP);
03330 
03331                   /* Anything that is not an industry or a company is using normal process */
03332                   GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK);
03333                   DrawString(x + text_left, x + text_right, y, tbl->legend);
03334                   break;
03335               }
03336               GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + row_height - 2, tbl->colour); // Legend colour.
03337 
03338               y += row_height;
03339             }
03340           } else {
03341             for (const LegendAndColour *tbl = _legend_table_old[this->map_type]; !tbl->end; ++tbl) {
03342               if (tbl->col_break || ((this->map_type == SMT_INDUSTRY || this->map_type == SMT_LINKSTATS || this->map_type == SMT_OWNER) && i++ >= number_of_rows)) {
03343                 /* Column break needed, continue at top, COLUMN_WIDTH pixels
03344                  * (one "row") to the right. */
03345                 x += rtl ? -(int)this->column_width : this->column_width;
03346                 y = y_org;
03347                 i = 1;
03348               }
03349 
03350               switch(this->map_type) {
03351                 case SMT_INDUSTRY:
03352                   /* Industry name must be formatted, since it's not in tiny font in the specs.
03353                    * So, draw with a parameter and use the STR_SMALLMAP_INDUSTRY string, which is tiny font. */
03354                   SetDParam(1, Industry::GetIndustryTypeCount(tbl->type));
03355                 case SMT_LINKSTATS:
03356                   SetDParam(0, tbl->legend);
03357                 case SMT_OWNER:
03358                   if (this->map_type != SMT_OWNER || tbl->company != INVALID_COMPANY) {
03359                     if (this->map_type == SMT_OWNER) SetDParam(0, tbl->company);
03360                     if (!tbl->show_on_map) {
03361                       /* Simply draw the string, not the black border of the legend colour.
03362                       * This will enforce the idea of the disabled item */
03363                       DrawString(x + text_left, x + text_right, y, string, TC_GREY);
03364                     } else {
03365                       DrawString(x + text_left, x + text_right, y, string, TC_BLACK);
03366                       GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK); // Outer border of the legend colour
03367                     }
03368                   break;
03369                   } // else fall through
03370                 default:
03371                   if (this->map_type == SMT_CONTOUR) SetDParam(0, tbl->height * TILE_HEIGHT_STEP);
03372 
03373                   /* Anything that is not an industry or a company is using normal process */
03374                   GfxFillRect(x + blob_left, y + 1, x + blob_right, y + row_height - 1, PC_BLACK);
03375                   DrawString(x + text_left, x + text_right, y, tbl->legend);
03376                   break;
03377               }
03378               GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + row_height - 2, tbl->colour); // Legend colour
03379 
03380               y += row_height;
03381             }
03382           }
03383         }
03384       } break;
03385     }
03386   }
03387 
03396   uint GetNumberRowsLegend(uint columns) const
03397   {
03398     /* reserve one column for link colours */
03399     uint num_rows_linkstats = CeilDiv(_smallmap_cargo_count, columns - 1);
03400 
03401     uint num_rows_others = CeilDiv(max(_smallmap_industry_count,_smallmap_company_count), columns);
03402     return max(this->min_number_of_fixed_rows, max(num_rows_linkstats, num_rows_others));
03403   }
03404 
03416   void SelectLegendItem(int click_pos, LegendAndColour *legend, int end_legend_item, int begin_legend_item = 0)
03417   {
03418     if (_ctrl_pressed) {
03419       /* Disable all, except the clicked one */
03420       bool changes = false;
03421       for (int i = begin_legend_item; i != end_legend_item; i++) {
03422         bool new_state = (i == click_pos);
03423         if (legend[i].show_on_map != new_state) {
03424           changes = true;
03425           legend[i].show_on_map = new_state;
03426         }
03427       }
03428       if (!changes) {
03429         /* Nothing changed? Then show all (again). */
03430         for (int i = begin_legend_item; i != end_legend_item; i++) {
03431           legend[i].show_on_map = true;
03432         }
03433       }
03434     } else {
03435       legend[click_pos].show_on_map = !legend[click_pos].show_on_map;
03436     }
03437   }
03438 
03443   void SwitchMapType(SmallMapType map_type)
03444   {
03445     this->RaiseWidget(this->map_type + SM_WIDGET_CONTOUR);
03446     this->map_type = map_type;
03447     this->LowerWidget(this->map_type + SM_WIDGET_CONTOUR);
03448 
03449     this->SetupWidgetData();
03450 
03451     this->SetDirty();
03452   }
03453 
03454   virtual void OnClick(Point pt, int widget, int click_count)
03455   {
03456     /* User clicked something, notify the industry chain window to stop sending newly selected industries. */
03457     InvalidateWindowClassesData(WC_INDUSTRY_CARGOES, NUM_INDUSTRYTYPES);
03458 
03459     switch (widget) {
03460       case SM_WIDGET_MAP: { // Map window
03461         /*
03462          * XXX: scrolling with the left mouse button is done by subsequently
03463          * clicking with the left mouse button; clicking once centers the
03464          * large map at the selected point. So by unclicking the left mouse
03465          * button here, it gets reclicked during the next inputloop, which
03466          * would make it look like the mouse is being dragged, while it is
03467          * actually being (virtually) clicked every inputloop.
03468          */
03469         _left_button_clicked = false;
03470 
03471         const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
03472 
03473         /* We need to take the height at the clicked position into account
03474          * (i.e. move the map northwards).
03475          * Basically, we compute the inverse of function RemapX/Y here.
03476          * Note that we have to subtract 2 from x and 16 from y here because
03477          * _cursor_pos.x/y - this->left/top includes the edge of the small map. */
03478         int offset_inside_sm_x = _cursor.pos.x - this->left + wid->pos_x;
03479         int offset_inside_sm_y = _cursor.pos.y - this->top - wid->pos_y;
03480         int clicked_screen_x = offset_inside_sm_x * TILE_SIZE + pt.x;
03481         int clicked_screen_y = offset_inside_sm_y * TILE_SIZE + pt.y;
03482         Point clicked_tile = TileCoordFromScreenCoord(clicked_screen_x, clicked_screen_y);
03483         clicked_tile.x /= TILE_SIZE;
03484         clicked_tile.y /= TILE_SIZE;
03485         int clicked_tile_height = TileHeightOutsideMap(clicked_tile.x, clicked_tile.y);
03486 
03487         DEBUG(map, 9, "clicked: offset_inside_sm (%i,%i), clicked_tile (%i,%i), clicked_screen (%i,%i), clicked_tile_height %i",
03488             offset_inside_sm_x, offset_inside_sm_y, clicked_tile.x, clicked_tile.y, clicked_screen_x, clicked_screen_y, clicked_tile_height);
03489 
03490         Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
03491         int sub;
03492         pt = this->PixelToWorld(pt.x - wid->pos_x, pt.y - wid->pos_y, &sub);
03493         int offset = this->zoom > 0 ? this->zoom * TILE_SIZE : TILE_SIZE / (-this->zoom);
03494         pt = RemapCoords(this->scroll_x + pt.x + offset - offset * sub / 4,
03495             this->scroll_y + pt.y + sub * offset / 4, 0);
03496 
03497         w->viewport->follow_vehicle = INVALID_VEHICLE;
03498         w->viewport->dest_scrollpos_x = pt.x - (w->viewport->virtual_width  >> 1);
03499         w->viewport->dest_scrollpos_y = pt.y - ((clicked_tile_height * TILE_HEIGHT) + (w->viewport->virtual_height >> 1)); // TODO: add moreheightlevels_v29 and merge with cargodist (when clicking the smallmap main vieport positioning is slighlty off)
03500 
03501         DEBUG(map, 9, "OnClick: scroll_x, scroll_y = (%i,%i), pt = (%i,%i), dest_scrollpos = (%i,%i), cursor = (%i,%i), left/top = (%i, %i), virtual = (%i,%i)",
03502             this->scroll_x, this->scroll_y, pt.x, pt.y,
03503             w->viewport->dest_scrollpos_x, w->viewport->dest_scrollpos_y,
03504             _cursor.pos.x, _cursor.pos.y, this->left, this->top,
03505             w->viewport->virtual_width, w->viewport->virtual_height);
03506 
03507         this->SetDirty();
03508         break;
03509       }
03510 
03511       case SM_WIDGET_ZOOM_IN:
03512       case SM_WIDGET_ZOOM_OUT: {
03513         const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
03514         Point pt = {wid->current_x / 2, wid->current_y / 2};
03515         this->SetZoomLevel((widget == SM_WIDGET_ZOOM_IN) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt);
03516         SndPlayFx(SND_15_BEEP);
03517         break;
03518       }
03519 
03520       case SM_WIDGET_CONTOUR:    // Show land contours
03521       case SM_WIDGET_VEHICLES:   // Show vehicles
03522       case SM_WIDGET_INDUSTRIES: // Show industries
03523       case SM_WIDGET_LINKSTATS:  // Show route map
03524       case SM_WIDGET_ROUTES:     // Show transport routes
03525       case SM_WIDGET_VEGETATION: // Show vegetation
03526       case SM_WIDGET_OWNERS:     // Show land owners
03527         this->SwitchMapType((SmallMapType)(widget - SM_WIDGET_CONTOUR));
03528         SndPlayFx(SND_15_BEEP);
03529         break;
03530 
03531       case SM_WIDGET_CENTERMAP: // Center the smallmap again
03532         this->SmallMapCenterOnCurrentPos();
03533         this->HandleButtonClick(SM_WIDGET_CENTERMAP);
03534         SndPlayFx(SND_15_BEEP);
03535         break;
03536 
03537       case SM_WIDGET_TOGGLETOWNNAME: // Toggle town names
03538         this->show_towns = !this->show_towns;
03539         this->SetWidgetLoweredState(SM_WIDGET_TOGGLETOWNNAME, this->show_towns);
03540 
03541         this->SetDirty();
03542         SndPlayFx(SND_15_BEEP);
03543         break;
03544 
03545       case SM_WIDGET_LEGEND: // Legend
03546         /* If industry type small map*/
03547         if (this->map_type == SMT_INDUSTRY || this->map_type == SMT_LINKSTATS || this->map_type == SMT_OWNER) {
03548           /* If click on industries label, find right industry type and enable/disable it */
03549           const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_LEGEND); // Label panel
03550           uint line = (pt.y - wi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_SMALL;
03551           uint columns = this->GetNumberColumnsLegend(wi->current_x);
03552           uint number_of_rows = this->GetNumberRowsLegend(columns);
03553           if (line >= number_of_rows) break;
03554 
03555           bool rtl = _current_text_dir == TD_RTL;
03556           int x = pt.x - wi->pos_x;
03557           if (rtl) x = wi->current_x - x;
03558           uint column = (x - WD_FRAMERECT_LEFT) / this->column_width;
03559           int click_pos = (column * number_of_rows) + line;
03560 
03561           /* Check if click is on industry label*/
03562           if (this->map_type == SMT_INDUSTRY) {
03563             if (click_pos < _smallmap_industry_count) {
03564               this->SelectLegendItem(click_pos, _legend_from_industries, _smallmap_industry_count);
03565             }
03566           /* Check if click was on linkstats label*/
03567           } else if (this->map_type == SMT_LINKSTATS) {
03568             if (click_pos < _smallmap_cargo_count) {
03569               this->SelectLegendItem(click_pos, _legend_linkstats, _smallmap_cargo_count);
03570             } else {
03571               uint stats_column = CeilDiv(_smallmap_cargo_count, number_of_rows);
03572               if (column == stats_column && line < NUM_STATS) {
03573                 this->SelectLegendItem(_smallmap_cargo_count + line, _legend_linkstats,
03574                     _smallmap_cargo_count + NUM_STATS, _smallmap_cargo_count);
03575               }
03576             }
03577           /* Check if click is on company label. */
03578           } else if (this->map_type == SMT_OWNER) {
03579             if (click_pos < _smallmap_company_count) {
03580             this->SelectLegendItem(click_pos, _legend_land_owners, _smallmap_company_count, NUM_NO_COMPANY_ENTRIES);
03581             }
03582           }
03583           this->SetDirty();
03584         }
03585         break;
03586 
03587       case SM_WIDGET_ENABLE_ALL: // enable/diable all items
03588       case SM_WIDGET_DISABLE_ALL: {
03589         LegendAndColour *tbl = NULL;
03590           switch (this->map_type) {
03591             case SMT_INDUSTRY:
03592               tbl = _legend_from_industries;
03593               break;
03594             case SMT_OWNER:
03595               tbl = &(_legend_land_owners[NUM_NO_COMPANY_ENTRIES]);
03596               break;
03597             case SMT_LINKSTATS:
03598               tbl = _legend_linkstats;
03599               break;
03600             default:
03601               NOT_REACHED();
03602           }
03603 
03604         for (;!tbl->end; ++tbl) tbl->show_on_map = (widget == SM_WIDGET_ENABLE_ALL);
03605         this->SetDirty();
03606         break;
03607       }
03608 
03609       case SM_WIDGET_SHOW_HEIGHT: // Enable/disable showing of heightmap.
03610         _smallmap_show_heightmap = !_smallmap_show_heightmap;
03611         this->SetWidgetLoweredState(SM_WIDGET_SHOW_HEIGHT, _smallmap_show_heightmap);
03612         this->SetDirty();
03613         break;
03614     }
03615   }
03616 
03617   virtual void OnMouseOver(Point pt, int widget)
03618   {
03619     static Point invalid = {-1, -1};
03620     if (widget == SM_WIDGET_MAP) {
03621       const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
03622       pt.x -= wid->pos_x;
03623       pt.y -= wid->pos_y;
03624       if (pt.x != cursor.x || pt.y != cursor.y) {
03625         this->refresh = 1;
03626         cursor = pt;
03627       }
03628     } else {
03629       cursor = invalid;
03630     }
03631   }
03632 
03640   virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
03641   {
03642     if (!gui_scope) return;
03643     switch (data) {
03644       case 1:
03645         /* The owner legend has already been rebuilt. */
03646         this->ReInit();
03647         break;
03648 
03649       case 0: {
03650         extern uint64 _displayed_industries;
03651         if (this->map_type != SMT_INDUSTRY) this->SwitchMapType(SMT_INDUSTRY);
03652 
03653         for (int i = 0; i != _smallmap_industry_count; i++) {
03654           _legend_from_industries[i].show_on_map = HasBit(_displayed_industries, _legend_from_industries[i].type);
03655         }
03656         break;
03657       }
03658 
03659       default: NOT_REACHED();
03660     }
03661     this->SetDirty();
03662   }
03663 
03664   virtual bool OnRightClick(Point pt, int widget)
03665   {
03666     if (widget != SM_WIDGET_MAP || _scrolling_viewport) return false;
03667 
03668     _scrolling_viewport = true;
03669     return true;
03670   }
03671 
03672   virtual void OnMouseWheel(int wheel)
03673   {
03674     if (_settings_client.gui.scrollwheel_scrolling == 0) {
03675       const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
03676       int cursor_x = _cursor.pos.x - this->left - wid->pos_x;
03677       int cursor_y = _cursor.pos.y - this->top  - wid->pos_y;
03678       if (IsInsideMM(cursor_x, 0, wid->current_x) && IsInsideMM(cursor_y, 0, wid->current_y)) {
03679         Point pt = {cursor_x, cursor_y};
03680         this->SetZoomLevel((wheel < 0) ? ZLC_ZOOM_IN : ZLC_ZOOM_OUT, &pt);
03681       }
03682     }
03683   }
03684 
03685   virtual void OnTick()
03686   {
03687     /* Update the window every now and then */
03688     if (--this->refresh != 0) return;
03689 
03690     this->RecalcVehiclePositions();
03691 
03692     this->refresh = FORCE_REFRESH_PERIOD;
03693     this->SetDirty();
03694   }
03695 
03703   void SetNewScroll(int sx, int sy, int sub)
03704   {
03705     const NWidgetBase *wi = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
03706     Point hv = InverseRemapCoords(wi->current_x * TILE_SIZE / 2, wi->current_y * TILE_SIZE / 2);
03707     if (this->zoom > 0) {
03708       hv.x *= this->zoom;
03709       hv.y *= this->zoom;
03710     } else {
03711       hv.x /= (-this->zoom);
03712       hv.y /= (-this->zoom);
03713     }
03714 
03715     if (sx < -hv.x) {
03716       sx = -hv.x;
03717       sub = 0;
03718     }
03719     if (sx > (int)(MapMaxX() * TILE_SIZE) - hv.x) {
03720       sx = MapMaxX() * TILE_SIZE - hv.x;
03721       sub = 0;
03722     }
03723     if (sy < -hv.y) {
03724       sy = -hv.y;
03725       sub = 0;
03726     }
03727     if (sy > (int)(MapMaxY() * TILE_SIZE) - hv.y) {
03728       sy = MapMaxY() * TILE_SIZE - hv.y;
03729       sub = 0;
03730     }
03731 
03732     this->scroll_x = sx;
03733     this->scroll_y = sy;
03734     this->subscroll = sub;
03735   }
03736 
03737   virtual void OnScroll(Point delta)
03738   {
03739     _cursor.fix_at = true;
03740 
03741     /* While tile is at (delta.x, delta.y)? */
03742     int sub;
03743     Point pt = this->PixelToWorld(delta.x, delta.y, &sub);
03744     this->SetNewScroll(this->scroll_x + pt.x, this->scroll_y + pt.y, sub);
03745 
03746     this->SetDirty();
03747   }
03748 
03749   void SmallMapCenterOnCurrentPos()
03750   {
03751     const ViewPort *vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
03752     Point pt = InverseRemapCoords(vp->virtual_left + vp->virtual_width  / 2, vp->virtual_top  + vp->virtual_height / 2);
03753 
03754     int sub;
03755     const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SM_WIDGET_MAP);
03756     Point sxy = this->ComputeScroll(pt.x, pt.y, max(0, (int)wid->current_x / 2 - 2), wid->current_y / 2, &sub);
03757     this->SetNewScroll(sxy.x, sxy.y, sub);
03758     this->SetDirty();
03759   }
03760 
03761   uint ColumnWidth() const {return column_width;}
03762 };
03763 
03764 SmallMapWindow::SmallMapType SmallMapWindow::map_type = SMT_CONTOUR;
03765 bool SmallMapWindow::show_towns = true;
03766 
03775 class NWidgetSmallmapDisplay : public NWidgetContainer {
03776   const SmallMapWindow *smallmap_window; 
03777 public:
03778   NWidgetSmallmapDisplay() : NWidgetContainer(NWID_VERTICAL)
03779   {
03780     this->smallmap_window = NULL;
03781   }
03782 
03783   virtual void SetupSmallestSize(Window *w, bool init_array)
03784   {
03785     NWidgetBase *display = this->head;
03786     NWidgetBase *bar = display->next;
03787 
03788     display->SetupSmallestSize(w, init_array);
03789     bar->SetupSmallestSize(w, init_array);
03790 
03791     this->smallmap_window = dynamic_cast<SmallMapWindow *>(w);
03792     this->smallest_x = max(display->smallest_x, bar->smallest_x + smallmap_window->GetMinLegendWidth());
03793     this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetLegendHeight(smallmap_window->min_number_of_columns));
03794 //    this->smallest_y = display->smallest_y + max(bar->smallest_y, smallmap_window->GetLegendHeight());
03795     this->fill_x = max(display->fill_x, bar->fill_x);
03796     this->fill_y = (display->fill_y == 0 && bar->fill_y == 0) ? 0 : min(display->fill_y, bar->fill_y);
03797     this->resize_x = max(display->resize_x, bar->resize_x);
03798     this->resize_y = min(display->resize_y, bar->resize_y);
03799   }
03800 
03801   virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
03802   {
03803     this->pos_x = x;
03804     this->pos_y = y;
03805     this->current_x = given_width;
03806     this->current_y = given_height;
03807 
03808     NWidgetBase *display = this->head;
03809     NWidgetBase *bar = display->next;
03810 
03811     if (sizing == ST_SMALLEST) {
03812       this->smallest_x = given_width;
03813       this->smallest_y = given_height;
03814       /* Make display and bar exactly equal to their minimal size. */
03815       display->AssignSizePosition(ST_SMALLEST, x, y, display->smallest_x, display->smallest_y, rtl);
03816       bar->AssignSizePosition(ST_SMALLEST, x, y + display->smallest_y, bar->smallest_x, bar->smallest_y, rtl);
03817     }
03818 
03819 //    uint bar_height = max(bar->smallest_y, this->smallmap_window->GetLegendHeight(this->smallmap_window->GetNumberColumnsLegend(given_width - bar->smallest_x)));
03820     uint bar_height = max(bar->smallest_y, this->smallmap_window->GetLegendHeight(given_width - bar->smallest_x));
03821     uint display_height = given_height - bar_height;
03822     display->AssignSizePosition(ST_RESIZE, x, y, given_width, display_height, rtl);
03823     bar->AssignSizePosition(ST_RESIZE, x, y + display_height, given_width, bar_height, rtl);
03824   }
03825 
03826   virtual NWidgetCore *GetWidgetFromPos(int x, int y)
03827   {
03828     if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
03829     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
03830       NWidgetCore *widget = child_wid->GetWidgetFromPos(x, y);
03831       if (widget != NULL) return widget;
03832     }
03833     return NULL;
03834   }
03835 
03836   virtual void Draw(const Window *w)
03837   {
03838     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) child_wid->Draw(w);
03839   }
03840 };
03841 
03843 static const NWidgetPart _nested_smallmap_display[] = {
03844   NWidget(WWT_PANEL, COLOUR_BROWN, SM_WIDGET_MAP_BORDER),
03845     NWidget(WWT_INSET, COLOUR_BROWN, SM_WIDGET_MAP), SetMinimalSize(346, 140), SetResize(1, 1), SetPadding(2, 2, 2, 2), EndContainer(),
03846   EndContainer(),
03847 };
03848 
03850 static const NWidgetPart _nested_smallmap_bar[] = {
03851   NWidget(WWT_PANEL, COLOUR_BROWN),
03852     NWidget(NWID_HORIZONTAL),
03853       NWidget(WWT_EMPTY, INVALID_COLOUR, SM_WIDGET_LEGEND), SetResize(1, 1),
03854       NWidget(NWID_VERTICAL),
03855         /* Top button row. */
03856         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
03857           NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_IN),
03858               SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN), SetFill(1, 1),
03859           NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_CENTERMAP),
03860               SetDataTip(SPR_IMG_SMALLMAP, STR_SMALLMAP_CENTER), SetFill(1, 1),
03861           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_BLANK), SetMinimalSize(22, 22),
03862               SetDataTip(SPR_DOT_SMALL, STR_NULL), SetFill(1, 1),
03863           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_CONTOUR),
03864               SetDataTip(SPR_IMG_SHOW_COUNTOURS, STR_SMALLMAP_TOOLTIP_SHOW_LAND_CONTOURS_ON_MAP), SetFill(1, 1),
03865           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEHICLES),
03866               SetDataTip(SPR_IMG_SHOW_VEHICLES, STR_SMALLMAP_TOOLTIP_SHOW_VEHICLES_ON_MAP), SetFill(1, 1),
03867           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_INDUSTRIES),
03868               SetDataTip(SPR_IMG_INDUSTRY, STR_SMALLMAP_TOOLTIP_SHOW_INDUSTRIES_ON_MAP), SetFill(1, 1),
03869         EndContainer(),
03870         /* Bottom button row. */
03871         NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
03872           NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, SM_WIDGET_ZOOM_OUT),
03873               SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT), SetFill(1, 1),
03874           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_TOGGLETOWNNAME),
03875               SetDataTip(SPR_IMG_TOWN, STR_SMALLMAP_TOOLTIP_TOGGLE_TOWN_NAMES_ON_OFF), SetFill(1, 1),
03876           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_LINKSTATS),
03877               SetDataTip(SPR_IMG_GRAPHS, STR_SMALLMAP_TOOLTIP_SHOW_LINK_STATS_ON_MAP), SetFill(1, 1),
03878           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_ROUTES),
03879               SetDataTip(SPR_IMG_SHOW_ROUTES, STR_SMALLMAP_TOOLTIP_SHOW_TRANSPORT_ROUTES_ON), SetFill(1, 1),
03880           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_VEGETATION),
03881               SetDataTip(SPR_IMG_PLANTTREES, STR_SMALLMAP_TOOLTIP_SHOW_VEGETATION_ON_MAP), SetFill(1, 1),
03882           NWidget(WWT_IMGBTN, COLOUR_BROWN, SM_WIDGET_OWNERS),
03883               SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_SMALLMAP_TOOLTIP_SHOW_LAND_OWNERS_ON_MAP), SetFill(1, 1),
03884         EndContainer(),
03885         NWidget(NWID_SPACER), SetResize(0, 1),
03886       EndContainer(),
03887     EndContainer(),
03888   EndContainer(),
03889 };
03890 
03891 static NWidgetBase *SmallMapDisplay(int *biggest_index)
03892 {
03893   NWidgetContainer *map_display = new NWidgetSmallmapDisplay;
03894 
03895   MakeNWidgets(_nested_smallmap_display, lengthof(_nested_smallmap_display), biggest_index, map_display);
03896   MakeNWidgets(_nested_smallmap_bar, lengthof(_nested_smallmap_bar), biggest_index, map_display);
03897   return map_display;
03898 }
03899 
03900 
03901 static const NWidgetPart _nested_smallmap_widgets[] = {
03902   NWidget(NWID_HORIZONTAL),
03903     NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
03904     NWidget(WWT_CAPTION, COLOUR_BROWN, SM_WIDGET_CAPTION), SetDataTip(STR_SMALLMAP_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
03905     NWidget(WWT_SHADEBOX, COLOUR_BROWN),
03906     NWidget(WWT_STICKYBOX, COLOUR_BROWN),
03907   EndContainer(),
03908   NWidgetFunction(SmallMapDisplay), // Smallmap display and legend bar + image buttons.
03909   /* Bottom button row and resize box. */
03910   NWidget(NWID_HORIZONTAL),
03911     NWidget(WWT_PANEL, COLOUR_BROWN),
03912       NWidget(NWID_HORIZONTAL),
03913         NWidget(NWID_SELECTION, INVALID_COLOUR, SM_WIDGET_SELECT_BUTTONS),
03914           NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
03915             NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, SM_WIDGET_ENABLE_ALL), SetDataTip(STR_SMALLMAP_ENABLE_ALL, STR_NULL),
03916             NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, SM_WIDGET_DISABLE_ALL), SetDataTip(STR_SMALLMAP_DISABLE_ALL, STR_NULL),
03917             NWidget(WWT_TEXTBTN, COLOUR_BROWN, SM_WIDGET_SHOW_HEIGHT), SetDataTip(STR_SMALLMAP_SHOW_HEIGHT, STR_SMALLMAP_TOOLTIP_SHOW_HEIGHT),
03918           EndContainer(),
03919           NWidget(NWID_SPACER), SetFill(1, 1),
03920         EndContainer(),
03921         NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
03922       EndContainer(),
03923     EndContainer(),
03924     NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
03925   EndContainer(),
03926 };
03927 
03928 static const WindowDesc _smallmap_desc(
03929   WDP_AUTO, 484, 314,
03930   WC_SMALLMAP, WC_NONE,
03931   WDF_UNCLICK_BUTTONS,
03932   _nested_smallmap_widgets, lengthof(_nested_smallmap_widgets)
03933 );
03934 
03938 void ShowSmallMap()
03939 {
03940   AllocateWindowDescFront<SmallMapWindow>(&_smallmap_desc, 0);
03941 }
03942 
03951 bool ScrollMainWindowTo(int x, int y, int z, bool instant)
03952 {
03953   bool res = ScrollWindowTo(x, y, z, FindWindowById(WC_MAIN_WINDOW, 0), instant);
03954 
03955   /* If a user scrolls to a tile (via what way what so ever) and already is on
03956    * that tile (e.g.: pressed twice), move the smallmap to that location,
03957    * so you directly see where you are on the smallmap. */
03958 
03959   if (res) return res;
03960 
03961   SmallMapWindow *w = dynamic_cast<SmallMapWindow*>(FindWindowById(WC_SMALLMAP, 0));
03962   if (w != NULL) w->SmallMapCenterOnCurrentPos();
03963 
03964   return res;
03965 }