landscape.cpp

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

Generated on Tue Jan 5 21:02:54 2010 for OpenTTD by  doxygen 1.5.6