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