# 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 }