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 "void_map.h"
00022 #include "tgp.h"
00023 #include "genworld.h"
00024 #include "fios.h"
00025 #include "date_func.h"
00026 #include "water.h"
00027 #include "effectvehicle_func.h"
00028 #include "landscape_type.h"
00029 #include "animated_tile_func.h"
00030 #include "core/random_func.hpp"
00031 #include "object_base.h"
00032 #include "company_func.h"
00033 #include "pathfinder/npf/aystar.h"
00034 #include <list>
00035 #include <set>
00036
00037 #include "table/strings.h"
00038 #include "table/sprites.h"
00039
00040 extern const TileTypeProcs
00041 _tile_type_clear_procs,
00042 _tile_type_rail_procs,
00043 _tile_type_road_procs,
00044 _tile_type_town_procs,
00045 _tile_type_trees_procs,
00046 _tile_type_station_procs,
00047 _tile_type_water_procs,
00048 _tile_type_void_procs,
00049 _tile_type_industry_procs,
00050 _tile_type_tunnelbridge_procs,
00051 _tile_type_object_procs;
00052
00058 const TileTypeProcs * const _tile_type_procs[16] = {
00059 &_tile_type_clear_procs,
00060 &_tile_type_rail_procs,
00061 &_tile_type_road_procs,
00062 &_tile_type_town_procs,
00063 &_tile_type_trees_procs,
00064 &_tile_type_station_procs,
00065 &_tile_type_water_procs,
00066 &_tile_type_void_procs,
00067 &_tile_type_industry_procs,
00068 &_tile_type_tunnelbridge_procs,
00069 &_tile_type_object_procs,
00070 };
00071
00073 extern const byte _slope_to_sprite_offset[32] = {
00074 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0,
00075 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 17, 0, 15, 18, 0,
00076 };
00077
00086 static SnowLine *_snow_line = NULL;
00087
00096 uint ApplyFoundationToSlope(Foundation f, Slope *s)
00097 {
00098 if (!IsFoundation(f)) return 0;
00099
00100 if (IsLeveledFoundation(f)) {
00101 uint dz = 1 + (IsSteepSlope(*s) ? 1 : 0);
00102 *s = SLOPE_FLAT;
00103 return dz;
00104 }
00105
00106 if (f != FOUNDATION_STEEP_BOTH && IsNonContinuousFoundation(f)) {
00107 *s = HalftileSlope(*s, GetHalftileFoundationCorner(f));
00108 return 0;
00109 }
00110
00111 if (IsSpecialRailFoundation(f)) {
00112 *s = SlopeWithThreeCornersRaised(OppositeCorner(GetRailFoundationCorner(f)));
00113 return 0;
00114 }
00115
00116 uint dz = IsSteepSlope(*s) ? 1 : 0;
00117 Corner highest_corner = GetHighestSlopeCorner(*s);
00118
00119 switch (f) {
00120 case FOUNDATION_INCLINED_X:
00121 *s = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? SLOPE_SW : SLOPE_NE);
00122 break;
00123
00124 case FOUNDATION_INCLINED_Y:
00125 *s = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? SLOPE_SE : SLOPE_NW);
00126 break;
00127
00128 case FOUNDATION_STEEP_LOWER:
00129 *s = SlopeWithOneCornerRaised(highest_corner);
00130 break;
00131
00132 case FOUNDATION_STEEP_BOTH:
00133 *s = HalftileSlope(SlopeWithOneCornerRaised(highest_corner), highest_corner);
00134 break;
00135
00136 default: NOT_REACHED();
00137 }
00138 return dz;
00139 }
00140
00141
00149 uint GetPartialPixelZ(int x, int y, Slope corners)
00150 {
00151 if (IsHalftileSlope(corners)) {
00152 switch (GetHalftileSlopeCorner(corners)) {
00153 case CORNER_W:
00154 if (x - y >= 0) return GetSlopeMaxPixelZ(corners);
00155 break;
00156
00157 case CORNER_S:
00158 if (x - (y ^ 0xF) >= 0) return GetSlopeMaxPixelZ(corners);
00159 break;
00160
00161 case CORNER_E:
00162 if (y - x >= 0) return GetSlopeMaxPixelZ(corners);
00163 break;
00164
00165 case CORNER_N:
00166 if ((y ^ 0xF) - x >= 0) return GetSlopeMaxPixelZ(corners);
00167 break;
00168
00169 default: NOT_REACHED();
00170 }
00171 }
00172
00173 int z = 0;
00174
00175 switch (RemoveHalftileSlope(corners)) {
00176 case SLOPE_W:
00177 if (x - y >= 0) {
00178 z = (x - y) >> 1;
00179 }
00180 break;
00181
00182 case SLOPE_S:
00183 y ^= 0xF;
00184 if ((x - y) >= 0) {
00185 z = (x - y) >> 1;
00186 }
00187 break;
00188
00189 case SLOPE_SW:
00190 z = (x >> 1) + 1;
00191 break;
00192
00193 case SLOPE_E:
00194 if (y - x >= 0) {
00195 z = (y - x) >> 1;
00196 }
00197 break;
00198
00199 case SLOPE_EW:
00200 case SLOPE_NS:
00201 case SLOPE_ELEVATED:
00202 z = 4;
00203 break;
00204
00205 case SLOPE_SE:
00206 z = (y >> 1) + 1;
00207 break;
00208
00209 case SLOPE_WSE:
00210 z = 8;
00211 y ^= 0xF;
00212 if (x - y < 0) {
00213 z += (x - y) >> 1;
00214 }
00215 break;
00216
00217 case SLOPE_N:
00218 y ^= 0xF;
00219 if (y - x >= 0) {
00220 z = (y - x) >> 1;
00221 }
00222 break;
00223
00224 case SLOPE_NW:
00225 z = (y ^ 0xF) >> 1;
00226 break;
00227
00228 case SLOPE_NWS:
00229 z = 8;
00230 if (x - y < 0) {
00231 z += (x - y) >> 1;
00232 }
00233 break;
00234
00235 case SLOPE_NE:
00236 z = (x ^ 0xF) >> 1;
00237 break;
00238
00239 case SLOPE_ENW:
00240 z = 8;
00241 y ^= 0xF;
00242 if (y - x < 0) {
00243 z += (y - x) >> 1;
00244 }
00245 break;
00246
00247 case SLOPE_SEN:
00248 z = 8;
00249 if (y - x < 0) {
00250 z += (y - x) >> 1;
00251 }
00252 break;
00253
00254 case SLOPE_STEEP_S:
00255 z = 1 + ((x + y) >> 1);
00256 break;
00257
00258 case SLOPE_STEEP_W:
00259 z = 1 + ((x + (y ^ 0xF)) >> 1);
00260 break;
00261
00262 case SLOPE_STEEP_N:
00263 z = 1 + (((x ^ 0xF) + (y ^ 0xF)) >> 1);
00264 break;
00265
00266 case SLOPE_STEEP_E:
00267 z = 1 + (((x ^ 0xF) + y) >> 1);
00268 break;
00269
00270 default: break;
00271 }
00272
00273 return z;
00274 }
00275
00276 int GetSlopePixelZ(int x, int y)
00277 {
00278 TileIndex tile = TileVirtXY(x, y);
00279
00280 return _tile_type_procs[GetTileType(tile)]->get_slope_z_proc(tile, x, y);
00281 }
00282
00292 int GetSlopeZInCorner(Slope tileh, Corner corner)
00293 {
00294 assert(!IsHalftileSlope(tileh));
00295 return ((tileh & SlopeWithOneCornerRaised(corner)) != 0 ? 1 : 0) + (tileh == SteepSlope(corner) ? 1 : 0);
00296 }
00297
00310 void GetSlopePixelZOnEdge(Slope tileh, DiagDirection edge, int *z1, int *z2)
00311 {
00312 static const Slope corners[4][4] = {
00313
00314
00315 {SLOPE_E, SLOPE_N, SLOPE_STEEP_E, SLOPE_STEEP_N},
00316 {SLOPE_S, SLOPE_E, SLOPE_STEEP_S, SLOPE_STEEP_E},
00317 {SLOPE_S, SLOPE_W, SLOPE_STEEP_S, SLOPE_STEEP_W},
00318 {SLOPE_W, SLOPE_N, SLOPE_STEEP_W, SLOPE_STEEP_N},
00319 };
00320
00321 int halftile_test = (IsHalftileSlope(tileh) ? SlopeWithOneCornerRaised(GetHalftileSlopeCorner(tileh)) : 0);
00322 if (halftile_test == corners[edge][0]) *z2 += TILE_HEIGHT;
00323 if (halftile_test == corners[edge][1]) *z1 += TILE_HEIGHT;
00324
00325 if ((tileh & corners[edge][0]) != 0) *z1 += TILE_HEIGHT;
00326 if ((tileh & corners[edge][1]) != 0) *z2 += TILE_HEIGHT;
00327 if (RemoveHalftileSlope(tileh) == corners[edge][2]) *z1 += TILE_HEIGHT;
00328 if (RemoveHalftileSlope(tileh) == corners[edge][3]) *z2 += TILE_HEIGHT;
00329 }
00330
00339 Slope GetFoundationSlope(TileIndex tile, int *z)
00340 {
00341 Slope tileh = GetTileSlope(tile, z);
00342 Foundation f = _tile_type_procs[GetTileType(tile)]->get_foundation_proc(tile, tileh);
00343 uint z_inc = ApplyFoundationToSlope(f, &tileh);
00344 if (z != NULL) *z += z_inc;
00345 return tileh;
00346 }
00347
00348
00349 bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
00350 {
00351 int z;
00352
00353 int z_W_here = z_here;
00354 int z_N_here = z_here;
00355 GetSlopePixelZOnEdge(slope_here, DIAGDIR_NW, &z_W_here, &z_N_here);
00356
00357 Slope slope = GetFoundationPixelSlope(TILE_ADDXY(tile, 0, -1), &z);
00358 int z_W = z;
00359 int z_N = z;
00360 GetSlopePixelZOnEdge(slope, DIAGDIR_SE, &z_W, &z_N);
00361
00362 return (z_N_here > z_N) || (z_W_here > z_W);
00363 }
00364
00365
00366 bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
00367 {
00368 int z;
00369
00370 int z_E_here = z_here;
00371 int z_N_here = z_here;
00372 GetSlopePixelZOnEdge(slope_here, DIAGDIR_NE, &z_E_here, &z_N_here);
00373
00374 Slope slope = GetFoundationPixelSlope(TILE_ADDXY(tile, -1, 0), &z);
00375 int z_E = z;
00376 int z_N = z;
00377 GetSlopePixelZOnEdge(slope, DIAGDIR_SW, &z_E, &z_N);
00378
00379 return (z_N_here > z_N) || (z_E_here > z_E);
00380 }
00381
00387 void DrawFoundation(TileInfo *ti, Foundation f)
00388 {
00389 if (!IsFoundation(f)) return;
00390
00391
00392 assert(f != FOUNDATION_STEEP_BOTH);
00393
00394 uint sprite_block = 0;
00395 int z;
00396 Slope slope = GetFoundationPixelSlope(ti->tile, &z);
00397
00398
00399
00400
00401
00402
00403
00404 if (!HasFoundationNW(ti->tile, slope, z)) sprite_block += 1;
00405 if (!HasFoundationNE(ti->tile, slope, z)) sprite_block += 2;
00406
00407
00408 SpriteID leveled_base = (sprite_block == 0 ? (int)SPR_FOUNDATION_BASE : (SPR_SLOPES_VIRTUAL_BASE + sprite_block * SPR_TRKFOUND_BLOCK_SIZE));
00409 SpriteID inclined_base = SPR_SLOPES_VIRTUAL_BASE + SPR_SLOPES_INCLINED_OFFSET + sprite_block * SPR_TRKFOUND_BLOCK_SIZE;
00410 SpriteID halftile_base = SPR_HALFTILE_FOUNDATION_BASE + sprite_block * SPR_HALFTILE_BLOCK_SIZE;
00411
00412 if (IsSteepSlope(ti->tileh)) {
00413 if (!IsNonContinuousFoundation(f)) {
00414
00415 AddSortableSpriteToDraw(
00416 leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z
00417 );
00418 }
00419
00420 Corner highest_corner = GetHighestSlopeCorner(ti->tileh);
00421 ti->z += ApplyPixelFoundationToSlope(f, &ti->tileh);
00422
00423 if (IsInclinedFoundation(f)) {
00424
00425 byte inclined = highest_corner * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
00426
00427 AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
00428 f == FOUNDATION_INCLINED_X ? 16 : 1,
00429 f == FOUNDATION_INCLINED_Y ? 16 : 1,
00430 TILE_HEIGHT, ti->z
00431 );
00432 OffsetGroundSprite(31, 9);
00433 } else if (IsLeveledFoundation(f)) {
00434 AddSortableSpriteToDraw(leveled_base + SlopeWithOneCornerRaised(highest_corner), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z - TILE_HEIGHT);
00435 OffsetGroundSprite(31, 1);
00436 } else if (f == FOUNDATION_STEEP_LOWER) {
00437
00438 OffsetGroundSprite(31, 1);
00439 } else {
00440
00441 int x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? 8 : 0);
00442 int y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? 8 : 0);
00443
00444 AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z + TILE_HEIGHT);
00445 OffsetGroundSprite(31, 9);
00446 }
00447 } else {
00448 if (IsLeveledFoundation(f)) {
00449
00450 AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
00451 OffsetGroundSprite(31, 1);
00452 } else if (IsNonContinuousFoundation(f)) {
00453
00454 Corner halftile_corner = GetHalftileFoundationCorner(f);
00455 int x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? 8 : 0);
00456 int y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? 8 : 0);
00457
00458 AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z);
00459 OffsetGroundSprite(31, 9);
00460 } else if (IsSpecialRailFoundation(f)) {
00461
00462 SpriteID spr;
00463 if (ti->tileh == SLOPE_NS || ti->tileh == SLOPE_EW) {
00464
00465 spr = leveled_base + SlopeWithThreeCornersRaised(GetRailFoundationCorner(f));
00466 } else {
00467
00468 spr = inclined_base + 2 * GetRailFoundationCorner(f) + ((ti->tileh == SLOPE_SW || ti->tileh == SLOPE_NE) ? 1 : 0);
00469 }
00470 AddSortableSpriteToDraw(spr, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
00471 OffsetGroundSprite(31, 9);
00472 } else {
00473
00474 byte inclined = GetHighestSlopeCorner(ti->tileh) * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
00475
00476 AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
00477 f == FOUNDATION_INCLINED_X ? 16 : 1,
00478 f == FOUNDATION_INCLINED_Y ? 16 : 1,
00479 TILE_HEIGHT, ti->z
00480 );
00481 OffsetGroundSprite(31, 9);
00482 }
00483 ti->z += ApplyPixelFoundationToSlope(f, &ti->tileh);
00484 }
00485 }
00486
00487 void DoClearSquare(TileIndex tile)
00488 {
00489
00490 if (_tile_type_procs[GetTileType(tile)]->animate_tile_proc != NULL) DeleteAnimatedTile(tile);
00491
00492 MakeClear(tile, CLEAR_GRASS, _generating_world ? 3 : 0);
00493 MarkTileDirtyByTile(tile);
00494 }
00495
00506 TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
00507 {
00508 return _tile_type_procs[GetTileType(tile)]->get_tile_track_status_proc(tile, mode, sub_mode, side);
00509 }
00510
00517 void ChangeTileOwner(TileIndex tile, Owner old_owner, Owner new_owner)
00518 {
00519 _tile_type_procs[GetTileType(tile)]->change_tile_owner_proc(tile, old_owner, new_owner);
00520 }
00521
00522 void GetTileDesc(TileIndex tile, TileDesc *td)
00523 {
00524 _tile_type_procs[GetTileType(tile)]->get_tile_desc_proc(tile, td);
00525 }
00526
00532 bool IsSnowLineSet()
00533 {
00534 return _snow_line != NULL;
00535 }
00536
00542 void SetSnowLine(byte table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS])
00543 {
00544 _snow_line = CallocT<SnowLine>(1);
00545 _snow_line->lowest_value = 0xFF;
00546 memcpy(_snow_line->table, table, sizeof(_snow_line->table));
00547
00548 for (uint i = 0; i < SNOW_LINE_MONTHS; i++) {
00549 for (uint j = 0; j < SNOW_LINE_DAYS; j++) {
00550 _snow_line->highest_value = max(_snow_line->highest_value, table[i][j]);
00551 _snow_line->lowest_value = min(_snow_line->lowest_value, table[i][j]);
00552 }
00553 }
00554 }
00555
00561 byte GetSnowLine()
00562 {
00563 if (_snow_line == NULL) return _settings_game.game_creation.snow_line_height;
00564
00565 YearMonthDay ymd;
00566 ConvertDateToYMD(_date, &ymd);
00567 return _snow_line->table[ymd.month][ymd.day];
00568 }
00569
00575 byte HighestSnowLine()
00576 {
00577 return _snow_line == NULL ? _settings_game.game_creation.snow_line_height : _snow_line->highest_value;
00578 }
00579
00585 byte LowestSnowLine()
00586 {
00587 return _snow_line == NULL ? _settings_game.game_creation.snow_line_height : _snow_line->lowest_value;
00588 }
00589
00594 void ClearSnowLine()
00595 {
00596 free(_snow_line);
00597 _snow_line = NULL;
00598 }
00599
00609 CommandCost CmdLandscapeClear(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00610 {
00611 CommandCost cost(EXPENSES_CONSTRUCTION);
00612 bool do_clear = false;
00613
00614 if ((flags & DC_FORCE_CLEAR_TILE) && HasTileWaterClass(tile) && IsTileOnWater(tile) && !IsWaterTile(tile) && !IsCoastTile(tile)) {
00615 if ((flags & DC_AUTO) && GetWaterClass(tile) == WATER_CLASS_CANAL) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
00616 do_clear = true;
00617 cost.AddCost(GetWaterClass(tile) == WATER_CLASS_CANAL ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER]);
00618 }
00619
00620 Company *c = (flags & (DC_AUTO | DC_BANKRUPT)) ? NULL : Company::GetIfValid(_current_company);
00621 if (c != NULL && (int)GB(c->clear_limit, 16, 16) < 1) {
00622 return_cmd_error(STR_ERROR_CLEARING_LIMIT_REACHED);
00623 }
00624
00625 const ClearedObjectArea *coa = FindClearedObject(tile);
00626
00627
00628
00629 if (coa != NULL && coa->first_tile != tile) {
00630
00631
00632
00633
00634
00635 if ((flags & DC_NO_WATER) && HasTileWaterClass(tile) && IsTileOnWater(tile)) {
00636 return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00637 }
00638 } else {
00639 cost.AddCost(_tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags));
00640 }
00641
00642 if (flags & DC_EXEC) {
00643 if (c != NULL) c->clear_limit -= 1 << 16;
00644 if (do_clear) DoClearSquare(tile);
00645 }
00646 return cost;
00647 }
00648
00659 CommandCost CmdClearArea(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00660 {
00661 if (p1 >= MapSize()) return CMD_ERROR;
00662
00663 Money money = GetAvailableMoneyForCommand();
00664 CommandCost cost(EXPENSES_CONSTRUCTION);
00665 CommandCost last_error = CMD_ERROR;
00666 bool had_success = false;
00667
00668 const Company *c = (flags & (DC_AUTO | DC_BANKRUPT)) ? NULL : Company::GetIfValid(_current_company);
00669 int limit = (c == NULL ? INT32_MAX : GB(c->clear_limit, 16, 16));
00670
00671 TileIterator *iter = HasBit(p2, 0) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(tile, p1);
00672 for (; *iter != INVALID_TILE; ++(*iter)) {
00673 TileIndex t = *iter;
00674 CommandCost ret = DoCommand(t, 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
00675 if (ret.Failed()) {
00676 last_error = ret;
00677
00678
00679 if (c != NULL && GB(c->clear_limit, 16, 16) < 1) break;
00680 continue;
00681 }
00682
00683 had_success = true;
00684 if (flags & DC_EXEC) {
00685 money -= ret.GetCost();
00686 if (ret.GetCost() > 0 && money < 0) {
00687 _additional_cash_required = ret.GetCost();
00688 delete iter;
00689 return cost;
00690 }
00691 DoCommand(t, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00692
00693
00694
00695 if ((t == tile || t == p1) && _pause_mode == PM_UNPAUSED) {
00696
00697 CreateEffectVehicleAbove(TileX(t) * TILE_SIZE + TILE_SIZE / 2, TileY(t) * TILE_SIZE + TILE_SIZE / 2, 2,
00698 TileX(tile) == TileX(p1) && TileY(tile) == TileY(p1) ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
00699 );
00700 }
00701 } else {
00702
00703 if (ret.GetCost() != 0 && --limit <= 0) break;
00704 }
00705 cost.AddCost(ret);
00706 }
00707
00708 delete iter;
00709 return had_success ? cost : last_error;
00710 }
00711
00712
00713 TileIndex _cur_tileloop_tile;
00714
00718 void RunTileLoop()
00719 {
00720
00721
00722
00723
00724
00725
00726 static const uint32 feedbacks[] = {
00727 0xD8F, 0x1296, 0x2496, 0x4357, 0x8679, 0x1030E, 0x206CD, 0x403FE, 0x807B8, 0x1004B2, 0x2006A8, 0x4004B2, 0x800B87
00728 };
00729 assert_compile(lengthof(feedbacks) == 2 * MAX_MAP_SIZE_BITS - 2 * MIN_MAP_SIZE_BITS + 1);
00730 const uint32 feedback = feedbacks[MapLogX() + MapLogY() - 2 * MIN_MAP_SIZE_BITS];
00731
00732
00733 uint count = 1 << (MapLogX() + MapLogY() - 8);
00734
00735 TileIndex tile = _cur_tileloop_tile;
00736
00737 assert(tile != 0);
00738
00739
00740 if (_tick_counter % 256 == 0) {
00741 _tile_type_procs[GetTileType(0)]->tile_loop_proc(0);
00742 count--;
00743 }
00744
00745 while (count--) {
00746 _tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
00747
00748
00749 tile = (tile >> 1) ^ (-(int32)(tile & 1) & feedback);
00750 }
00751
00752 _cur_tileloop_tile = tile;
00753 }
00754
00755 void InitializeLandscape()
00756 {
00757 uint maxx = MapMaxX();
00758 uint maxy = MapMaxY();
00759 uint sizex = MapSizeX();
00760
00761 uint y;
00762 for (y = _settings_game.construction.freeform_edges ? 1 : 0; y < maxy; y++) {
00763 uint x;
00764 for (x = _settings_game.construction.freeform_edges ? 1 : 0; x < maxx; x++) {
00765 MakeClear(sizex * y + x, CLEAR_GRASS, 3);
00766 SetTileHeight(sizex * y + x, 0);
00767 SetTropicZone(sizex * y + x, TROPICZONE_NORMAL);
00768 ClearBridgeMiddle(sizex * y + x);
00769 }
00770 MakeVoid(sizex * y + x);
00771 }
00772 for (uint x = 0; x < sizex; x++) MakeVoid(sizex * y + x);
00773 }
00774
00775 static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4 };
00776 static const byte _genterrain_tbl_2[5] = { 0, 0, 0, 0, 33 };
00777
00778 static void GenerateTerrain(int type, uint flag)
00779 {
00780 uint32 r = Random();
00781
00782 const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845, ST_MAPGEN);
00783 if (templ == NULL) usererror("Map generator sprites could not be loaded");
00784
00785 uint x = r & MapMaxX();
00786 uint y = (r >> MapLogX()) & MapMaxY();
00787
00788 if (x < 2 || y < 2) return;
00789
00790 DiagDirection direction = (DiagDirection)GB(r, 22, 2);
00791 uint w = templ->width;
00792 uint h = templ->height;
00793
00794 if (DiagDirToAxis(direction) == AXIS_Y) Swap(w, h);
00795
00796 const byte *p = templ->data;
00797
00798 if ((flag & 4) != 0) {
00799 uint xw = x * MapSizeY();
00800 uint yw = y * MapSizeX();
00801 uint bias = (MapSizeX() + MapSizeY()) * 16;
00802
00803 switch (flag & 3) {
00804 default: NOT_REACHED();
00805 case 0:
00806 if (xw + yw > MapSize() - bias) return;
00807 break;
00808
00809 case 1:
00810 if (yw < xw + bias) return;
00811 break;
00812
00813 case 2:
00814 if (xw + yw < MapSize() + bias) return;
00815 break;
00816
00817 case 3:
00818 if (xw < yw + bias) return;
00819 break;
00820 }
00821 }
00822
00823 if (x + w >= MapMaxX() - 1) return;
00824 if (y + h >= MapMaxY() - 1) return;
00825
00826 TileIndex tile = TileXY(x, y);
00827
00828 switch (direction) {
00829 default: NOT_REACHED();
00830 case DIAGDIR_NE:
00831 do {
00832 TileIndex tile_cur = tile;
00833
00834 for (uint w_cur = w; w_cur != 0; --w_cur) {
00835 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
00836 p++;
00837 tile_cur++;
00838 }
00839 tile += TileDiffXY(0, 1);
00840 } while (--h != 0);
00841 break;
00842
00843 case DIAGDIR_SE:
00844 do {
00845 TileIndex tile_cur = tile;
00846
00847 for (uint h_cur = h; h_cur != 0; --h_cur) {
00848 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
00849 p++;
00850 tile_cur += TileDiffXY(0, 1);
00851 }
00852 tile += TileDiffXY(1, 0);
00853 } while (--w != 0);
00854 break;
00855
00856 case DIAGDIR_SW:
00857 tile += TileDiffXY(w - 1, 0);
00858 do {
00859 TileIndex tile_cur = tile;
00860
00861 for (uint w_cur = w; w_cur != 0; --w_cur) {
00862 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
00863 p++;
00864 tile_cur--;
00865 }
00866 tile += TileDiffXY(0, 1);
00867 } while (--h != 0);
00868 break;
00869
00870 case DIAGDIR_NW:
00871 tile += TileDiffXY(0, h - 1);
00872 do {
00873 TileIndex tile_cur = tile;
00874
00875 for (uint h_cur = h; h_cur != 0; --h_cur) {
00876 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
00877 p++;
00878 tile_cur -= TileDiffXY(0, 1);
00879 }
00880 tile += TileDiffXY(1, 0);
00881 } while (--w != 0);
00882 break;
00883 }
00884 }
00885
00886
00887 #include "table/genland.h"
00888
00889 static void CreateDesertOrRainForest()
00890 {
00891 TileIndex update_freq = MapSize() / 4;
00892 const TileIndexDiffC *data;
00893
00894 for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00895 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00896
00897 if (!IsValidTile(tile)) continue;
00898
00899 for (data = _make_desert_or_rainforest_data;
00900 data != endof(_make_desert_or_rainforest_data); ++data) {
00901 TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00902 if (t != INVALID_TILE && (TileHeight(t) >= 4 || IsTileType(t, MP_WATER))) break;
00903 }
00904 if (data == endof(_make_desert_or_rainforest_data)) {
00905 SetTropicZone(tile, TROPICZONE_DESERT);
00906 }
00907 }
00908
00909 for (uint i = 0; i != 256; i++) {
00910 if ((i % 64) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00911
00912 RunTileLoop();
00913 }
00914
00915 for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00916 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00917
00918 if (!IsValidTile(tile)) continue;
00919
00920 for (data = _make_desert_or_rainforest_data;
00921 data != endof(_make_desert_or_rainforest_data); ++data) {
00922 TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00923 if (t != INVALID_TILE && IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_DESERT)) break;
00924 }
00925 if (data == endof(_make_desert_or_rainforest_data)) {
00926 SetTropicZone(tile, TROPICZONE_RAINFOREST);
00927 }
00928 }
00929 }
00930
00937 static bool FindSpring(TileIndex tile, void *user_data)
00938 {
00939 int referenceHeight;
00940 if (!IsTileFlat(tile, &referenceHeight) || IsWaterTile(tile)) return false;
00941
00942
00943 if (_settings_game.game_creation.landscape == LT_TROPIC && GetTropicZone(tile) != TROPICZONE_RAINFOREST) return false;
00944
00945
00946 uint num = 0;
00947 for (int dx = -1; dx <= 1; dx++) {
00948 for (int dy = -1; dy <= 1; dy++) {
00949 TileIndex t = TileAddWrap(tile, dx, dy);
00950 if (t != INVALID_TILE && GetTileMaxZ(t) > referenceHeight) num++;
00951 }
00952 }
00953
00954 if (num < 4) return false;
00955
00956
00957 for (int dx = -16; dx <= 16; dx++) {
00958 for (int dy = -16; dy <= 16; dy++) {
00959 TileIndex t = TileAddWrap(tile, dx, dy);
00960 if (t != INVALID_TILE && GetTileMaxZ(t) > referenceHeight + 2) return false;
00961 }
00962 }
00963
00964 return true;
00965 }
00966
00973 static bool MakeLake(TileIndex tile, void *user_data)
00974 {
00975 uint height = *(uint*)user_data;
00976 if (!IsValidTile(tile) || TileHeight(tile) != height || !IsTileFlat(tile)) return false;
00977 if (_settings_game.game_creation.landscape == LT_TROPIC && GetTropicZone(tile) == TROPICZONE_DESERT) return false;
00978
00979 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
00980 TileIndex t2 = tile + TileOffsByDiagDir(d);
00981 if (IsWaterTile(t2)) {
00982 MakeRiver(tile, Random());
00983 return false;
00984 }
00985 }
00986
00987 return false;
00988 }
00989
00996 static bool FlowsDown(TileIndex begin, TileIndex end)
00997 {
00998 assert(DistanceManhattan(begin, end) == 1);
00999
01000 int heightBegin;
01001 int heightEnd;
01002 Slope slopeBegin = GetTileSlope(begin, &heightBegin);
01003 Slope slopeEnd = GetTileSlope(end, &heightEnd);
01004
01005 return heightEnd <= heightBegin &&
01006
01007 (slopeEnd == SLOPE_FLAT || IsInclinedSlope(slopeEnd)) &&
01008
01009 ((slopeEnd == slopeBegin && heightEnd < heightBegin) || slopeEnd == SLOPE_FLAT || slopeBegin == SLOPE_FLAT);
01010 }
01011
01012
01013 static int32 River_EndNodeCheck(AyStar *aystar, OpenListNode *current)
01014 {
01015 return current->path.node.tile == *(TileIndex*)aystar->user_target ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
01016 }
01017
01018
01019 static int32 River_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
01020 {
01021 return 1 + RandomRange(_settings_game.game_creation.river_route_random);
01022 }
01023
01024
01025 static int32 River_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
01026 {
01027 return DistanceManhattan(*(TileIndex*)aystar->user_target, current->tile);
01028 }
01029
01030
01031 static void River_GetNeighbours(AyStar *aystar, OpenListNode *current)
01032 {
01033 TileIndex tile = current->path.node.tile;
01034
01035 aystar->num_neighbours = 0;
01036 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
01037 TileIndex t2 = tile + TileOffsByDiagDir(d);
01038 if (IsValidTile(t2) && FlowsDown(tile, t2)) {
01039 aystar->neighbours[aystar->num_neighbours].tile = t2;
01040 aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR;
01041 aystar->num_neighbours++;
01042 }
01043 }
01044 }
01045
01046
01047 static void River_FoundEndNode(AyStar *aystar, OpenListNode *current)
01048 {
01049 for (PathNode *path = ¤t->path; path != NULL; path = path->parent) {
01050 TileIndex tile = path->node.tile;
01051 if (!IsWaterTile(tile)) {
01052 MakeRiver(tile, Random());
01053
01054 CircularTileSearch(&tile, 5, RiverModifyDesertZone, NULL);
01055 }
01056 }
01057 }
01058
01059 static const uint RIVER_HASH_SIZE = 8;
01060
01067 static uint River_Hash(uint tile, uint dir)
01068 {
01069 return GB(TileHash(TileX(tile), TileY(tile)), 0, RIVER_HASH_SIZE);
01070 }
01071
01077 static void BuildRiver(TileIndex begin, TileIndex end)
01078 {
01079 AyStar finder;
01080 MemSetT(&finder, 0);
01081 finder.CalculateG = River_CalculateG;
01082 finder.CalculateH = River_CalculateH;
01083 finder.GetNeighbours = River_GetNeighbours;
01084 finder.EndNodeCheck = River_EndNodeCheck;
01085 finder.FoundEndNode = River_FoundEndNode;
01086 finder.user_target = &end;
01087
01088 finder.Init(River_Hash, 1 << RIVER_HASH_SIZE);
01089
01090 AyStarNode start;
01091 start.tile = begin;
01092 start.direction = INVALID_TRACKDIR;
01093 finder.AddStartNode(&start, 0);
01094 finder.Main();
01095 finder.Free();
01096 }
01097
01104 static bool FlowRiver(TileIndex spring, TileIndex begin)
01105 {
01106 #define SET_MARK(x) marks.insert(x)
01107 #define IS_MARKED(x) (marks.find(x) != marks.end())
01108
01109 uint height = TileHeight(begin);
01110 if (IsWaterTile(begin)) return DistanceManhattan(spring, begin) > _settings_game.game_creation.min_river_length;
01111
01112 std::set<TileIndex> marks;
01113 SET_MARK(begin);
01114
01115
01116 std::list<TileIndex> queue;
01117 queue.push_back(begin);
01118
01119 bool found = false;
01120 uint count = 0;
01121 TileIndex end;
01122 do {
01123 end = queue.front();
01124 queue.pop_front();
01125
01126 uint height2 = TileHeight(end);
01127 if (IsTileFlat(end) && (height2 < height || (height2 == height && IsWaterTile(end)))) {
01128 found = true;
01129 break;
01130 }
01131
01132 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
01133 TileIndex t2 = end + TileOffsByDiagDir(d);
01134 if (IsValidTile(t2) && !IS_MARKED(t2) && FlowsDown(end, t2)) {
01135 SET_MARK(t2);
01136 count++;
01137 queue.push_back(t2);
01138 }
01139 }
01140 } while (!queue.empty());
01141
01142 if (found) {
01143
01144 found = FlowRiver(spring, end);
01145 } else if (count > 32) {
01146
01147 TileIndex lakeCenter = 0;
01148 int i = RandomRange(count - 1) + 1;
01149 std::set<TileIndex>::const_iterator cit = marks.begin();
01150 while (--i) cit++;
01151 lakeCenter = *cit;
01152
01153 if (IsValidTile(lakeCenter) &&
01154
01155 IsTileFlat(lakeCenter) &&
01156
01157 TileHeight(begin) == TileHeight(lakeCenter) &&
01158
01159 lakeCenter != begin &&
01160
01161 (_settings_game.game_creation.landscape != LT_TROPIC || GetTropicZone(lakeCenter) != TROPICZONE_DESERT) &&
01162
01163 DistanceManhattan(spring, lakeCenter) > _settings_game.game_creation.min_river_length) {
01164 end = lakeCenter;
01165 MakeRiver(lakeCenter, Random());
01166 uint range = RandomRange(8) + 3;
01167 CircularTileSearch(&lakeCenter, range, MakeLake, &height);
01168
01169 lakeCenter = end;
01170 CircularTileSearch(&lakeCenter, range, MakeLake, &height);
01171 found = true;
01172 }
01173 }
01174
01175 marks.clear();
01176 if (found) BuildRiver(begin, end);
01177 return found;
01178 }
01179
01183 static void CreateRivers()
01184 {
01185 int amount = _settings_game.game_creation.amount_of_rivers;
01186 if (amount == 0) return;
01187
01188 uint wells = ScaleByMapSize(4 << _settings_game.game_creation.amount_of_rivers);
01189 SetGeneratingWorldProgress(GWP_RIVER, wells + 256 / 64);
01190
01191 for (; wells != 0; wells--) {
01192 IncreaseGeneratingWorldProgress(GWP_RIVER);
01193 for (int tries = 0; tries < 128; tries++) {
01194 TileIndex t = RandomTile();
01195 if (!CircularTileSearch(&t, 8, FindSpring, NULL)) continue;
01196 if (FlowRiver(t, t)) break;
01197 }
01198 }
01199
01200
01201 for (uint i = 0; i != 256; i++) {
01202 if (i % 64 == 0) IncreaseGeneratingWorldProgress(GWP_RIVER);
01203 RunTileLoop();
01204 }
01205 }
01206
01207 void GenerateLandscape(byte mode)
01208 {
01210 enum GenLandscapeSteps {
01211 GLS_HEIGHTMAP = 3,
01212 GLS_TERRAGENESIS = 5,
01213 GLS_ORIGINAL = 2,
01214 GLS_TROPIC = 12,
01215 GLS_OTHER = 0,
01216 };
01217 uint steps = (_settings_game.game_creation.landscape == LT_TROPIC) ? GLS_TROPIC : GLS_OTHER;
01218
01219 if (mode == GWM_HEIGHTMAP) {
01220 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP);
01221 LoadHeightmap(_file_to_saveload.name);
01222 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
01223 } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) {
01224 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS);
01225 GenerateTerrainPerlin();
01226 } else {
01227 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_ORIGINAL);
01228 if (_settings_game.construction.freeform_edges) {
01229 for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0));
01230 for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y));
01231 }
01232 switch (_settings_game.game_creation.landscape) {
01233 case LT_ARCTIC: {
01234 uint32 r = Random();
01235
01236 for (uint i = ScaleByMapSize(GB(r, 0, 7) + 950); i != 0; --i) {
01237 GenerateTerrain(2, 0);
01238 }
01239
01240 uint flag = GB(r, 7, 2) | 4;
01241 for (uint i = ScaleByMapSize(GB(r, 9, 7) + 450); i != 0; --i) {
01242 GenerateTerrain(4, flag);
01243 }
01244 break;
01245 }
01246
01247 case LT_TROPIC: {
01248 uint32 r = Random();
01249
01250 for (uint i = ScaleByMapSize(GB(r, 0, 7) + 170); i != 0; --i) {
01251 GenerateTerrain(0, 0);
01252 }
01253
01254 uint flag = GB(r, 7, 2) | 4;
01255 for (uint i = ScaleByMapSize(GB(r, 9, 8) + 1700); i != 0; --i) {
01256 GenerateTerrain(0, flag);
01257 }
01258
01259 flag ^= 2;
01260
01261 for (uint i = ScaleByMapSize(GB(r, 17, 7) + 410); i != 0; --i) {
01262 GenerateTerrain(3, flag);
01263 }
01264 break;
01265 }
01266
01267 default: {
01268 uint32 r = Random();
01269
01270 assert(_settings_game.difficulty.quantity_sea_lakes != CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY);
01271 uint i = ScaleByMapSize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100);
01272 for (; i != 0; --i) {
01273 GenerateTerrain(_settings_game.difficulty.terrain_type, 0);
01274 }
01275 break;
01276 }
01277 }
01278 }
01279
01280
01281
01282 FixSlopes();
01283 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
01284 ConvertGroundTilesIntoWaterTiles();
01285 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
01286
01287 if (_settings_game.game_creation.landscape == LT_TROPIC) CreateDesertOrRainForest();
01288
01289 CreateRivers();
01290 }
01291
01292 void OnTick_Town();
01293 void OnTick_Trees();
01294 void OnTick_Station();
01295 void OnTick_Industry();
01296
01297 void OnTick_Companies();
01298 void OnTick_LinkGraph();
01299
01300 void CallLandscapeTick()
01301 {
01302 OnTick_Town();
01303 OnTick_Trees();
01304 OnTick_Station();
01305 OnTick_Industry();
01306
01307 OnTick_Companies();
01308 OnTick_LinkGraph();
01309 }