landscape.cpp

Go to the documentation of this file.
00001 /* $Id: landscape.cpp 15718 2009-03-15 00:32:18Z 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   _snow_line->lowest_value = 0xFF;
00543   memcpy(_snow_line->table, table, sizeof(_snow_line->table));
00544 
00545   for (uint i = 0; i < SNOW_LINE_MONTHS; i++) {
00546     for (uint j = 0; j < SNOW_LINE_DAYS; j++) {
00547       _snow_line->highest_value = max(_snow_line->highest_value, table[i][j]);
00548       _snow_line->lowest_value = min(_snow_line->lowest_value, table[i][j]);
00549     }
00550   }
00551 }
00552 
00558 byte GetSnowLine(void)
00559 {
00560   if (_snow_line == NULL) return _settings_game.game_creation.snow_line;
00561 
00562   YearMonthDay ymd;
00563   ConvertDateToYMD(_date, &ymd);
00564   return _snow_line->table[ymd.month][ymd.day];
00565 }
00566 
00572 byte HighestSnowLine(void)
00573 {
00574   return _snow_line == NULL ? _settings_game.game_creation.snow_line : _snow_line->highest_value;
00575 }
00576 
00582 byte LowestSnowLine(void)
00583 {
00584   return _snow_line == NULL ? _settings_game.game_creation.snow_line : _snow_line->lowest_value;
00585 }
00586 
00591 void ClearSnowLine(void)
00592 {
00593   free(_snow_line);
00594   _snow_line = NULL;
00595 }
00596 
00603 CommandCost CmdLandscapeClear(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00604 {
00605   return _tile_type_procs[GetTileType(tile)]->clear_tile_proc(tile, flags);
00606 }
00607 
00614 CommandCost CmdClearArea(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00615 {
00616   if (p1 >= MapSize()) return CMD_ERROR;
00617 
00618   /* make sure sx,sy are smaller than ex,ey */
00619   int ex = TileX(tile);
00620   int ey = TileY(tile);
00621   int sx = TileX(p1);
00622   int sy = TileY(p1);
00623   if (ex < sx) Swap(ex, sx);
00624   if (ey < sy) Swap(ey, sy);
00625 
00626   Money money = GetAvailableMoneyForCommand();
00627   CommandCost cost(EXPENSES_CONSTRUCTION);
00628   bool success = false;
00629 
00630   for (int x = sx; x <= ex; ++x) {
00631     for (int y = sy; y <= ey; ++y) {
00632       CommandCost ret = DoCommand(TileXY(x, y), 0, 0, flags & ~DC_EXEC, CMD_LANDSCAPE_CLEAR);
00633       if (CmdFailed(ret)) continue;
00634       success = true;
00635 
00636       if (flags & DC_EXEC) {
00637         money -= ret.GetCost();
00638         if (ret.GetCost() > 0 && money < 0) {
00639           _additional_cash_required = ret.GetCost();
00640           return cost;
00641         }
00642         DoCommand(TileXY(x, y), 0, 0, flags, CMD_LANDSCAPE_CLEAR);
00643 
00644         /* draw explosion animation... */
00645         if ((x == sx || x == ex) && (y == sy || y == ey)) {
00646           /* big explosion in each corner, or small explosion for single tiles */
00647           CreateEffectVehicleAbove(x * TILE_SIZE + TILE_SIZE / 2, y * TILE_SIZE + TILE_SIZE / 2, 2,
00648             sy == ey && sx == ex ? EV_EXPLOSION_SMALL : EV_EXPLOSION_LARGE
00649           );
00650         }
00651       }
00652       cost.AddCost(ret);
00653     }
00654   }
00655 
00656   return (success) ? cost : CMD_ERROR;
00657 }
00658 
00659 
00660 TileIndex _cur_tileloop_tile;
00661 #define TILELOOP_BITS 4
00662 #define TILELOOP_SIZE (1 << TILELOOP_BITS)
00663 #define TILELOOP_ASSERTMASK ((TILELOOP_SIZE - 1) + ((TILELOOP_SIZE - 1) << MapLogX()))
00664 #define TILELOOP_CHKMASK (((1 << (MapLogX() - TILELOOP_BITS))-1) << TILELOOP_BITS)
00665 
00666 void RunTileLoop()
00667 {
00668   TileIndex tile = _cur_tileloop_tile;
00669 
00670   assert((tile & ~TILELOOP_ASSERTMASK) == 0);
00671   uint count = (MapSizeX() / TILELOOP_SIZE) * (MapSizeY() / TILELOOP_SIZE);
00672   do {
00673     _tile_type_procs[GetTileType(tile)]->tile_loop_proc(tile);
00674 
00675     if (TileX(tile) < MapSizeX() - TILELOOP_SIZE) {
00676       tile += TILELOOP_SIZE; // no overflow
00677     } else {
00678       tile = TILE_MASK(tile - TILELOOP_SIZE * (MapSizeX() / TILELOOP_SIZE - 1) + TileDiffXY(0, TILELOOP_SIZE)); // x would overflow, also increase y
00679     }
00680   } while (--count != 0);
00681   assert((tile & ~TILELOOP_ASSERTMASK) == 0);
00682 
00683   tile += 9;
00684   if (tile & TILELOOP_CHKMASK) {
00685     tile = (tile + MapSizeX()) & TILELOOP_ASSERTMASK;
00686   }
00687   _cur_tileloop_tile = tile;
00688 }
00689 
00690 void InitializeLandscape()
00691 {
00692   uint maxx = MapMaxX();
00693   uint maxy = MapMaxY();
00694   uint sizex = MapSizeX();
00695 
00696   uint y;
00697   for (y = _settings_game.construction.freeform_edges ? 1 : 0; y < maxy; y++) {
00698     uint x;
00699     for (x = _settings_game.construction.freeform_edges ? 1 : 0; x < maxx; x++) {
00700       MakeClear(sizex * y + x, CLEAR_GRASS, 3);
00701       SetTileHeight(sizex * y + x, 0);
00702       SetTropicZone(sizex * y + x, TROPICZONE_NORMAL);
00703       ClearBridgeMiddle(sizex * y + x);
00704     }
00705     MakeVoid(sizex * y + x);
00706   }
00707   for (uint x = 0; x < sizex; x++) MakeVoid(sizex * y + x);
00708 }
00709 
00710 static const byte _genterrain_tbl_1[5] = { 10, 22, 33, 37, 4  };
00711 static const byte _genterrain_tbl_2[5] = {  0,  0,  0,  0, 33 };
00712 
00713 static void GenerateTerrain(int type, uint flag)
00714 {
00715   uint32 r = Random();
00716 
00717   const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845, ST_MAPGEN);
00718 
00719   uint x = r & MapMaxX();
00720   uint y = (r >> MapLogX()) & MapMaxY();
00721 
00722   if (x < 2 || y < 2) return;
00723 
00724   DiagDirection direction = (DiagDirection)GB(r, 22, 2);
00725   uint w = templ->width;
00726   uint h = templ->height;
00727 
00728   if (DiagDirToAxis(direction) == AXIS_Y) Swap(w, h);
00729 
00730   const byte *p = templ->data;
00731 
00732   if ((flag & 4) != 0) {
00733     uint xw = x * MapSizeY();
00734     uint yw = y * MapSizeX();
00735     uint bias = (MapSizeX() + MapSizeY()) * 16;
00736 
00737     switch (flag & 3) {
00738       default: NOT_REACHED();
00739       case 0:
00740         if (xw + yw > MapSize() - bias) return;
00741         break;
00742 
00743       case 1:
00744         if (yw < xw + bias) return;
00745         break;
00746 
00747       case 2:
00748         if (xw + yw < MapSize() + bias) return;
00749         break;
00750 
00751       case 3:
00752         if (xw < yw + bias) return;
00753         break;
00754     }
00755   }
00756 
00757   if (x + w >= MapMaxX() - 1) return;
00758   if (y + h >= MapMaxY() - 1) return;
00759 
00760   Tile *tile = &_m[TileXY(x, y)];
00761 
00762   switch (direction) {
00763     default: NOT_REACHED();
00764     case DIAGDIR_NE:
00765       do {
00766         Tile *tile_cur = tile;
00767 
00768         for (uint w_cur = w; w_cur != 0; --w_cur) {
00769           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00770           p++;
00771           tile_cur++;
00772         }
00773         tile += TileDiffXY(0, 1);
00774       } while (--h != 0);
00775       break;
00776 
00777     case DIAGDIR_SE:
00778       do {
00779         Tile *tile_cur = tile;
00780 
00781         for (uint h_cur = h; h_cur != 0; --h_cur) {
00782           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00783           p++;
00784           tile_cur += TileDiffXY(0, 1);
00785         }
00786         tile += TileDiffXY(1, 0);
00787       } while (--w != 0);
00788       break;
00789 
00790     case DIAGDIR_SW:
00791       tile += TileDiffXY(w - 1, 0);
00792       do {
00793         Tile *tile_cur = tile;
00794 
00795         for (uint w_cur = w; w_cur != 0; --w_cur) {
00796           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00797           p++;
00798           tile_cur--;
00799         }
00800         tile += TileDiffXY(0, 1);
00801       } while (--h != 0);
00802       break;
00803 
00804     case DIAGDIR_NW:
00805       tile += TileDiffXY(0, h - 1);
00806       do {
00807         Tile *tile_cur = tile;
00808 
00809         for (uint h_cur = h; h_cur != 0; --h_cur) {
00810           if (GB(*p, 0, 4) >= tile_cur->type_height) tile_cur->type_height = GB(*p, 0, 4);
00811           p++;
00812           tile_cur -= TileDiffXY(0, 1);
00813         }
00814         tile += TileDiffXY(1, 0);
00815       } while (--w != 0);
00816       break;
00817   }
00818 
00819   FixSlopes();
00820 }
00821 
00822 
00823 #include "table/genland.h"
00824 
00825 static void CreateDesertOrRainForest()
00826 {
00827   TileIndex update_freq = MapSize() / 4;
00828   const TileIndexDiffC *data;
00829 
00830   for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00831     if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00832 
00833     for (data = _make_desert_or_rainforest_data;
00834         data != endof(_make_desert_or_rainforest_data); ++data) {
00835       TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00836       if (t != INVALID_TILE && (TileHeight(t) >= 4 || IsTileType(t, MP_WATER))) break;
00837     }
00838     if (data == endof(_make_desert_or_rainforest_data))
00839       SetTropicZone(tile, TROPICZONE_DESERT);
00840   }
00841 
00842   for (uint i = 0; i != 256; i++) {
00843     if ((i % 64) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00844 
00845     RunTileLoop();
00846   }
00847 
00848   for (TileIndex tile = 0; tile != MapSize(); ++tile) {
00849     if ((tile % update_freq) == 0) IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00850 
00851     for (data = _make_desert_or_rainforest_data;
00852         data != endof(_make_desert_or_rainforest_data); ++data) {
00853       TileIndex t = AddTileIndexDiffCWrap(tile, *data);
00854       if (t != INVALID_TILE && IsTileType(t, MP_CLEAR) && IsClearGround(t, CLEAR_DESERT)) break;
00855     }
00856     if (data == endof(_make_desert_or_rainforest_data))
00857       SetTropicZone(tile, TROPICZONE_RAINFOREST);
00858   }
00859 }
00860 
00861 void GenerateLandscape(byte mode)
00862 {
00863   static const int gwp_desert_amount = 4 + 8;
00864 
00865   if (mode == GW_HEIGHTMAP) {
00866     SetGeneratingWorldProgress(GWP_LANDSCAPE, (_settings_game.game_creation.landscape == LT_TROPIC) ? 1 + gwp_desert_amount : 1);
00867     LoadHeightmap(_file_to_saveload.name);
00868     IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00869   } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) {
00870     SetGeneratingWorldProgress(GWP_LANDSCAPE, (_settings_game.game_creation.landscape == LT_TROPIC) ? 3 + gwp_desert_amount : 3);
00871     GenerateTerrainPerlin();
00872   } else {
00873     if (_settings_game.construction.freeform_edges) {
00874       for (uint x = 0; x < MapSizeX(); x++) MakeVoid(TileXY(x, 0));
00875       for (uint y = 0; y < MapSizeY(); y++) MakeVoid(TileXY(0, y));
00876     }
00877     switch (_settings_game.game_creation.landscape) {
00878       case LT_ARCTIC: {
00879         SetGeneratingWorldProgress(GWP_LANDSCAPE, 2);
00880 
00881         uint32 r = Random();
00882 
00883         for (uint i = ScaleByMapSize(GB(r, 0, 7) + 950); i != 0; --i) {
00884           GenerateTerrain(2, 0);
00885         }
00886         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00887 
00888         uint flag = GB(r, 7, 2) | 4;
00889         for (uint i = ScaleByMapSize(GB(r, 9, 7) + 450); i != 0; --i) {
00890           GenerateTerrain(4, flag);
00891         }
00892         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00893       } break;
00894 
00895       case LT_TROPIC: {
00896         SetGeneratingWorldProgress(GWP_LANDSCAPE, 3 + gwp_desert_amount);
00897 
00898         uint32 r = Random();
00899 
00900         for (uint i = ScaleByMapSize(GB(r, 0, 7) + 170); i != 0; --i) {
00901           GenerateTerrain(0, 0);
00902         }
00903         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00904 
00905         uint flag = GB(r, 7, 2) | 4;
00906         for (uint i = ScaleByMapSize(GB(r, 9, 8) + 1700); i != 0; --i) {
00907           GenerateTerrain(0, flag);
00908         }
00909         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00910 
00911         flag ^= 2;
00912 
00913         for (uint i = ScaleByMapSize(GB(r, 17, 7) + 410); i != 0; --i) {
00914           GenerateTerrain(3, flag);
00915         }
00916         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00917       } break;
00918 
00919       default: {
00920         SetGeneratingWorldProgress(GWP_LANDSCAPE, 1);
00921 
00922         uint32 r = Random();
00923 
00924         uint i = ScaleByMapSize(GB(r, 0, 7) + (3 - _settings_game.difficulty.quantity_sea_lakes) * 256 + 100);
00925         for (; i != 0; --i) {
00926           GenerateTerrain(_settings_game.difficulty.terrain_type, 0);
00927         }
00928         IncreaseGeneratingWorldProgress(GWP_LANDSCAPE);
00929       } break;
00930     }
00931   }
00932 
00933   ConvertGroundTilesIntoWaterTiles();
00934 
00935   if (_settings_game.game_creation.landscape == LT_TROPIC) CreateDesertOrRainForest();
00936 }
00937 
00938 void OnTick_Town();
00939 void OnTick_Trees();
00940 void OnTick_Station();
00941 void OnTick_Industry();
00942 
00943 void OnTick_Companies();
00944 void OnTick_Train();
00945 
00946 void CallLandscapeTick()
00947 {
00948   OnTick_Town();
00949   OnTick_Trees();
00950   OnTick_Station();
00951   OnTick_Industry();
00952 
00953   OnTick_Companies();
00954   OnTick_Train();
00955 }

Generated on Sun Mar 15 22:49:46 2009 for openttd by  doxygen 1.5.6