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