# landscape.cpp

Go to the documentation of this file.

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