landscape.cpp

Go to the documentation of this file.
00001 /* $Id: landscape.cpp 19857 2010-05-18 21:44:47Z 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 "variables.h"
00022 #include "void_map.h"
00023 #include "tgp.h"
00024 #include "genworld.h"
00025 #include "fios.h"
00026 #include "functions.h"
00027 #include "date_func.h"
00028 #include "water.h"
00029 #include "effectvehicle_func.h"
00030 #include "landscape_type.h"
00031 #include "animated_tile_func.h"
00032 #include "core/random_func.hpp"
00033 
00034 #include "table/sprites.h"
00035 
00036 extern const TileTypeProcs
00037   _tile_type_clear_procs,
00038   _tile_type_rail_procs,
00039   _tile_type_road_procs,
00040   _tile_type_town_procs,
00041   _tile_type_trees_procs,
00042   _tile_type_station_procs,
00043   _tile_type_water_procs,
00044   _tile_type_dummy_procs,
00045   _tile_type_industry_procs,
00046   _tile_type_tunnelbridge_procs,
00047   _tile_type_unmovable_procs;
00048 
00052 const TileTypeProcs * const _tile_type_procs[16] = {
00053   &_tile_type_clear_procs,        
00054   &_tile_type_rail_procs,         
00055   &_tile_type_road_procs,         
00056   &_tile_type_town_procs,         
00057   &_tile_type_trees_procs,        
00058   &_tile_type_station_procs,      
00059   &_tile_type_water_procs,        
00060   &_tile_type_dummy_procs,        
00061   &_tile_type_industry_procs,     
00062   &_tile_type_tunnelbridge_procs, 
00063   &_tile_type_unmovable_procs,    
00064 };
00065 
00066 /* landscape slope => sprite */
00067 const byte _tileh_to_sprite[32] = {
00068   0, 1, 2, 3, 4, 5, 6,  7, 8, 9, 10, 11, 12, 13, 14, 0,
00069   0, 0, 0, 0, 0, 0, 0, 16, 0, 0,  0, 17,  0, 15, 18, 0,
00070 };
00071 
00079 static SnowLine *_snow_line = NULL;
00080 
00089 uint ApplyFoundationToSlope(Foundation f, Slope *s)
00090 {
00091   if (!IsFoundation(f)) return 0;
00092 
00093   if (IsLeveledFoundation(f)) {
00094     uint dz = TILE_HEIGHT + (IsSteepSlope(*s) ? TILE_HEIGHT : 0);
00095     *s = SLOPE_FLAT;
00096     return dz;
00097   }
00098 
00099   if (f != FOUNDATION_STEEP_BOTH && IsNonContinuousFoundation(f)) {
00100     *s = HalftileSlope(*s, GetHalftileFoundationCorner(f));
00101     return 0;
00102   }
00103 
00104   if (IsSpecialRailFoundation(f)) {
00105     *s = SlopeWithThreeCornersRaised(OppositeCorner(GetRailFoundationCorner(f)));
00106     return 0;
00107   }
00108 
00109   uint dz = IsSteepSlope(*s) ? TILE_HEIGHT : 0;
00110   Corner highest_corner = GetHighestSlopeCorner(*s);
00111 
00112   switch (f) {
00113     case FOUNDATION_INCLINED_X:
00114       *s = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? SLOPE_SW : SLOPE_NE);
00115       break;
00116 
00117     case FOUNDATION_INCLINED_Y:
00118       *s = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? SLOPE_SE : SLOPE_NW);
00119       break;
00120 
00121     case FOUNDATION_STEEP_LOWER:
00122       *s = SlopeWithOneCornerRaised(highest_corner);
00123       break;
00124 
00125     case FOUNDATION_STEEP_BOTH:
00126       *s = HalftileSlope(SlopeWithOneCornerRaised(highest_corner), highest_corner);
00127       break;
00128 
00129     default: NOT_REACHED();
00130   }
00131   return dz;
00132 }
00133 
00134 
00142 uint GetPartialZ(int x, int y, Slope corners)
00143 {
00144   if (IsHalftileSlope(corners)) {
00145     switch (GetHalftileSlopeCorner(corners)) {
00146       case CORNER_W:
00147         if (x - y >= 0) return GetSlopeMaxZ(corners);
00148         break;
00149 
00150       case CORNER_S:
00151         if (x - (y ^ 0xF) >= 0) return GetSlopeMaxZ(corners);
00152         break;
00153 
00154       case CORNER_E:
00155         if (y - x >= 0) return GetSlopeMaxZ(corners);
00156         break;
00157 
00158       case CORNER_N:
00159         if ((y ^ 0xF) - x >= 0) return GetSlopeMaxZ(corners);
00160         break;
00161 
00162       default: NOT_REACHED();
00163     }
00164   }
00165 
00166   int z = 0;
00167 
00168   switch (RemoveHalftileSlope(corners)) {
00169     case SLOPE_W:
00170       if (x - y >= 0) {
00171         z = (x - y) >> 1;
00172       }
00173       break;
00174 
00175     case SLOPE_S:
00176       y ^= 0xF;
00177       if ((x - y) >= 0) {
00178         z = (x - y) >> 1;
00179       }
00180       break;
00181 
00182     case SLOPE_SW:
00183       z = (x >> 1) + 1;
00184       break;
00185 
00186     case SLOPE_E:
00187       if (y - x >= 0) {
00188         z = (y - x) >> 1;
00189       }
00190       break;
00191 
00192     case SLOPE_EW:
00193     case SLOPE_NS:
00194     case SLOPE_ELEVATED:
00195       z = 4;
00196       break;
00197 
00198     case SLOPE_SE:
00199       z = (y >> 1) + 1;
00200       break;
00201 
00202     case SLOPE_WSE:
00203       z = 8;
00204       y ^= 0xF;
00205       if (x - y < 0) {
00206         z += (x - y) >> 1;
00207       }
00208       break;
00209 
00210     case SLOPE_N:
00211       y ^= 0xF;
00212       if (y - x >= 0) {
00213         z = (y - x) >> 1;
00214       }
00215       break;
00216 
00217     case SLOPE_NW:
00218       z = (y ^ 0xF) >> 1;
00219       break;
00220 
00221     case SLOPE_NWS:
00222       z = 8;
00223       if (x - y < 0) {
00224         z += (x - y) >> 1;
00225       }
00226       break;
00227 
00228     case SLOPE_NE:
00229       z = (x ^ 0xF) >> 1;
00230       break;
00231 
00232     case SLOPE_ENW:
00233       z = 8;
00234       y ^= 0xF;
00235       if (y - x < 0) {
00236         z += (y - x) >> 1;
00237       }
00238       break;
00239 
00240     case SLOPE_SEN:
00241       z = 8;
00242       if (y - x < 0) {
00243         z += (y - x) >> 1;
00244       }
00245       break;
00246 
00247     case SLOPE_STEEP_S:
00248       z = 1 + ((x + y) >> 1);
00249       break;
00250 
00251     case SLOPE_STEEP_W:
00252       z = 1 + ((x + (y ^ 0xF)) >> 1);
00253       break;
00254 
00255     case SLOPE_STEEP_N:
00256       z = 1 + (((x ^ 0xF) + (y ^ 0xF)) >> 1);
00257       break;
00258 
00259     case SLOPE_STEEP_E:
00260       z = 1 + (((x ^ 0xF) + y) >> 1);
00261       break;
00262 
00263     default: break;
00264   }
00265 
00266   return z;
00267 }
00268 
00269 uint GetSlopeZ(int x, int y)
00270 {
00271   TileIndex tile = TileVirtXY(x, y);
00272 
00273   return _tile_type_procs[GetTileType(tile)]->get_slope_z_proc(tile, x, y);
00274 }
00275 
00285 int GetSlopeZInCorner(Slope tileh, Corner corner)
00286 {
00287   assert(!IsHalftileSlope(tileh));
00288   return ((tileh & SlopeWithOneCornerRaised(corner)) != 0 ? TILE_HEIGHT : 0) + (tileh == SteepSlope(corner) ? TILE_HEIGHT : 0);
00289 }
00290 
00303 void GetSlopeZOnEdge(Slope tileh, DiagDirection edge, int *z1, int *z2)
00304 {
00305   static const Slope corners[4][4] = {
00306     /*    corner     |          steep slope
00307      *  z1      z2   |       z1             z2        */
00308     {SLOPE_E, SLOPE_N, SLOPE_STEEP_E, SLOPE_STEEP_N}, // DIAGDIR_NE, z1 = E, z2 = N
00309     {SLOPE_S, SLOPE_E, SLOPE_STEEP_S, SLOPE_STEEP_E}, // DIAGDIR_SE, z1 = S, z2 = E
00310     {SLOPE_S, SLOPE_W, SLOPE_STEEP_S, SLOPE_STEEP_W}, // DIAGDIR_SW, z1 = S, z2 = W
00311     {SLOPE_W, SLOPE_N, SLOPE_STEEP_W, SLOPE_STEEP_N}, // DIAGDIR_NW, z1 = W, z2 = N
00312   };
00313 
00314   int halftile_test = (IsHalftileSlope(tileh) ? SlopeWithOneCornerRaised(GetHalftileSlopeCorner(tileh)) : 0);
00315   if (halftile_test == corners[edge][0]) *z2 += TILE_HEIGHT; // The slope is non-continuous in z2. z2 is on the upper side.
00316   if (halftile_test == corners[edge][1]) *z1 += TILE_HEIGHT; // The slope is non-continuous in z1. z1 is on the upper side.
00317 
00318   if ((tileh & corners[edge][0]) != 0) *z1 += TILE_HEIGHT; // z1 is raised
00319   if ((tileh & corners[edge][1]) != 0) *z2 += TILE_HEIGHT; // z2 is raised
00320   if (RemoveHalftileSlope(tileh) == corners[edge][2]) *z1 += TILE_HEIGHT; // z1 is highest corner of a steep slope
00321   if (RemoveHalftileSlope(tileh) == corners[edge][3]) *z2 += TILE_HEIGHT; // z2 is highest corner of a steep slope
00322 }
00323 
00332 Slope GetFoundationSlope(TileIndex tile, uint *z)
00333 {
00334   Slope tileh = GetTileSlope(tile, z);
00335   Foundation f = _tile_type_procs[GetTileType(tile)]->get_foundation_proc(tile, tileh);
00336   uint z_inc = ApplyFoundationToSlope(f, &tileh);
00337   if (z != NULL) *z += z_inc;
00338   return tileh;
00339 }
00340 
00341 
00342 bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
00343 {
00344   uint z;
00345 
00346   int z_W_here = z_here;
00347   int z_N_here = z_here;
00348   GetSlopeZOnEdge(slope_here, DIAGDIR_NW, &z_W_here, &z_N_here);
00349 
00350   Slope slope = GetFoundationSlope(TILE_ADDXY(tile, 0, -1), &z);
00351   int z_W = z;
00352   int z_N = z;
00353   GetSlopeZOnEdge(slope, DIAGDIR_SE, &z_W, &z_N);
00354 
00355   return (z_N_here > z_N) || (z_W_here > z_W);
00356 }
00357 
00358 
00359 bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
00360 {
00361   uint z;
00362 
00363   int z_E_here = z_here;
00364   int z_N_here = z_here;
00365   GetSlopeZOnEdge(slope_here, DIAGDIR_NE, &z_E_here, &z_N_here);
00366 
00367   Slope slope = GetFoundationSlope(TILE_ADDXY(tile, -1, 0), &z);
00368   int z_E = z;
00369   int z_N = z;
00370   GetSlopeZOnEdge(slope, DIAGDIR_SW, &z_E, &z_N);
00371 
00372   return (z_N_here > z_N) || (z_E_here > z_E);
00373 }
00374 
00380 void DrawFoundation(TileInfo *ti, Foundation f)
00381 {
00382   if (!IsFoundation(f)) return;
00383 
00384   /* Two part foundations must be drawn separately */
00385   assert(f != FOUNDATION_STEEP_BOTH);
00386 
00387   uint sprite_block = 0;
00388   uint z;
00389   Slope slope = GetFoundationSlope(ti->tile, &z);
00390 
00391   /* Select the needed block of foundations sprites
00392    * Block 0: Walls at NW and NE edge
00393    * Block 1: Wall  at        NE edge
00394    * Block 2: Wall  at NW        edge
00395    * Block 3: No walls at NW or NE edge
00396    */
00397   if (!HasFoundationNW(ti->tile, slope, z)) sprite_block += 1;
00398   if (!HasFoundationNE(ti->tile, slope, z)) sprite_block += 2;
00399 
00400   /* Use the original slope sprites if NW and NE borders should be visible */
00401   SpriteID leveled_base = (sprite_block == 0 ? (int)SPR_FOUNDATION_BASE : (SPR_SLOPES_VIRTUAL_BASE + sprite_block * SPR_TRKFOUND_BLOCK_SIZE));
00402   SpriteID inclined_base = SPR_SLOPES_VIRTUAL_BASE + SPR_SLOPES_INCLINED_OFFSET + sprite_block * SPR_TRKFOUND_BLOCK_SIZE;
00403   SpriteID halftile_base = SPR_HALFTILE_FOUNDATION_BASE + sprite_block * SPR_HALFTILE_BLOCK_SIZE;
00404 
00405   if (IsSteepSlope(ti->tileh)) {
00406     if (!IsNonContinuousFoundation(f)) {
00407       /* Lower part of foundation */
00408       AddSortableSpriteToDraw(
00409         leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z
00410       );
00411     }
00412 
00413     Corner highest_corner = GetHighestSlopeCorner(ti->tileh);
00414     ti->z += ApplyFoundationToSlope(f, &ti->tileh);
00415 
00416     if (IsInclinedFoundation(f)) {
00417       /* inclined foundation */
00418       byte inclined = highest_corner * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
00419 
00420       AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
00421         f == FOUNDATION_INCLINED_X ? 16 : 1,
00422         f == FOUNDATION_INCLINED_Y ? 16 : 1,
00423         TILE_HEIGHT, ti->z
00424       );
00425       OffsetGroundSprite(31, 9);
00426     } else if (IsLeveledFoundation(f)) {
00427       AddSortableSpriteToDraw(leveled_base + SlopeWithOneCornerRaised(highest_corner), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z - TILE_HEIGHT);
00428       OffsetGroundSprite(31, 1);
00429     } else if (f == FOUNDATION_STEEP_LOWER) {
00430       /* one corner raised */
00431       OffsetGroundSprite(31, 1);
00432     } else {
00433       /* halftile foundation */
00434       int x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? 8 : 0);
00435       int y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? 8 : 0);
00436 
00437       AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z + TILE_HEIGHT);
00438       OffsetGroundSprite(31, 9);
00439     }
00440   } else {
00441     if (IsLeveledFoundation(f)) {
00442       /* leveled foundation */
00443       AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
00444       OffsetGroundSprite(31, 1);
00445     } else if (IsNonContinuousFoundation(f)) {
00446       /* halftile foundation */
00447       Corner halftile_corner = GetHalftileFoundationCorner(f);
00448       int x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? 8 : 0);
00449       int y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? 8 : 0);
00450 
00451       AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z);
00452       OffsetGroundSprite(31, 9);
00453     } else if (IsSpecialRailFoundation(f)) {
00454       /* anti-zig-zag foundation */
00455       SpriteID spr;
00456       if (ti->tileh == SLOPE_NS || ti->tileh == SLOPE_EW) {
00457         /* half of leveled foundation under track corner */
00458         spr = leveled_base + SlopeWithThreeCornersRaised(GetRailFoundationCorner(f));
00459       } else {
00460         /* tile-slope = sloped along X/Y, foundation-slope = three corners raised */
00461         spr = inclined_base + 2 * GetRailFoundationCorner(f) + ((ti->tileh == SLOPE_SW || ti->tileh == SLOPE_NE) ? 1 : 0);
00462       }
00463       AddSortableSpriteToDraw(spr, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
00464       OffsetGroundSprite(31, 9);
00465     } else {
00466       /* inclined foundation */
00467       byte inclined = GetHighestSlopeCorner(ti->tileh) * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
00468 
00469       AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
00470         f == FOUNDATION_INCLINED_X ? 16 : 1,
00471         f == FOUNDATION_INCLINED_Y ? 16 : 1,
00472         TILE_HEIGHT, ti->z
00473       );
00474       OffsetGroundSprite(31, 9);
00475     }
00476     ti->z += ApplyFoundationToSlope(f, &ti->tileh);
00477   }
00478 }
00479 
00480 void DoClearSquare(TileIndex tile)
00481 {
00482   /* If the tile can have animation and we clear it, delete it from the animated tile list. */
00483   if (_tile_type_procs[GetTileType(tile)]->animate_tile_proc != NULL) DeleteAnimatedTile(tile);
00484 
00485   MakeClear(tile, CLEAR_GRASS, _generating_world ? 3 : 0);
00486   MarkTileDirtyByTile(tile);
00487 }
00488 
00498 TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
00499 {
00500   return _tile_type_procs[GetTileType(tile)]->get_tile_track_status_proc(tile, mode, sub_mode, side);
00501 }
00502 
00509 void ChangeTileOwner(TileIndex tile, Owner old_owner, Owner new_owner)
00510 {
00511   _tile_type_procs[GetTileType(tile)]->change_tile_owner_proc(tile, old_owner, new_owner);
00512 }
00513 
00514 void GetTileDesc(TileIndex tile, TileDesc *td)
00515 {
00516   _tile_type_procs[GetTileType(tile)]->get_tile_desc_proc(tile, td);
00517 }
00518 
00524 bool IsSnowLineSet()
00525 {
00526   return _snow_line != NULL;
00527 }
00528 
00534 void SetSnowLine(byte table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS])
00535 {
00536   _snow_line = CallocT<SnowLine>(1);
00537   _snow_line->lowest_value = 0xFF;
00538   memcpy(_snow_line->table, table, sizeof(_snow_line->table));
00539 
00540   for (uint i = 0; i < SNOW_LINE_MONTHS; i++) {
00541     for (uint j = 0; j < SNOW_LINE_DAYS; j++) {
00542       _snow_line->highest_value = max(_snow_line->highest_value, table[i][j]);
00543       _snow_line->lowest_value = min(_snow_line->lowest_value, table[i][j]);
00544     }
00545   }
00546 }
00547 
00553 byte GetSnowLine()
00554 {
00555   if (_snow_line == NULL) return _settings_game.game_creation.snow_line;
00556 
00557   YearMonthDay ymd;
00558   ConvertDateToYMD(_date, &ymd);
00559   return _snow_line->table[ymd.month][ymd.day];
00560 }
00561 
00567 byte HighestSnowLine()
00568 {
00569   return _snow_line == NULL ? _settings_game.game_creation.snow_line : _snow_line->highest_value;
00570 }
00571 
00577 byte LowestSnowLine()
00578 {
00579   return _snow_line == NULL ? _settings_game.game_creation.snow_line : _snow_line->lowest_value;
00580 }
00581 
00586 void ClearSnowLine()
00587 {
00588   free(_snow_line);
00589   _snow_line = NULL;
00590 }
00591 
00600 CommandCost CmdLandscapeClear(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00601 {
00602   return _tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags);
00603 }
00604 
00613 CommandCost CmdClearArea(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00614 {
00615   if (p1 >= MapSize()) return CMD_ERROR;
00616 
00617   /* make sure sx,sy are smaller than ex,ey */
00618   int ex = TileX(tile);
00619   int ey = TileY(tile);
00620   int sx = TileX(p1);
00621   int sy = TileY(p1);
00622   if (ex < sx) Swap(ex, sx);
00623   if (ey < sy) Swap(ey, sy);
00624 
00625   Money money = GetAvailableMoneyForCommand();
00626   CommandCost cost(EXPENSES_CONSTRUCTION);
00627   bool success = false;
00628 
00629   for (int x = sx; x <= ex; ++x) {
00630     for (int y = sy; y <= ey; ++y) {
00631       CommandCost ret = DoCommand(TileXY(x, y), 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
00632       if (ret.Failed()) continue;
00633       success = true;
00634 
00635       if (flags & DC_EXEC) {
00636         money -= ret.GetCost();
00637         if (ret.GetCost() > 0 && money < 0) {
00638           _additional_cash_required = ret.GetCost();
00639           return cost;
00640         }
00641         DoCommand(TileXY(x, y), 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00642 
00643         /* draw explosion animation... */
00644         if ((x == sx || x == ex) && (y == sy || y == ey)) {
00645           /* big explosion in each corner, or small explosion for single tiles */
00646           CreateEffectVehicleAbove(x * TILE_SIZE + TILE_SIZE / 2, y * TILE_SIZE + TILE_SIZE / 2, 2,
00647             sy == ey && sx == ex ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
00648           );
00649         }
00650       }
00651       cost.AddCost(ret);
00652     }
00653   }
00654 
00655   return (success) ? cost : CMD_ERROR;
00656 }
00657 
00658 
00659 TileIndex _cur_tileloop_tile;
00660 #define TILELOOP_BITS 4
00661 #define TILELOOP_SIZE (1 << TILELOOP_BITS)
00662 #define TILELOOP_ASSERTMASK ((TILELOOP_SIZE - 1) + ((TILELOOP_SIZE - 1) << MapLogX()))
00663 #define TILELOOP_CHKMASK (((1 << (MapLogX() - TILELOOP_BITS))-1) << TILELOOP_BITS)
00664 
00665 void RunTileLoop()
00666 {
00667   TileIndex tile = _cur_tileloop_tile;
00668 
00669   assert((tile & ~TILELOOP_ASSERTMASK) == 0);
00670   uint count = (MapSizeX() / TILELOOP_SIZE) * (MapSizeY() / TILELOOP_SIZE);
00671   do {
00672     _tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
00673 
00674     if (TileX(tile) < MapSizeX() - TILELOOP_SIZE) {
00675       tile += TILELOOP_SIZE; // no overflow
00676     } else {
00677       tile = TILE_MASK(tile - TILELOOP_SIZE * (MapSizeX() / TILELOOP_SIZE - 1) + TileDiffXY(0, TILELOOP_SIZE)); // x would overflow, also increase y
00678     }
00679   } while (--count != 0);
00680   assert((tile & ~TILELOOP_ASSERTMASK) == 0);
00681 
00682   tile += 9;
00683   if (tile & TILELOOP_CHKMASK) {
00684     tile = (tile + MapSizeX()) & TILELOOP_ASSERTMASK;
00685   }
00686   _cur_tileloop_tile = tile;
00687 }
00688 
00689 void InitializeLandscape()
00690 {
00691   uint maxx = MapMaxX();
00692   uint maxy = MapMaxY();
00693   uint sizex = MapSizeX();
00694 
00695   uint y;
00696   for (y = _settings_game.construction.freeform_edges ? 1 : 0; y < maxy; y++) {
00697     uint x;
00698     for (x = _settings_game.construction.freeform_edges ? 1 : 0; x < maxx; x++) {
00699       MakeClear(sizex * y + x, CLEAR_GRASS, 3);
00700       SetTileHeight(sizex * y + x, 0);
00701       SetTropicZone(sizex * y + x, TROPICZONE_NORMAL);
00702       ClearBridgeMiddle(sizex * y + x);
00703     }
00704     MakeVoid(sizex * y + x);
00705   }
00706   for (uint x = 0; x < sizex; x++) MakeVoid(sizex * y + x);
00707 }
00708 
00709 static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4  };
00710 static const byte _genterrain_tbl_2[5] = {  0,  0,  0,  0, 33 };
00711 
00712 static void GenerateTerrain(int type, uint flag)
00713 {
00714   uint32 r = Random();
00715 
00716   const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845, ST_MAPGEN);
00717 
00718   uint x = r & MapMaxX();
00719   uint y = (r >> MapLogX()) & MapMaxY();
00720 
00721   if (x < 2 || y < 2) return;
00722 
00723   DiagDirection direction = (DiagDirection)GB(r, 22, 2);
00724   uint w = templ->width;
00725   uint h = templ->height;
00726 
00727   if (DiagDirToAxis(direction) == AXIS_Y) Swap(w, h);
00728 
00729   const byte *p = templ->data;
00730 
00731   if ((flag & 4) != 0) {
00732     uint xw = x * MapSizeY();
00733     uint yw = y * MapSizeX();
00734     uint bias = (MapSizeX() + MapSizeY()) * 16;
00735 
00736     switch (flag & 3) {
00737       default: NOT_REACHED();
00738       case 0:
00739         if (xw + yw > MapSize() - bias) return;
00740         break;
00741 
00742       case 1:
00743         if (yw < xw + bias) return;
00744         break;
00745 
00746       case 2:
00747         if (xw + yw < MapSize() + bias) return;
00748         break;
00749 
00750       case 3:
00751         if (xw < yw + bias) return;
00752         break;
00753     }
00754   }
00755 
00756   if (x + w >= MapMaxX() - 1) return;
00757   if (y + h >= MapMaxY() - 1) return;
00758 
00759   Tile *tile = &_m[TileXY(x, y)];
00760 
00761   switch (direction) {
00762     default: NOT_REACHED();
00763     case DIAGDIR_NE:
00764       do {
00765         Tile *tile_cur = tile;
00766 
00767         for (uint w_cur = w; w_cur != 0; --w_cur) {
00768           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00769           p++;
00770           tile_cur++;
00771         }
00772         tile += TileDiffXY(0, 1);
00773       } while (--h != 0);
00774       break;
00775 
00776     case DIAGDIR_SE:
00777       do {
00778         Tile *tile_cur = tile;
00779 
00780         for (uint h_cur = h; h_cur != 0; --h_cur) {
00781           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00782           p++;
00783           tile_cur += TileDiffXY(0, 1);
00784         }
00785         tile += TileDiffXY(1, 0);
00786       } while (--w != 0);
00787       break;
00788 
00789     case DIAGDIR_SW:
00790       tile += TileDiffXY(w - 1, 0);
00791       do {
00792         Tile *tile_cur = tile;
00793 
00794         for (uint w_cur = w; w_cur != 0; --w_cur) {
00795           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00796           p++;
00797           tile_cur--;
00798         }
00799         tile += TileDiffXY(0, 1);
00800       } while (--h != 0);
00801       break;
00802 
00803     case DIAGDIR_NW:
00804       tile += TileDiffXY(0, h - 1);
00805       do {
00806         Tile *tile_cur = tile;
00807 
00808         for (uint h_cur = h; h_cur != 0; --h_cur) {
00809           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00810           p++;
00811           tile_cur -= TileDiffXY(0, 1);
00812         }
00813         tile += TileDiffXY(1, 0);
00814       } while (--w != 0);
00815       break;
00816   }
00817 }
00818 
00819 
00820 #include "table/genland.h"
00821 
00822 static void CreateDesertOrRainForest()
00823 {
00824   TileIndex update_freq = MapSize() / 4;
00825   const TileIndexDiffC *data;
00826 
00827   for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00828     if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00829 
00830     if (!IsValidTile(tile)) continue;
00831 
00832     for (data = _make_desert_or_rainforest_data;
00833         data != endof(_make_desert_or_rainforest_data); ++data) {
00834       TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00835       if (t != INVALID_TILE && (TileHeight(t) >= 4 || IsTileType(t, MP_WATER))) break;
00836     }
00837     if (data == endof(_make_desert_or_rainforest_data))
00838       SetTropicZone(tile, TROPICZONE_DESERT);
00839   }
00840 
00841   for (uint i = 0; i != 256; i++) {
00842     if ((i % 64) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00843 
00844     RunTileLoop();
00845   }
00846 
00847   for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00848     if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00849 
00850     if (!IsValidTile(tile)) continue;
00851 
00852     for (data = _make_desert_or_rainforest_data;
00853         data != endof(_make_desert_or_rainforest_data); ++data) {
00854       TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00855       if (t != INVALID_TILE && IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_DESERT)) break;
00856     }
00857     if (data == endof(_make_desert_or_rainforest_data))
00858       SetTropicZone(tile, TROPICZONE_RAINFOREST);
00859   }
00860 }
00861 
00862 void GenerateLandscape(byte mode)
00863 {
00865   enum GenLandscapeSteps {
00866     GLS_HEIGHTMAP    =  3, 
00867     GLS_TERRAGENESIS =  5, 
00868     GLS_ORIGINAL     =  2, 
00869     GLS_TROPIC       = 12, 
00870     GLS_OTHER        =  0, 
00871   };
00872   uint steps = (_settings_game.game_creation.landscape == LT_TROPIC) ? GLS_TROPIC : GLS_OTHER;
00873 
00874   if (mode == GWM_HEIGHTMAP) {
00875     SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP);
00876     LoadHeightmap(_file_to_saveload.name);
00877     IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00878   } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) {
00879     SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS);
00880     GenerateTerrainPerlin();
00881   } else {
00882     SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_ORIGINAL);
00883     if (_settings_game.construction.freeform_edges) {
00884       for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0));
00885       for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y));
00886     }
00887     switch (_settings_game.game_creation.landscape) {
00888       case LT_ARCTIC: {
00889         uint32 r = Random();
00890 
00891         for (uint i = ScaleByMapSize(GB(r, 0, 7) + 950); i != 0; --i) {
00892           GenerateTerrain(2, 0);
00893         }
00894 
00895         uint flag = GB(r, 7, 2) | 4;
00896         for (uint i = ScaleByMapSize(GB(r, 9, 7) + 450); i != 0; --i) {
00897           GenerateTerrain(4, flag);
00898         }
00899       } break;
00900 
00901       case LT_TROPIC: {
00902         uint32 r = Random();
00903 
00904         for (uint i = ScaleByMapSize(GB(r, 0, 7) + 170); i != 0; --i) {
00905           GenerateTerrain(0, 0);
00906         }
00907 
00908         uint flag = GB(r, 7, 2) | 4;
00909         for (uint i = ScaleByMapSize(GB(r, 9, 8) + 1700); i != 0; --i) {
00910           GenerateTerrain(0, flag);
00911         }
00912 
00913         flag ^= 2;
00914 
00915         for (uint i = ScaleByMapSize(GB(r, 17, 7) + 410); i != 0; --i) {
00916           GenerateTerrain(3, flag);
00917         }
00918       } break;
00919 
00920       default: {
00921         uint32 r = Random();
00922 
00923         uint i = ScaleByMapSize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100);
00924         for (; i != 0; --i) {
00925           GenerateTerrain(_settings_game.difficulty.terrain_type, 0);
00926         }
00927       } break;
00928     }
00929   }
00930 
00931   /* Do not call IncreaseGeneratingWorldProgress() before FixSlopes(),
00932    * it allows screen redraw. Drawing of broken slopes crashes the game */
00933   FixSlopes();
00934   IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00935   ConvertGroundTilesIntoWaterTiles();
00936   IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00937 
00938   if (_settings_game.game_creation.landscape == LT_TROPIC) CreateDesertOrRainForest();
00939 }
00940 
00941 void OnTick_Town();
00942 void OnTick_Trees();
00943 void OnTick_Station();
00944 void OnTick_Industry();
00945 
00946 void OnTick_Companies();
00947 
00948 void CallLandscapeTick()
00949 {
00950   OnTick_Town();
00951   OnTick_Trees();
00952   OnTick_Station();
00953   OnTick_Industry();
00954 
00955   OnTick_Companies();
00956 }

Generated on Sat Jun 5 21:52:05 2010 for OpenTTD by  doxygen 1.6.1