# landscape.cpp

Go to the documentation of this file.

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