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 TileIterator *iter = HasBit(p2, 0) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(tile, p1);
00671 for (; *iter != INVALID_TILE; ++(*iter)) {
00672 TileIndex t = *iter;
00673 CommandCost ret = DoCommand(t, 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
00674 if (ret.Failed()) {
00675 last_error = ret;
00676
00677
00678 if (c != NULL && GB(c->clear_limit, 16, 16) < 1) break;
00679 continue;
00680 }
00681
00682 had_success = true;
00683 if (flags & DC_EXEC) {
00684 money -= ret.GetCost();
00685 if (ret.GetCost() > 0 && money < 0) {
00686 _additional_cash_required = ret.GetCost();
00687 delete iter;
00688 return cost;
00689 }
00690 DoCommand(t, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00691
00692
00693
00694 if ((t == tile || t == p1) && _pause_mode == PM_UNPAUSED) {
00695
00696 CreateEffectVehicleAbove(TileX(t) * TILE_SIZE + TILE_SIZE / 2, TileY(t) * TILE_SIZE + TILE_SIZE / 2, 2,
00697 TileX(tile) == TileX(p1) && TileY(tile) == TileY(p1) ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
00698 );
00699 }
00700 } else {
00701
00702 if (ret.GetCost() != 0 && --limit <= 0) break;
00703 }
00704 cost.AddCost(ret);
00705 }
00706
00707 delete iter;
00708 return had_success ? cost : last_error;
00709 }
00710
00711
00712 TileIndex _cur_tileloop_tile;
00713
00717 void RunTileLoop()
00718 {
00719
00720
00721
00722
00723
00724
00725 static const uint32 feedbacks[] = {
00726 0xD8F, 0x1296, 0x2496, 0x4357, 0x8679, 0x1030E, 0x206CD, 0x403FE, 0x807B8, 0x1004B2, 0x2006A8
00727 };
00728 const uint32 feedback = feedbacks[MapLogX() + MapLogY() - 12];
00729
00730
00731 uint count = 1 << (MapLogX() + MapLogY() - 8);
00732
00733 TileIndex tile = _cur_tileloop_tile;
00734
00735 assert(tile != 0);
00736
00737
00738 if (_tick_counter % 256 == 0) {
00739 _tile_type_procs[GetTileType(0)]->tile_loop_proc(0);
00740 count--;
00741 }
00742
00743 while (count--) {
00744 _tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
00745
00746
00747 tile = (tile >> 1) ^ (-(int32)(tile & 1) & feedback);
00748 }
00749
00750 _cur_tileloop_tile = tile;
00751 }
00752
00753 void InitializeLandscape()
00754 {
00755 uint maxx = MapMaxX();
00756 uint maxy = MapMaxY();
00757 uint sizex = MapSizeX();
00758
00759 uint y;
00760 for (y = _settings_game.construction.freeform_edges ? 1 : 0; y < maxy; y++) {
00761 uint x;
00762 for (x = _settings_game.construction.freeform_edges ? 1 : 0; x < maxx; x++) {
00763 MakeClear(sizex * y + x, CLEAR_GRASS, 3);
00764 SetTileHeight(sizex * y + x, 0);
00765 SetTropicZone(sizex * y + x, TROPICZONE_NORMAL);
00766 ClearBridgeMiddle(sizex * y + x);
00767 }
00768 MakeVoid(sizex * y + x);
00769 }
00770 for (uint x = 0; x < sizex; x++) MakeVoid(sizex * y + x);
00771 }
00772
00773 static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4 };
00774 static const byte _genterrain_tbl_2[5] = { 0, 0, 0, 0, 33 };
00775
00776 static void GenerateTerrain(int type, uint flag)
00777 {
00778 uint32 r = Random();
00779
00780 const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845, ST_MAPGEN);
00781 if (templ == NULL) usererror("Map generator sprites could not be loaded");
00782
00783 uint x = r & MapMaxX();
00784 uint y = (r >> MapLogX()) & MapMaxY();
00785
00786 if (x < 2 || y < 2) return;
00787
00788 DiagDirection direction = (DiagDirection)GB(r, 22, 2);
00789 uint w = templ->width;
00790 uint h = templ->height;
00791
00792 if (DiagDirToAxis(direction) == AXIS_Y) Swap(w, h);
00793
00794 const byte *p = templ->data;
00795
00796 if ((flag & 4) != 0) {
00797 uint xw = x * MapSizeY();
00798 uint yw = y * MapSizeX();
00799 uint bias = (MapSizeX() + MapSizeY()) * 16;
00800
00801 switch (flag & 3) {
00802 default: NOT_REACHED();
00803 case 0:
00804 if (xw + yw > MapSize() - bias) return;
00805 break;
00806
00807 case 1:
00808 if (yw < xw + bias) return;
00809 break;
00810
00811 case 2:
00812 if (xw + yw < MapSize() + bias) return;
00813 break;
00814
00815 case 3:
00816 if (xw < yw + bias) return;
00817 break;
00818 }
00819 }
00820
00821 if (x + w >= MapMaxX() - 1) return;
00822 if (y + h >= MapMaxY() - 1) return;
00823
00824 TileIndex tile = TileXY(x, y);
00825
00826 switch (direction) {
00827 default: NOT_REACHED();
00828 case DIAGDIR_NE:
00829 do {
00830 TileIndex tile_cur = tile;
00831
00832 for (uint w_cur = w; w_cur != 0; --w_cur) {
00833 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
00834 p++;
00835 tile_cur++;
00836 }
00837 tile += TileDiffXY(0, 1);
00838 } while (--h != 0);
00839 break;
00840
00841 case DIAGDIR_SE:
00842 do {
00843 TileIndex tile_cur = tile;
00844
00845 for (uint h_cur = h; h_cur != 0; --h_cur) {
00846 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
00847 p++;
00848 tile_cur += TileDiffXY(0, 1);
00849 }
00850 tile += TileDiffXY(1, 0);
00851 } while (--w != 0);
00852 break;
00853
00854 case DIAGDIR_SW:
00855 tile += TileDiffXY(w - 1, 0);
00856 do {
00857 TileIndex tile_cur = tile;
00858
00859 for (uint w_cur = w; w_cur != 0; --w_cur) {
00860 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
00861 p++;
00862 tile_cur--;
00863 }
00864 tile += TileDiffXY(0, 1);
00865 } while (--h != 0);
00866 break;
00867
00868 case DIAGDIR_NW:
00869 tile += TileDiffXY(0, h - 1);
00870 do {
00871 TileIndex tile_cur = tile;
00872
00873 for (uint h_cur = h; h_cur != 0; --h_cur) {
00874 if (GB(*p, 0, 4) >= TileHeight(tile_cur)) SetTileHeight(tile_cur, GB(*p, 0, 4));
00875 p++;
00876 tile_cur -= TileDiffXY(0, 1);
00877 }
00878 tile += TileDiffXY(1, 0);
00879 } while (--w != 0);
00880 break;
00881 }
00882 }
00883
00884
00885 #include "table/genland.h"
00886
00887 static void CreateDesertOrRainForest()
00888 {
00889 TileIndex update_freq = MapSize() / 4;
00890 const TileIndexDiffC *data;
00891
00892 for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00893 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00894
00895 if (!IsValidTile(tile)) continue;
00896
00897 for (data = _make_desert_or_rainforest_data;
00898 data != endof(_make_desert_or_rainforest_data); ++data) {
00899 TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00900 if (t != INVALID_TILE && (TileHeight(t) >= 4 || IsTileType(t, MP_WATER))) break;
00901 }
00902 if (data == endof(_make_desert_or_rainforest_data)) {
00903 SetTropicZone(tile, TROPICZONE_DESERT);
00904 }
00905 }
00906
00907 for (uint i = 0; i != 256; i++) {
00908 if ((i % 64) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00909
00910 RunTileLoop();
00911 }
00912
00913 for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00914 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00915
00916 if (!IsValidTile(tile)) continue;
00917
00918 for (data = _make_desert_or_rainforest_data;
00919 data != endof(_make_desert_or_rainforest_data); ++data) {
00920 TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00921 if (t != INVALID_TILE && IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_DESERT)) break;
00922 }
00923 if (data == endof(_make_desert_or_rainforest_data)) {
00924 SetTropicZone(tile, TROPICZONE_RAINFOREST);
00925 }
00926 }
00927 }
00928
00935 static bool FindSpring(TileIndex tile, void *user_data)
00936 {
00937 int referenceHeight;
00938 if (!IsTileFlat(tile, &referenceHeight) || IsWaterTile(tile)) return false;
00939
00940
00941 if (_settings_game.game_creation.landscape == LT_TROPIC && GetTropicZone(tile) != TROPICZONE_RAINFOREST) return false;
00942
00943
00944 uint num = 0;
00945 for (int dx = -1; dx <= 1; dx++) {
00946 for (int dy = -1; dy <= 1; dy++) {
00947 TileIndex t = TileAddWrap(tile, dx, dy);
00948 if (t != INVALID_TILE && GetTileMaxZ(t) > referenceHeight) num++;
00949 }
00950 }
00951
00952 if (num < 4) return false;
00953
00954
00955 for (int dx = -16; dx <= 16; dx++) {
00956 for (int dy = -16; dy <= 16; dy++) {
00957 TileIndex t = TileAddWrap(tile, dx, dy);
00958 if (t != INVALID_TILE && GetTileMaxZ(t) > referenceHeight + 2) return false;
00959 }
00960 }
00961
00962 return true;
00963 }
00964
00971 static bool MakeLake(TileIndex tile, void *user_data)
00972 {
00973 uint height = *(uint*)user_data;
00974 if (!IsValidTile(tile) || TileHeight(tile) != height || !IsTileFlat(tile)) return false;
00975 if (_settings_game.game_creation.landscape == LT_TROPIC && GetTropicZone(tile) == TROPICZONE_DESERT) return false;
00976
00977 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
00978 TileIndex t2 = tile + TileOffsByDiagDir(d);
00979 if (IsWaterTile(t2)) {
00980 MakeRiver(tile, Random());
00981 return false;
00982 }
00983 }
00984
00985 return false;
00986 }
00987
00994 static bool FlowsDown(TileIndex begin, TileIndex end)
00995 {
00996 assert(DistanceManhattan(begin, end) == 1);
00997
00998 int heightBegin;
00999 int heightEnd;
01000 Slope slopeBegin = GetTileSlope(begin, &heightBegin);
01001 Slope slopeEnd = GetTileSlope(end, &heightEnd);
01002
01003 return heightEnd <= heightBegin &&
01004
01005 (slopeEnd == SLOPE_FLAT || IsInclinedSlope(slopeEnd)) &&
01006
01007 ((slopeEnd == slopeBegin && heightEnd < heightBegin) || slopeEnd == SLOPE_FLAT || slopeBegin == SLOPE_FLAT);
01008 }
01009
01010
01011 static int32 River_EndNodeCheck(AyStar *aystar, OpenListNode *current)
01012 {
01013 return current->path.node.tile == *(TileIndex*)aystar->user_target ? AYSTAR_FOUND_END_NODE : AYSTAR_DONE;
01014 }
01015
01016
01017 static int32 River_CalculateG(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
01018 {
01019 return 1 + RandomRange(_settings_game.game_creation.river_route_random);
01020 }
01021
01022
01023 static int32 River_CalculateH(AyStar *aystar, AyStarNode *current, OpenListNode *parent)
01024 {
01025 return DistanceManhattan(*(TileIndex*)aystar->user_target, current->tile);
01026 }
01027
01028
01029 static void River_GetNeighbours(AyStar *aystar, OpenListNode *current)
01030 {
01031 TileIndex tile = current->path.node.tile;
01032
01033 aystar->num_neighbours = 0;
01034 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
01035 TileIndex t2 = tile + TileOffsByDiagDir(d);
01036 if (IsValidTile(t2) && FlowsDown(tile, t2)) {
01037 aystar->neighbours[aystar->num_neighbours].tile = t2;
01038 aystar->neighbours[aystar->num_neighbours].direction = INVALID_TRACKDIR;
01039 aystar->num_neighbours++;
01040 }
01041 }
01042 }
01043
01044
01045 static void River_FoundEndNode(AyStar *aystar, OpenListNode *current)
01046 {
01047 for (PathNode *path = ¤t->path; path != NULL; path = path->parent) {
01048 TileIndex tile = path->node.tile;
01049 if (!IsWaterTile(tile)) {
01050 MakeRiver(tile, Random());
01051
01052 CircularTileSearch(&tile, 5, RiverModifyDesertZone, NULL);
01053 }
01054 }
01055 }
01056
01057 static const uint RIVER_HASH_SIZE = 8;
01058
01065 static uint River_Hash(uint tile, uint dir)
01066 {
01067 return GB(TileHash(TileX(tile), TileY(tile)), 0, RIVER_HASH_SIZE);
01068 }
01069
01075 static void BuildRiver(TileIndex begin, TileIndex end)
01076 {
01077 AyStar finder;
01078 MemSetT(&finder, 0);
01079 finder.CalculateG = River_CalculateG;
01080 finder.CalculateH = River_CalculateH;
01081 finder.GetNeighbours = River_GetNeighbours;
01082 finder.EndNodeCheck = River_EndNodeCheck;
01083 finder.FoundEndNode = River_FoundEndNode;
01084 finder.user_target = &end;
01085
01086 finder.Init(River_Hash, 1 << RIVER_HASH_SIZE);
01087
01088 AyStarNode start;
01089 start.tile = begin;
01090 start.direction = INVALID_TRACKDIR;
01091 finder.AddStartNode(&start, 0);
01092 finder.Main();
01093 finder.Free();
01094 }
01095
01103 static bool FlowRiver(bool *marks, TileIndex spring, TileIndex begin)
01104 {
01105 uint height = TileHeight(begin);
01106 if (IsWaterTile(begin)) return DistanceManhattan(spring, begin) > _settings_game.game_creation.min_river_length;
01107
01108 MemSetT(marks, 0, MapSize());
01109 marks[begin] = true;
01110
01111
01112 std::list<TileIndex> queue;
01113 queue.push_back(begin);
01114
01115 bool found = false;
01116 uint count = 0;
01117 TileIndex end;
01118 do {
01119 end = queue.front();
01120 queue.pop_front();
01121
01122 uint height2 = TileHeight(end);
01123 if (IsTileFlat(end) && (height2 < height || (height2 == height && IsWaterTile(end)))) {
01124 found = true;
01125 break;
01126 }
01127
01128 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
01129 TileIndex t2 = end + TileOffsByDiagDir(d);
01130 if (IsValidTile(t2) && !marks[t2] && FlowsDown(end, t2)) {
01131 marks[t2] = true;
01132 count++;
01133 queue.push_back(t2);
01134 }
01135 }
01136 } while (!queue.empty());
01137
01138 if (found) {
01139
01140 found = FlowRiver(marks, spring, end);
01141 } else if (count > 32) {
01142
01143 TileIndex lakeCenter = 0;
01144 for (int i = RandomRange(count - 1); i != 0; lakeCenter++) {
01145 if (marks[lakeCenter]) i--;
01146 }
01147
01148 if (IsValidTile(lakeCenter) &&
01149
01150 IsTileFlat(lakeCenter) &&
01151
01152 TileHeight(begin) == TileHeight(lakeCenter) &&
01153
01154 lakeCenter != begin &&
01155
01156 (_settings_game.game_creation.landscape != LT_TROPIC || GetTropicZone(lakeCenter) != TROPICZONE_DESERT) &&
01157
01158 DistanceManhattan(spring, lakeCenter) > _settings_game.game_creation.min_river_length) {
01159 end = lakeCenter;
01160 MakeRiver(lakeCenter, Random());
01161 uint range = RandomRange(8) + 3;
01162 CircularTileSearch(&lakeCenter, range, MakeLake, &height);
01163
01164 lakeCenter = end;
01165 CircularTileSearch(&lakeCenter, range, MakeLake, &height);
01166 found = true;
01167 }
01168 }
01169
01170 if (found) BuildRiver(begin, end);
01171 return found;
01172 }
01173
01177 static void CreateRivers()
01178 {
01179 int amount = _settings_game.game_creation.amount_of_rivers;
01180 if (amount == 0) return;
01181
01182 uint wells = ScaleByMapSize(4 << _settings_game.game_creation.amount_of_rivers);
01183 SetGeneratingWorldProgress(GWP_RIVER, wells + 256 / 64);
01184 bool *marks = CallocT<bool>(MapSize());
01185
01186 for (; wells != 0; wells--) {
01187 IncreaseGeneratingWorldProgress(GWP_RIVER);
01188 for (int tries = 0; tries < 128; tries++) {
01189 TileIndex t = RandomTile();
01190 if (!CircularTileSearch(&t, 8, FindSpring, NULL)) continue;
01191 if (FlowRiver(marks, t, t)) break;
01192 }
01193 }
01194
01195 free(marks);
01196
01197
01198 for (uint i = 0; i != 256; i++) {
01199 if (i % 64 == 0) IncreaseGeneratingWorldProgress(GWP_RIVER);
01200 RunTileLoop();
01201 }
01202 }
01203
01204 void GenerateLandscape(byte mode)
01205 {
01207 enum GenLandscapeSteps {
01208 GLS_HEIGHTMAP = 3,
01209 GLS_TERRAGENESIS = 5,
01210 GLS_ORIGINAL = 2,
01211 GLS_TROPIC = 12,
01212 GLS_OTHER = 0,
01213 };
01214 uint steps = (_settings_game.game_creation.landscape == LT_TROPIC) ? GLS_TROPIC : GLS_OTHER;
01215
01216 if (mode == GWM_HEIGHTMAP) {
01217 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP);
01218 LoadHeightmap(_file_to_saveload.name);
01219 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
01220 } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) {
01221 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS);
01222 GenerateTerrainPerlin();
01223 } else {
01224 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_ORIGINAL);
01225 if (_settings_game.construction.freeform_edges) {
01226 for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0));
01227 for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y));
01228 }
01229 switch (_settings_game.game_creation.landscape) {
01230 case LT_ARCTIC: {
01231 uint32 r = Random();
01232
01233 for (uint i = ScaleByMapSize(GB(r, 0, 7) + 950); i != 0; --i) {
01234 GenerateTerrain(2, 0);
01235 }
01236
01237 uint flag = GB(r, 7, 2) | 4;
01238 for (uint i = ScaleByMapSize(GB(r, 9, 7) + 450); i != 0; --i) {
01239 GenerateTerrain(4, flag);
01240 }
01241 break;
01242 }
01243
01244 case LT_TROPIC: {
01245 uint32 r = Random();
01246
01247 for (uint i = ScaleByMapSize(GB(r, 0, 7) + 170); i != 0; --i) {
01248 GenerateTerrain(0, 0);
01249 }
01250
01251 uint flag = GB(r, 7, 2) | 4;
01252 for (uint i = ScaleByMapSize(GB(r, 9, 8) + 1700); i != 0; --i) {
01253 GenerateTerrain(0, flag);
01254 }
01255
01256 flag ^= 2;
01257
01258 for (uint i = ScaleByMapSize(GB(r, 17, 7) + 410); i != 0; --i) {
01259 GenerateTerrain(3, flag);
01260 }
01261 break;
01262 }
01263
01264 default: {
01265 uint32 r = Random();
01266
01267 assert(_settings_game.difficulty.quantity_sea_lakes != CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY);
01268 uint i = ScaleByMapSize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100);
01269 for (; i != 0; --i) {
01270 GenerateTerrain(_settings_game.difficulty.terrain_type, 0);
01271 }
01272 break;
01273 }
01274 }
01275 }
01276
01277
01278
01279 FixSlopes();
01280 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
01281 ConvertGroundTilesIntoWaterTiles();
01282 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
01283
01284 if (_settings_game.game_creation.landscape == LT_TROPIC) CreateDesertOrRainForest();
01285
01286 CreateRivers();
01287 }
01288
01289 void OnTick_Town();
01290 void OnTick_Trees();
01291 void OnTick_Station();
01292 void OnTick_Industry();
01293
01294 void OnTick_Companies();
01295 void OnTick_LinkGraph();
01296
01297 void CallLandscapeTick()
01298 {
01299 OnTick_Town();
01300 OnTick_Trees();
01301 OnTick_Station();
01302 OnTick_Industry();
01303
01304 OnTick_Companies();
01305 OnTick_LinkGraph();
01306 }