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