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 }

Generated on Mon Feb 16 23:12:07 2009 for openttd by  doxygen 1.5.6