tile_map.h

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 #ifndef TILE_MAP_H
00013 #define TILE_MAP_H
00014 
00015 #include "slope_type.h"
00016 #include "map_func.h"
00017 #include "core/bitmath_func.hpp"
00018 #include "core/math_func.hpp"
00019 #include "settings_type.h"
00020 
00031 static inline bool AllowMoreHeightlevels()
00032 {
00033   return _settings_game.construction.allow_more_heightlevels;
00034 }
00035 
00042 static inline uint GetMaxTileHeight()
00043 {
00044   if (AllowMoreHeightlevels()) {
00045     return MAX_TILE_HEIGHT_EXTENDED;
00046   } else {
00047     return MAX_TILE_HEIGHT_OLD;
00048   }
00049 }
00050 
00057 static inline uint GetMaxSnowlineHeight()
00058 {
00059   if (AllowMoreHeightlevels()) {
00060     return MAX_SNOWLINE_HEIGHT_EXTENDED;
00061   } else {
00062     return MAX_SNOWLINE_HEIGHT_OLD;
00063   }
00064 }
00065 
00072 static inline uint GetMaxTreelineHeight()
00073 {
00074   if (AllowMoreHeightlevels()) {
00075     return MAX_TREELINE_HEIGHT_EXTENDED;
00076   } else {
00077     return MAX_TREELINE_HEIGHT_OLD;
00078   }
00079 }
00080 
00090 static inline uint TileHeight(TileIndex tile)
00091 {
00092   assert(tile < MapSize());
00093 
00094   if (AllowMoreHeightlevels()) {
00095     return _map_heightdata[tile].heightlevel;
00096   } else {
00097     return GB(_m[tile].type_height, 0, 4);
00098   }
00099 }
00100 
00105 static inline uint TileHeightOutsideMap(int x, int y)
00106 {
00107   /* In all cases: Descend to heightlevel 0 as fast as possible.
00108    * So: If we are at the 0-side of the map (x<0 or y<0), we must
00109    * subtract the distance to coordinate 0 from the heightlevel.
00110    * In other words: Subtract e.g. -x. If we are at the MapMax
00111    * side of the map, we also need to subtract the distance to
00112    * the edge of map, e.g. MapMaxX - x.
00113    *
00114    * NOTE: Assuming constant heightlevel outside map would be
00115    * simpler here. However, then we run into painting problems,
00116    * since whenever a heightlevel change at the map border occurs,
00117    * we would need to repaint anything outside map.
00118    * In contrast, by doing it this way, we can localize this change,
00119    * which means we may assume constant heightlevel for all tiles
00120    * at more than <heightlevel at map border> distance from the
00121    * map border. */
00122   if (x < 0) {
00123     if (y < 0) {
00124       return max((int)TileHeight(TileXY(0, 0)) - (-x) - (-y), 0);
00125     } else if (y < (int)MapMaxY()) {
00126       return max((int)TileHeight(TileXY(0, y)) - (-x), 0);
00127     } else {
00128       return max((int)TileHeight(TileXY(0, (int)MapMaxY())) - (-x) - (y - (int)MapMaxY()), 0);
00129     }
00130   } else if (x < (int)MapMaxX()) {
00131     if (y < 0) {
00132       return max((int)TileHeight(TileXY(x, 0)) - (-y), 0);
00133     } else if (y < (int)MapMaxY()) {
00134       return TileHeight(TileXY(x, y));
00135     } else {
00136       return max((int)TileHeight(TileXY(x, (int)MapMaxY())) - (y - (int)MapMaxY()), 0);
00137     }
00138   } else {
00139     if (y < 0) {
00140       return max((int)TileHeight(TileXY((int)MapMaxX(), 0)) - (x - (int)MapMaxX()) - (-y), 0);
00141     } else if (y < (int)MapMaxY()) {
00142       return max((int)TileHeight(TileXY((int)MapMaxX(), y)) - (x - (int)MapMaxX()), 0);
00143     } else {
00144       return max((int)TileHeight(TileXY((int)MapMaxX(), (int)MapMaxY())) - (x - (int)MapMaxX()) - (y - (int)MapMaxY()), 0);
00145     }
00146   }
00147 }
00148 
00157 static inline void SetTileHeight(TileIndex tile, uint height)
00158 {
00159   assert(tile < MapSize());
00160 
00161   if (height > GetMaxTileHeight()) {
00162     /* Make sure height is within allowed range. */
00163     height = GetMaxTileHeight();
00164   }
00165 
00166   if (AllowMoreHeightlevels()) {
00167     _map_heightdata[tile].heightlevel = height;
00168   } else {
00169     SB(_m[tile].type_height, 0, 4, height);
00170   }
00171 }
00172 
00181 static inline uint TilePixelHeight(TileIndex tile)
00182 {
00183   return TileHeight(tile) * TILE_HEIGHT;
00184 }
00185 
00193 static inline TileType GetTileType(TileIndex tile)
00194 {
00195   assert(tile < MapSize());
00196   return (TileType)GB(_m[tile].type_height, 4, 4);
00197 }
00198 
00211 static inline void SetTileType(TileIndex tile, TileType type)
00212 {
00213   assert(tile < MapSize());
00214   /* VOID tiles (and no others) are exactly allowed at the lower left and right
00215    * edges of the map. If _settings_game.construction.freeform_edges is true,
00216    * the upper edges of the map are also VOID tiles. */
00217   assert((TileX(tile) == MapMaxX() || TileY(tile) == MapMaxY() || (_settings_game.construction.freeform_edges && (TileX(tile) == 0 || TileY(tile) == 0))) == (type == MP_VOID));
00218   SB(_m[tile].type_height, 4, 4, type);
00219 }
00220 
00230 static inline bool IsTileType(TileIndex tile, TileType type)
00231 {
00232   return GetTileType(tile) == type;
00233 }
00234 
00241 static inline bool IsValidTile(TileIndex tile)
00242 {
00243   return tile < MapSize() && !IsTileType(tile, MP_VOID);
00244 }
00245 
00258 static inline Owner GetTileOwner(TileIndex tile)
00259 {
00260   assert(IsValidTile(tile));
00261   assert(!IsTileType(tile, MP_HOUSE));
00262   assert(!IsTileType(tile, MP_INDUSTRY));
00263 
00264   return (Owner)GB(_m[tile].m1, 0, 5);
00265 }
00266 
00278 static inline void SetTileOwner(TileIndex tile, Owner owner)
00279 {
00280   assert(IsValidTile(tile));
00281   assert(!IsTileType(tile, MP_HOUSE));
00282   assert(!IsTileType(tile, MP_INDUSTRY));
00283 
00284   SB(_m[tile].m1, 0, 5, owner);
00285 }
00286 
00294 static inline bool IsTileOwner(TileIndex tile, Owner owner)
00295 {
00296   return GetTileOwner(tile) == owner;
00297 }
00298 
00305 static inline void SetTropicZone(TileIndex tile, TropicZone type)
00306 {
00307   assert(tile < MapSize());
00308   assert(!IsTileType(tile, MP_VOID) || type == TROPICZONE_NORMAL);
00309   SB(_m[tile].m6, 0, 2, type);
00310 }
00311 
00318 static inline TropicZone GetTropicZone(TileIndex tile)
00319 {
00320   assert(tile < MapSize());
00321   return (TropicZone)GB(_m[tile].m6, 0, 2);
00322 }
00323 
00330 static inline byte GetAnimationFrame(TileIndex t)
00331 {
00332   assert(IsTileType(t, MP_HOUSE) || IsTileType(t, MP_OBJECT) || IsTileType(t, MP_INDUSTRY) ||IsTileType(t, MP_STATION));
00333   return _me[t].m7;
00334 }
00335 
00342 static inline void SetAnimationFrame(TileIndex t, byte frame)
00343 {
00344   assert(IsTileType(t, MP_HOUSE) || IsTileType(t, MP_OBJECT) || IsTileType(t, MP_INDUSTRY) ||IsTileType(t, MP_STATION));
00345   _me[t].m7 = frame;
00346 }
00347 
00348 Slope GetTileSlope(TileIndex tile, uint *h);
00349 Slope GetTileSlopeOutsideMap(int x, int y, uint *h);
00350 uint GetTileZ(TileIndex tile);
00351 uint GetTileZOutsideMap(int x, int y);
00352 uint GetTileMaxZ(TileIndex tile);
00353 
00382 uint GetTileMaxZOutsideMap(int x, int y);
00383 
00391 static inline uint TileHash(uint x, uint y)
00392 {
00393   uint hash = x >> 4;
00394   hash ^= x >> 6;
00395   hash ^= y >> 4;
00396   hash -= y >> 6;
00397   return hash;
00398 }
00399 
00409 static inline uint TileHash2Bit(uint x, uint y)
00410 {
00411   return GB(TileHash(x, y), 0, 2);
00412 }
00413 
00414 #endif /* TILE_MAP_H */