landscape.cpp

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

Generated on Fri Dec 31 17:15:32 2010 for OpenTTD by  doxygen 1.6.1