landscape.cpp

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

Generated on Mon Sep 22 20:34:16 2008 for openttd by  doxygen 1.5.6