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 if (!IsValidTile(tile)) continue;
00831
00832 for (data = _make_desert_or_rainforest_data;
00833 data != endof(_make_desert_or_rainforest_data); ++data) {
00834 TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00835 if (t != INVALID_TILE && (TileHeight(t) >= 4 || IsTileType(t, MP_WATER))) break;
00836 }
00837 if (data == endof(_make_desert_or_rainforest_data))
00838 SetTropicZone(tile, TROPICZONE_DESERT);
00839 }
00840
00841 for (uint i = 0; i != 256; i++) {
00842 if ((i % 64) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00843
00844 RunTileLoop();
00845 }
00846
00847 for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00848 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00849
00850 if (!IsValidTile(tile)) continue;
00851
00852 for (data = _make_desert_or_rainforest_data;
00853 data != endof(_make_desert_or_rainforest_data); ++data) {
00854 TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00855 if (t != INVALID_TILE && IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_DESERT)) break;
00856 }
00857 if (data == endof(_make_desert_or_rainforest_data))
00858 SetTropicZone(tile, TROPICZONE_RAINFOREST);
00859 }
00860 }
00861
00862 void GenerateLandscape(byte mode)
00863 {
00865 enum GenLandscapeSteps {
00866 GLS_HEIGHTMAP = 3,
00867 GLS_TERRAGENESIS = 5,
00868 GLS_ORIGINAL = 2,
00869 GLS_TROPIC = 12,
00870 GLS_OTHER = 0,
00871 };
00872 uint steps = (_settings_game.game_creation.landscape == LT_TROPIC) ? GLS_TROPIC : GLS_OTHER;
00873
00874 if (mode == GWM_HEIGHTMAP) {
00875 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP);
00876 LoadHeightmap(_file_to_saveload.name);
00877 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00878 } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) {
00879 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS);
00880 GenerateTerrainPerlin();
00881 } else {
00882 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_ORIGINAL);
00883 if (_settings_game.construction.freeform_edges) {
00884 for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0));
00885 for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y));
00886 }
00887 switch (_settings_game.game_creation.landscape) {
00888 case LT_ARCTIC: {
00889 uint32 r = Random();
00890
00891 for (uint i = ScaleByMapSize(GB(r, 0, 7) + 950); i != 0; --i) {
00892 GenerateTerrain(2, 0);
00893 }
00894
00895 uint flag = GB(r, 7, 2) | 4;
00896 for (uint i = ScaleByMapSize(GB(r, 9, 7) + 450); i != 0; --i) {
00897 GenerateTerrain(4, flag);
00898 }
00899 } break;
00900
00901 case LT_TROPIC: {
00902 uint32 r = Random();
00903
00904 for (uint i = ScaleByMapSize(GB(r, 0, 7) + 170); i != 0; --i) {
00905 GenerateTerrain(0, 0);
00906 }
00907
00908 uint flag = GB(r, 7, 2) | 4;
00909 for (uint i = ScaleByMapSize(GB(r, 9, 8) + 1700); i != 0; --i) {
00910 GenerateTerrain(0, flag);
00911 }
00912
00913 flag ^= 2;
00914
00915 for (uint i = ScaleByMapSize(GB(r, 17, 7) + 410); i != 0; --i) {
00916 GenerateTerrain(3, flag);
00917 }
00918 } break;
00919
00920 default: {
00921 uint32 r = Random();
00922
00923 uint i = ScaleByMapSize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100);
00924 for (; i != 0; --i) {
00925 GenerateTerrain(_settings_game.difficulty.terrain_type, 0);
00926 }
00927 } break;
00928 }
00929 }
00930
00931
00932
00933 FixSlopes();
00934 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00935 ConvertGroundTilesIntoWaterTiles();
00936 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00937
00938 if (_settings_game.game_creation.landscape == LT_TROPIC) CreateDesertOrRainForest();
00939 }
00940
00941 void OnTick_Town();
00942 void OnTick_Trees();
00943 void OnTick_Station();
00944 void OnTick_Industry();
00945
00946 void OnTick_Companies();
00947
00948 void CallLandscapeTick()
00949 {
00950 OnTick_Town();
00951 OnTick_Trees();
00952 OnTick_Station();
00953 OnTick_Industry();
00954
00955 OnTick_Companies();
00956 }