landscape.cpp

Go to the documentation of this file.
00001 /* $Id: landscape.cpp 21767 2011-01-10 21:58:05Z rubidium $ */
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 
00014 #include "stdafx.h"
00015 #include "heightmap.h"
00016 #include "clear_map.h"
00017 #include "spritecache.h"
00018 #include "viewport_func.h"
00019 #include "command_func.h"
00020 #include "landscape.h"
00021 #include "void_map.h"
00022 #include "tgp.h"
00023 #include "genworld.h"
00024 #include "fios.h"
00025 #include "functions.h"
00026 #include "date_func.h"
00027 #include "water.h"
00028 #include "effectvehicle_func.h"
00029 #include "landscape_type.h"
00030 #include "animated_tile_func.h"
00031 #include "core/random_func.hpp"
00032 #include "object_base.h"
00033 #include "water_map.h"
00034 #include "economy_func.h"
00035 #include "company_func.h"
00036 
00037 #include "table/strings.h"
00038 #include "table/sprites.h"
00039 
00040 extern const TileTypeProcs
00041   _tile_type_clear_procs,
00042   _tile_type_rail_procs,
00043   _tile_type_road_procs,
00044   _tile_type_town_procs,
00045   _tile_type_trees_procs,
00046   _tile_type_station_procs,
00047   _tile_type_water_procs,
00048   _tile_type_void_procs,
00049   _tile_type_industry_procs,
00050   _tile_type_tunnelbridge_procs,
00051   _tile_type_object_procs;
00052 
00058 const TileTypeProcs * const _tile_type_procs[16] = {
00059   &_tile_type_clear_procs,        
00060   &_tile_type_rail_procs,         
00061   &_tile_type_road_procs,         
00062   &_tile_type_town_procs,         
00063   &_tile_type_trees_procs,        
00064   &_tile_type_station_procs,      
00065   &_tile_type_water_procs,        
00066   &_tile_type_void_procs,         
00067   &_tile_type_industry_procs,     
00068   &_tile_type_tunnelbridge_procs, 
00069   &_tile_type_object_procs,       
00070 };
00071 
00073 extern const byte _slope_to_sprite_offset[32] = {
00074   0, 1, 2, 3, 4, 5, 6,  7, 8, 9, 10, 11, 12, 13, 14, 0,
00075   0, 0, 0, 0, 0, 0, 0, 16, 0, 0,  0, 17,  0, 15, 18, 0,
00076 };
00077 
00086 static SnowLine *_snow_line = NULL;
00087 
00096 uint ApplyFoundationToSlope(Foundation f, Slope *s)
00097 {
00098   if (!IsFoundation(f)) return 0;
00099 
00100   if (IsLeveledFoundation(f)) {
00101     uint dz = TILE_HEIGHT + (IsSteepSlope(*s) ? TILE_HEIGHT : 0);
00102     *s = SLOPE_FLAT;
00103     return dz;
00104   }
00105 
00106   if (f != FOUNDATION_STEEP_BOTH && IsNonContinuousFoundation(f)) {
00107     *s = HalftileSlope(*s, GetHalftileFoundationCorner(f));
00108     return 0;
00109   }
00110 
00111   if (IsSpecialRailFoundation(f)) {
00112     *s = SlopeWithThreeCornersRaised(OppositeCorner(GetRailFoundationCorner(f)));
00113     return 0;
00114   }
00115 
00116   uint dz = IsSteepSlope(*s) ? TILE_HEIGHT : 0;
00117   Corner highest_corner = GetHighestSlopeCorner(*s);
00118 
00119   switch (f) {
00120     case FOUNDATION_INCLINED_X:
00121       *s = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? SLOPE_SW : SLOPE_NE);
00122       break;
00123 
00124     case FOUNDATION_INCLINED_Y:
00125       *s = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? SLOPE_SE : SLOPE_NW);
00126       break;
00127 
00128     case FOUNDATION_STEEP_LOWER:
00129       *s = SlopeWithOneCornerRaised(highest_corner);
00130       break;
00131 
00132     case FOUNDATION_STEEP_BOTH:
00133       *s = HalftileSlope(SlopeWithOneCornerRaised(highest_corner), highest_corner);
00134       break;
00135 
00136     default: NOT_REACHED();
00137   }
00138   return dz;
00139 }
00140 
00141 
00149 uint GetPartialZ(int x, int y, Slope corners)
00150 {
00151   if (IsHalftileSlope(corners)) {
00152     switch (GetHalftileSlopeCorner(corners)) {
00153       case CORNER_W:
00154         if (x - y >= 0) return GetSlopeMaxZ(corners);
00155         break;
00156 
00157       case CORNER_S:
00158         if (x - (y ^ 0xF) >= 0) return GetSlopeMaxZ(corners);
00159         break;
00160 
00161       case CORNER_E:
00162         if (y - x >= 0) return GetSlopeMaxZ(corners);
00163         break;
00164 
00165       case CORNER_N:
00166         if ((y ^ 0xF) - x >= 0) return GetSlopeMaxZ(corners);
00167         break;
00168 
00169       default: NOT_REACHED();
00170     }
00171   }
00172 
00173   int z = 0;
00174 
00175   switch (RemoveHalftileSlope(corners)) {
00176     case SLOPE_W:
00177       if (x - y >= 0) {
00178         z = (x - y) >> 1;
00179       }
00180       break;
00181 
00182     case SLOPE_S:
00183       y ^= 0xF;
00184       if ((x - y) >= 0) {
00185         z = (x - y) >> 1;
00186       }
00187       break;
00188 
00189     case SLOPE_SW:
00190       z = (x >> 1) + 1;
00191       break;
00192 
00193     case SLOPE_E:
00194       if (y - x >= 0) {
00195         z = (y - x) >> 1;
00196       }
00197       break;
00198 
00199     case SLOPE_EW:
00200     case SLOPE_NS:
00201     case SLOPE_ELEVATED:
00202       z = 4;
00203       break;
00204 
00205     case SLOPE_SE:
00206       z = (y >> 1) + 1;
00207       break;
00208 
00209     case SLOPE_WSE:
00210       z = 8;
00211       y ^= 0xF;
00212       if (x - y < 0) {
00213         z += (x - y) >> 1;
00214       }
00215       break;
00216 
00217     case SLOPE_N:
00218       y ^= 0xF;
00219       if (y - x >= 0) {
00220         z = (y - x) >> 1;
00221       }
00222       break;
00223 
00224     case SLOPE_NW:
00225       z = (y ^ 0xF) >> 1;
00226       break;
00227 
00228     case SLOPE_NWS:
00229       z = 8;
00230       if (x - y < 0) {
00231         z += (x - y) >> 1;
00232       }
00233       break;
00234 
00235     case SLOPE_NE:
00236       z = (x ^ 0xF) >> 1;
00237       break;
00238 
00239     case SLOPE_ENW:
00240       z = 8;
00241       y ^= 0xF;
00242       if (y - x < 0) {
00243         z += (y - x) >> 1;
00244       }
00245       break;
00246 
00247     case SLOPE_SEN:
00248       z = 8;
00249       if (y - x < 0) {
00250         z += (y - x) >> 1;
00251       }
00252       break;
00253 
00254     case SLOPE_STEEP_S:
00255       z = 1 + ((x + y) >> 1);
00256       break;
00257 
00258     case SLOPE_STEEP_W:
00259       z = 1 + ((x + (y ^ 0xF)) >> 1);
00260       break;
00261 
00262     case SLOPE_STEEP_N:
00263       z = 1 + (((x ^ 0xF) + (y ^ 0xF)) >> 1);
00264       break;
00265 
00266     case SLOPE_STEEP_E:
00267       z = 1 + (((x ^ 0xF) + y) >> 1);
00268       break;
00269 
00270     default: break;
00271   }
00272 
00273   return z;
00274 }
00275 
00276 uint GetSlopeZ(int x, int y)
00277 {
00278   TileIndex tile = TileVirtXY(x, y);
00279 
00280   return _tile_type_procs[GetTileType(tile)]->get_slope_z_proc(tile, x, y);
00281 }
00282 
00292 int GetSlopeZInCorner(Slope tileh, Corner corner)
00293 {
00294   assert(!IsHalftileSlope(tileh));
00295   return ((tileh & SlopeWithOneCornerRaised(corner)) != 0 ? TILE_HEIGHT : 0) + (tileh == SteepSlope(corner) ? TILE_HEIGHT : 0);
00296 }
00297 
00310 void GetSlopeZOnEdge(Slope tileh, DiagDirection edge, int *z1, int *z2)
00311 {
00312   static const Slope corners[4][4] = {
00313     /*    corner     |          steep slope
00314      *  z1      z2   |       z1             z2        */
00315     {SLOPE_E, SLOPE_N, SLOPE_STEEP_E, SLOPE_STEEP_N}, // DIAGDIR_NE, z1 = E, z2 = N
00316     {SLOPE_S, SLOPE_E, SLOPE_STEEP_S, SLOPE_STEEP_E}, // DIAGDIR_SE, z1 = S, z2 = E
00317     {SLOPE_S, SLOPE_W, SLOPE_STEEP_S, SLOPE_STEEP_W}, // DIAGDIR_SW, z1 = S, z2 = W
00318     {SLOPE_W, SLOPE_N, SLOPE_STEEP_W, SLOPE_STEEP_N}, // DIAGDIR_NW, z1 = W, z2 = N
00319   };
00320 
00321   int halftile_test = (IsHalftileSlope(tileh) ? SlopeWithOneCornerRaised(GetHalftileSlopeCorner(tileh)) : 0);
00322   if (halftile_test == corners[edge][0]) *z2 += TILE_HEIGHT; // The slope is non-continuous in z2. z2 is on the upper side.
00323   if (halftile_test == corners[edge][1]) *z1 += TILE_HEIGHT; // The slope is non-continuous in z1. z1 is on the upper side.
00324 
00325   if ((tileh & corners[edge][0]) != 0) *z1 += TILE_HEIGHT; // z1 is raised
00326   if ((tileh & corners[edge][1]) != 0) *z2 += TILE_HEIGHT; // z2 is raised
00327   if (RemoveHalftileSlope(tileh) == corners[edge][2]) *z1 += TILE_HEIGHT; // z1 is highest corner of a steep slope
00328   if (RemoveHalftileSlope(tileh) == corners[edge][3]) *z2 += TILE_HEIGHT; // z2 is highest corner of a steep slope
00329 }
00330 
00339 Slope GetFoundationSlope(TileIndex tile, uint *z)
00340 {
00341   Slope tileh = GetTileSlope(tile, z);
00342   Foundation f = _tile_type_procs[GetTileType(tile)]->get_foundation_proc(tile, tileh);
00343   uint z_inc = ApplyFoundationToSlope(f, &tileh);
00344   if (z != NULL) *z += z_inc;
00345   return tileh;
00346 }
00347 
00348 
00349 bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
00350 {
00351   uint z;
00352 
00353   int z_W_here = z_here;
00354   int z_N_here = z_here;
00355   GetSlopeZOnEdge(slope_here, DIAGDIR_NW, &z_W_here, &z_N_here);
00356 
00357   Slope slope = GetFoundationSlope(TILE_ADDXY(tile, 0, -1), &z);
00358   int z_W = z;
00359   int z_N = z;
00360   GetSlopeZOnEdge(slope, DIAGDIR_SE, &z_W, &z_N);
00361 
00362   return (z_N_here > z_N) || (z_W_here > z_W);
00363 }
00364 
00365 
00366 bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
00367 {
00368   uint z;
00369 
00370   int z_E_here = z_here;
00371   int z_N_here = z_here;
00372   GetSlopeZOnEdge(slope_here, DIAGDIR_NE, &z_E_here, &z_N_here);
00373 
00374   Slope slope = GetFoundationSlope(TILE_ADDXY(tile, -1, 0), &z);
00375   int z_E = z;
00376   int z_N = z;
00377   GetSlopeZOnEdge(slope, DIAGDIR_SW, &z_E, &z_N);
00378 
00379   return (z_N_here > z_N) || (z_E_here > z_E);
00380 }
00381 
00387 void DrawFoundation(TileInfo *ti, Foundation f)
00388 {
00389   if (!IsFoundation(f)) return;
00390 
00391   /* Two part foundations must be drawn separately */
00392   assert(f != FOUNDATION_STEEP_BOTH);
00393 
00394   uint sprite_block = 0;
00395   uint z;
00396   Slope slope = GetFoundationSlope(ti->tile, &z);
00397 
00398   /* Select the needed block of foundations sprites
00399    * Block 0: Walls at NW and NE edge
00400    * Block 1: Wall  at        NE edge
00401    * Block 2: Wall  at NW        edge
00402    * Block 3: No walls at NW or NE edge
00403    */
00404   if (!HasFoundationNW(ti->tile, slope, z)) sprite_block += 1;
00405   if (!HasFoundationNE(ti->tile, slope, z)) sprite_block += 2;
00406 
00407   /* Use the original slope sprites if NW and NE borders should be visible */
00408   SpriteID leveled_base = (sprite_block == 0 ? (int)SPR_FOUNDATION_BASE : (SPR_SLOPES_VIRTUAL_BASE + sprite_block * SPR_TRKFOUND_BLOCK_SIZE));
00409   SpriteID inclined_base = SPR_SLOPES_VIRTUAL_BASE + SPR_SLOPES_INCLINED_OFFSET + sprite_block * SPR_TRKFOUND_BLOCK_SIZE;
00410   SpriteID halftile_base = SPR_HALFTILE_FOUNDATION_BASE + sprite_block * SPR_HALFTILE_BLOCK_SIZE;
00411 
00412   if (IsSteepSlope(ti->tileh)) {
00413     if (!IsNonContinuousFoundation(f)) {
00414       /* Lower part of foundation */
00415       AddSortableSpriteToDraw(
00416         leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z
00417       );
00418     }
00419 
00420     Corner highest_corner = GetHighestSlopeCorner(ti->tileh);
00421     ti->z += ApplyFoundationToSlope(f, &ti->tileh);
00422 
00423     if (IsInclinedFoundation(f)) {
00424       /* inclined foundation */
00425       byte inclined = highest_corner * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
00426 
00427       AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
00428         f == FOUNDATION_INCLINED_X ? 16 : 1,
00429         f == FOUNDATION_INCLINED_Y ? 16 : 1,
00430         TILE_HEIGHT, ti->z
00431       );
00432       OffsetGroundSprite(31, 9);
00433     } else if (IsLeveledFoundation(f)) {
00434       AddSortableSpriteToDraw(leveled_base + SlopeWithOneCornerRaised(highest_corner), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z - TILE_HEIGHT);
00435       OffsetGroundSprite(31, 1);
00436     } else if (f == FOUNDATION_STEEP_LOWER) {
00437       /* one corner raised */
00438       OffsetGroundSprite(31, 1);
00439     } else {
00440       /* halftile foundation */
00441       int x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? 8 : 0);
00442       int y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? 8 : 0);
00443 
00444       AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z + TILE_HEIGHT);
00445       OffsetGroundSprite(31, 9);
00446     }
00447   } else {
00448     if (IsLeveledFoundation(f)) {
00449       /* leveled foundation */
00450       AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
00451       OffsetGroundSprite(31, 1);
00452     } else if (IsNonContinuousFoundation(f)) {
00453       /* halftile foundation */
00454       Corner halftile_corner = GetHalftileFoundationCorner(f);
00455       int x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? 8 : 0);
00456       int y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? 8 : 0);
00457 
00458       AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z);
00459       OffsetGroundSprite(31, 9);
00460     } else if (IsSpecialRailFoundation(f)) {
00461       /* anti-zig-zag foundation */
00462       SpriteID spr;
00463       if (ti->tileh == SLOPE_NS || ti->tileh == SLOPE_EW) {
00464         /* half of leveled foundation under track corner */
00465         spr = leveled_base + SlopeWithThreeCornersRaised(GetRailFoundationCorner(f));
00466       } else {
00467         /* tile-slope = sloped along X/Y, foundation-slope = three corners raised */
00468         spr = inclined_base + 2 * GetRailFoundationCorner(f) + ((ti->tileh == SLOPE_SW || ti->tileh == SLOPE_NE) ? 1 : 0);
00469       }
00470       AddSortableSpriteToDraw(spr, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
00471       OffsetGroundSprite(31, 9);
00472     } else {
00473       /* inclined foundation */
00474       byte inclined = GetHighestSlopeCorner(ti->tileh) * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
00475 
00476       AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
00477         f == FOUNDATION_INCLINED_X ? 16 : 1,
00478         f == FOUNDATION_INCLINED_Y ? 16 : 1,
00479         TILE_HEIGHT, ti->z
00480       );
00481       OffsetGroundSprite(31, 9);
00482     }
00483     ti->z += ApplyFoundationToSlope(f, &ti->tileh);
00484   }
00485 }
00486 
00487 void DoClearSquare(TileIndex tile)
00488 {
00489   /* If the tile can have animation and we clear it, delete it from the animated tile list. */
00490   if (_tile_type_procs[GetTileType(tile)]->animate_tile_proc != NULL) DeleteAnimatedTile(tile);
00491 
00492   MakeClear(tile, CLEAR_GRASS, _generating_world ? 3 : 0);
00493   MarkTileDirtyByTile(tile);
00494 }
00495 
00506 TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
00507 {
00508   return _tile_type_procs[GetTileType(tile)]->get_tile_track_status_proc(tile, mode, sub_mode, side);
00509 }
00510 
00517 void ChangeTileOwner(TileIndex tile, Owner old_owner, Owner new_owner)
00518 {
00519   _tile_type_procs[GetTileType(tile)]->change_tile_owner_proc(tile, old_owner, new_owner);
00520 }
00521 
00522 void GetTileDesc(TileIndex tile, TileDesc *td)
00523 {
00524   _tile_type_procs[GetTileType(tile)]->get_tile_desc_proc(tile, td);
00525 }
00526 
00532 bool IsSnowLineSet()
00533 {
00534   return _snow_line != NULL;
00535 }
00536 
00542 void SetSnowLine(byte table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS])
00543 {
00544   _snow_line = CallocT<SnowLine>(1);
00545   _snow_line->lowest_value = 0xFF;
00546   memcpy(_snow_line->table, table, sizeof(_snow_line->table));
00547 
00548   for (uint i = 0; i < SNOW_LINE_MONTHS; i++) {
00549     for (uint j = 0; j < SNOW_LINE_DAYS; j++) {
00550       _snow_line->highest_value = max(_snow_line->highest_value, table[i][j]);
00551       _snow_line->lowest_value = min(_snow_line->lowest_value, table[i][j]);
00552     }
00553   }
00554 }
00555 
00561 byte GetSnowLine()
00562 {
00563   if (_snow_line == NULL) return _settings_game.game_creation.snow_line;
00564 
00565   YearMonthDay ymd;
00566   ConvertDateToYMD(_date, &ymd);
00567   return _snow_line->table[ymd.month][ymd.day];
00568 }
00569 
00575 byte HighestSnowLine()
00576 {
00577   return _snow_line == NULL ? _settings_game.game_creation.snow_line : _snow_line->highest_value;
00578 }
00579 
00585 byte LowestSnowLine()
00586 {
00587   return _snow_line == NULL ? _settings_game.game_creation.snow_line : _snow_line->lowest_value;
00588 }
00589 
00594 void ClearSnowLine()
00595 {
00596   free(_snow_line);
00597   _snow_line = NULL;
00598 }
00599 
00609 CommandCost CmdLandscapeClear(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00610 {
00611   CommandCost cost(EXPENSES_CONSTRUCTION);
00612   bool do_clear = false;
00613   /* Test for stuff which results in water when cleared. Then add the cost to also clear the water. */
00614   if ((flags & DC_FORCE_CLEAR_TILE) && HasTileWaterClass(tile) && IsTileOnWater(tile) && !IsWaterTile(tile) && !IsCoastTile(tile)) {
00615     if ((flags & DC_AUTO) && GetWaterClass(tile) == WATER_CLASS_CANAL) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
00616     do_clear = true;
00617     cost.AddCost(GetWaterClass(tile) == WATER_CLASS_CANAL ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER]);
00618   }
00619 
00620   Company *c = (flags & (DC_AUTO | DC_BANKRUPT)) ? NULL : Company::GetIfValid(_current_company);
00621   if (c != NULL && (int)GB(c->clear_limit, 16, 16) < 1) {
00622     return_cmd_error(STR_ERROR_CLEARING_LIMIT_REACHED);
00623   }
00624 
00625   const ClearedObjectArea *coa = FindClearedObject(tile);
00626 
00627   /* If this tile was the first tile which caused object destruction, always
00628    * pass it on to the tile_type_proc. That way multiple test runs and the exec run stay consistent. */
00629   if (coa != NULL && coa->first_tile != tile) {
00630     /* If this tile belongs to an object which was already cleared via another tile, pretend it has been
00631      * already removed.
00632      * However, we need to check stuff, which is not the same for all object tiles. (e.g. being on water or not) */
00633 
00634     /* If a object is removed, it leaves either bare land or water. */
00635     if ((flags & DC_NO_WATER) && HasTileWaterClass(tile) && IsTileOnWater(tile)) {
00636       return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00637     }
00638   } else {
00639     cost.AddCost(_tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags));
00640   }
00641 
00642   if (flags & DC_EXEC) {
00643     if (c != NULL) c->clear_limit -= 1 << 16;
00644     if (do_clear) DoClearSquare(tile);
00645   }
00646   return cost;
00647 }
00648 
00659 CommandCost CmdClearArea(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00660 {
00661   if (p1 >= MapSize()) return CMD_ERROR;
00662 
00663   Money money = GetAvailableMoneyForCommand();
00664   CommandCost cost(EXPENSES_CONSTRUCTION);
00665   CommandCost last_error = CMD_ERROR;
00666   bool had_success = false;
00667 
00668   const Company *c = (flags & (DC_AUTO | DC_BANKRUPT)) ? NULL : Company::GetIfValid(_current_company);
00669   int limit = (c == NULL ? INT32_MAX : GB(c->clear_limit, 16, 16));
00670 
00671   TileArea ta(tile, p1);
00672   TileIterator *iter = HasBit(p2, 0) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(ta);
00673   for (; *iter != INVALID_TILE; ++(*iter)) {
00674     TileIndex t = *iter;
00675     CommandCost ret = DoCommand(t, 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
00676     if (ret.Failed()) {
00677       last_error = ret;
00678 
00679       /* We may not clear more tiles. */
00680       if (c != NULL && GB(c->clear_limit, 16, 16) < 1) break;
00681       continue;
00682     }
00683 
00684     had_success = true;
00685     if (flags & DC_EXEC) {
00686       money -= ret.GetCost();
00687       if (ret.GetCost() > 0 && money < 0) {
00688         _additional_cash_required = ret.GetCost();
00689         delete iter;
00690         return cost;
00691       }
00692       DoCommand(t, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00693 
00694       /* draw explosion animation... */
00695       TileIndex off = t - ta.tile;
00696       if ((TileX(off) == 0 || TileX(off) == ta.w - 1U) && (TileY(off) == 0 || TileY(off) == ta.h - 1U)) {
00697         /* big explosion in each corner, or small explosion for single tiles */
00698         CreateEffectVehicleAbove(TileX(t) * TILE_SIZE + TILE_SIZE / 2, TileY(t) * TILE_SIZE + TILE_SIZE / 2, 2,
00699           ta.w == 1 && ta.h == 1 ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
00700         );
00701       }
00702     } else {
00703       /* When we're at the clearing limit we better bail (unneed) testing as well. */
00704       if (ret.GetCost() != 0 && --limit <= 0) break;
00705     }
00706     cost.AddCost(ret);
00707   }
00708 
00709   delete iter;
00710   return had_success ? cost : last_error;
00711 }
00712 
00713 
00714 TileIndex _cur_tileloop_tile;
00715 #define TILELOOP_BITS 4
00716 #define TILELOOP_SIZE (1 << TILELOOP_BITS)
00717 #define TILELOOP_ASSERTMASK ((TILELOOP_SIZE - 1) + ((TILELOOP_SIZE - 1) << MapLogX()))
00718 #define TILELOOP_CHKMASK (((1 << (MapLogX() - TILELOOP_BITS))-1) << TILELOOP_BITS)
00719 
00720 void RunTileLoop()
00721 {
00722   TileIndex tile = _cur_tileloop_tile;
00723 
00724   assert((tile & ~TILELOOP_ASSERTMASK) == 0);
00725   uint count = (MapSizeX() / TILELOOP_SIZE) * (MapSizeY() / TILELOOP_SIZE);
00726   do {
00727     _tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
00728 
00729     if (TileX(tile) < MapSizeX() - TILELOOP_SIZE) {
00730       tile += TILELOOP_SIZE; // no overflow
00731     } else {
00732       tile = TILE_MASK(tile - TILELOOP_SIZE * (MapSizeX() / TILELOOP_SIZE - 1) + TileDiffXY(0, TILELOOP_SIZE)); // x would overflow, also increase y
00733     }
00734   } while (--count != 0);
00735   assert((tile & ~TILELOOP_ASSERTMASK) == 0);
00736 
00737   tile += 9;
00738   if (tile & TILELOOP_CHKMASK) {
00739     tile = (tile + MapSizeX()) & TILELOOP_ASSERTMASK;
00740   }
00741   _cur_tileloop_tile = tile;
00742 }
00743 
00744 void InitializeLandscape()
00745 {
00746   uint maxx = MapMaxX();
00747   uint maxy = MapMaxY();
00748   uint sizex = MapSizeX();
00749 
00750   uint y;
00751   for (y = _settings_game.construction.freeform_edges ? 1 : 0; y < maxy; y++) {
00752     uint x;
00753     for (x = _settings_game.construction.freeform_edges ? 1 : 0; x < maxx; x++) {
00754       MakeClear(sizex * y + x, CLEAR_GRASS, 3);
00755       SetTileHeight(sizex * y + x, 0);
00756       SetTropicZone(sizex * y + x, TROPICZONE_NORMAL);
00757       ClearBridgeMiddle(sizex * y + x);
00758     }
00759     MakeVoid(sizex * y + x);
00760   }
00761   for (uint x = 0; x < sizex; x++) MakeVoid(sizex * y + x);
00762 }
00763 
00764 static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4  };
00765 static const byte _genterrain_tbl_2[5] = {  0,  0,  0,  0, 33 };
00766 
00767 static void GenerateTerrain(int type, uint flag)
00768 {
00769   uint32 r = Random();
00770 
00771   const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845, ST_MAPGEN);
00772 
00773   uint x = r & MapMaxX();
00774   uint y = (r >> MapLogX()) & MapMaxY();
00775 
00776   if (x < 2 || y < 2) return;
00777 
00778   DiagDirection direction = (DiagDirection)GB(r, 22, 2);
00779   uint w = templ->width;
00780   uint h = templ->height;
00781 
00782   if (DiagDirToAxis(direction) == AXIS_Y) Swap(w, h);
00783 
00784   const byte *p = templ->data;
00785 
00786   if ((flag & 4) != 0) {
00787     uint xw = x * MapSizeY();
00788     uint yw = y * MapSizeX();
00789     uint bias = (MapSizeX() + MapSizeY()) * 16;
00790 
00791     switch (flag & 3) {
00792       default: NOT_REACHED();
00793       case 0:
00794         if (xw + yw > MapSize() - bias) return;
00795         break;
00796 
00797       case 1:
00798         if (yw < xw + bias) return;
00799         break;
00800 
00801       case 2:
00802         if (xw + yw < MapSize() + bias) return;
00803         break;
00804 
00805       case 3:
00806         if (xw < yw + bias) return;
00807         break;
00808     }
00809   }
00810 
00811   if (x + w >= MapMaxX() - 1) return;
00812   if (y + h >= MapMaxY() - 1) return;
00813 
00814   Tile *tile = &_m[TileXY(x, y)];
00815 
00816   switch (direction) {
00817     default: NOT_REACHED();
00818     case DIAGDIR_NE:
00819       do {
00820         Tile *tile_cur = tile;
00821 
00822         for (uint w_cur = w; w_cur != 0; --w_cur) {
00823           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00824           p++;
00825           tile_cur++;
00826         }
00827         tile += TileDiffXY(0, 1);
00828       } while (--h != 0);
00829       break;
00830 
00831     case DIAGDIR_SE:
00832       do {
00833         Tile *tile_cur = tile;
00834 
00835         for (uint h_cur = h; h_cur != 0; --h_cur) {
00836           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00837           p++;
00838           tile_cur += TileDiffXY(0, 1);
00839         }
00840         tile += TileDiffXY(1, 0);
00841       } while (--w != 0);
00842       break;
00843 
00844     case DIAGDIR_SW:
00845       tile += TileDiffXY(w - 1, 0);
00846       do {
00847         Tile *tile_cur = tile;
00848 
00849         for (uint w_cur = w; w_cur != 0; --w_cur) {
00850           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00851           p++;
00852           tile_cur--;
00853         }
00854         tile += TileDiffXY(0, 1);
00855       } while (--h != 0);
00856       break;
00857 
00858     case DIAGDIR_NW:
00859       tile += TileDiffXY(0, h - 1);
00860       do {
00861         Tile *tile_cur = tile;
00862 
00863         for (uint h_cur = h; h_cur != 0; --h_cur) {
00864           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00865           p++;
00866           tile_cur -= TileDiffXY(0, 1);
00867         }
00868         tile += TileDiffXY(1, 0);
00869       } while (--w != 0);
00870       break;
00871   }
00872 }
00873 
00874 
00875 #include "table/genland.h"
00876 
00877 static void CreateDesertOrRainForest()
00878 {
00879   TileIndex update_freq = MapSize() / 4;
00880   const TileIndexDiffC *data;
00881 
00882   for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00883     if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00884 
00885     if (!IsValidTile(tile)) continue;
00886 
00887     for (data = _make_desert_or_rainforest_data;
00888         data != endof(_make_desert_or_rainforest_data); ++data) {
00889       TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00890       if (t != INVALID_TILE && (TileHeight(t) >= 4 || IsTileType(t, MP_WATER))) break;
00891     }
00892     if (data == endof(_make_desert_or_rainforest_data)) {
00893       SetTropicZone(tile, TROPICZONE_DESERT);
00894     }
00895   }
00896 
00897   for (uint i = 0; i != 256; i++) {
00898     if ((i % 64) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00899 
00900     RunTileLoop();
00901   }
00902 
00903   for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00904     if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00905 
00906     if (!IsValidTile(tile)) continue;
00907 
00908     for (data = _make_desert_or_rainforest_data;
00909         data != endof(_make_desert_or_rainforest_data); ++data) {
00910       TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00911       if (t != INVALID_TILE && IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_DESERT)) break;
00912     }
00913     if (data == endof(_make_desert_or_rainforest_data)) {
00914       SetTropicZone(tile, TROPICZONE_RAINFOREST);
00915     }
00916   }
00917 }
00918 
00919 void GenerateLandscape(byte mode)
00920 {
00922   enum GenLandscapeSteps {
00923     GLS_HEIGHTMAP    =  3, 
00924     GLS_TERRAGENESIS =  5, 
00925     GLS_ORIGINAL     =  2, 
00926     GLS_TROPIC       = 12, 
00927     GLS_OTHER        =  0, 
00928   };
00929   uint steps = (_settings_game.game_creation.landscape == LT_TROPIC) ? GLS_TROPIC : GLS_OTHER;
00930 
00931   if (mode == GWM_HEIGHTMAP) {
00932     SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP);
00933     LoadHeightmap(_file_to_saveload.name);
00934     IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00935   } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) {
00936     SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS);
00937     GenerateTerrainPerlin();
00938   } else {
00939     SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_ORIGINAL);
00940     if (_settings_game.construction.freeform_edges) {
00941       for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0));
00942       for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y));
00943     }
00944     switch (_settings_game.game_creation.landscape) {
00945       case LT_ARCTIC: {
00946         uint32 r = Random();
00947 
00948         for (uint i = ScaleByMapSize(GB(r, 0, 7) + 950); i != 0; --i) {
00949           GenerateTerrain(2, 0);
00950         }
00951 
00952         uint flag = GB(r, 7, 2) | 4;
00953         for (uint i = ScaleByMapSize(GB(r, 9, 7) + 450); i != 0; --i) {
00954           GenerateTerrain(4, flag);
00955         }
00956         break;
00957       }
00958 
00959       case LT_TROPIC: {
00960         uint32 r = Random();
00961 
00962         for (uint i = ScaleByMapSize(GB(r, 0, 7) + 170); i != 0; --i) {
00963           GenerateTerrain(0, 0);
00964         }
00965 
00966         uint flag = GB(r, 7, 2) | 4;
00967         for (uint i = ScaleByMapSize(GB(r, 9, 8) + 1700); i != 0; --i) {
00968           GenerateTerrain(0, flag);
00969         }
00970 
00971         flag ^= 2;
00972 
00973         for (uint i = ScaleByMapSize(GB(r, 17, 7) + 410); i != 0; --i) {
00974           GenerateTerrain(3, flag);
00975         }
00976         break;
00977       }
00978 
00979       default: {
00980         uint32 r = Random();
00981 
00982         assert(_settings_game.difficulty.quantity_sea_lakes != CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY);
00983         uint i = ScaleByMapSize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100);
00984         for (; i != 0; --i) {
00985           GenerateTerrain(_settings_game.difficulty.terrain_type, 0);
00986         }
00987         break;
00988       }
00989     }
00990   }
00991 
00992   /* Do not call IncreaseGeneratingWorldProgress() before FixSlopes(),
00993    * it allows screen redraw. Drawing of broken slopes crashes the game */
00994   FixSlopes();
00995   IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00996   ConvertGroundTilesIntoWaterTiles();
00997   IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00998 
00999   if (_settings_game.game_creation.landscape == LT_TROPIC) CreateDesertOrRainForest();
01000 }
01001 
01002 void OnTick_Town();
01003 void OnTick_Trees();
01004 void OnTick_Station();
01005 void OnTick_Industry();
01006 
01007 void OnTick_Companies();
01008 
01009 void CallLandscapeTick()
01010 {
01011   OnTick_Town();
01012   OnTick_Trees();
01013   OnTick_Station();
01014   OnTick_Industry();
01015 
01016   OnTick_Companies();
01017 }

Generated on Thu Jan 20 22:57:34 2011 for OpenTTD by  doxygen 1.6.1