Files
@ r28060:53690f1ef210
Branch filter:
Location: cpp/openttd-patchpack/source/src/road.cpp
r28060:53690f1ef210
10.2 KiB
text/x-c
Feature: Base graphics can offer parameters for additional settings.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | /*
* This file is part of OpenTTD.
* 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.
* 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.
* 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/>.
*/
/** @file road.cpp Generic road related functions. */
#include "stdafx.h"
#include "rail_map.h"
#include "road_map.h"
#include "water_map.h"
#include "genworld.h"
#include "company_func.h"
#include "company_base.h"
#include "engine_base.h"
#include "timer/timer_game_calendar.h"
#include "landscape.h"
#include "road.h"
#include "road_func.h"
#include "roadveh.h"
#include "safeguards.h"
/**
* Return if the tile is a valid tile for a crossing.
*
* @param tile the current tile
* @param ax the axis of the road over the rail
* @return true if it is a valid tile
*/
static bool IsPossibleCrossing(const TileIndex tile, Axis ax)
{
return (IsTileType(tile, MP_RAILWAY) &&
GetRailTileType(tile) == RAIL_TILE_NORMAL &&
GetTrackBits(tile) == (ax == AXIS_X ? TRACK_BIT_Y : TRACK_BIT_X) &&
GetFoundationSlope(tile) == SLOPE_FLAT);
}
/**
* Clean up unnecessary RoadBits of a planned tile.
* @param tile current tile
* @param org_rb planned RoadBits
* @return optimised RoadBits
*/
RoadBits CleanUpRoadBits(const TileIndex tile, RoadBits org_rb)
{
if (!IsValidTile(tile)) return ROAD_NONE;
for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) {
const TileIndex neighbor_tile = TileAddByDiagDir(tile, dir);
/* Get the Roadbit pointing to the neighbor_tile */
const RoadBits target_rb = DiagDirToRoadBits(dir);
/* If the roadbit is in the current plan */
if (org_rb & target_rb) {
bool connective = false;
const RoadBits mirrored_rb = MirrorRoadBits(target_rb);
if (IsValidTile(neighbor_tile)) {
switch (GetTileType(neighbor_tile)) {
/* Always connective ones */
case MP_CLEAR: case MP_TREES:
connective = true;
break;
/* The conditionally connective ones */
case MP_TUNNELBRIDGE:
case MP_STATION:
case MP_ROAD:
if (IsNormalRoadTile(neighbor_tile)) {
/* Always connective */
connective = true;
} else {
const RoadBits neighbor_rb = GetAnyRoadBits(neighbor_tile, RTT_ROAD) | GetAnyRoadBits(neighbor_tile, RTT_TRAM);
/* Accept only connective tiles */
connective = (neighbor_rb & mirrored_rb) != ROAD_NONE;
}
break;
case MP_RAILWAY:
connective = IsPossibleCrossing(neighbor_tile, DiagDirToAxis(dir));
break;
case MP_WATER:
/* Check for real water tile */
connective = !IsWater(neighbor_tile);
break;
/* The definitely not connective ones */
default: break;
}
}
/* If the neighbor tile is inconnective, remove the planned road connection to it */
if (!connective) org_rb ^= target_rb;
}
}
return org_rb;
}
/**
* Finds out, whether given company has a given RoadType available for construction.
* @param company ID of company
* @param roadtypet RoadType to test
* @return true if company has the requested RoadType available
*/
bool HasRoadTypeAvail(const CompanyID company, RoadType roadtype)
{
if (company == OWNER_DEITY || company == OWNER_TOWN || _game_mode == GM_EDITOR || _generating_world) {
const RoadTypeInfo *rti = GetRoadTypeInfo(roadtype);
if (rti->label == 0) return false;
/* Not yet introduced at this date. */
if (IsInsideMM(rti->introduction_date, 0, static_cast<int32_t>(CalendarTime::MAX_DATE)) && rti->introduction_date > TimerGameCalendar::date) return false;
/*
* Do not allow building hidden road types, except when a town may build it.
* The GS under deity mode, as well as anybody in the editor builds roads that are
* owned by towns. So if a town may build it, it should be buildable by them too.
*/
return (rti->flags & ROTFB_HIDDEN) == 0 || (rti->flags & ROTFB_TOWN_BUILD) != 0;
} else {
const Company *c = Company::GetIfValid(company);
if (c == nullptr) return false;
return HasBit(c->avail_roadtypes & ~_roadtypes_hidden_mask, roadtype);
}
}
static RoadTypes GetMaskForRoadTramType(RoadTramType rtt)
{
return rtt == RTT_TRAM ? _roadtypes_type : ~_roadtypes_type;
}
/**
* Test if any buildable RoadType is available for a company.
* @param company the company in question
* @return true if company has any RoadTypes available
*/
bool HasAnyRoadTypesAvail(CompanyID company, RoadTramType rtt)
{
return (Company::Get(company)->avail_roadtypes & ~_roadtypes_hidden_mask & GetMaskForRoadTramType(rtt)) != ROADTYPES_NONE;
}
/**
* Validate functions for rail building.
* @param roadtype road type to check.
* @return true if the current company may build the road.
*/
bool ValParamRoadType(RoadType roadtype)
{
return roadtype < ROADTYPE_END && HasRoadTypeAvail(_current_company, roadtype);
}
/**
* Add the road types that are to be introduced at the given date.
* @param rt Roadtype
* @param current The currently available roadtypes.
* @param date The date for the introduction comparisons.
* @return The road types that should be available when date
* introduced road types are taken into account as well.
*/
RoadTypes AddDateIntroducedRoadTypes(RoadTypes current, TimerGameCalendar::Date date)
{
RoadTypes rts = current;
for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
const RoadTypeInfo *rti = GetRoadTypeInfo(rt);
/* Unused road type. */
if (rti->label == 0) continue;
/* Not date introduced. */
if (!IsInsideMM(rti->introduction_date, 0, static_cast<int32_t>(CalendarTime::MAX_DATE))) continue;
/* Not yet introduced at this date. */
if (rti->introduction_date > date) continue;
/* Have we introduced all required roadtypes? */
RoadTypes required = rti->introduction_required_roadtypes;
if ((rts & required) != required) continue;
rts |= rti->introduces_roadtypes;
}
/* When we added roadtypes we need to run this method again; the added
* roadtypes might enable more rail types to become introduced. */
return rts == current ? rts : AddDateIntroducedRoadTypes(rts, date);
}
/**
* Get the road types the given company can build.
* @param company the company to get the road types for.
* @param introduces If true, include road types introduced by other road types
* @return the road types.
*/
RoadTypes GetCompanyRoadTypes(CompanyID company, bool introduces)
{
RoadTypes rts = ROADTYPES_NONE;
for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
const EngineInfo *ei = &e->info;
if (HasBit(ei->climates, _settings_game.game_creation.landscape) &&
(HasBit(e->company_avail, company) || TimerGameCalendar::date >= e->intro_date + CalendarTime::DAYS_IN_YEAR)) {
const RoadVehicleInfo *rvi = &e->u.road;
assert(rvi->roadtype < ROADTYPE_END);
if (introduces) {
rts |= GetRoadTypeInfo(rvi->roadtype)->introduces_roadtypes;
} else {
SetBit(rts, rvi->roadtype);
}
}
}
if (introduces) return AddDateIntroducedRoadTypes(rts, TimerGameCalendar::date);
return rts;
}
/**
* Get list of road types, regardless of company availability.
* @param introduces If true, include road types introduced by other road types
* @return the road types.
*/
RoadTypes GetRoadTypes(bool introduces)
{
RoadTypes rts = ROADTYPES_NONE;
for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
const EngineInfo *ei = &e->info;
if (!HasBit(ei->climates, _settings_game.game_creation.landscape)) continue;
const RoadVehicleInfo *rvi = &e->u.road;
assert(rvi->roadtype < ROADTYPE_END);
if (introduces) {
rts |= GetRoadTypeInfo(rvi->roadtype)->introduces_roadtypes;
} else {
SetBit(rts, rvi->roadtype);
}
}
if (introduces) return AddDateIntroducedRoadTypes(rts, CalendarTime::MAX_DATE);
return rts;
}
/**
* Get the road type for a given label.
* @param label the roadtype label.
* @param allow_alternate_labels Search in the alternate label lists as well.
* @return the roadtype.
*/
RoadType GetRoadTypeByLabel(RoadTypeLabel label, bool allow_alternate_labels)
{
/* Loop through each road type until the label is found */
for (RoadType r = ROADTYPE_BEGIN; r != ROADTYPE_END; r++) {
const RoadTypeInfo *rti = GetRoadTypeInfo(r);
if (rti->label == label) return r;
}
if (allow_alternate_labels) {
/* Test if any road type defines the label as an alternate. */
for (RoadType r = ROADTYPE_BEGIN; r != ROADTYPE_END; r++) {
const RoadTypeInfo *rti = GetRoadTypeInfo(r);
if (std::find(rti->alternate_labels.begin(), rti->alternate_labels.end(), label) != rti->alternate_labels.end()) return r;
}
}
/* No matching label was found, so it is invalid */
return INVALID_ROADTYPE;
}
/**
* Returns the available RoadSubTypes for the provided RoadType
* If the given company is valid then will be returned a list of the available sub types at the current date, while passing
* a deity company will make all the sub types available
* @param rt the RoadType to filter
* @param c the company ID to check the roadtype against
* @param any_date whether to return only currently introduced roadtypes or also future ones
* @returns the existing RoadSubTypes
*/
RoadTypes ExistingRoadTypes(CompanyID c)
{
/* Check only players which can actually own vehicles, editor and gamescripts are considered deities */
if (c < OWNER_END) {
const Company *company = Company::GetIfValid(c);
if (company != nullptr) return company->avail_roadtypes;
}
RoadTypes known_roadtypes = ROADTYPES_NONE;
/* Find used roadtypes */
for (Engine *e : Engine::IterateType(VEH_ROAD)) {
/* Check if the roadtype can be used in the current climate */
if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
/* Check whether available for all potential companies */
if (e->company_avail != MAX_UVALUE(CompanyMask)) continue;
known_roadtypes |= GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes;
}
/* Get the date introduced roadtypes as well. */
known_roadtypes = AddDateIntroducedRoadTypes(known_roadtypes, CalendarTime::MAX_DATE);
return known_roadtypes;
}
|