# landscape.cpp

    00001 /* $Id: landscape.cpp 13827 2008-07-25 19:54:14Z rubidium $ */
    00002
    00003 #include "stdafx.h"
    00004 #include "openttd.h"
    00005 #include "bridge_map.h"
    00006 #include "heightmap.h"
    00007 #include "clear_map.h"
    00008 #include "spritecache.h"
    00009 #include <stdarg.h>
    00010 #include "viewport_func.h"
    00011 #include "command_func.h"
    00012 #include "landscape.h"
    00013 #include "variables.h"
    00014 #include "void_map.h"
    00015 #include "water_map.h"
    00016 #include "tgp.h"
    00017 #include "genworld.h"
    00018 #include "tile_cmd.h"
    00019 #include "core/alloc_func.hpp"
    00020 #include "fios.h"
    00021 #include "window_func.h"
    00022 #include "functions.h"
    00023 #include "date_func.h"
    00024 #include "vehicle_func.h"
    00025 #include "settings_type.h"
    00026 #include "water.h"
    00027
    00028 #include "table/sprites.h"
    00029
    00030 extern const TileTypeProcs
    00031   _tile_type_clear_procs,
    00032   _tile_type_rail_procs,
    00033   _tile_type_road_procs,
    00034   _tile_type_town_procs,
    00035   _tile_type_trees_procs,
    00036   _tile_type_station_procs,
    00037   _tile_type_water_procs,
    00038   _tile_type_dummy_procs,
    00039   _tile_type_industry_procs,
    00040   _tile_type_tunnelbridge_procs,
    00041   _tile_type_unmovable_procs;
    00042
    00043 const TileTypeProcs * const _tile_type_procs[16] = {
    00044   &_tile_type_clear_procs,
    00045   &_tile_type_rail_procs,
    00046   &_tile_type_road_procs,
    00047   &_tile_type_town_procs,
    00048   &_tile_type_trees_procs,
    00049   &_tile_type_station_procs,
    00050   &_tile_type_water_procs,
    00051   &_tile_type_dummy_procs,
    00052   &_tile_type_industry_procs,
    00053   &_tile_type_tunnelbridge_procs,
    00054   &_tile_type_unmovable_procs,
    00055 };
    00056
    00057 /* landscape slope => sprite */
    00058 const byte _tileh_to_sprite[32] = {
    00059   0, 1, 2, 3, 4, 5, 6,  7, 8, 9, 10, 11, 12, 13, 14, 0,
    00060   0, 0, 0, 0, 0, 0, 0, 16, 0, 0,  0, 17,  0, 15, 18, 0,
    00061 };
    00062
    00063 SnowLine *_snow_line = NULL;
    00064
    00073 uint ApplyFoundationToSlope(Foundation f, Slope *s)
    00074 {
    00075
    00076   if (!IsFoundation(f)) return 0;
    00077
    00078   if (IsLeveledFoundation(f)) {
    00079     uint dz = TILE_HEIGHT + (IsSteepSlope(*s) ? TILE_HEIGHT : 0);
    00080     *s = SLOPE_FLAT;
    00081     return dz;
    00082   }
    00083
    00084   if (f != FOUNDATION_STEEP_BOTH && IsNonContinuousFoundation(f)) {
    00085     *s = HalftileSlope(*s, GetHalftileFoundationCorner(f));
    00086     return 0;
    00087   }
    00088
    00089   if (IsSpecialRailFoundation(f)) {
    00090     *s = SlopeWithThreeCornersRaised(OppositeCorner(GetRailFoundationCorner(f)));
    00091     return 0;
    00092   }
    00093
    00094   uint dz = IsSteepSlope(*s) ? TILE_HEIGHT : 0;
    00095   Corner highest_corner = GetHighestSlopeCorner(*s);
    00096
    00097   switch (f) {
    00098     case FOUNDATION_INCLINED_X:
    00099       *s = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? SLOPE_SW : SLOPE_NE);
    00100       break;
    00101
    00102     case FOUNDATION_INCLINED_Y:
    00103       *s = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? SLOPE_SE : SLOPE_NW);
    00104       break;
    00105
    00106     case FOUNDATION_STEEP_LOWER:
    00107       *s = SlopeWithOneCornerRaised(highest_corner);
    00108       break;
    00109
    00110     case FOUNDATION_STEEP_BOTH:
    00111       *s = HalftileSlope(SlopeWithOneCornerRaised(highest_corner), highest_corner);
    00112       break;
    00113
    00114     default: NOT_REACHED();
    00115   }
    00116   return dz;
    00117 }
    00118
    00119
    00120 uint GetPartialZ(int x, int y, Slope corners)
    00121 {
    00122   if (IsHalftileSlope(corners)) {
    00123     switch (GetHalftileSlopeCorner(corners)) {
    00124       case CORNER_W:
    00125         if (x - y >= 0) return GetSlopeMaxZ(corners);
    00126         break;
    00127
    00128       case CORNER_S:
    00129         if (x - (y ^ 0xF) >= 0) return GetSlopeMaxZ(corners);
    00130         break;
    00131
    00132       case CORNER_E:
    00133         if (y - x >= 0) return GetSlopeMaxZ(corners);
    00134         break;
    00135
    00136       case CORNER_N:
    00137         if ((y ^ 0xF) - x >= 0) return GetSlopeMaxZ(corners);
    00138         break;
    00139
    00140       default: NOT_REACHED();
    00141     }
    00142   }
    00143
    00144   int z = 0;
    00145
    00146   switch (RemoveHalftileSlope(corners)) {
    00147   case SLOPE_W:
    00148     if (x - y >= 0)
    00149       z = (x - y) >> 1;
    00150     break;
    00151
    00152   case SLOPE_S:
    00153     y ^= 0xF;
    00154     if ( (x - y) >= 0)
    00155       z = (x - y) >> 1;
    00156     break;
    00157
    00158   case SLOPE_SW:
    00159     z = (x >> 1) + 1;
    00160     break;
    00161
    00162   case SLOPE_E:
    00163     if (y - x >= 0)
    00164       z = (y - x) >> 1;
    00165     break;
    00166
    00167   case SLOPE_EW:
    00168   case SLOPE_NS:
    00169   case SLOPE_ELEVATED:
    00170     z = 4;
    00171     break;
    00172
    00173   case SLOPE_SE:
    00174     z = (y >> 1) + 1;
    00175     break;
    00176
    00177   case SLOPE_WSE:
    00178     z = 8;
    00179     y ^= 0xF;
    00180     if (x - y < 0)
    00181       z += (x - y) >> 1;
    00182     break;
    00183
    00184   case SLOPE_N:
    00185     y ^= 0xF;
    00186     if (y - x >= 0)
    00187       z = (y - x) >> 1;
    00188     break;
    00189
    00190   case SLOPE_NW:
    00191     z = (y ^ 0xF) >> 1;
    00192     break;
    00193
    00194   case SLOPE_NWS:
    00195     z = 8;
    00196     if (x - y < 0)
    00197       z += (x - y) >> 1;
    00198     break;
    00199
    00200   case SLOPE_NE:
    00201     z = (x ^ 0xF) >> 1;
    00202     break;
    00203
    00204   case SLOPE_ENW:
    00205     z = 8;
    00206     y ^= 0xF;
    00207     if (y - x < 0)
    00208       z += (y - x) >> 1;
    00209     break;
    00210
    00211   case SLOPE_SEN:
    00212     z = 8;
    00213     if (y - x < 0)
    00214       z += (y - x) >> 1;
    00215     break;
    00216
    00217   case SLOPE_STEEP_S:
    00218     z = 1 + ((x + y) >> 1);
    00219     break;
    00220
    00221   case SLOPE_STEEP_W:
    00222     z = 1 + ((x + (y ^ 0xF)) >> 1);
    00223     break;
    00224
    00225   case SLOPE_STEEP_N:
    00226     z = 1 + (((x ^ 0xF) + (y ^ 0xF)) >> 1);
    00227     break;
    00228
    00229   case SLOPE_STEEP_E:
    00230     z = 1 + (((x ^ 0xF) + y) >> 1);
    00231     break;
    00232
    00233     default: break;
    00234   }
    00235
    00236   return z;
    00237 }
    00238
    00239 uint GetSlopeZ(int x, int y)
    00240 {
    00241   TileIndex tile = TileVirtXY(x, y);
    00242
    00243   return _tile_type_procs[GetTileType(tile)]->get_slope_z_proc(tile, x, y);
    00244 }
    00245
    00255 int GetSlopeZInCorner(Slope tileh, Corner corner)
    00256 {
    00257   assert(!IsHalftileSlope(tileh));
    00258   return ((tileh & SlopeWithOneCornerRaised(corner)) != 0 ? TILE_HEIGHT : 0) + (tileh == SteepSlope(corner) ? TILE_HEIGHT : 0);
    00259 }
    00260
    00273 void GetSlopeZOnEdge(Slope tileh, DiagDirection edge, int *z1, int *z2)
    00274 {
    00275   static const Slope corners[4][4] = {
    00276     /*    corner     |          steep slope
    00277      *  z1      z2   |       z1             z2        */
    00278     {SLOPE_E, SLOPE_N, SLOPE_STEEP_E, SLOPE_STEEP_N}, // DIAGDIR_NE, z1 = E, z2 = N
    00279     {SLOPE_S, SLOPE_E, SLOPE_STEEP_S, SLOPE_STEEP_E}, // DIAGDIR_SE, z1 = S, z2 = E
    00280     {SLOPE_S, SLOPE_W, SLOPE_STEEP_S, SLOPE_STEEP_W}, // DIAGDIR_SW, z1 = S, z2 = W
    00281     {SLOPE_W, SLOPE_N, SLOPE_STEEP_W, SLOPE_STEEP_N}, // DIAGDIR_NW, z1 = W, z2 = N
    00282   };
    00283
    00284   int halftile_test = (IsHalftileSlope(tileh) ? SlopeWithOneCornerRaised(GetHalftileSlopeCorner(tileh)) : 0);
    00285   if (halftile_test == corners[edge][0]) *z2 += TILE_HEIGHT; // The slope is non-continuous in z2. z2 is on the upper side.
    00286   if (halftile_test == corners[edge][1]) *z1 += TILE_HEIGHT; // The slope is non-continuous in z1. z1 is on the upper side.
    00287
    00288   if ((tileh & corners[edge][0]) != 0) *z1 += TILE_HEIGHT; // z1 is raised
    00289   if ((tileh & corners[edge][1]) != 0) *z2 += TILE_HEIGHT; // z2 is raised
    00290   if (RemoveHalftileSlope(tileh) == corners[edge][2]) *z1 += TILE_HEIGHT; // z1 is highest corner of a steep slope
    00291   if (RemoveHalftileSlope(tileh) == corners[edge][3]) *z2 += TILE_HEIGHT; // z2 is highest corner of a steep slope
    00292 }
    00293
    00302 Slope GetFoundationSlope(TileIndex tile, uint* z)
    00303 {
    00304   Slope tileh = GetTileSlope(tile, z);
    00305   Foundation f = _tile_type_procs[GetTileType(tile)]->get_foundation_proc(tile, tileh);
    00306   uint z_inc = ApplyFoundationToSlope(f, &tileh);
    00307   if (z != NULL) *z += z_inc;
    00308   return tileh;
    00309 }
    00310
    00311
    00312 static bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
    00313 {
    00314   uint z;
    00315
    00316   int z_W_here = z_here;
    00317   int z_N_here = z_here;
    00318   GetSlopeZOnEdge(slope_here, DIAGDIR_NW, &z_W_here, &z_N_here);
    00319
    00320   Slope slope = GetFoundationSlope(TILE_ADDXY(tile, 0, -1), &z);
    00321   int z_W = z;
    00322   int z_N = z;
    00323   GetSlopeZOnEdge(slope, DIAGDIR_SE, &z_W, &z_N);
    00324
    00325   return (z_N_here > z_N) || (z_W_here > z_W);
    00326 }
    00327
    00328
    00329 static bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
    00330 {
    00331   uint z;
    00332
    00333   int z_E_here = z_here;
    00334   int z_N_here = z_here;
    00335   GetSlopeZOnEdge(slope_here, DIAGDIR_NE, &z_E_here, &z_N_here);
    00336
    00337   Slope slope = GetFoundationSlope(TILE_ADDXY(tile, -1, 0), &z);
    00338   int z_E = z;
    00339   int z_N = z;
    00340   GetSlopeZOnEdge(slope, DIAGDIR_SW, &z_E, &z_N);
    00341
    00342   return (z_N_here > z_N) || (z_E_here > z_E);
    00343 }
    00344
    00345
    00346 void DrawFoundation(TileInfo *ti, Foundation f)
    00347 {
    00348   if (!IsFoundation(f)) return;
    00349
    00350   /* Two part foundations must be drawn separately */
    00351   assert(f != FOUNDATION_STEEP_BOTH);
    00352
    00353   uint sprite_block = 0;
    00354   uint z;
    00355   Slope slope = GetFoundationSlope(ti->tile, &z);
    00356
    00357   /* Select the needed block of foundations sprites
    00358    * Block 0: Walls at NW and NE edge
    00359    * Block 1: Wall  at        NE edge
    00360    * Block 2: Wall  at NW        edge
    00361    * Block 3: No walls at NW or NE edge
    00362    */
    00363   if (!HasFoundationNW(ti->tile, slope, z)) sprite_block += 1;
    00364   if (!HasFoundationNE(ti->tile, slope, z)) sprite_block += 2;
    00365
    00366   /* Use the original slope sprites if NW and NE borders should be visible */
    00367   SpriteID leveled_base = (sprite_block == 0 ? (int)SPR_FOUNDATION_BASE : (SPR_SLOPES_VIRTUAL_BASE + sprite_block * SPR_TRKFOUND_BLOCK_SIZE));
    00368   SpriteID inclined_base = SPR_SLOPES_VIRTUAL_BASE + SPR_SLOPES_INCLINED_OFFSET + sprite_block * SPR_TRKFOUND_BLOCK_SIZE;
    00369   SpriteID halftile_base = SPR_HALFTILE_FOUNDATION_BASE + sprite_block * SPR_HALFTILE_BLOCK_SIZE;
    00370
    00371   if (IsSteepSlope(ti->tileh)) {
    00372     if (!IsNonContinuousFoundation(f)) {
    00373       /* Lower part of foundation */
    00374       AddSortableSpriteToDraw(
    00375         leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z
    00376       );
    00377     }
    00378
    00379     Corner highest_corner = GetHighestSlopeCorner(ti->tileh);
    00380     ti->z += ApplyFoundationToSlope(f, &ti->tileh);
    00381
    00382     if (IsInclinedFoundation(f)) {
    00383       /* inclined foundation */
    00384       byte inclined = highest_corner * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
    00385
    00386       AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y, 16, 16, 1, ti->z);
    00387       OffsetGroundSprite(31, 9);
    00388     } else if (IsLeveledFoundation(f)) {
    00389       AddSortableSpriteToDraw(leveled_base + SlopeWithOneCornerRaised(highest_corner), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z - TILE_HEIGHT);
    00390       OffsetGroundSprite(31, 1);
    00391     } else if (f == FOUNDATION_STEEP_LOWER) {
    00392       /* one corner raised */
    00393       OffsetGroundSprite(31, 1);
    00394     } else {
    00395       /* halftile foundation */
    00396       int x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? 8 : 0);
    00397       int y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? 8 : 0);
    00398
    00399       AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z + TILE_HEIGHT);
    00400       OffsetGroundSprite(31, 9);
    00401     }
    00402   } else {
    00403     if (IsLeveledFoundation(f)) {
    00404       /* leveled foundation */
    00405       AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
    00406       OffsetGroundSprite(31, 1);
    00407     } else if (IsNonContinuousFoundation(f)) {
    00408       /* halftile foundation */
    00409       Corner halftile_corner = GetHalftileFoundationCorner(f);
    00410       int x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? 8 : 0);
    00411       int y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? 8 : 0);
    00412
    00413       AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z);
    00414       OffsetGroundSprite(31, 9);
    00415     } else if (IsSpecialRailFoundation(f)) {
    00416       /* anti-zig-zag foundation */
    00417       SpriteID spr;
    00418       if (ti->tileh == SLOPE_NS || ti->tileh == SLOPE_EW) {
    00419         /* half of leveled foundation under track corner */
    00420         spr = leveled_base + SlopeWithThreeCornersRaised(GetRailFoundationCorner(f));
    00421       } else {
    00422         /* tile-slope = sloped along X/Y, foundation-slope = three corners raised */
    00423         spr = inclined_base + 2 * GetRailFoundationCorner(f) + ((ti->tileh == SLOPE_SW || ti->tileh == SLOPE_NE) ? 1 : 0);
    00424       }
    00425       AddSortableSpriteToDraw(spr, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
    00426       OffsetGroundSprite(31, 9);
    00427     } else {
    00428       /* inclined foundation */
    00429       byte inclined = GetHighestSlopeCorner(ti->tileh) * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
    00430
    00431       AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y, 16, 16, 1, ti->z);
    00432       OffsetGroundSprite(31, 9);
    00433     }
    00434     ti->z += ApplyFoundationToSlope(f, &ti->tileh);
    00435   }
    00436 }
    00437
    00438 void DoClearSquare(TileIndex tile)
    00439 {
    00440   MakeClear(tile, CLEAR_GRASS, _generating_world ? 3 : 0);
    00441   MarkTileDirtyByTile(tile);
    00442 }
    00443
    00453 TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
    00454 {
    00455   return _tile_type_procs[GetTileType(tile)]->get_tile_track_status_proc(tile, mode, sub_mode, side);
    00456 }
    00457
    00458 void ChangeTileOwner(TileIndex tile, PlayerID old_player, PlayerID new_player)
    00459 {
    00460   _tile_type_procs[GetTileType(tile)]->change_tile_owner_proc(tile, old_player, new_player);
    00461 }
    00462
    00463 void GetAcceptedCargo(TileIndex tile, AcceptedCargo ac)
    00464 {
    00465   memset(ac, 0, sizeof(AcceptedCargo));
    00466   _tile_type_procs[GetTileType(tile)]->get_accepted_cargo_proc(tile, ac);
    00467 }
    00468
    00469 void AnimateTile(TileIndex tile)
    00470 {
    00471   _tile_type_procs[GetTileType(tile)]->animate_tile_proc(tile);
    00472 }
    00473
    00474 void ClickTile(TileIndex tile)
    00475 {
    00476   _tile_type_procs[GetTileType(tile)]->click_tile_proc(tile);
    00477 }
    00478
    00479 void GetTileDesc(TileIndex tile, TileDesc *td)
    00480 {
    00481   _tile_type_procs[GetTileType(tile)]->get_tile_desc_proc(tile, td);
    00482 }
    00483
    00488 bool IsSnowLineSet(void)
    00489 {
    00490   return _snow_line != NULL;
    00491 }
    00492
    00497 void SetSnowLine(byte table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS])
    00498 {
    00499   _snow_line = CallocT<SnowLine>(1);
    00500   memcpy(_snow_line->table, table, sizeof(_snow_line->table));
    00501
    00502   for (uint i = 0; i < SNOW_LINE_MONTHS; i++) {
    00503     for (uint j = 0; j < SNOW_LINE_DAYS; j++) {
    00504       _snow_line->highest_value = max(_snow_line->highest_value, table[i][j]);
    00505     }
    00506   }
    00507 }
    00508
    00513 byte GetSnowLine(void)
    00514 {
    00515   if (_snow_line == NULL) return _opt.snow_line;
    00516
    00517   YearMonthDay ymd;
    00518   ConvertDateToYMD(_date, &ymd);
    00519   return _snow_line->table[ymd.month][ymd.day];
    00520 }
    00521
    00526 byte HighestSnowLine(void)
    00527 {
    00528   return _snow_line == NULL ? _opt.snow_line : _snow_line->highest_value;
    00529 }
    00530
    00534 void ClearSnowLine(void)
    00535 {
    00536   free(_snow_line);
    00537   _snow_line = NULL;
    00538 }
    00539
    00546 CommandCost CmdLandscapeClear(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    00547 {
    00548   return _tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags);
    00549 }
    00550
    00557 CommandCost CmdClearArea(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    00558 {
    00559   CommandCost ret, money;
    00560   CommandCost cost(EXPENSES_CONSTRUCTION);
    00561   int ex;
    00562   int ey;
    00563   int sx, sy;
    00564   int x, y;
    00565   bool success = false;
    00566
    00567   if (p1 >= MapSize()) return CMD_ERROR;
    00568
    00569   /* make sure sx,sy are smaller than ex,ey */
    00570   ex = TileX(tile);
    00571   ey = TileY(tile);
    00572   sx = TileX(p1);
    00573   sy = TileY(p1);
    00574   if (ex < sx) Swap(ex, sx);
    00575   if (ey < sy) Swap(ey, sy);
    00576
    00577   money.AddCost(GetAvailableMoneyForCommand());
    00578
    00579   for (x = sx; x <= ex; ++x) {
    00580     for (y = sy; y <= ey; ++y) {
    00581       ret = DoCommand(TileXY(x, y), 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
    00582       if (CmdFailed(ret)) continue;
    00583       success = true;
    00584
    00585       if (flags & DC_EXEC) {
    00586         money.AddCost(-ret.GetCost());
    00587         if (ret.GetCost() > 0 && money.GetCost() < 0) {
    00588           _additional_cash_required = ret.GetCost();
    00589           return cost;
    00590         }
    00591         DoCommand(TileXY(x, y), 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00592
    00593         /* draw explosion animation... */
    00594         if ((x == sx || x == ex) && (y == sy || y == ey)) {
    00595           /* big explosion in each corner, or small explosion for single tiles */
    00596           CreateEffectVehicleAbove(x * TILE_SIZE + TILE_SIZE / 2, y * TILE_SIZE + TILE_SIZE / 2, 2,
    00597             sy == ey && sx == ex ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
    00598           );
    00599         }
    00600       }
    00601       cost.AddCost(ret);
    00602     }
    00603   }
    00604
    00605   return (success) ? cost : CMD_ERROR;
    00606 }
    00607
    00608
    00609 #define TILELOOP_BITS 4
    00610 #define TILELOOP_SIZE (1 << TILELOOP_BITS)
    00611 #define TILELOOP_ASSERTMASK ((TILELOOP_SIZE - 1) + ((TILELOOP_SIZE - 1) << MapLogX()))
    00612 #define TILELOOP_CHKMASK (((1 << (MapLogX() - TILELOOP_BITS))-1) << TILELOOP_BITS)
    00613
    00614 void RunTileLoop()
    00615 {
    00616   TileIndex tile;
    00617   uint count;
    00618
    00619   tile = _cur_tileloop_tile;
    00620
    00621   assert( (tile & ~TILELOOP_ASSERTMASK) == 0);
    00622   count = (MapSizeX() / TILELOOP_SIZE) * (MapSizeY() / TILELOOP_SIZE);
    00623   do {
    00624     _tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
    00625
    00626     if (TileX(tile) < MapSizeX() - TILELOOP_SIZE) {
    00627       tile += TILELOOP_SIZE; // no overflow
    00628     } else {
    00629       tile = TILE_MASK(tile - TILELOOP_SIZE * (MapSizeX() / TILELOOP_SIZE - 1) + TileDiffXY(0, TILELOOP_SIZE)); /* x would overflow, also increase y */
    00630     }
    00631   } while (--count);
    00632   assert( (tile & ~TILELOOP_ASSERTMASK) == 0);
    00633
    00634   tile += 9;
    00635   if (tile & TILELOOP_CHKMASK)
    00636     tile = (tile + MapSizeX()) & TILELOOP_ASSERTMASK;
    00637   _cur_tileloop_tile = tile;
    00638 }
    00639
    00640 void InitializeLandscape()
    00641 {
    00642   uint maxx = MapMaxX();
    00643   uint maxy = MapMaxY();
    00644   uint sizex = MapSizeX();
    00645   uint x;
    00646   uint y;
    00647
    00648   for (y = 0; y < maxy; y++) {
    00649     for (x = 0; x < maxx; x++) {
    00650       MakeClear(sizex * y + x, CLEAR_GRASS, 3);
    00651       SetTileHeight(sizex * y + x, 0);
    00652       SetTropicZone(sizex * y + x, TROPICZONE_NORMAL);
    00653       ClearBridgeMiddle(sizex * y + x);
    00654     }
    00655     MakeVoid(sizex * y + x);
    00656   }
    00657   for (x = 0; x < sizex; x++) MakeVoid(sizex * y + x);
    00658 }
    00659
    00660 static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4  };
    00661 static const byte _genterrain_tbl_2[5] = {  0,  0,  0,  0, 33 };
    00662
    00663 static void GenerateTerrain(int type, int flag)
    00664 {
    00665   uint32 r;
    00666   uint x;
    00667   uint y;
    00668   uint w;
    00669   uint h;
    00670   const Sprite* templ;
    00671   const byte *p;
    00672   Tile* tile;
    00673   byte direction;
    00674
    00675   r = Random();
    00676   templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845);
    00677
    00678   x = r & MapMaxX();
    00679   y = (r >> MapLogX()) & MapMaxY();
    00680
    00681
    00682   if (x < 2 || y < 2) return;
    00683
    00684   direction = GB(r, 22, 2);
    00685   if (direction & 1) {
    00686     w = templ->height;
    00687     h = templ->width;
    00688   } else {
    00689     w = templ->width;
    00690     h = templ->height;
    00691   }
    00692   p = templ->data;
    00693
    00694   if (flag & 4) {
    00695     uint xw = x * MapSizeY();
    00696     uint yw = y * MapSizeX();
    00697     uint bias = (MapSizeX() + MapSizeY()) * 16;
    00698
    00699     switch (flag & 3) {
    00700       case 0:
    00701         if (xw + yw > MapSize() - bias) return;
    00702         break;
    00703
    00704       case 1:
    00705         if (yw < xw + bias) return;
    00706         break;
    00707
    00708       case 2:
    00709         if (xw + yw < MapSize() + bias) return;
    00710         break;
    00711
    00712       case 3:
    00713         if (xw < yw + bias) return;
    00714         break;
    00715     }
    00716   }
    00717
    00718   if (x + w >= MapMaxX() - 1) return;
    00719   if (y + h >= MapMaxY() - 1) return;
    00720
    00721   tile = &_m[TileXY(x, y)];
    00722
    00723   switch (direction) {
    00724     case 0:
    00725       do {
    00726         Tile* tile_cur = tile;
    00727         uint w_cur;
    00728
    00729         for (w_cur = w; w_cur != 0; --w_cur) {
    00730           if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
    00731           p++;
    00732           tile_cur++;
    00733         }
    00734         tile += TileDiffXY(0, 1);
    00735       } while (--h != 0);
    00736       break;
    00737
    00738     case 1:
    00739       do {
    00740         Tile* tile_cur = tile;
    00741         uint h_cur;
    00742
    00743         for (h_cur = h; h_cur != 0; --h_cur) {
    00744           if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
    00745           p++;
    00746           tile_cur += TileDiffXY(0, 1);
    00747         }
    00748         tile++;
    00749       } while (--w != 0);
    00750       break;
    00751
    00752     case 2:
    00753       tile += TileDiffXY(w - 1, 0);
    00754       do {
    00755         Tile* tile_cur = tile;
    00756         uint w_cur;
    00757
    00758         for (w_cur = w; w_cur != 0; --w_cur) {
    00759           if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
    00760           p++;
    00761           tile_cur--;
    00762         }
    00763         tile += TileDiffXY(0, 1);
    00764       } while (--h != 0);
    00765       break;
    00766
    00767     case 3:
    00768       tile += TileDiffXY(0, h - 1);
    00769       do {
    00770         Tile* tile_cur = tile;
    00771         uint h_cur;
    00772
    00773         for (h_cur = h; h_cur != 0; --h_cur) {
    00774           if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
    00775           p++;
    00776           tile_cur -= TileDiffXY(0, 1);
    00777         }
    00778         tile++;
    00779       } while (--w != 0);
    00780       break;
    00781   }
    00782 }
    00783
    00784
    00785 #include "table/genland.h"
    00786
    00787 static void CreateDesertOrRainForest()
    00788 {
    00789   TileIndex tile;
    00790   TileIndex update_freq = MapSize() / 4;
    00791   const TileIndexDiffC *data;
    00792   uint i;
    00793
    00794   for (tile = 0; tile != MapSize(); ++tile) {
    00795     if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00796
    00797     for (data = _make_desert_or_rainforest_data;
    00798         data != endof(_make_desert_or_rainforest_data); ++data) {
    00799       TileIndex t = TILE_MASK(tile + ToTileIndexDiff(*data));
    00800       if (TileHeight(t) >= 4 || IsTileType(t, MP_WATER)) break;
    00801     }
    00802     if (data == endof(_make_desert_or_rainforest_data))
    00803       SetTropicZone(tile, TROPICZONE_DESERT);
    00804   }
    00805
    00806   for (i = 0; i != 256; i++) {
    00807     if ((i % 64) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00808
    00809     RunTileLoop();
    00810   }
    00811
    00812   for (tile = 0; tile != MapSize(); ++tile) {
    00813     if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00814
    00815     for (data = _make_desert_or_rainforest_data;
    00816         data != endof(_make_desert_or_rainforest_data); ++data) {
    00817       TileIndex t = TILE_MASK(tile + ToTileIndexDiff(*data));
    00818       if (IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_DESERT)) break;
    00819     }
    00820     if (data == endof(_make_desert_or_rainforest_data))
    00821       SetTropicZone(tile, TROPICZONE_RAINFOREST);
    00822   }
    00823 }
    00824
    00825 void GenerateLandscape(byte mode)
    00826 {
    00827   const int gwp_desert_amount = 4 + 8;
    00828   uint i;
    00829   uint flag;
    00830   uint32 r;
    00831
    00832   if (mode == GW_HEIGHTMAP) {
    00833     SetGeneratingWorldProgress(GWP_LANDSCAPE, (_opt.landscape == LT_TROPIC) ? 1 + gwp_desert_amount : 1);
    00834     LoadHeightmap(_file_to_saveload.name);
    00835     IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00836   } else if (_patches.land_generator == LG_TERRAGENESIS) {
    00837     SetGeneratingWorldProgress(GWP_LANDSCAPE, (_opt.landscape == LT_TROPIC) ? 3 + gwp_desert_amount : 3);
    00838     GenerateTerrainPerlin();
    00839   } else {
    00840     switch (_opt.landscape) {
    00841       case LT_ARCTIC:
    00842         SetGeneratingWorldProgress(GWP_LANDSCAPE, 2);
    00843
    00844         for (i = ScaleByMapSize((Random() & 0x7F) + 950); i != 0; --i) {
    00845           GenerateTerrain(2, 0);
    00846         }
    00847         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00848
    00849         r = Random();
    00850         flag = GB(r, 0, 2) | 4;
    00851         for (i = ScaleByMapSize(GB(r, 16, 7) + 450); i != 0; --i) {
    00852           GenerateTerrain(4, flag);
    00853         }
    00854         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00855         break;
    00856
    00857       case LT_TROPIC:
    00858         SetGeneratingWorldProgress(GWP_LANDSCAPE, 3 + gwp_desert_amount);
    00859
    00860         for (i = ScaleByMapSize((Random() & 0x7F) + 170); i != 0; --i) {
    00861           GenerateTerrain(0, 0);
    00862         }
    00863         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00864
    00865         r = Random();
    00866         flag = GB(r, 0, 2) | 4;
    00867         for (i = ScaleByMapSize(GB(r, 16, 8) + 1700); i != 0; --i) {
    00868           GenerateTerrain(0, flag);
    00869         }
    00870         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00871
    00872         flag ^= 2;
    00873
    00874         for (i = ScaleByMapSize((Random() & 0x7F) + 410); i != 0; --i) {
    00875           GenerateTerrain(3, flag);
    00876         }
    00877         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00878         break;
    00879
    00880       default:
    00881         SetGeneratingWorldProgress(GWP_LANDSCAPE, 1);
    00882
    00883         i = ScaleByMapSize((Random() & 0x7F) + (3 - _opt.diff.quantity_sea_lakes) * 256 + 100);
    00884         for (; i != 0; --i) {
    00885           GenerateTerrain(_opt.diff.terrain_type, 0);
    00886         }
    00887         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00888         break;
    00889     }
    00890   }
    00891
    00892   ConvertGroundTilesIntoWaterTiles();
    00893
    00894   if (_opt.landscape == LT_TROPIC) CreateDesertOrRainForest();
    00895 }
    00896
    00897 void OnTick_Town();
    00898 void OnTick_Trees();
    00899 void OnTick_Station();
    00900 void OnTick_Industry();
    00901
    00902 void OnTick_Players();
    00903 void OnTick_Train();
    00904
    00905 void CallLandscapeTick()
    00906 {
    00907   OnTick_Town();
    00908   OnTick_Trees();
    00909   OnTick_Station();
    00910   OnTick_Industry();
    00911
    00912   OnTick_Players();
    00913   OnTick_Train();
    00914 }
    00915
    00916 TileIndex AdjustTileCoordRandomly(TileIndex a, byte rng)
    00917 {
    00918   int rn = rng;
    00919   uint32 r = Random();
    00920
    00921   return TILE_MASK(TileXY(
    00922     TileX(a) + (GB(r, 0, 8) * rn * 2 >> 8) - rn,
    00923     TileY(a) + (GB(r, 8, 8) * rn * 2 >> 8) - rn
    00924   ));
    00925 }