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