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 "functions.h"
00026 #include "date_func.h"
00027 #include "water.h"
00028 #include "effectvehicle_func.h"
00029 #include "landscape_type.h"
00030 #include "animated_tile_func.h"
00031 #include "core/random_func.hpp"
00032 #include "object_base.h"
00033 #include "water_map.h"
00034 #include "economy_func.h"
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 = TILE_HEIGHT + (IsSteepSlope(*s) ? TILE_HEIGHT : 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) ? TILE_HEIGHT : 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 GetPartialZ(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 GetSlopeMaxZ(corners);
00154 break;
00155
00156 case CORNER_S:
00157 if (x - (y ^ 0xF) >= 0) return GetSlopeMaxZ(corners);
00158 break;
00159
00160 case CORNER_E:
00161 if (y - x >= 0) return GetSlopeMaxZ(corners);
00162 break;
00163
00164 case CORNER_N:
00165 if ((y ^ 0xF) - x >= 0) return GetSlopeMaxZ(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 uint GetSlopeZ(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 ? TILE_HEIGHT : 0) + (tileh == SteepSlope(corner) ? TILE_HEIGHT : 0);
00295 }
00296
00309 void GetSlopeZOnEdge(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, uint *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 uint z;
00351
00352 int z_W_here = z_here;
00353 int z_N_here = z_here;
00354 GetSlopeZOnEdge(slope_here, DIAGDIR_NW, &z_W_here, &z_N_here);
00355
00356 Slope slope = GetFoundationSlope(TILE_ADDXY(tile, 0, -1), &z);
00357 int z_W = z;
00358 int z_N = z;
00359 GetSlopeZOnEdge(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 uint z;
00368
00369 int z_E_here = z_here;
00370 int z_N_here = z_here;
00371 GetSlopeZOnEdge(slope_here, DIAGDIR_NE, &z_E_here, &z_N_here);
00372
00373 Slope slope = GetFoundationSlope(TILE_ADDXY(tile, -1, 0), &z);
00374 int z_E = z;
00375 int z_N = z;
00376 GetSlopeZOnEdge(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 uint z;
00395 Slope slope = GetFoundationSlope(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 += ApplyFoundationToSlope(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 += ApplyFoundationToSlope(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;
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 : _snow_line->highest_value;
00577 }
00578
00584 byte LowestSnowLine()
00585 {
00586 return _snow_line == NULL ? _settings_game.game_creation.snow_line : _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 const ClearedObjectArea *coa = FindClearedObject(tile);
00620
00621
00622
00623 if (coa != NULL && coa->first_tile != tile) {
00624
00625
00626
00627
00628
00629 if ((flags & DC_NO_WATER) && HasTileWaterClass(tile) && IsTileOnWater(tile)) {
00630 return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00631 }
00632 if (do_clear && (flags & DC_EXEC)) DoClearSquare(tile);
00633 return cost;
00634 }
00635 cost.AddCost(_tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags));
00636 if (do_clear && (flags & DC_EXEC)) DoClearSquare(tile);
00637 return cost;
00638 }
00639
00650 CommandCost CmdClearArea(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00651 {
00652 if (p1 >= MapSize()) return CMD_ERROR;
00653
00654 Money money = GetAvailableMoneyForCommand();
00655 CommandCost cost(EXPENSES_CONSTRUCTION);
00656 CommandCost last_error = CMD_ERROR;
00657 bool had_success = false;
00658
00659 TileArea ta(tile, p1);
00660 TileIterator *iter = HasBit(p2, 0) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(ta);
00661 for (; *iter != INVALID_TILE; ++(*iter)) {
00662 TileIndex t = *iter;
00663 CommandCost ret = DoCommand(t, 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
00664 if (ret.Failed()) {
00665 last_error = ret;
00666 continue;
00667 }
00668
00669 had_success = true;
00670 if (flags & DC_EXEC) {
00671 money -= ret.GetCost();
00672 if (ret.GetCost() > 0 && money < 0) {
00673 _additional_cash_required = ret.GetCost();
00674 delete iter;
00675 return cost;
00676 }
00677 DoCommand(t, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00678
00679
00680 TileIndex off = t - ta.tile;
00681 if ((TileX(off) == 0 || TileX(off) == ta.w - 1U) && (TileY(off) == 0 || TileY(off) == ta.h - 1U)) {
00682
00683 CreateEffectVehicleAbove(TileX(t) * TILE_SIZE + TILE_SIZE / 2, TileY(t) * TILE_SIZE + TILE_SIZE / 2, 2,
00684 ta.w == 1 && ta.h == 1 ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
00685 );
00686 }
00687 }
00688 cost.AddCost(ret);
00689 }
00690
00691 delete iter;
00692 return had_success ? cost : last_error;
00693 }
00694
00695
00696 TileIndex _cur_tileloop_tile;
00697 #define TILELOOP_BITS 4
00698 #define TILELOOP_SIZE (1 << TILELOOP_BITS)
00699 #define TILELOOP_ASSERTMASK ((TILELOOP_SIZE - 1) + ((TILELOOP_SIZE - 1) << MapLogX()))
00700 #define TILELOOP_CHKMASK (((1 << (MapLogX() - TILELOOP_BITS))-1) << TILELOOP_BITS)
00701
00702 void RunTileLoop()
00703 {
00704 TileIndex tile = _cur_tileloop_tile;
00705
00706 assert((tile & ~TILELOOP_ASSERTMASK) == 0);
00707 uint count = (MapSizeX() / TILELOOP_SIZE) * (MapSizeY() / TILELOOP_SIZE);
00708 do {
00709 _tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
00710
00711 if (TileX(tile) < MapSizeX() - TILELOOP_SIZE) {
00712 tile += TILELOOP_SIZE;
00713 } else {
00714 tile = TILE_MASK(tile - TILELOOP_SIZE * (MapSizeX() / TILELOOP_SIZE - 1) + TileDiffXY(0, TILELOOP_SIZE));
00715 }
00716 } while (--count != 0);
00717 assert((tile & ~TILELOOP_ASSERTMASK) == 0);
00718
00719 tile += 9;
00720 if (tile & TILELOOP_CHKMASK) {
00721 tile = (tile + MapSizeX()) & TILELOOP_ASSERTMASK;
00722 }
00723 _cur_tileloop_tile = tile;
00724 }
00725
00726 void InitializeLandscape()
00727 {
00728 uint maxx = MapMaxX();
00729 uint maxy = MapMaxY();
00730 uint sizex = MapSizeX();
00731
00732 uint y;
00733 for (y = _settings_game.construction.freeform_edges ? 1 : 0; y < maxy; y++) {
00734 uint x;
00735 for (x = _settings_game.construction.freeform_edges ? 1 : 0; x < maxx; x++) {
00736 MakeClear(sizex * y + x, CLEAR_GRASS, 3);
00737 SetTileHeight(sizex * y + x, 0);
00738 SetTropicZone(sizex * y + x, TROPICZONE_NORMAL);
00739 ClearBridgeMiddle(sizex * y + x);
00740 }
00741 MakeVoid(sizex * y + x);
00742 }
00743 for (uint x = 0; x < sizex; x++) MakeVoid(sizex * y + x);
00744 }
00745
00746 static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4 };
00747 static const byte _genterrain_tbl_2[5] = { 0, 0, 0, 0, 33 };
00748
00749 static void GenerateTerrain(int type, uint flag)
00750 {
00751 uint32 r = Random();
00752
00753 const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845, ST_MAPGEN);
00754
00755 uint x = r & MapMaxX();
00756 uint y = (r >> MapLogX()) & MapMaxY();
00757
00758 if (x < 2 || y < 2) return;
00759
00760 DiagDirection direction = (DiagDirection)GB(r, 22, 2);
00761 uint w = templ->width;
00762 uint h = templ->height;
00763
00764 if (DiagDirToAxis(direction) == AXIS_Y) Swap(w, h);
00765
00766 const byte *p = templ->data;
00767
00768 if ((flag & 4) != 0) {
00769 uint xw = x * MapSizeY();
00770 uint yw = y * MapSizeX();
00771 uint bias = (MapSizeX() + MapSizeY()) * 16;
00772
00773 switch (flag & 3) {
00774 default: NOT_REACHED();
00775 case 0:
00776 if (xw + yw > MapSize() - bias) return;
00777 break;
00778
00779 case 1:
00780 if (yw < xw + bias) return;
00781 break;
00782
00783 case 2:
00784 if (xw + yw < MapSize() + bias) return;
00785 break;
00786
00787 case 3:
00788 if (xw < yw + bias) return;
00789 break;
00790 }
00791 }
00792
00793 if (x + w >= MapMaxX() - 1) return;
00794 if (y + h >= MapMaxY() - 1) return;
00795
00796 Tile *tile = &_m[TileXY(x, y)];
00797
00798 switch (direction) {
00799 default: NOT_REACHED();
00800 case DIAGDIR_NE:
00801 do {
00802 Tile *tile_cur = tile;
00803
00804 for (uint w_cur = w; w_cur != 0; --w_cur) {
00805 if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00806 p++;
00807 tile_cur++;
00808 }
00809 tile += TileDiffXY(0, 1);
00810 } while (--h != 0);
00811 break;
00812
00813 case DIAGDIR_SE:
00814 do {
00815 Tile *tile_cur = tile;
00816
00817 for (uint h_cur = h; h_cur != 0; --h_cur) {
00818 if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00819 p++;
00820 tile_cur += TileDiffXY(0, 1);
00821 }
00822 tile += TileDiffXY(1, 0);
00823 } while (--w != 0);
00824 break;
00825
00826 case DIAGDIR_SW:
00827 tile += TileDiffXY(w - 1, 0);
00828 do {
00829 Tile *tile_cur = tile;
00830
00831 for (uint w_cur = w; w_cur != 0; --w_cur) {
00832 if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00833 p++;
00834 tile_cur--;
00835 }
00836 tile += TileDiffXY(0, 1);
00837 } while (--h != 0);
00838 break;
00839
00840 case DIAGDIR_NW:
00841 tile += TileDiffXY(0, h - 1);
00842 do {
00843 Tile *tile_cur = tile;
00844
00845 for (uint h_cur = h; h_cur != 0; --h_cur) {
00846 if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = 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 }
00855
00856
00857 #include "table/genland.h"
00858
00859 static void CreateDesertOrRainForest()
00860 {
00861 TileIndex update_freq = MapSize() / 4;
00862 const TileIndexDiffC *data;
00863
00864 for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00865 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00866
00867 if (!IsValidTile(tile)) continue;
00868
00869 for (data = _make_desert_or_rainforest_data;
00870 data != endof(_make_desert_or_rainforest_data); ++data) {
00871 TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00872 if (t != INVALID_TILE && (TileHeight(t) >= 4 || IsTileType(t, MP_WATER))) break;
00873 }
00874 if (data == endof(_make_desert_or_rainforest_data)) {
00875 SetTropicZone(tile, TROPICZONE_DESERT);
00876 }
00877 }
00878
00879 for (uint i = 0; i != 256; i++) {
00880 if ((i % 64) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00881
00882 RunTileLoop();
00883 }
00884
00885 for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00886 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00887
00888 if (!IsValidTile(tile)) continue;
00889
00890 for (data = _make_desert_or_rainforest_data;
00891 data != endof(_make_desert_or_rainforest_data); ++data) {
00892 TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00893 if (t != INVALID_TILE && IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_DESERT)) break;
00894 }
00895 if (data == endof(_make_desert_or_rainforest_data)) {
00896 SetTropicZone(tile, TROPICZONE_RAINFOREST);
00897 }
00898 }
00899 }
00900
00901 void GenerateLandscape(byte mode)
00902 {
00904 enum GenLandscapeSteps {
00905 GLS_HEIGHTMAP = 3,
00906 GLS_TERRAGENESIS = 5,
00907 GLS_ORIGINAL = 2,
00908 GLS_TROPIC = 12,
00909 GLS_OTHER = 0,
00910 };
00911 uint steps = (_settings_game.game_creation.landscape == LT_TROPIC) ? GLS_TROPIC : GLS_OTHER;
00912
00913 if (mode == GWM_HEIGHTMAP) {
00914 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP);
00915 LoadHeightmap(_file_to_saveload.name);
00916 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00917 } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) {
00918 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS);
00919 GenerateTerrainPerlin();
00920 } else {
00921 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_ORIGINAL);
00922 if (_settings_game.construction.freeform_edges) {
00923 for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0));
00924 for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y));
00925 }
00926 switch (_settings_game.game_creation.landscape) {
00927 case LT_ARCTIC: {
00928 uint32 r = Random();
00929
00930 for (uint i = ScaleByMapSize(GB(r, 0, 7) + 950); i != 0; --i) {
00931 GenerateTerrain(2, 0);
00932 }
00933
00934 uint flag = GB(r, 7, 2) | 4;
00935 for (uint i = ScaleByMapSize(GB(r, 9, 7) + 450); i != 0; --i) {
00936 GenerateTerrain(4, flag);
00937 }
00938 break;
00939 }
00940
00941 case LT_TROPIC: {
00942 uint32 r = Random();
00943
00944 for (uint i = ScaleByMapSize(GB(r, 0, 7) + 170); i != 0; --i) {
00945 GenerateTerrain(0, 0);
00946 }
00947
00948 uint flag = GB(r, 7, 2) | 4;
00949 for (uint i = ScaleByMapSize(GB(r, 9, 8) + 1700); i != 0; --i) {
00950 GenerateTerrain(0, flag);
00951 }
00952
00953 flag ^= 2;
00954
00955 for (uint i = ScaleByMapSize(GB(r, 17, 7) + 410); i != 0; --i) {
00956 GenerateTerrain(3, flag);
00957 }
00958 break;
00959 }
00960
00961 default: {
00962 uint32 r = Random();
00963
00964 assert(_settings_game.difficulty.quantity_sea_lakes != CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY);
00965 uint i = ScaleByMapSize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100);
00966 for (; i != 0; --i) {
00967 GenerateTerrain(_settings_game.difficulty.terrain_type, 0);
00968 }
00969 break;
00970 }
00971 }
00972 }
00973
00974
00975
00976 FixSlopes();
00977 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00978 ConvertGroundTilesIntoWaterTiles();
00979 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00980
00981 if (_settings_game.game_creation.landscape == LT_TROPIC) CreateDesertOrRainForest();
00982 }
00983
00984 void OnTick_Town();
00985 void OnTick_Trees();
00986 void OnTick_Station();
00987 void OnTick_Industry();
00988
00989 void OnTick_Companies();
00990
00991 void CallLandscapeTick()
00992 {
00993 OnTick_Town();
00994 OnTick_Trees();
00995 OnTick_Station();
00996 OnTick_Industry();
00997
00998 OnTick_Companies();
00999 }