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 #include "company_func.h"
00036
00037 #include "table/strings.h"
00038 #include "table/sprites.h"
00039
00040 extern const TileTypeProcs
00041 _tile_type_clear_procs,
00042 _tile_type_rail_procs,
00043 _tile_type_road_procs,
00044 _tile_type_town_procs,
00045 _tile_type_trees_procs,
00046 _tile_type_station_procs,
00047 _tile_type_water_procs,
00048 _tile_type_void_procs,
00049 _tile_type_industry_procs,
00050 _tile_type_tunnelbridge_procs,
00051 _tile_type_object_procs;
00052
00058 const TileTypeProcs * const _tile_type_procs[16] = {
00059 &_tile_type_clear_procs,
00060 &_tile_type_rail_procs,
00061 &_tile_type_road_procs,
00062 &_tile_type_town_procs,
00063 &_tile_type_trees_procs,
00064 &_tile_type_station_procs,
00065 &_tile_type_water_procs,
00066 &_tile_type_void_procs,
00067 &_tile_type_industry_procs,
00068 &_tile_type_tunnelbridge_procs,
00069 &_tile_type_object_procs,
00070 };
00071
00073 extern const byte _slope_to_sprite_offset[32] = {
00074 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0,
00075 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 17, 0, 15, 18, 0,
00076 };
00077
00086 static SnowLine *_snow_line = NULL;
00087
00096 uint ApplyFoundationToSlope(Foundation f, Slope *s)
00097 {
00098 if (!IsFoundation(f)) return 0;
00099
00100 if (IsLeveledFoundation(f)) {
00101 uint dz = TILE_HEIGHT + (IsSteepSlope(*s) ? TILE_HEIGHT : 0);
00102 *s = SLOPE_FLAT;
00103 return dz;
00104 }
00105
00106 if (f != FOUNDATION_STEEP_BOTH && IsNonContinuousFoundation(f)) {
00107 *s = HalftileSlope(*s, GetHalftileFoundationCorner(f));
00108 return 0;
00109 }
00110
00111 if (IsSpecialRailFoundation(f)) {
00112 *s = SlopeWithThreeCornersRaised(OppositeCorner(GetRailFoundationCorner(f)));
00113 return 0;
00114 }
00115
00116 uint dz = IsSteepSlope(*s) ? TILE_HEIGHT : 0;
00117 Corner highest_corner = GetHighestSlopeCorner(*s);
00118
00119 switch (f) {
00120 case FOUNDATION_INCLINED_X:
00121 *s = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? SLOPE_SW : SLOPE_NE);
00122 break;
00123
00124 case FOUNDATION_INCLINED_Y:
00125 *s = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? SLOPE_SE : SLOPE_NW);
00126 break;
00127
00128 case FOUNDATION_STEEP_LOWER:
00129 *s = SlopeWithOneCornerRaised(highest_corner);
00130 break;
00131
00132 case FOUNDATION_STEEP_BOTH:
00133 *s = HalftileSlope(SlopeWithOneCornerRaised(highest_corner), highest_corner);
00134 break;
00135
00136 default: NOT_REACHED();
00137 }
00138 return dz;
00139 }
00140
00141
00149 uint GetPartialZ(int x, int y, Slope corners)
00150 {
00151 if (IsHalftileSlope(corners)) {
00152 switch (GetHalftileSlopeCorner(corners)) {
00153 case CORNER_W:
00154 if (x - y >= 0) return GetSlopeMaxZ(corners);
00155 break;
00156
00157 case CORNER_S:
00158 if (x - (y ^ 0xF) >= 0) return GetSlopeMaxZ(corners);
00159 break;
00160
00161 case CORNER_E:
00162 if (y - x >= 0) return GetSlopeMaxZ(corners);
00163 break;
00164
00165 case CORNER_N:
00166 if ((y ^ 0xF) - x >= 0) return GetSlopeMaxZ(corners);
00167 break;
00168
00169 default: NOT_REACHED();
00170 }
00171 }
00172
00173 int z = 0;
00174
00175 switch (RemoveHalftileSlope(corners)) {
00176 case SLOPE_W:
00177 if (x - y >= 0) {
00178 z = (x - y) >> 1;
00179 }
00180 break;
00181
00182 case SLOPE_S:
00183 y ^= 0xF;
00184 if ((x - y) >= 0) {
00185 z = (x - y) >> 1;
00186 }
00187 break;
00188
00189 case SLOPE_SW:
00190 z = (x >> 1) + 1;
00191 break;
00192
00193 case SLOPE_E:
00194 if (y - x >= 0) {
00195 z = (y - x) >> 1;
00196 }
00197 break;
00198
00199 case SLOPE_EW:
00200 case SLOPE_NS:
00201 case SLOPE_ELEVATED:
00202 z = 4;
00203 break;
00204
00205 case SLOPE_SE:
00206 z = (y >> 1) + 1;
00207 break;
00208
00209 case SLOPE_WSE:
00210 z = 8;
00211 y ^= 0xF;
00212 if (x - y < 0) {
00213 z += (x - y) >> 1;
00214 }
00215 break;
00216
00217 case SLOPE_N:
00218 y ^= 0xF;
00219 if (y - x >= 0) {
00220 z = (y - x) >> 1;
00221 }
00222 break;
00223
00224 case SLOPE_NW:
00225 z = (y ^ 0xF) >> 1;
00226 break;
00227
00228 case SLOPE_NWS:
00229 z = 8;
00230 if (x - y < 0) {
00231 z += (x - y) >> 1;
00232 }
00233 break;
00234
00235 case SLOPE_NE:
00236 z = (x ^ 0xF) >> 1;
00237 break;
00238
00239 case SLOPE_ENW:
00240 z = 8;
00241 y ^= 0xF;
00242 if (y - x < 0) {
00243 z += (y - x) >> 1;
00244 }
00245 break;
00246
00247 case SLOPE_SEN:
00248 z = 8;
00249 if (y - x < 0) {
00250 z += (y - x) >> 1;
00251 }
00252 break;
00253
00254 case SLOPE_STEEP_S:
00255 z = 1 + ((x + y) >> 1);
00256 break;
00257
00258 case SLOPE_STEEP_W:
00259 z = 1 + ((x + (y ^ 0xF)) >> 1);
00260 break;
00261
00262 case SLOPE_STEEP_N:
00263 z = 1 + (((x ^ 0xF) + (y ^ 0xF)) >> 1);
00264 break;
00265
00266 case SLOPE_STEEP_E:
00267 z = 1 + (((x ^ 0xF) + y) >> 1);
00268 break;
00269
00270 default: break;
00271 }
00272
00273 return z;
00274 }
00275
00276 uint GetSlopeZ(int x, int y)
00277 {
00278 TileIndex tile = TileVirtXY(x, y);
00279
00280 return _tile_type_procs[GetTileType(tile)]->get_slope_z_proc(tile, x, y);
00281 }
00282
00292 int GetSlopeZInCorner(Slope tileh, Corner corner)
00293 {
00294 assert(!IsHalftileSlope(tileh));
00295 return ((tileh & SlopeWithOneCornerRaised(corner)) != 0 ? TILE_HEIGHT : 0) + (tileh == SteepSlope(corner) ? TILE_HEIGHT : 0);
00296 }
00297
00310 void GetSlopeZOnEdge(Slope tileh, DiagDirection edge, int *z1, int *z2)
00311 {
00312 static const Slope corners[4][4] = {
00313
00314
00315 {SLOPE_E, SLOPE_N, SLOPE_STEEP_E, SLOPE_STEEP_N},
00316 {SLOPE_S, SLOPE_E, SLOPE_STEEP_S, SLOPE_STEEP_E},
00317 {SLOPE_S, SLOPE_W, SLOPE_STEEP_S, SLOPE_STEEP_W},
00318 {SLOPE_W, SLOPE_N, SLOPE_STEEP_W, SLOPE_STEEP_N},
00319 };
00320
00321 int halftile_test = (IsHalftileSlope(tileh) ? SlopeWithOneCornerRaised(GetHalftileSlopeCorner(tileh)) : 0);
00322 if (halftile_test == corners[edge][0]) *z2 += TILE_HEIGHT;
00323 if (halftile_test == corners[edge][1]) *z1 += TILE_HEIGHT;
00324
00325 if ((tileh & corners[edge][0]) != 0) *z1 += TILE_HEIGHT;
00326 if ((tileh & corners[edge][1]) != 0) *z2 += TILE_HEIGHT;
00327 if (RemoveHalftileSlope(tileh) == corners[edge][2]) *z1 += TILE_HEIGHT;
00328 if (RemoveHalftileSlope(tileh) == corners[edge][3]) *z2 += TILE_HEIGHT;
00329 }
00330
00339 Slope GetFoundationSlope(TileIndex tile, uint *z)
00340 {
00341 Slope tileh = GetTileSlope(tile, z);
00342 Foundation f = _tile_type_procs[GetTileType(tile)]->get_foundation_proc(tile, tileh);
00343 uint z_inc = ApplyFoundationToSlope(f, &tileh);
00344 if (z != NULL) *z += z_inc;
00345 return tileh;
00346 }
00347
00348
00349 bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
00350 {
00351 uint z;
00352
00353 int z_W_here = z_here;
00354 int z_N_here = z_here;
00355 GetSlopeZOnEdge(slope_here, DIAGDIR_NW, &z_W_here, &z_N_here);
00356
00357 Slope slope = GetFoundationSlope(TILE_ADDXY(tile, 0, -1), &z);
00358 int z_W = z;
00359 int z_N = z;
00360 GetSlopeZOnEdge(slope, DIAGDIR_SE, &z_W, &z_N);
00361
00362 return (z_N_here > z_N) || (z_W_here > z_W);
00363 }
00364
00365
00366 bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
00367 {
00368 uint z;
00369
00370 int z_E_here = z_here;
00371 int z_N_here = z_here;
00372 GetSlopeZOnEdge(slope_here, DIAGDIR_NE, &z_E_here, &z_N_here);
00373
00374 Slope slope = GetFoundationSlope(TILE_ADDXY(tile, -1, 0), &z);
00375 int z_E = z;
00376 int z_N = z;
00377 GetSlopeZOnEdge(slope, DIAGDIR_SW, &z_E, &z_N);
00378
00379 return (z_N_here > z_N) || (z_E_here > z_E);
00380 }
00381
00387 void DrawFoundation(TileInfo *ti, Foundation f)
00388 {
00389 if (!IsFoundation(f)) return;
00390
00391
00392 assert(f != FOUNDATION_STEEP_BOTH);
00393
00394 uint sprite_block = 0;
00395 uint z;
00396 Slope slope = GetFoundationSlope(ti->tile, &z);
00397
00398
00399
00400
00401
00402
00403
00404 if (!HasFoundationNW(ti->tile, slope, z)) sprite_block += 1;
00405 if (!HasFoundationNE(ti->tile, slope, z)) sprite_block += 2;
00406
00407
00408 SpriteID leveled_base = (sprite_block == 0 ? (int)SPR_FOUNDATION_BASE : (SPR_SLOPES_VIRTUAL_BASE + sprite_block * SPR_TRKFOUND_BLOCK_SIZE));
00409 SpriteID inclined_base = SPR_SLOPES_VIRTUAL_BASE + SPR_SLOPES_INCLINED_OFFSET + sprite_block * SPR_TRKFOUND_BLOCK_SIZE;
00410 SpriteID halftile_base = SPR_HALFTILE_FOUNDATION_BASE + sprite_block * SPR_HALFTILE_BLOCK_SIZE;
00411
00412 if (IsSteepSlope(ti->tileh)) {
00413 if (!IsNonContinuousFoundation(f)) {
00414
00415 AddSortableSpriteToDraw(
00416 leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z
00417 );
00418 }
00419
00420 Corner highest_corner = GetHighestSlopeCorner(ti->tileh);
00421 ti->z += ApplyFoundationToSlope(f, &ti->tileh);
00422
00423 if (IsInclinedFoundation(f)) {
00424
00425 byte inclined = highest_corner * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
00426
00427 AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
00428 f == FOUNDATION_INCLINED_X ? 16 : 1,
00429 f == FOUNDATION_INCLINED_Y ? 16 : 1,
00430 TILE_HEIGHT, ti->z
00431 );
00432 OffsetGroundSprite(31, 9);
00433 } else if (IsLeveledFoundation(f)) {
00434 AddSortableSpriteToDraw(leveled_base + SlopeWithOneCornerRaised(highest_corner), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z - TILE_HEIGHT);
00435 OffsetGroundSprite(31, 1);
00436 } else if (f == FOUNDATION_STEEP_LOWER) {
00437
00438 OffsetGroundSprite(31, 1);
00439 } else {
00440
00441 int x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? 8 : 0);
00442 int y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? 8 : 0);
00443
00444 AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z + TILE_HEIGHT);
00445 OffsetGroundSprite(31, 9);
00446 }
00447 } else {
00448 if (IsLeveledFoundation(f)) {
00449
00450 AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
00451 OffsetGroundSprite(31, 1);
00452 } else if (IsNonContinuousFoundation(f)) {
00453
00454 Corner halftile_corner = GetHalftileFoundationCorner(f);
00455 int x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? 8 : 0);
00456 int y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? 8 : 0);
00457
00458 AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z);
00459 OffsetGroundSprite(31, 9);
00460 } else if (IsSpecialRailFoundation(f)) {
00461
00462 SpriteID spr;
00463 if (ti->tileh == SLOPE_NS || ti->tileh == SLOPE_EW) {
00464
00465 spr = leveled_base + SlopeWithThreeCornersRaised(GetRailFoundationCorner(f));
00466 } else {
00467
00468 spr = inclined_base + 2 * GetRailFoundationCorner(f) + ((ti->tileh == SLOPE_SW || ti->tileh == SLOPE_NE) ? 1 : 0);
00469 }
00470 AddSortableSpriteToDraw(spr, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
00471 OffsetGroundSprite(31, 9);
00472 } else {
00473
00474 byte inclined = GetHighestSlopeCorner(ti->tileh) * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
00475
00476 AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
00477 f == FOUNDATION_INCLINED_X ? 16 : 1,
00478 f == FOUNDATION_INCLINED_Y ? 16 : 1,
00479 TILE_HEIGHT, ti->z
00480 );
00481 OffsetGroundSprite(31, 9);
00482 }
00483 ti->z += ApplyFoundationToSlope(f, &ti->tileh);
00484 }
00485 }
00486
00487 void DoClearSquare(TileIndex tile)
00488 {
00489
00490 if (_tile_type_procs[GetTileType(tile)]->animate_tile_proc != NULL) DeleteAnimatedTile(tile);
00491
00492 MakeClear(tile, CLEAR_GRASS, _generating_world ? 3 : 0);
00493 MarkTileDirtyByTile(tile);
00494 }
00495
00506 TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
00507 {
00508 return _tile_type_procs[GetTileType(tile)]->get_tile_track_status_proc(tile, mode, sub_mode, side);
00509 }
00510
00517 void ChangeTileOwner(TileIndex tile, Owner old_owner, Owner new_owner)
00518 {
00519 _tile_type_procs[GetTileType(tile)]->change_tile_owner_proc(tile, old_owner, new_owner);
00520 }
00521
00522 void GetTileDesc(TileIndex tile, TileDesc *td)
00523 {
00524 _tile_type_procs[GetTileType(tile)]->get_tile_desc_proc(tile, td);
00525 }
00526
00532 bool IsSnowLineSet()
00533 {
00534 return _snow_line != NULL;
00535 }
00536
00542 void SetSnowLine(byte table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS])
00543 {
00544 _snow_line = CallocT<SnowLine>(1);
00545 _snow_line->lowest_value = 0xFF;
00546 memcpy(_snow_line->table, table, sizeof(_snow_line->table));
00547
00548 for (uint i = 0; i < SNOW_LINE_MONTHS; i++) {
00549 for (uint j = 0; j < SNOW_LINE_DAYS; j++) {
00550 _snow_line->highest_value = max(_snow_line->highest_value, table[i][j]);
00551 _snow_line->lowest_value = min(_snow_line->lowest_value, table[i][j]);
00552 }
00553 }
00554 }
00555
00561 byte GetSnowLine()
00562 {
00563 if (_snow_line == NULL) return _settings_game.game_creation.snow_line;
00564
00565 YearMonthDay ymd;
00566 ConvertDateToYMD(_date, &ymd);
00567 return _snow_line->table[ymd.month][ymd.day];
00568 }
00569
00575 byte HighestSnowLine()
00576 {
00577 return _snow_line == NULL ? _settings_game.game_creation.snow_line : _snow_line->highest_value;
00578 }
00579
00585 byte LowestSnowLine()
00586 {
00587 return _snow_line == NULL ? _settings_game.game_creation.snow_line : _snow_line->lowest_value;
00588 }
00589
00594 void ClearSnowLine()
00595 {
00596 free(_snow_line);
00597 _snow_line = NULL;
00598 }
00599
00609 CommandCost CmdLandscapeClear(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00610 {
00611 CommandCost cost(EXPENSES_CONSTRUCTION);
00612 bool do_clear = false;
00613
00614 if ((flags & DC_FORCE_CLEAR_TILE) && HasTileWaterClass(tile) && IsTileOnWater(tile) && !IsWaterTile(tile) && !IsCoastTile(tile)) {
00615 if ((flags & DC_AUTO) && GetWaterClass(tile) == WATER_CLASS_CANAL) return_cmd_error(STR_ERROR_MUST_DEMOLISH_CANAL_FIRST);
00616 do_clear = true;
00617 cost.AddCost(GetWaterClass(tile) == WATER_CLASS_CANAL ? _price[PR_CLEAR_CANAL] : _price[PR_CLEAR_WATER]);
00618 }
00619
00620 Company *c = (flags & DC_AUTO) ? NULL : Company::GetIfValid(_current_company);
00621 if (c != NULL && (int)GB(c->clear_limit, 16, 16) < 1) {
00622 return_cmd_error(STR_ERROR_CLEARING_LIMIT_REACHED);
00623 }
00624
00625 const ClearedObjectArea *coa = FindClearedObject(tile);
00626
00627
00628
00629 if (coa != NULL && coa->first_tile != tile) {
00630
00631
00632
00633
00634
00635 if ((flags & DC_NO_WATER) && HasTileWaterClass(tile) && IsTileOnWater(tile)) {
00636 return_cmd_error(STR_ERROR_CAN_T_BUILD_ON_WATER);
00637 }
00638 } else {
00639 cost.AddCost(_tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags));
00640 }
00641
00642 if (flags & DC_EXEC) {
00643 if (c != NULL) c->clear_limit -= 1 << 16;
00644 if (do_clear) DoClearSquare(tile);
00645 }
00646 return cost;
00647 }
00648
00659 CommandCost CmdClearArea(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00660 {
00661 if (p1 >= MapSize()) return CMD_ERROR;
00662
00663 Money money = GetAvailableMoneyForCommand();
00664 CommandCost cost(EXPENSES_CONSTRUCTION);
00665 CommandCost last_error = CMD_ERROR;
00666 bool had_success = false;
00667
00668 const Company *c = (flags & DC_AUTO) ? NULL : Company::GetIfValid(_current_company);
00669 int limit = (c == NULL ? INT32_MAX : GB(c->clear_limit, 16, 16));
00670
00671 TileArea ta(tile, p1);
00672 TileIterator *iter = HasBit(p2, 0) ? (TileIterator *)new DiagonalTileIterator(tile, p1) : new OrthogonalTileIterator(ta);
00673 for (; *iter != INVALID_TILE; ++(*iter)) {
00674 TileIndex t = *iter;
00675 CommandCost ret = DoCommand(t, 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
00676 if (ret.Failed()) {
00677 last_error = ret;
00678
00679
00680 if (c != NULL && GB(c->clear_limit, 16, 16) < 1) break;
00681 continue;
00682 }
00683
00684 had_success = true;
00685 if (flags & DC_EXEC) {
00686 money -= ret.GetCost();
00687 if (ret.GetCost() > 0 && money < 0) {
00688 _additional_cash_required = ret.GetCost();
00689 delete iter;
00690 return cost;
00691 }
00692 DoCommand(t, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
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)) {
00697
00698 CreateEffectVehicleAbove(TileX(t) * TILE_SIZE + TILE_SIZE / 2, TileY(t) * TILE_SIZE + TILE_SIZE / 2, 2,
00699 ta.w == 1 && ta.h == 1 ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
00700 );
00701 }
00702 } else {
00703
00704 if (ret.GetCost() != 0 && --limit <= 0) break;
00705 }
00706 cost.AddCost(ret);
00707 }
00708
00709 delete iter;
00710 return had_success ? cost : last_error;
00711 }
00712
00713
00714 TileIndex _cur_tileloop_tile;
00715 #define TILELOOP_BITS 4
00716 #define TILELOOP_SIZE (1 << TILELOOP_BITS)
00717 #define TILELOOP_ASSERTMASK ((TILELOOP_SIZE - 1) + ((TILELOOP_SIZE - 1) << MapLogX()))
00718 #define TILELOOP_CHKMASK (((1 << (MapLogX() - TILELOOP_BITS))-1) << TILELOOP_BITS)
00719
00720 void RunTileLoop()
00721 {
00722 TileIndex tile = _cur_tileloop_tile;
00723
00724 assert((tile & ~TILELOOP_ASSERTMASK) == 0);
00725 uint count = (MapSizeX() / TILELOOP_SIZE) * (MapSizeY() / TILELOOP_SIZE);
00726 do {
00727 _tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
00728
00729 if (TileX(tile) < MapSizeX() - TILELOOP_SIZE) {
00730 tile += TILELOOP_SIZE;
00731 } else {
00732 tile = TILE_MASK(tile - TILELOOP_SIZE * (MapSizeX() / TILELOOP_SIZE - 1) + TileDiffXY(0, TILELOOP_SIZE));
00733 }
00734 } while (--count != 0);
00735 assert((tile & ~TILELOOP_ASSERTMASK) == 0);
00736
00737 tile += 9;
00738 if (tile & TILELOOP_CHKMASK) {
00739 tile = (tile + MapSizeX()) & TILELOOP_ASSERTMASK;
00740 }
00741 _cur_tileloop_tile = tile;
00742 }
00743
00744 void InitializeLandscape()
00745 {
00746 uint maxx = MapMaxX();
00747 uint maxy = MapMaxY();
00748 uint sizex = MapSizeX();
00749
00750 uint y;
00751 for (y = _settings_game.construction.freeform_edges ? 1 : 0; y < maxy; y++) {
00752 uint x;
00753 for (x = _settings_game.construction.freeform_edges ? 1 : 0; x < maxx; x++) {
00754 MakeClear(sizex * y + x, CLEAR_GRASS, 3);
00755 SetTileHeight(sizex * y + x, 0);
00756 SetTropicZone(sizex * y + x, TROPICZONE_NORMAL);
00757 ClearBridgeMiddle(sizex * y + x);
00758 }
00759 MakeVoid(sizex * y + x);
00760 }
00761 for (uint x = 0; x < sizex; x++) MakeVoid(sizex * y + x);
00762 }
00763
00764 static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4 };
00765 static const byte _genterrain_tbl_2[5] = { 0, 0, 0, 0, 33 };
00766
00767 static void GenerateTerrain(int type, uint flag)
00768 {
00769 uint32 r = Random();
00770
00771 const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845, ST_MAPGEN);
00772
00773 uint x = r & MapMaxX();
00774 uint y = (r >> MapLogX()) & MapMaxY();
00775
00776 if (x < 2 || y < 2) return;
00777
00778 DiagDirection direction = (DiagDirection)GB(r, 22, 2);
00779 uint w = templ->width;
00780 uint h = templ->height;
00781
00782 if (DiagDirToAxis(direction) == AXIS_Y) Swap(w, h);
00783
00784 const byte *p = templ->data;
00785
00786 if ((flag & 4) != 0) {
00787 uint xw = x * MapSizeY();
00788 uint yw = y * MapSizeX();
00789 uint bias = (MapSizeX() + MapSizeY()) * 16;
00790
00791 switch (flag & 3) {
00792 default: NOT_REACHED();
00793 case 0:
00794 if (xw + yw > MapSize() - bias) return;
00795 break;
00796
00797 case 1:
00798 if (yw < xw + bias) return;
00799 break;
00800
00801 case 2:
00802 if (xw + yw < MapSize() + bias) return;
00803 break;
00804
00805 case 3:
00806 if (xw < yw + bias) return;
00807 break;
00808 }
00809 }
00810
00811 if (x + w >= MapMaxX() - 1) return;
00812 if (y + h >= MapMaxY() - 1) return;
00813
00814 Tile *tile = &_m[TileXY(x, y)];
00815
00816 switch (direction) {
00817 default: NOT_REACHED();
00818 case DIAGDIR_NE:
00819 do {
00820 Tile *tile_cur = tile;
00821
00822 for (uint w_cur = w; w_cur != 0; --w_cur) {
00823 if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00824 p++;
00825 tile_cur++;
00826 }
00827 tile += TileDiffXY(0, 1);
00828 } while (--h != 0);
00829 break;
00830
00831 case DIAGDIR_SE:
00832 do {
00833 Tile *tile_cur = tile;
00834
00835 for (uint h_cur = h; h_cur != 0; --h_cur) {
00836 if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00837 p++;
00838 tile_cur += TileDiffXY(0, 1);
00839 }
00840 tile += TileDiffXY(1, 0);
00841 } while (--w != 0);
00842 break;
00843
00844 case DIAGDIR_SW:
00845 tile += TileDiffXY(w - 1, 0);
00846 do {
00847 Tile *tile_cur = tile;
00848
00849 for (uint w_cur = w; w_cur != 0; --w_cur) {
00850 if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00851 p++;
00852 tile_cur--;
00853 }
00854 tile += TileDiffXY(0, 1);
00855 } while (--h != 0);
00856 break;
00857
00858 case DIAGDIR_NW:
00859 tile += TileDiffXY(0, h - 1);
00860 do {
00861 Tile *tile_cur = tile;
00862
00863 for (uint h_cur = h; h_cur != 0; --h_cur) {
00864 if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00865 p++;
00866 tile_cur -= TileDiffXY(0, 1);
00867 }
00868 tile += TileDiffXY(1, 0);
00869 } while (--w != 0);
00870 break;
00871 }
00872 }
00873
00874
00875 #include "table/genland.h"
00876
00877 static void CreateDesertOrRainForest()
00878 {
00879 TileIndex update_freq = MapSize() / 4;
00880 const TileIndexDiffC *data;
00881
00882 for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00883 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00884
00885 if (!IsValidTile(tile)) continue;
00886
00887 for (data = _make_desert_or_rainforest_data;
00888 data != endof(_make_desert_or_rainforest_data); ++data) {
00889 TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00890 if (t != INVALID_TILE && (TileHeight(t) >= 4 || IsTileType(t, MP_WATER))) break;
00891 }
00892 if (data == endof(_make_desert_or_rainforest_data)) {
00893 SetTropicZone(tile, TROPICZONE_DESERT);
00894 }
00895 }
00896
00897 for (uint i = 0; i != 256; i++) {
00898 if ((i % 64) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00899
00900 RunTileLoop();
00901 }
00902
00903 for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00904 if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00905
00906 if (!IsValidTile(tile)) continue;
00907
00908 for (data = _make_desert_or_rainforest_data;
00909 data != endof(_make_desert_or_rainforest_data); ++data) {
00910 TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00911 if (t != INVALID_TILE && IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_DESERT)) break;
00912 }
00913 if (data == endof(_make_desert_or_rainforest_data)) {
00914 SetTropicZone(tile, TROPICZONE_RAINFOREST);
00915 }
00916 }
00917 }
00918
00919 void GenerateLandscape(byte mode)
00920 {
00922 enum GenLandscapeSteps {
00923 GLS_HEIGHTMAP = 3,
00924 GLS_TERRAGENESIS = 5,
00925 GLS_ORIGINAL = 2,
00926 GLS_TROPIC = 12,
00927 GLS_OTHER = 0,
00928 };
00929 uint steps = (_settings_game.game_creation.landscape == LT_TROPIC) ? GLS_TROPIC : GLS_OTHER;
00930
00931 if (mode == GWM_HEIGHTMAP) {
00932 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP);
00933 LoadHeightmap(_file_to_saveload.name);
00934 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00935 } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) {
00936 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS);
00937 GenerateTerrainPerlin();
00938 } else {
00939 SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_ORIGINAL);
00940 if (_settings_game.construction.freeform_edges) {
00941 for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0));
00942 for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y));
00943 }
00944 switch (_settings_game.game_creation.landscape) {
00945 case LT_ARCTIC: {
00946 uint32 r = Random();
00947
00948 for (uint i = ScaleByMapSize(GB(r, 0, 7) + 950); i != 0; --i) {
00949 GenerateTerrain(2, 0);
00950 }
00951
00952 uint flag = GB(r, 7, 2) | 4;
00953 for (uint i = ScaleByMapSize(GB(r, 9, 7) + 450); i != 0; --i) {
00954 GenerateTerrain(4, flag);
00955 }
00956 break;
00957 }
00958
00959 case LT_TROPIC: {
00960 uint32 r = Random();
00961
00962 for (uint i = ScaleByMapSize(GB(r, 0, 7) + 170); i != 0; --i) {
00963 GenerateTerrain(0, 0);
00964 }
00965
00966 uint flag = GB(r, 7, 2) | 4;
00967 for (uint i = ScaleByMapSize(GB(r, 9, 8) + 1700); i != 0; --i) {
00968 GenerateTerrain(0, flag);
00969 }
00970
00971 flag ^= 2;
00972
00973 for (uint i = ScaleByMapSize(GB(r, 17, 7) + 410); i != 0; --i) {
00974 GenerateTerrain(3, flag);
00975 }
00976 break;
00977 }
00978
00979 default: {
00980 uint32 r = Random();
00981
00982 assert(_settings_game.difficulty.quantity_sea_lakes != CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY);
00983 uint i = ScaleByMapSize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100);
00984 for (; i != 0; --i) {
00985 GenerateTerrain(_settings_game.difficulty.terrain_type, 0);
00986 }
00987 break;
00988 }
00989 }
00990 }
00991
00992
00993
00994 FixSlopes();
00995 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00996 ConvertGroundTilesIntoWaterTiles();
00997 IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00998
00999 if (_settings_game.game_creation.landscape == LT_TROPIC) CreateDesertOrRainForest();
01000 }
01001
01002 void OnTick_Town();
01003 void OnTick_Trees();
01004 void OnTick_Station();
01005 void OnTick_Industry();
01006
01007 void OnTick_Companies();
01008
01009 void CallLandscapeTick()
01010 {
01011 OnTick_Town();
01012 OnTick_Trees();
01013 OnTick_Station();
01014 OnTick_Industry();
01015
01016 OnTick_Companies();
01017 }