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