trafficlight.cpp

Go to the documentation of this file.
00001 /* $Id: trafficlight.cpp $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "openttd.h"
00014 #include "landscape.h"
00015 #include "sprite.h"
00016 #include "viewport_func.h"
00017 #include "road_map.h"
00018 #include "command_func.h"
00019 #include "cheat_func.h"
00020 #include "animated_tile_func.h"
00021 #include "economy_func.h"
00022 #include "road_cmd.h"
00023 #include "company_func.h"
00024 #include "company_base.h"
00025 #include "settings_type.h"
00026 #include "trafficlight.h"
00027 #include "trafficlight_type.h"
00028 #include "date_func.h"
00029 #include "company_func.h"
00030 
00031 #include "table/sprites.h"
00032 #include "table/strings.h"
00033 
00034 #include <set>
00035 
00036 
00037 /* A traffic light consist (TLC) is a set of adjacent tiles with traffic lights on them.
00038  * They are linked together to form a big traffic light junction. */
00039 typedef std::set<TileIndex> TLC;
00040 
00048 TLC *GetTrafficLightConsist(TileIndex tile, bool checkroadworks)
00049 {
00050   TLC *visited;
00051   TLC *candidates;
00052 
00053   visited = new TLC;
00054   candidates = new TLC;
00055   candidates->insert(tile);
00056 
00057   while (!candidates->empty()) {
00058     TLC::iterator cur = candidates->begin();
00059     if (checkroadworks && HasRoadWorks(*cur)) {
00060       delete visited;
00061       delete candidates;
00062       return 0;
00063     }
00064     uint8 distance_between_traffic_lights = _tlc_distance[_settings_game.construction.max_tlc_distance];
00065     for (int i = 0; i < distance_between_traffic_lights; i++) {
00066       TileIndex neighbor = *cur + ToTileIndexDiff(_tl_check_offsets[i]);
00067       if (HasTrafficLights(neighbor) && (visited->find(neighbor) == visited->end())) candidates->insert(neighbor);
00068     }
00069     visited->insert(*cur);
00070     candidates->erase(cur);
00071   }
00072   delete candidates;
00073   return visited;
00074 }
00075 
00082 TileIndex GetTLCLowestTileIndexOrRoadWorks(TileIndex tile)
00083 {
00084   TLC *consist = GetTrafficLightConsist(tile, true);
00085   TileIndex result = 0;
00086   if (consist != 0) result = *(consist->begin());
00087   delete consist;
00088   return result;
00089 }
00090 
00098 TrafficLightState GetTLState(TileIndex tile)
00099 {
00100   assert(HasTrafficLights(tile));
00101   if (_game_mode == GM_EDITOR) return TLS_OFF;    
00102   tile = GetTLCLowestTileIndexOrRoadWorks(tile);
00103   if (tile == 0) return TLS_OFF;                  
00104 
00105   uint16 tl_total = 16 * _settings_game.construction.traffic_lights_green_phase;          // There are (16 * patchsetting) "TL ticks".
00106   uint16 tl_tick = ((_tick_counter / 16) + 5 * TileX(tile) + 7 * TileY(tile)) % tl_total; // Each "TL tick" consists of 16 gameticks.
00107 
00108   if (tl_tick < ((tl_total / 2) - 2)) return TLS_X_GREEN_Y_RED;      
00109   if (tl_tick < ((tl_total / 2) - 1)) return TLS_X_YELLOW_Y_RED;     
00110   if (tl_tick < (tl_total / 2))       return TLS_X_RED_Y_REDYELLOW;  
00111   if (tl_tick < (tl_total - 2))       return TLS_X_RED_Y_GREEN;      
00112   if (tl_tick < (tl_total - 1))       return TLS_X_RED_Y_YELLOW;     
00113   if (tl_tick < tl_total)             return TLS_X_REDYELLOW_Y_RED;  
00114 
00115   NOT_REACHED();
00116   return TLS_OFF;
00117 }
00118 
00122 static const TrackdirBits _tls_to_trackdir[7] = {
00123   TRACKDIR_BIT_MASK,                                
00124   TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_Y_SE |           
00125     TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_LOWER_W |    
00126     TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_RIGHT_N,      
00127   TRACKDIR_BIT_MASK,                                
00128   TRACKDIR_BIT_MASK,                                
00129   TRACKDIR_BIT_X_SW | TRACKDIR_BIT_X_NE |           
00130     TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_LOWER_E |    
00131     TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_RIGHT_S,      
00132   TRACKDIR_BIT_MASK,                                
00133   TRACKDIR_BIT_MASK,                                
00134 };
00135 
00141 TrackdirBits GetIntraTLCAllowedDirections(TileIndex tile)
00142 {
00143   TrackdirBits trackdirbits = TRACKDIR_BIT_NONE;
00144 
00145   if (HasTrafficLights(tile + TileDiffXY( 1,  0))) // SW.
00146     trackdirbits |= TRACKDIR_BIT_X_NE | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_LEFT_N;
00147   if (HasTrafficLights(tile + TileDiffXY( 0,  1))) // SE
00148     trackdirbits |= TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_RIGHT_N;
00149   if (HasTrafficLights(tile + TileDiffXY( 0, -1))) // NW.
00150     trackdirbits |= TRACKDIR_BIT_Y_SE | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_LEFT_S;
00151   if (HasTrafficLights(tile + TileDiffXY(-1,  0))) // NE.
00152     trackdirbits |= TRACKDIR_BIT_X_SW | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_RIGHT_S;
00153 
00154   return trackdirbits;
00155 }
00156 
00162 TrackdirBits GetTrafficLightDisallowedDirections(TileIndex tile)
00163 {
00164   return (_tls_to_trackdir[GetTLState(tile)] & ~GetIntraTLCAllowedDirections(tile));
00165 }
00166 
00172 bool CheckTLCSize(TileIndex tile)
00173 {
00174   if (_settings_game.construction.max_tlc_size == 0) return true;
00175   TLC *consist = GetTrafficLightConsist(tile, false);
00176   bool result = (consist->size() <= _settings_game.construction.max_tlc_size);
00177   delete consist;
00178   return result;
00179 }
00180 
00189 CommandCost CmdBuildTrafficLights(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00190 {
00191   /* Check if traffic lights are enabled. */
00192   if (!_settings_game.construction.traffic_lights) return CMD_ERROR; // Sanity check.
00193 
00194   /* Check for correct location (road). */
00195   if (!IsTileType(tile, MP_ROAD) || GetRoadTileType(tile) != ROAD_TILE_NORMAL) return_cmd_error(STR_ERROR_THERE_IS_NO_ROAD);
00196 
00197   /* Check owner only if a valid player is executing this command. */
00198   if (Company::IsValidID(_current_company)) {
00199     Owner owner = GetTileOwner(tile);
00200     if (owner == OWNER_TOWN) {
00201       if (!_settings_game.construction.allow_building_tls_in_towns) return_cmd_error(STR_ERROR_TRAFFIC_LIGHTS_NOT_ALLOWED_ON_TOWN_ROADS);
00202     } else {
00203       if (owner != OWNER_NONE && !IsTileOwner(tile, _current_company)) return_cmd_error(STR_ERROR_AREA_IS_OWNED_BY_ANOTHER); // Owned by ... already displayed in CheckOwnership.
00204     }
00205   }
00206 
00207   /* Check junction and already built. */
00208   if (CountBits(GetAllRoadBits(tile)) < 3) return_cmd_error(STR_ERROR_CAN_ONLY_BE_PLACED_ON_ROAD_JUNCTIONS);
00209   if (HasTrafficLights(tile)) return_cmd_error(STR_ERROR_ALREADY_BUILT);
00210 
00211   if (!CheckTLCSize(tile)) return_cmd_error(STR_ERROR_TRAFFIC_LIGHT_CONSIST_TOO_BIG);
00212 
00213   /* Now we may build the traffic lights. */
00214   if (flags & DC_EXEC) {
00215     MakeTrafficLights(tile);
00216     AddAnimatedTile(tile);
00217     MarkTileDirtyByTile(tile);
00218   }
00219   return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
00220 }
00221 
00230 CommandCost CmdRemoveTrafficLights(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00231 {
00232   /* Check for correct location (road with traffic lights). */
00233   if (!IsTileType(tile, MP_ROAD) || GetRoadTileType(tile) != ROAD_TILE_NORMAL || !HasTrafficLights(tile)) return CMD_ERROR;
00234 
00235   /* Check owner, but only if a valid player is executing this command. */
00236   if (Company::IsValidID(_current_company)) {
00237     Owner owner = GetTileOwner(tile);
00238     if (owner == OWNER_TOWN) {
00239       if (!_settings_game.construction.allow_building_tls_in_towns && !_cheats.magic_bulldozer.value) return_cmd_error(STR_ERROR_TRAFFIC_LIGHTS_NOT_ALLOWED_ON_TOWN_ROADS);
00240     } else {
00241       if (owner != OWNER_NONE && !IsTileOwner(tile, _current_company)) return CMD_ERROR; // Owned by ... already displayed in CheckOwnership.
00242     }
00243   }
00244 
00245   /* Now we may remove the traffic lights. */
00246   if (flags & DC_EXEC) {
00247     DeleteAnimatedTile(tile);
00248     ClearTrafficLights(tile);
00249     MarkTileDirtyByTile(tile);
00250   }
00251   return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS]);
00252 }
00256 void ClearAllTrafficLights()
00257 {
00258   /* Iterate over the whole map and remove any trafficlights found. */
00259   for (TileIndex tile = 0; tile < MapSize(); tile++) {
00260     if (HasTrafficLights(tile)) {
00261       DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_TRAFFICLIGHTS);
00262     }
00263   }
00264 }
00265 
00270 void DrawTrafficLights(TileInfo* ti)
00271 {
00272   RoadBits road = GetAllRoadBits(ti->tile);
00273   TrafficLightState state = GetTLState(ti->tile);
00274 
00275   const TileIndex neighbor[4] = { ti->tile + TileDiffXY(1, 0), // SW.
00276           ti->tile + TileDiffXY(0, 1),                 // SE.
00277           ti->tile + TileDiffXY(0, -1),                // NW.
00278           ti->tile + TileDiffXY(-1, 0)};               // NE.
00279   const RoadBits rb[4] = {ROAD_SW, ROAD_SE, ROAD_NW, ROAD_NE};
00280 
00281   /* Draw the four directions. */
00282   byte rs = _settings_game.vehicle.road_side;
00283   for (int i = 0; i < 4; i++) {
00284     if (road & rb[i] && !HasTrafficLights(neighbor[i])) {
00285       DisallowedRoadDirections drd = DRD_NONE;
00286       if (IsTileType(neighbor[i], MP_ROAD) && IsNormalRoad(neighbor[i])) drd = GetDisallowedRoadDirections(neighbor[i]);
00287       if (drd != ((i % 2 == 0) ? DRD_SOUTHBOUND : DRD_NORTHBOUND) && drd != DRD_BOTH)
00288         DrawRoadDetail(_tls_to_sprites[state][i], ti, _tl_offsets[rs][i].x, _tl_offsets[rs][i].y, 12);
00289     }
00290   }
00291 }