# landscape.cpp

Go to the documentation of this file.

    00001 /* $Id: landscape.cpp 15434 2009-02-09 21:20:05Z rubidium $ */
    00002
    00007 #include "stdafx.h"
    00008 #include "heightmap.h"
    00009 #include "clear_map.h"
    00010 #include "spritecache.h"
    00011 #include "viewport_func.h"
    00012 #include "command_func.h"
    00013 #include "landscape.h"
    00014 #include "variables.h"
    00015 #include "void_map.h"
    00016 #include "tgp.h"
    00017 #include "genworld.h"
    00018 #include "fios.h"
    00019 #include "functions.h"
    00020 #include "date_func.h"
    00021 #include "water.h"
    00022 #include "effectvehicle_func.h"
    00023 #include "landscape_type.h"
    00024 #include "settings_type.h"
    00025
    00026 #include "table/sprites.h"
    00027
    00028 extern const TileTypeProcs
    00029   _tile_type_clear_procs,
    00030   _tile_type_rail_procs,
    00031   _tile_type_road_procs,
    00032   _tile_type_town_procs,
    00033   _tile_type_trees_procs,
    00034   _tile_type_station_procs,
    00035   _tile_type_water_procs,
    00036   _tile_type_dummy_procs,
    00037   _tile_type_industry_procs,
    00038   _tile_type_tunnelbridge_procs,
    00039   _tile_type_unmovable_procs;
    00040
    00044 const TileTypeProcs * const _tile_type_procs[16] = {
    00045   &_tile_type_clear_procs,
    00046   &_tile_type_rail_procs,
    00047   &_tile_type_road_procs,
    00048   &_tile_type_town_procs,
    00049   &_tile_type_trees_procs,
    00050   &_tile_type_station_procs,
    00051   &_tile_type_water_procs,
    00052   &_tile_type_dummy_procs,
    00053   &_tile_type_industry_procs,
    00054   &_tile_type_tunnelbridge_procs,
    00055   &_tile_type_unmovable_procs,
    00056 };
    00057
    00058 /* landscape slope => sprite */
    00059 const byte _tileh_to_sprite[32] = {
    00060   0, 1, 2, 3, 4, 5, 6,  7, 8, 9, 10, 11, 12, 13, 14, 0,
    00061   0, 0, 0, 0, 0, 0, 0, 16, 0, 0,  0, 17,  0, 15, 18, 0,
    00062 };
    00063
    00071 SnowLine *_snow_line = NULL;
    00072
    00081 uint ApplyFoundationToSlope(Foundation f, Slope *s)
    00082 {
    00083   if (!IsFoundation(f)) return 0;
    00084
    00085   if (IsLeveledFoundation(f)) {
    00086     uint dz = TILE_HEIGHT + (IsSteepSlope(*s) ? TILE_HEIGHT : 0);
    00087     *s = SLOPE_FLAT;
    00088     return dz;
    00089   }
    00090
    00091   if (f != FOUNDATION_STEEP_BOTH && IsNonContinuousFoundation(f)) {
    00092     *s = HalftileSlope(*s, GetHalftileFoundationCorner(f));
    00093     return 0;
    00094   }
    00095
    00096   if (IsSpecialRailFoundation(f)) {
    00097     *s = SlopeWithThreeCornersRaised(OppositeCorner(GetRailFoundationCorner(f)));
    00098     return 0;
    00099   }
    00100
    00101   uint dz = IsSteepSlope(*s) ? TILE_HEIGHT : 0;
    00102   Corner highest_corner = GetHighestSlopeCorner(*s);
    00103
    00104   switch (f) {
    00105     case FOUNDATION_INCLINED_X:
    00106       *s = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? SLOPE_SW : SLOPE_NE);
    00107       break;
    00108
    00109     case FOUNDATION_INCLINED_Y:
    00110       *s = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? SLOPE_SE : SLOPE_NW);
    00111       break;
    00112
    00113     case FOUNDATION_STEEP_LOWER:
    00114       *s = SlopeWithOneCornerRaised(highest_corner);
    00115       break;
    00116
    00117     case FOUNDATION_STEEP_BOTH:
    00118       *s = HalftileSlope(SlopeWithOneCornerRaised(highest_corner), highest_corner);
    00119       break;
    00120
    00121     default: NOT_REACHED();
    00122   }
    00123   return dz;
    00124 }
    00125
    00126
    00134 uint GetPartialZ(int x, int y, Slope corners)
    00135 {
    00136   if (IsHalftileSlope(corners)) {
    00137     switch (GetHalftileSlopeCorner(corners)) {
    00138       case CORNER_W:
    00139         if (x - y >= 0) return GetSlopeMaxZ(corners);
    00140         break;
    00141
    00142       case CORNER_S:
    00143         if (x - (y ^ 0xF) >= 0) return GetSlopeMaxZ(corners);
    00144         break;
    00145
    00146       case CORNER_E:
    00147         if (y - x >= 0) return GetSlopeMaxZ(corners);
    00148         break;
    00149
    00150       case CORNER_N:
    00151         if ((y ^ 0xF) - x >= 0) return GetSlopeMaxZ(corners);
    00152         break;
    00153
    00154       default: NOT_REACHED();
    00155     }
    00156   }
    00157
    00158   int z = 0;
    00159
    00160   switch (RemoveHalftileSlope(corners)) {
    00161     case SLOPE_W:
    00162       if (x - y >= 0) {
    00163         z = (x - y) >> 1;
    00164       }
    00165       break;
    00166
    00167     case SLOPE_S:
    00168       y ^= 0xF;
    00169       if ((x - y) >= 0) {
    00170         z = (x - y) >> 1;
    00171       }
    00172       break;
    00173
    00174     case SLOPE_SW:
    00175       z = (x >> 1) + 1;
    00176       break;
    00177
    00178     case SLOPE_E:
    00179       if (y - x >= 0) {
    00180         z = (y - x) >> 1;
    00181       }
    00182       break;
    00183
    00184     case SLOPE_EW:
    00185     case SLOPE_NS:
    00186     case SLOPE_ELEVATED:
    00187       z = 4;
    00188       break;
    00189
    00190     case SLOPE_SE:
    00191       z = (y >> 1) + 1;
    00192       break;
    00193
    00194     case SLOPE_WSE:
    00195       z = 8;
    00196       y ^= 0xF;
    00197       if (x - y < 0) {
    00198         z += (x - y) >> 1;
    00199       }
    00200       break;
    00201
    00202     case SLOPE_N:
    00203       y ^= 0xF;
    00204       if (y - x >= 0) {
    00205         z = (y - x) >> 1;
    00206       }
    00207       break;
    00208
    00209     case SLOPE_NW:
    00210       z = (y ^ 0xF) >> 1;
    00211       break;
    00212
    00213     case SLOPE_NWS:
    00214       z = 8;
    00215       if (x - y < 0) {
    00216         z += (x - y) >> 1;
    00217       }
    00218       break;
    00219
    00220     case SLOPE_NE:
    00221       z = (x ^ 0xF) >> 1;
    00222       break;
    00223
    00224     case SLOPE_ENW:
    00225       z = 8;
    00226       y ^= 0xF;
    00227       if (y - x < 0) {
    00228         z += (y - x) >> 1;
    00229       }
    00230       break;
    00231
    00232     case SLOPE_SEN:
    00233       z = 8;
    00234       if (y - x < 0) {
    00235         z += (y - x) >> 1;
    00236       }
    00237       break;
    00238
    00239     case SLOPE_STEEP_S:
    00240       z = 1 + ((x + y) >> 1);
    00241       break;
    00242
    00243     case SLOPE_STEEP_W:
    00244       z = 1 + ((x + (y ^ 0xF)) >> 1);
    00245       break;
    00246
    00247     case SLOPE_STEEP_N:
    00248       z = 1 + (((x ^ 0xF) + (y ^ 0xF)) >> 1);
    00249       break;
    00250
    00251     case SLOPE_STEEP_E:
    00252       z = 1 + (((x ^ 0xF) + y) >> 1);
    00253       break;
    00254
    00255     default: break;
    00256   }
    00257
    00258   return z;
    00259 }
    00260
    00261 uint GetSlopeZ(int x, int y)
    00262 {
    00263   TileIndex tile = TileVirtXY(x, y);
    00264
    00265   return _tile_type_procs[GetTileType(tile)]->get_slope_z_proc(tile, x, y);
    00266 }
    00267
    00277 int GetSlopeZInCorner(Slope tileh, Corner corner)
    00278 {
    00279   assert(!IsHalftileSlope(tileh));
    00280   return ((tileh & SlopeWithOneCornerRaised(corner)) != 0 ? TILE_HEIGHT : 0) + (tileh == SteepSlope(corner) ? TILE_HEIGHT : 0);
    00281 }
    00282
    00295 void GetSlopeZOnEdge(Slope tileh, DiagDirection edge, int *z1, int *z2)
    00296 {
    00297   static const Slope corners[4][4] = {
    00298     /*    corner     |          steep slope
    00299      *  z1      z2   |       z1             z2        */
    00300     {SLOPE_E, SLOPE_N, SLOPE_STEEP_E, SLOPE_STEEP_N}, // DIAGDIR_NE, z1 = E, z2 = N
    00301     {SLOPE_S, SLOPE_E, SLOPE_STEEP_S, SLOPE_STEEP_E}, // DIAGDIR_SE, z1 = S, z2 = E
    00302     {SLOPE_S, SLOPE_W, SLOPE_STEEP_S, SLOPE_STEEP_W}, // DIAGDIR_SW, z1 = S, z2 = W
    00303     {SLOPE_W, SLOPE_N, SLOPE_STEEP_W, SLOPE_STEEP_N}, // DIAGDIR_NW, z1 = W, z2 = N
    00304   };
    00305
    00306   int halftile_test = (IsHalftileSlope(tileh) ? SlopeWithOneCornerRaised(GetHalftileSlopeCorner(tileh)) : 0);
    00307   if (halftile_test == corners[edge][0]) *z2 += TILE_HEIGHT; // The slope is non-continuous in z2. z2 is on the upper side.
    00308   if (halftile_test == corners[edge][1]) *z1 += TILE_HEIGHT; // The slope is non-continuous in z1. z1 is on the upper side.
    00309
    00310   if ((tileh & corners[edge][0]) != 0) *z1 += TILE_HEIGHT; // z1 is raised
    00311   if ((tileh & corners[edge][1]) != 0) *z2 += TILE_HEIGHT; // z2 is raised
    00312   if (RemoveHalftileSlope(tileh) == corners[edge][2]) *z1 += TILE_HEIGHT; // z1 is highest corner of a steep slope
    00313   if (RemoveHalftileSlope(tileh) == corners[edge][3]) *z2 += TILE_HEIGHT; // z2 is highest corner of a steep slope
    00314 }
    00315
    00324 Slope GetFoundationSlope(TileIndex tile, uint *z)
    00325 {
    00326   Slope tileh = GetTileSlope(tile, z);
    00327   Foundation f = _tile_type_procs[GetTileType(tile)]->get_foundation_proc(tile, tileh);
    00328   uint z_inc = ApplyFoundationToSlope(f, &tileh);
    00329   if (z != NULL) *z += z_inc;
    00330   return tileh;
    00331 }
    00332
    00333
    00334 static bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
    00335 {
    00336   uint z;
    00337
    00338   int z_W_here = z_here;
    00339   int z_N_here = z_here;
    00340   GetSlopeZOnEdge(slope_here, DIAGDIR_NW, &z_W_here, &z_N_here);
    00341
    00342   Slope slope = GetFoundationSlope(TILE_ADDXY(tile, 0, -1), &z);
    00343   int z_W = z;
    00344   int z_N = z;
    00345   GetSlopeZOnEdge(slope, DIAGDIR_SE, &z_W, &z_N);
    00346
    00347   return (z_N_here > z_N) || (z_W_here > z_W);
    00348 }
    00349
    00350
    00351 static bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
    00352 {
    00353   uint z;
    00354
    00355   int z_E_here = z_here;
    00356   int z_N_here = z_here;
    00357   GetSlopeZOnEdge(slope_here, DIAGDIR_NE, &z_E_here, &z_N_here);
    00358
    00359   Slope slope = GetFoundationSlope(TILE_ADDXY(tile, -1, 0), &z);
    00360   int z_E = z;
    00361   int z_N = z;
    00362   GetSlopeZOnEdge(slope, DIAGDIR_SW, &z_E, &z_N);
    00363
    00364   return (z_N_here > z_N) || (z_E_here > z_E);
    00365 }
    00366
    00372 void DrawFoundation(TileInfo *ti, Foundation f)
    00373 {
    00374   if (!IsFoundation(f)) return;
    00375
    00376   /* Two part foundations must be drawn separately */
    00377   assert(f != FOUNDATION_STEEP_BOTH);
    00378
    00379   uint sprite_block = 0;
    00380   uint z;
    00381   Slope slope = GetFoundationSlope(ti->tile, &z);
    00382
    00383   /* Select the needed block of foundations sprites
    00384    * Block 0: Walls at NW and NE edge
    00385    * Block 1: Wall  at        NE edge
    00386    * Block 2: Wall  at NW        edge
    00387    * Block 3: No walls at NW or NE edge
    00388    */
    00389   if (!HasFoundationNW(ti->tile, slope, z)) sprite_block += 1;
    00390   if (!HasFoundationNE(ti->tile, slope, z)) sprite_block += 2;
    00391
    00392   /* Use the original slope sprites if NW and NE borders should be visible */
    00393   SpriteID leveled_base = (sprite_block == 0 ? (int)SPR_FOUNDATION_BASE : (SPR_SLOPES_VIRTUAL_BASE + sprite_block * SPR_TRKFOUND_BLOCK_SIZE));
    00394   SpriteID inclined_base = SPR_SLOPES_VIRTUAL_BASE + SPR_SLOPES_INCLINED_OFFSET + sprite_block * SPR_TRKFOUND_BLOCK_SIZE;
    00395   SpriteID halftile_base = SPR_HALFTILE_FOUNDATION_BASE + sprite_block * SPR_HALFTILE_BLOCK_SIZE;
    00396
    00397   if (IsSteepSlope(ti->tileh)) {
    00398     if (!IsNonContinuousFoundation(f)) {
    00399       /* Lower part of foundation */
    00400       AddSortableSpriteToDraw(
    00401         leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z
    00402       );
    00403     }
    00404
    00405     Corner highest_corner = GetHighestSlopeCorner(ti->tileh);
    00406     ti->z += ApplyFoundationToSlope(f, &ti->tileh);
    00407
    00408     if (IsInclinedFoundation(f)) {
    00409       /* inclined foundation */
    00410       byte inclined = highest_corner * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
    00411
    00412       AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
    00413         f == FOUNDATION_INCLINED_X ? 16 : 1,
    00414         f == FOUNDATION_INCLINED_Y ? 16 : 1,
    00415         TILE_HEIGHT, ti->z
    00416       );
    00417       OffsetGroundSprite(31, 9);
    00418     } else if (IsLeveledFoundation(f)) {
    00419       AddSortableSpriteToDraw(leveled_base + SlopeWithOneCornerRaised(highest_corner), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z - TILE_HEIGHT);
    00420       OffsetGroundSprite(31, 1);
    00421     } else if (f == FOUNDATION_STEEP_LOWER) {
    00422       /* one corner raised */
    00423       OffsetGroundSprite(31, 1);
    00424     } else {
    00425       /* halftile foundation */
    00426       int x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? 8 : 0);
    00427       int y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? 8 : 0);
    00428
    00429       AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z + TILE_HEIGHT);
    00430       OffsetGroundSprite(31, 9);
    00431     }
    00432   } else {
    00433     if (IsLeveledFoundation(f)) {
    00434       /* leveled foundation */
    00435       AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
    00436       OffsetGroundSprite(31, 1);
    00437     } else if (IsNonContinuousFoundation(f)) {
    00438       /* halftile foundation */
    00439       Corner halftile_corner = GetHalftileFoundationCorner(f);
    00440       int x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? 8 : 0);
    00441       int y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? 8 : 0);
    00442
    00443       AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z);
    00444       OffsetGroundSprite(31, 9);
    00445     } else if (IsSpecialRailFoundation(f)) {
    00446       /* anti-zig-zag foundation */
    00447       SpriteID spr;
    00448       if (ti->tileh == SLOPE_NS || ti->tileh == SLOPE_EW) {
    00449         /* half of leveled foundation under track corner */
    00450         spr = leveled_base + SlopeWithThreeCornersRaised(GetRailFoundationCorner(f));
    00451       } else {
    00452         /* tile-slope = sloped along X/Y, foundation-slope = three corners raised */
    00453         spr = inclined_base + 2 * GetRailFoundationCorner(f) + ((ti->tileh == SLOPE_SW || ti->tileh == SLOPE_NE) ? 1 : 0);
    00454       }
    00455       AddSortableSpriteToDraw(spr, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
    00456       OffsetGroundSprite(31, 9);
    00457     } else {
    00458       /* inclined foundation */
    00459       byte inclined = GetHighestSlopeCorner(ti->tileh) * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
    00460
    00461       AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y,
    00462         f == FOUNDATION_INCLINED_X ? 16 : 1,
    00463         f == FOUNDATION_INCLINED_Y ? 16 : 1,
    00464         TILE_HEIGHT, ti->z
    00465       );
    00466       OffsetGroundSprite(31, 9);
    00467     }
    00468     ti->z += ApplyFoundationToSlope(f, &ti->tileh);
    00469   }
    00470 }
    00471
    00472 void DoClearSquare(TileIndex tile)
    00473 {
    00474   MakeClear(tile, CLEAR_GRASS, _generating_world ? 3 : 0);
    00475   MarkTileDirtyByTile(tile);
    00476 }
    00477
    00487 TrackStatus GetTileTrackStatus(TileIndex tile, TransportType mode, uint sub_mode, DiagDirection side)
    00488 {
    00489   return _tile_type_procs[GetTileType(tile)]->get_tile_track_status_proc(tile, mode, sub_mode, side);
    00490 }
    00491
    00498 void ChangeTileOwner(TileIndex tile, Owner old_owner, Owner new_owner)
    00499 {
    00500   _tile_type_procs[GetTileType(tile)]->change_tile_owner_proc(tile, old_owner, new_owner);
    00501 }
    00502
    00503 void GetAcceptedCargo(TileIndex tile, AcceptedCargo ac)
    00504 {
    00505   memset(ac, 0, sizeof(AcceptedCargo));
    00506   _tile_type_procs[GetTileType(tile)]->get_accepted_cargo_proc(tile, ac);
    00507 }
    00508
    00509 void AnimateTile(TileIndex tile)
    00510 {
    00511   _tile_type_procs[GetTileType(tile)]->animate_tile_proc(tile);
    00512 }
    00513
    00514 bool ClickTile(TileIndex tile)
    00515 {
    00516   return _tile_type_procs[GetTileType(tile)]->click_tile_proc(tile);
    00517 }
    00518
    00519 void GetTileDesc(TileIndex tile, TileDesc *td)
    00520 {
    00521   _tile_type_procs[GetTileType(tile)]->get_tile_desc_proc(tile, td);
    00522 }
    00523
    00529 bool IsSnowLineSet(void)
    00530 {
    00531   return _snow_line != NULL;
    00532 }
    00533
    00539 void SetSnowLine(byte table[SNOW_LINE_MONTHS][SNOW_LINE_DAYS])
    00540 {
    00541   _snow_line = CallocT<SnowLine>(1);
    00542   memcpy(_snow_line->table, table, sizeof(_snow_line->table));
    00543
    00544   for (uint i = 0; i < SNOW_LINE_MONTHS; i++) {
    00545     for (uint j = 0; j < SNOW_LINE_DAYS; j++) {
    00546       _snow_line->highest_value = max(_snow_line->highest_value, table[i][j]);
    00547     }
    00548   }
    00549 }
    00550
    00556 byte GetSnowLine(void)
    00557 {
    00558   if (_snow_line == NULL) return _settings_game.game_creation.snow_line;
    00559
    00560   YearMonthDay ymd;
    00561   ConvertDateToYMD(_date, &ymd);
    00562   return _snow_line->table[ymd.month][ymd.day];
    00563 }
    00564
    00570 byte HighestSnowLine(void)
    00571 {
    00572   return _snow_line == NULL ? _settings_game.game_creation.snow_line : _snow_line->highest_value;
    00573 }
    00574
    00579 void ClearSnowLine(void)
    00580 {
    00581   free(_snow_line);
    00582   _snow_line = NULL;
    00583 }
    00584
    00591 CommandCost CmdLandscapeClear(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00592 {
    00593   return _tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags);
    00594 }
    00595
    00602 CommandCost CmdClearArea(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00603 {
    00604   if (p1 >= MapSize()) return CMD_ERROR;
    00605
    00606   /* make sure sx,sy are smaller than ex,ey */
    00607   int ex = TileX(tile);
    00608   int ey = TileY(tile);
    00609   int sx = TileX(p1);
    00610   int sy = TileY(p1);
    00611   if (ex < sx) Swap(ex, sx);
    00612   if (ey < sy) Swap(ey, sy);
    00613
    00614   Money money = GetAvailableMoneyForCommand();
    00615   CommandCost cost(EXPENSES_CONSTRUCTION);
    00616   bool success = false;
    00617
    00618   for (int x = sx; x <= ex; ++x) {
    00619     for (int y = sy; y <= ey; ++y) {
    00620       CommandCost ret = DoCommand(TileXY(x, y), 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
    00621       if (CmdFailed(ret)) continue;
    00622       success = true;
    00623
    00624       if (flags & DC_EXEC) {
    00625         money -= ret.GetCost();
    00626         if (ret.GetCost() > 0 && money < 0) {
    00627           _additional_cash_required = ret.GetCost();
    00628           return cost;
    00629         }
    00630         DoCommand(TileXY(x, y), 0, 0, flags, CMD_LANDSCAPE_CLEAR);
    00631
    00632         /* draw explosion animation... */
    00633         if ((x == sx || x == ex) && (y == sy || y == ey)) {
    00634           /* big explosion in each corner, or small explosion for single tiles */
    00635           CreateEffectVehicleAbove(x * TILE_SIZE + TILE_SIZE / 2, y * TILE_SIZE + TILE_SIZE / 2, 2,
    00636             sy == ey && sx == ex ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
    00637           );
    00638         }
    00639       }
    00640       cost.AddCost(ret);
    00641     }
    00642   }
    00643
    00644   return (success) ? cost : CMD_ERROR;
    00645 }
    00646
    00647
    00648 TileIndex _cur_tileloop_tile;
    00649 #define TILELOOP_BITS 4
    00650 #define TILELOOP_SIZE (1 << TILELOOP_BITS)
    00651 #define TILELOOP_ASSERTMASK ((TILELOOP_SIZE - 1) + ((TILELOOP_SIZE - 1) << MapLogX()))
    00652 #define TILELOOP_CHKMASK (((1 << (MapLogX() - TILELOOP_BITS))-1) << TILELOOP_BITS)
    00653
    00654 void RunTileLoop()
    00655 {
    00656   TileIndex tile = _cur_tileloop_tile;
    00657
    00658   assert((tile & ~TILELOOP_ASSERTMASK) == 0);
    00659   uint count = (MapSizeX() / TILELOOP_SIZE) * (MapSizeY() / TILELOOP_SIZE);
    00660   do {
    00661     _tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
    00662
    00663     if (TileX(tile) < MapSizeX() - TILELOOP_SIZE) {
    00664       tile += TILELOOP_SIZE; // no overflow
    00665     } else {
    00666       tile = TILE_MASK(tile - TILELOOP_SIZE * (MapSizeX() / TILELOOP_SIZE - 1) + TileDiffXY(0, TILELOOP_SIZE)); /* x would overflow, also increase y */
    00667     }
    00668   } while (--count != 0);
    00669   assert((tile & ~TILELOOP_ASSERTMASK) == 0);
    00670
    00671   tile += 9;
    00672   if (tile & TILELOOP_CHKMASK) {
    00673     tile = (tile + MapSizeX()) & TILELOOP_ASSERTMASK;
    00674   }
    00675   _cur_tileloop_tile = tile;
    00676 }
    00677
    00678 void InitializeLandscape()
    00679 {
    00680   uint maxx = MapMaxX();
    00681   uint maxy = MapMaxY();
    00682   uint sizex = MapSizeX();
    00683
    00684   uint y;
    00685   for (y = _settings_game.construction.freeform_edges ? 1 : 0; y < maxy; y++) {
    00686     uint x;
    00687     for (x = _settings_game.construction.freeform_edges ? 1 : 0; x < maxx; x++) {
    00688       MakeClear(sizex * y + x, CLEAR_GRASS, 3);
    00689       SetTileHeight(sizex * y + x, 0);
    00690       SetTropicZone(sizex * y + x, TROPICZONE_NORMAL);
    00691       ClearBridgeMiddle(sizex * y + x);
    00692     }
    00693     MakeVoid(sizex * y + x);
    00694   }
    00695   for (uint x = 0; x < sizex; x++) MakeVoid(sizex * y + x);
    00696 }
    00697
    00698 static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4  };
    00699 static const byte _genterrain_tbl_2[5] = {  0,  0,  0,  0, 33 };
    00700
    00701 static void GenerateTerrain(int type, uint flag)
    00702 {
    00703   uint32 r = Random();
    00704
    00705   const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845, ST_MAPGEN);
    00706
    00707   uint x = r & MapMaxX();
    00708   uint y = (r >> MapLogX()) & MapMaxY();
    00709
    00710   if (x < 2 || y < 2) return;
    00711
    00712   DiagDirection direction = (DiagDirection)GB(r, 22, 2);
    00713   uint w = templ->width;
    00714   uint h = templ->height;
    00715
    00716   if (DiagDirToAxis(direction) == AXIS_Y) Swap(w, h);
    00717
    00718   const byte *p = templ->data;
    00719
    00720   if ((flag & 4) != 0) {
    00721     uint xw = x * MapSizeY();
    00722     uint yw = y * MapSizeX();
    00723     uint bias = (MapSizeX() + MapSizeY()) * 16;
    00724
    00725     switch (flag & 3) {
    00726       default: NOT_REACHED();
    00727       case 0:
    00728         if (xw + yw > MapSize() - bias) return;
    00729         break;
    00730
    00731       case 1:
    00732         if (yw < xw + bias) return;
    00733         break;
    00734
    00735       case 2:
    00736         if (xw + yw < MapSize() + bias) return;
    00737         break;
    00738
    00739       case 3:
    00740         if (xw < yw + bias) return;
    00741         break;
    00742     }
    00743   }
    00744
    00745   if (x + w >= MapMaxX() - 1) return;
    00746   if (y + h >= MapMaxY() - 1) return;
    00747
    00748   Tile *tile = &_m[TileXY(x, y)];
    00749
    00750   switch (direction) {
    00751     default: NOT_REACHED();
    00752     case DIAGDIR_NE:
    00753       do {
    00754         Tile *tile_cur = tile;
    00755
    00756         for (uint w_cur = w; w_cur != 0; --w_cur) {
    00757           if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
    00758           p++;
    00759           tile_cur++;
    00760         }
    00761         tile += TileDiffXY(0, 1);
    00762       } while (--h != 0);
    00763       break;
    00764
    00765     case DIAGDIR_SE:
    00766       do {
    00767         Tile *tile_cur = tile;
    00768
    00769         for (uint h_cur = h; h_cur != 0; --h_cur) {
    00770           if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
    00771           p++;
    00772           tile_cur += TileDiffXY(0, 1);
    00773         }
    00774         tile += TileDiffXY(1, 0);
    00775       } while (--w != 0);
    00776       break;
    00777
    00778     case DIAGDIR_SW:
    00779       tile += TileDiffXY(w - 1, 0);
    00780       do {
    00781         Tile *tile_cur = tile;
    00782
    00783         for (uint w_cur = w; w_cur != 0; --w_cur) {
    00784           if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
    00785           p++;
    00786           tile_cur--;
    00787         }
    00788         tile += TileDiffXY(0, 1);
    00789       } while (--h != 0);
    00790       break;
    00791
    00792     case DIAGDIR_NW:
    00793       tile += TileDiffXY(0, h - 1);
    00794       do {
    00795         Tile *tile_cur = tile;
    00796
    00797         for (uint h_cur = h; h_cur != 0; --h_cur) {
    00798           if (*p >= tile_cur->type_height) tile_cur->type_height = *p;
    00799           p++;
    00800           tile_cur -= TileDiffXY(0, 1);
    00801         }
    00802         tile += TileDiffXY(1, 0);
    00803       } while (--w != 0);
    00804       break;
    00805   }
    00806 }
    00807
    00808
    00809 #include "table/genland.h"
    00810
    00811 static void CreateDesertOrRainForest()
    00812 {
    00813   TileIndex update_freq = MapSize() / 4;
    00814   const TileIndexDiffC *data;
    00815
    00816   for (TileIndex tile = 0; tile != MapSize(); ++tile) {
    00817     if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00818
    00819     for (data = _make_desert_or_rainforest_data;
    00820         data != endof(_make_desert_or_rainforest_data); ++data) {
    00821       TileIndex t = TILE_MASK(tile + ToTileIndexDiff(*data));
    00822       if (TileHeight(t) >= 4 || IsTileType(t, MP_WATER)) break;
    00823     }
    00824     if (data == endof(_make_desert_or_rainforest_data))
    00825       SetTropicZone(tile, TROPICZONE_DESERT);
    00826   }
    00827
    00828   for (uint i = 0; i != 256; i++) {
    00829     if ((i % 64) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00830
    00831     RunTileLoop();
    00832   }
    00833
    00834   for (TileIndex tile = 0; tile != MapSize(); ++tile) {
    00835     if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00836
    00837     for (data = _make_desert_or_rainforest_data;
    00838         data != endof(_make_desert_or_rainforest_data); ++data) {
    00839       TileIndex t = TILE_MASK(tile + ToTileIndexDiff(*data));
    00840       if (IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_DESERT)) break;
    00841     }
    00842     if (data == endof(_make_desert_or_rainforest_data))
    00843       SetTropicZone(tile, TROPICZONE_RAINFOREST);
    00844   }
    00845 }
    00846
    00847 void GenerateLandscape(byte mode)
    00848 {
    00849   static const int gwp_desert_amount = 4 + 8;
    00850
    00851   if (mode == GW_HEIGHTMAP) {
    00852     SetGeneratingWorldProgress(GWP_LANDSCAPE, (_settings_game.game_creation.landscape == LT_TROPIC) ? 1 + gwp_desert_amount : 1);
    00853     LoadHeightmap(_file_to_saveload.name);
    00854     IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00855   } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) {
    00856     SetGeneratingWorldProgress(GWP_LANDSCAPE, (_settings_game.game_creation.landscape == LT_TROPIC) ? 3 + gwp_desert_amount : 3);
    00857     GenerateTerrainPerlin();
    00858   } else {
    00859     switch (_settings_game.game_creation.landscape) {
    00860       case LT_ARCTIC: {
    00861         SetGeneratingWorldProgress(GWP_LANDSCAPE, 2);
    00862
    00863         uint32 r = Random();
    00864
    00865         for (uint i = ScaleByMapSize(GB(r, 0, 7) + 950); i != 0; --i) {
    00866           GenerateTerrain(2, 0);
    00867         }
    00868         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00869
    00870         uint flag = GB(r, 7, 2) | 4;
    00871         for (uint i = ScaleByMapSize(GB(r, 9, 7) + 450); i != 0; --i) {
    00872           GenerateTerrain(4, flag);
    00873         }
    00874         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00875       } break;
    00876
    00877       case LT_TROPIC: {
    00878         SetGeneratingWorldProgress(GWP_LANDSCAPE, 3 + gwp_desert_amount);
    00879
    00880         uint32 r = Random();
    00881
    00882         for (uint i = ScaleByMapSize(GB(r, 0, 7) + 170); i != 0; --i) {
    00883           GenerateTerrain(0, 0);
    00884         }
    00885         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00886
    00887         uint flag = GB(r, 7, 2) | 4;
    00888         for (uint i = ScaleByMapSize(GB(r, 9, 8) + 1700); i != 0; --i) {
    00889           GenerateTerrain(0, flag);
    00890         }
    00891         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00892
    00893         flag ^= 2;
    00894
    00895         for (uint i = ScaleByMapSize(GB(r, 17, 7) + 410); i != 0; --i) {
    00896           GenerateTerrain(3, flag);
    00897         }
    00898         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00899       } break;
    00900
    00901       default: {
    00902         SetGeneratingWorldProgress(GWP_LANDSCAPE, 1);
    00903
    00904         uint32 r = Random();
    00905
    00906         uint i = ScaleByMapSize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100);
    00907         for (; i != 0; --i) {
    00908           GenerateTerrain(_settings_game.difficulty.terrain_type, 0);
    00909         }
    00910         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
    00911       } break;
    00912     }
    00913   }
    00914
    00915   ConvertGroundTilesIntoWaterTiles();
    00916
    00917   if (_settings_game.game_creation.landscape == LT_TROPIC) CreateDesertOrRainForest();
    00918 }
    00919
    00920 void OnTick_Town();
    00921 void OnTick_Trees();
    00922 void OnTick_Station();
    00923 void OnTick_Industry();
    00924
    00925 void OnTick_Companies();
    00926 void OnTick_Train();
    00927
    00928 void CallLandscapeTick()
    00929 {
    00930   OnTick_Town();
    00931   OnTick_Trees();
    00932   OnTick_Station();
    00933   OnTick_Industry();
    00934
    00935   OnTick_Companies();
    00936   OnTick_Train();
    00937 }
    00938
    00939 TileIndex AdjustTileCoordRandomly(TileIndex a, byte rng)
    00940 {
    00941   int rn = rng;
    00942   uint32 r = Random();
    00943
    00944   return TILE_MASK(TileXY(
    00945     TileX(a) + (GB(r, 0, 8) * rn * 2 >> 8) - rn,
    00946     TileY(a) + (GB(r, 8, 8) * rn * 2 >> 8) - rn
    00947   ));
    00948 }