00001
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
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
00299
00300 {SLOPE_E, SLOPE_N, SLOPE_STEEP_E, SLOPE_STEEP_N},
00301 {SLOPE_S, SLOPE_E, SLOPE_STEEP_S, SLOPE_STEEP_E},
00302 {SLOPE_S, SLOPE_W, SLOPE_STEEP_S, SLOPE_STEEP_W},
00303 {SLOPE_W, SLOPE_N, SLOPE_STEEP_W, SLOPE_STEEP_N},
00304 };
00305
00306 int halftile_test = (IsHalftileSlope(tileh) ? SlopeWithOneCornerRaised(GetHalftileSlopeCorner(tileh)) : 0);
00307 if (halftile_test == corners[edge][0]) *z2 += TILE_HEIGHT;
00308 if (halftile_test == corners[edge][1]) *z1 += TILE_HEIGHT;
00309
00310 if ((tileh & corners[edge][0]) != 0) *z1 += TILE_HEIGHT;
00311 if ((tileh & corners[edge][1]) != 0) *z2 += TILE_HEIGHT;
00312 if (RemoveHalftileSlope(tileh) == corners[edge][2]) *z1 += TILE_HEIGHT;
00313 if (RemoveHalftileSlope(tileh) == corners[edge][3]) *z2 += TILE_HEIGHT;
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
00377 assert(f != FOUNDATION_STEEP_BOTH);
00378
00379 uint sprite_block = 0;
00380 uint z;
00381 Slope slope = GetFoundationSlope(ti->tile, &z);
00382
00383
00384
00385
00386
00387
00388
00389 if (!HasFoundationNW(ti->tile, slope, z)) sprite_block += 1;
00390 if (!HasFoundationNE(ti->tile, slope, z)) sprite_block += 2;
00391
00392
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
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
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
00423 OffsetGroundSprite(31, 1);
00424 } else {
00425
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
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
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
00447 SpriteID spr;
00448 if (ti->tileh == SLOPE_NS || ti->tileh == SLOPE_EW) {
00449
00450 spr = leveled_base + SlopeWithThreeCornersRaised(GetRailFoundationCorner(f));
00451 } else {
00452
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
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
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
00645 if ((x == sx || x == ex) && (y == sy || y == ey)) {
00646
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;
00677 } else {
00678 tile = TILE_MASK(tile - TILELOOP_SIZE * (MapSizeX() / TILELOOP_SIZE - 1) + TileDiffXY(0, TILELOOP_SIZE));
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 (*p >= tile_cur->type_height) tile_cur->type_height = *p;
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 (*p >= tile_cur->type_height) tile_cur->type_height = *p;
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 (*p >= tile_cur->type_height) tile_cur->type_height = *p;
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 (*p >= tile_cur->type_height) tile_cur->type_height = *p;
00811 p++;
00812 tile_cur -= TileDiffXY(0, 1);
00813 }
00814 tile += TileDiffXY(1, 0);
00815 } while (--w != 0);
00816 break;
00817 }
00818 }
00819
00820
00821 #include "table/genland.h"
00822
00823 static void CreateDesertOrRainForest()
00824 {
00825 TileIndex update_freq = MapSize() / 4;
00826 const TileIndexDiffC *data;
00827
00828 for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00829 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00830
00831 for (data = _make_desert_or_rainforest_data;
00832 data != endof(_make_desert_or_rainforest_data); ++data) {
00833 TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00834 if (t != INVALID_TILE && (TileHeight(t) >= 4 || IsTileType(t, MP_WATER))) break;
00835 }
00836 if (data == endof(_make_desert_or_rainforest_data))
00837 SetTropicZone(tile, TROPICZONE_DESERT);
00838 }
00839
00840 for (uint i = 0; i != 256; i++) {
00841 if ((i % 64) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00842
00843 RunTileLoop();
00844 }
00845
00846 for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00847 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00848
00849 for (data = _make_desert_or_rainforest_data;
00850 data != endof(_make_desert_or_rainforest_data); ++data) {
00851 TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00852 if (t != INVALID_TILE && IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_DESERT)) break;
00853 }
00854 if (data == endof(_make_desert_or_rainforest_data))
00855 SetTropicZone(tile, TROPICZONE_RAINFOREST);
00856 }
00857 }
00858
00859 void GenerateLandscape(byte mode)
00860 {
00861 static const int gwp_desert_amount = 4 + 8;
00862
00863 if (mode == GW_HEIGHTMAP) {
00864 SetGeneratingWorldProgress(GWP_LANDSCAPE, (_settings_game.game_creation.landscape == LT_TROPIC) ? 1 + gwp_desert_amount : 1);
00865 LoadHeightmap(_file_to_saveload.name);
00866 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00867 } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) {
00868 SetGeneratingWorldProgress(GWP_LANDSCAPE, (_settings_game.game_creation.landscape == LT_TROPIC) ? 3 + gwp_desert_amount : 3);
00869 GenerateTerrainPerlin();
00870 } else {
00871 if (_settings_game.construction.freeform_edges) {
00872 for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0));
00873 for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y));
00874 }
00875 switch (_settings_game.game_creation.landscape) {
00876 case LT_ARCTIC: {
00877 SetGeneratingWorldProgress(GWP_LANDSCAPE, 2);
00878
00879 uint32 r = Random();
00880
00881 for (uint i = ScaleByMapSize(GB(r, 0, 7) + 950); i != 0; --i) {
00882 GenerateTerrain(2, 0);
00883 }
00884 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00885
00886 uint flag = GB(r, 7, 2) | 4;
00887 for (uint i = ScaleByMapSize(GB(r, 9, 7) + 450); i != 0; --i) {
00888 GenerateTerrain(4, flag);
00889 }
00890 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00891 } break;
00892
00893 case LT_TROPIC: {
00894 SetGeneratingWorldProgress(GWP_LANDSCAPE, 3 + gwp_desert_amount);
00895
00896 uint32 r = Random();
00897
00898 for (uint i = ScaleByMapSize(GB(r, 0, 7) + 170); i != 0; --i) {
00899 GenerateTerrain(0, 0);
00900 }
00901 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00902
00903 uint flag = GB(r, 7, 2) | 4;
00904 for (uint i = ScaleByMapSize(GB(r, 9, 8) + 1700); i != 0; --i) {
00905 GenerateTerrain(0, flag);
00906 }
00907 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00908
00909 flag ^= 2;
00910
00911 for (uint i = ScaleByMapSize(GB(r, 17, 7) + 410); i != 0; --i) {
00912 GenerateTerrain(3, flag);
00913 }
00914 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00915 } break;
00916
00917 default: {
00918 SetGeneratingWorldProgress(GWP_LANDSCAPE, 1);
00919
00920 uint32 r = Random();
00921
00922 uint i = ScaleByMapSize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100);
00923 for (; i != 0; --i) {
00924 GenerateTerrain(_settings_game.difficulty.terrain_type, 0);
00925 }
00926 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00927 } break;
00928 }
00929 }
00930
00931 ConvertGroundTilesIntoWaterTiles();
00932
00933 if (_settings_game.game_creation.landscape == LT_TROPIC) CreateDesertOrRainForest();
00934 }
00935
00936 void OnTick_Town();
00937 void OnTick_Trees();
00938 void OnTick_Station();
00939 void OnTick_Industry();
00940
00941 void OnTick_Companies();
00942 void OnTick_Train();
00943
00944 void CallLandscapeTick()
00945 {
00946 OnTick_Town();
00947 OnTick_Trees();
00948 OnTick_Station();
00949 OnTick_Industry();
00950
00951 OnTick_Companies();
00952 OnTick_Train();
00953 }