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