infrastructure.cpp

Go to the documentation of this file.
00001 /* $Id$ */
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 "infrastructure_func.h"
00014 #include "train.h"
00015 #include "aircraft.h"
00016 #include "vehicle_func.h"
00017 #include "station_base.h"
00018 #include "depot_base.h"
00019 #include "pbs.h"
00020 #include "signal_func.h"
00021 #include "window_func.h"
00022 #include "gui.h"
00023 #include "pathfinder/yapf/yapf_cache.h"
00024 
00025 #include "table/strings.h"
00026 
00033 static void PaySharingFee(Vehicle *v, Owner infra_owner, Money cost)
00034 {
00035   Company *c = Company::Get(v->owner);
00036   if (!_settings_game.sharing.payment_in_debt) {
00037     /* Do not allow fee payment to drop (money - loan) below 0. */
00038     cost = min(cost, (c->money - c->current_loan) << 8);
00039     if (cost <= 0) return;
00040   }
00041   v->profit_this_year -= cost;
00042   SubtractMoneyFromCompanyFract(v->owner, CommandCost(v->GetExpenseType(false), cost));
00043   SubtractMoneyFromCompanyFract(infra_owner, CommandCost(v->GetExpenseType(true), -cost));
00044 }
00045 
00051 void PayStationSharingFee(Vehicle *v, const Station *st)
00052 {
00053   if (v->owner == st->owner || st->owner == OWNER_NONE || v->type == VEH_TRAIN) return;
00054   Money cost;
00055   switch (v->type) {
00056     case VEH_ROAD:     cost = _settings_game.sharing.fee_road;  break;
00057     case VEH_SHIP:     cost = _settings_game.sharing.fee_water; break;
00058     case VEH_AIRCRAFT: cost = _settings_game.sharing.fee_air;   break;
00059     default: NOT_REACHED();
00060   }
00061   PaySharingFee(v, st->owner, (cost << 8) / DAY_TICKS);
00062 }
00063 
00068 void PayDailyTrackSharingFee(Train *v)
00069 {
00070   Owner owner = GetTileOwner(v->tile);
00071   if (owner == v->owner) return;
00072   Money cost = _settings_game.sharing.fee_rail << 8;
00073   /* Cost is calculated per 1000 tonnes */
00074   cost = cost * v->tcache.cached_weight / 1000;
00075   /* Only pay the required fraction */
00076   cost = cost * v->running_ticks / DAY_TICKS;
00077   if (cost != 0) PaySharingFee(v, owner, cost);
00078 }
00079 
00086 static bool VehiclePositionIsAllowed(const Vehicle *v, Owner owner = INVALID_OWNER)
00087 {
00088   switch (v->type) {
00089     case VEH_TRAIN:
00090       for (const Vehicle *u = v; u != NULL; u = u->Next()) {
00091         if (!IsInfraUsageAllowed(GetTileOwner(u->tile), v->owner, VEH_TRAIN) || GetTileOwner(u->tile) == owner) return false;
00092       }
00093       return true;
00094     case VEH_ROAD:
00095       for (const Vehicle *u = v; u != NULL; u = u->Next()) {
00096         if (IsRoadDepotTile(u->tile) || IsStandardRoadStopTile(u->tile)) {
00097           if (!IsInfraUsageAllowed(GetTileOwner(u->tile), v->owner, VEH_ROAD) || GetTileOwner(u->tile) == owner) return false;
00098         }
00099       }
00100       return true;
00101     case VEH_SHIP:
00102       if (IsShipDepotTile(v->tile) && v->IsStoppedInDepot()) {
00103         return IsInfraUsageAllowed(GetTileOwner(v->tile), v->owner, VEH_SHIP) && GetTileOwner(v->tile) != owner;
00104       }
00105       return true;
00106     case VEH_AIRCRAFT: {
00107       const Aircraft *a = Aircraft::From(v);
00108       if (a->state != FLYING && Station::IsValidID(a->targetairport)) {
00109         Owner station_owner = Station::Get(a->targetairport)->owner;
00110         return IsInfraUsageAllowed(station_owner, a->owner, VEH_AIRCRAFT) && station_owner != owner;
00111       }
00112       return true;
00113     }
00114     default: return true;
00115   }
00116 }
00117 
00126 static bool OrderDestinationIsAllowed(const Order *order, const Vehicle *v, Owner owner = INVALID_OWNER)
00127 {
00128   Owner dest_owner;
00129   switch (order->GetType()) {
00130     case OT_GOTO_STATION:
00131     case OT_GOTO_WAYPOINT: dest_owner = BaseStation::Get(order->GetDestination())->owner; break;
00132     case OT_GOTO_DEPOT:    dest_owner = (v->type == VEH_AIRCRAFT) ? Station::Get(order->GetDestination())->owner : GetTileOwner(Depot::Get(order->GetDestination())->xy); break;
00133     case OT_LOADING:       dest_owner = Station::Get(v->last_station_visited)->owner; break;
00134     default: return true;
00135   }
00136   return dest_owner != owner && IsInfraUsageAllowed(dest_owner, v->owner, v->type);
00137 }
00138 
00144 static void RemoveAndSellVehicle(Vehicle *v, bool give_money)
00145 {
00146   assert(v->Previous() == NULL);
00147 
00148   if (give_money) {
00149     /* compute total value and give that to the owner */
00150     Money value = 0;
00151     for (Vehicle *u = v->First(); u != NULL; u = u->Next()) {
00152       value += v->value;
00153     }
00154     CompanyID old = _current_company;
00155     _current_company = v->owner;
00156     SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -value));
00157     _current_company = old;
00158   }
00159 
00160   /* take special measures for trains, but not when sharing is disabled or when the train is a free wagon chain */
00161   if (_settings_game.sharing.sharing_rail && v->type == VEH_TRAIN && Train::From(v)->IsFrontEngine()) {
00162     DeleteVisibleTrain(Train::From(v));
00163   } else {
00164     delete v;
00165   }
00166 }
00167 
00171 static void FixAllReservations()
00172 {
00173   /* if this function is called, we can safely assume that sharing of rails is being switched off */
00174   assert(!_settings_game.sharing.sharing_rail);
00175   Train *v;
00176   FOR_ALL_TRAINS(v) {
00177     if (!v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0) continue;
00178     /* It might happen that the train reserved additional tracks,
00179      * but FollowTrainReservation can't detect those because they are no longer reachable.
00180      * detect this by first finding the end of the reservation,
00181      * then switch sharing on and try again. If these two ends differ,
00182      * unreserve the path, switch sharing off and try to reserve a new path */
00183     PBSTileInfo end_tile_info = FollowTrainReservation(v);
00184 
00185     /* first do a quick test to determine whether the next tile has any reservation at all */
00186     TileIndex next_tile = end_tile_info.tile + TileOffsByDiagDir(TrackdirToExitdir(end_tile_info.trackdir));
00187     /* If the next tile doesn't have a reservation at all, the reservation surely ends here. Thus all is well */
00188     if (GetReservedTrackbits(next_tile) == TRACK_BIT_NONE) continue;
00189 
00190     /* change sharing setting temporarily */
00191     _settings_game.sharing.sharing_rail = true;
00192     PBSTileInfo end_tile_info2 = FollowTrainReservation(v);
00193     /* if these two reservation ends differ, unreserve the path and try to reserve a new path */
00194     if (end_tile_info.tile != end_tile_info2.tile || end_tile_info.trackdir != end_tile_info2.trackdir) {
00195       FreeTrainTrackReservation(v);
00196       _settings_game.sharing.sharing_rail = false;
00197       TryPathReserve(v, true);
00198     } else {
00199       _settings_game.sharing.sharing_rail = false;
00200     }
00201   }
00202 }
00203 
00211 bool CheckSharingChangePossible(VehicleType type)
00212 {
00213   if (type != VEH_AIRCRAFT) YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK);
00214   /* Only do something when sharing is being disabled */
00215   if (GetSharingSetting(type)) return true;
00216 
00217   StringID error_message = STR_NULL;
00218   Vehicle *v;
00219   FOR_ALL_VEHICLES(v) {
00220     if (type != v->type) continue;
00221     if (v->Previous() != NULL) continue;
00222 
00223     /* Check vehicle positiion */
00224     if (!VehiclePositionIsAllowed(v)) {
00225       error_message = STR_CONFIG_SETTING_SHARING_USED_BY_VEHICLES;
00226       /* Break immediately, this error message takes precedence over the others. */
00227       break;
00228     }
00229 
00230     /* Check current order */
00231     if (!OrderDestinationIsAllowed(&v->current_order, v)) {
00232       error_message = STR_CONFIG_SETTING_SHARING_ORDERS_TO_OTHERS;
00233     }
00234 
00235     /* Check order list */
00236     if (v->FirstShared() != v) continue;
00237     Order *o;
00238     FOR_VEHICLE_ORDERS(v, o) {
00239       if (!OrderDestinationIsAllowed(o, v)) {
00240         error_message = STR_CONFIG_SETTING_SHARING_ORDERS_TO_OTHERS;
00241       }
00242     }
00243   }
00244 
00245   if (error_message != STR_NULL) {
00246     ShowErrorMessage(error_message, INVALID_STRING_ID, 0, 0);
00247     return false;
00248   }
00249 
00250   if (type == VEH_TRAIN) FixAllReservations();
00251 
00252   return true;
00253 }
00254 
00261 void HandleSharingCompanyDeletion(Owner owner)
00262 {
00263   YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK);
00264 
00265   Vehicle *v;
00266   FOR_ALL_VEHICLES(v) {
00267     if (!IsCompanyBuildableVehicleType(v) || v->Previous() != NULL) continue;
00268     /* vehicle position */
00269     if (v->owner == owner || !VehiclePositionIsAllowed(v, owner)) {
00270       RemoveAndSellVehicle(v, v->owner != owner);
00271       continue;
00272     }
00273     /* current order */
00274     if (!OrderDestinationIsAllowed(&v->current_order, v, owner)) {
00275       if (v->current_order.IsType(OT_LOADING)) {
00276         v->LeaveStation();
00277       } else {
00278         v->current_order.MakeDummy();
00279       }
00280       SetWindowDirty(WC_VEHICLE_VIEW, v->index);
00281     }
00282 
00283     /* order list */
00284     if (v->FirstShared() != v) continue;
00285 
00286     Order *o;
00287     int id = -1;
00288     FOR_VEHICLE_ORDERS(v, o) {
00289       id++;
00290       if (OrderDestinationIsAllowed(o, v, owner)) continue;
00291 
00292       o->MakeDummy();
00293       for (const Vehicle *w = v; w != NULL; w = w->NextShared()) {
00294         /* In GUI, simulate by removing the order and adding it back */
00295         InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
00296         InvalidateVehicleOrder(w, (id << 8) | INVALID_VEH_ORDER_ID);
00297       }
00298     }
00299   }
00300 }
00301 
00307 void UpdateAllBlockSignals(Owner owner)
00308 {
00309   Owner last_owner = INVALID_OWNER;
00310   TileIndex tile = 0;
00311   do {
00312     if (IsTileType(tile, MP_RAILWAY) && HasSignals(tile)) {
00313       Owner track_owner = GetTileOwner(tile);
00314       if (owner != INVALID_OWNER && track_owner != owner) continue;
00315 
00316       if (!IsOneSignalBlock(track_owner, last_owner)) {
00317         /* Cannot update signals of two different companies in one run,
00318          * if these signal blocks are not joined */
00319         UpdateSignalsInBuffer();
00320         last_owner = track_owner;
00321       }
00322       TrackBits bits = GetTrackBits(tile);
00323       do {
00324         Track track = RemoveFirstTrack(&bits);
00325         if (HasSignalOnTrack(tile, track)) {
00326           AddTrackToSignalBuffer(tile, track, track_owner);
00327         }
00328       } while (bits != TRACK_BIT_NONE);
00329     } else if (IsLevelCrossingTile(tile) && (owner == INVALID_OWNER || GetTileOwner(owner) == owner)) {
00330       UpdateLevelCrossing(tile);
00331     }
00332   } while (++tile != MapSize());
00333 
00334   UpdateSignalsInBuffer();
00335 }

Generated on Sat Dec 26 20:06:01 2009 for OpenTTD by  doxygen 1.5.6