diff -r c43adf6620c6 config.lib
--- a/config.lib Wed Dec 30 18:07:28 2009 +0000
+++ b/config.lib Tue Jun 22 17:59:34 2010 +0200
@@ -11,7 +11,7 @@
}
set_default() {
- released_version=""
+ released_version="IS2.1.1"
ignore_extra_parameters="0"
# We set all kinds of defaults for params. Later on the user can override
diff -r c43adf6620c6 findversion.sh
--- a/findversion.sh Wed Dec 30 18:07:28 2009 +0000
+++ b/findversion.sh Tue Jun 22 17:59:34 2010 +0200
@@ -121,4 +121,4 @@
REV="${REV}-$BRANCH"
fi
-echo "$REV $REV_NR $MODIFIED $CLEAN_REV"
+echo "IS2.1.1 $REV_NR $MODIFIED IS2.1.1"
diff -r c43adf6620c6 projects/determineversion.vbs
--- a/projects/determineversion.vbs Wed Dec 30 18:07:28 2009 +0000
+++ b/projects/determineversion.vbs Tue Jun 22 17:59:34 2010 +0200
@@ -39,6 +39,7 @@
modified = Mid(version, InStrRev(version, Chr(9)) + 1)
version = Mid(version, 1, InStr(version, Chr(9)) - 1)
Else
+ version = "IS2.1.1"
revision = 0
modified = 1
End If
diff -r c43adf6620c6 projects/openttd_vs80.vcproj
--- a/projects/openttd_vs80.vcproj Wed Dec 30 18:07:28 2009 +0000
+++ b/projects/openttd_vs80.vcproj Tue Jun 22 17:59:34 2010 +0200
@@ -584,6 +584,10 @@
>
+
+
@@ -1072,6 +1076,10 @@
>
+
+
diff -r c43adf6620c6 projects/openttd_vs90.vcproj
--- a/projects/openttd_vs90.vcproj Wed Dec 30 18:07:28 2009 +0000
+++ b/projects/openttd_vs90.vcproj Tue Jun 22 17:59:34 2010 +0200
@@ -581,6 +581,10 @@
>
+
+
@@ -1069,6 +1073,10 @@
>
+
+
diff -r c43adf6620c6 source.list
--- a/source.list Wed Dec 30 18:07:28 2009 +0000
+++ b/source.list Tue Jun 22 17:59:34 2010 +0200
@@ -31,6 +31,7 @@
gfxinit.cpp
heightmap.cpp
highscore.cpp
+infrastructure.cpp
ini.cpp
landscape.cpp
map.cpp
@@ -177,6 +178,7 @@
industry.h
industry_type.h
industrytype.h
+infrastructure_func.h
ini_type.h
landscape.h
landscape_type.h
diff -r c43adf6620c6 src/aircraft_cmd.cpp
--- a/src/aircraft_cmd.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/aircraft_cmd.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -35,6 +35,7 @@
#include "effectvehicle_func.h"
#include "station_base.h"
#include "cargotype.h"
+#include "infrastructure_func.h"
#include "table/strings.h"
#include "table/sprites.h"
@@ -113,7 +114,7 @@
const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type);
FOR_ALL_STATIONS(st) {
- if (st->owner != v->owner || !(st->facilities & FACIL_AIRPORT)) continue;
+ if (!IsInfraUsageAllowed(st->owner, v->owner, VEH_AIRCRAFT) || !(st->facilities & FACIL_AIRPORT)) continue;
const AirportFTAClass *afc = st->Airport();
if (afc->nof_depots == 0 || (
@@ -144,7 +145,7 @@
FOR_VEHICLE_ORDERS(v, order) {
const Station *st = Station::Get(order->station);
- if (st->owner == v->owner && (st->facilities & FACIL_AIRPORT)) {
+ if (IsInfraUsageAllowed(st->owner, v->owner, VEH_AIRCRAFT) && (st->facilities & FACIL_AIRPORT)) {
/* If an airport doesn't have a hangar, skip it */
if (st->Airport()->nof_depots != 0)
return true;
@@ -247,7 +248,7 @@
/* to just query the cost, it is not neccessary to have a valid tile (automation/AI) */
if (flags & DC_QUERY_COST) return value;
- if (!IsHangarTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
+ if (!IsHangarTile(tile) || !CheckInfraUsageAllowed(GetTileOwner(tile), VEH_AIRCRAFT)) return CMD_ERROR;
/* Prevent building aircraft types at places which can't handle them */
if (!CanVehicleUseStation(p1, Station::GetByTile(tile))) return CMD_ERROR;
@@ -1533,7 +1534,7 @@
/* runway busy or not allowed to use this airstation, circle */
if ((apc->flags & (v->subtype == AIR_HELICOPTER ? AirportFTAClass::HELICOPTERS : AirportFTAClass::AIRPLANES)) &&
st->airport_tile != INVALID_TILE &&
- (st->owner == OWNER_NONE || st->owner == v->owner)) {
+ IsInfraUsageAllowed(st->owner, v->owner, VEH_AIRCRAFT)) {
/* {32,FLYING,NOTHING_block,37}, {32,LANDING,N,33}, {32,HELILANDING,N,41},
* if it is an airplane, look for LANDING, for helicopter HELILANDING
* it is possible to choose from multiple landing runways, so loop until a free one is found */
diff -r c43adf6620c6 src/depot_gui.cpp
--- a/src/depot_gui.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/depot_gui.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -29,6 +29,7 @@
#include "tilehighlight_func.h"
#include "window_gui.h"
#include "vehiclelist.h"
+#include "infrastructure_func.h"
#include "table/strings.h"
#include "table/sprites.h"
@@ -696,7 +697,7 @@
/* Setup disabled buttons. */
TileIndex tile = this->window_number;
- this->SetWidgetsDisabledState(!IsTileOwner(tile, _local_company),
+ this->SetWidgetsDisabledState(!(Company::IsValidID(_local_company) && IsInfraTileUsageAllowed(tile, _local_company, this->type)),
DEPOT_WIDGET_STOP_ALL,
DEPOT_WIDGET_START_ALL,
DEPOT_WIDGET_SELL,
diff -r c43adf6620c6 src/economy.cpp
--- a/src/economy.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/economy.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -46,6 +46,7 @@
#include "waypoint_base.h"
#include "economy_base.h"
#include "core/pool_func.hpp"
+#include "infrastructure_func.h"
#include "table/strings.h"
#include "table/sprites.h"
@@ -366,7 +367,8 @@
ClrBit(t->have_ratings, old_owner);
}
- {
+ /* Change ownership of vehicles */
+ if (new_owner != INVALID_OWNER) {
FreeUnitIDGenerator unitidgen[] = {
FreeUnitIDGenerator(VEH_TRAIN, new_owner), FreeUnitIDGenerator(VEH_ROAD, new_owner),
FreeUnitIDGenerator(VEH_SHIP, new_owner), FreeUnitIDGenerator(VEH_AIRCRAFT, new_owner)
@@ -375,16 +377,16 @@
Vehicle *v;
FOR_ALL_VEHICLES(v) {
if (v->owner == old_owner && IsCompanyBuildableVehicleType(v->type)) {
- if (new_owner == INVALID_OWNER) {
- if (v->Previous() == NULL) delete v;
- } else {
- v->owner = new_owner;
- v->colourmap = PAL_NONE;
- if (v->IsEngineCountable()) Company::Get(new_owner)->num_engines[v->engine_type]++;
- if (v->IsPrimaryVehicle()) v->unitnumber = unitidgen[v->type].NextID();
- }
+ v->owner = new_owner;
+ v->colourmap = PAL_NONE;
+ if (v->IsEngineCountable()) Company::Get(new_owner)->num_engines[v->engine_type]++;
+ if (v->IsPrimaryVehicle()) v->unitnumber = unitidgen[v->type].NextID();
}
}
+ } else {
+ /* Depending on sharing settings, other companies could be affected too.
+ * Let the infrastructure sharing code handle this. */
+ HandleSharingCompanyDeletion(old_owner);
}
/* Change ownership of tiles */
@@ -399,22 +401,13 @@
* and signals were not propagated
* Similiar with crossings - it is needed to bar crossings that weren't before
* because of different owner of crossing and approaching train */
- tile = 0;
-
- do {
- if (IsTileType(tile, MP_RAILWAY) && IsTileOwner(tile, new_owner) && HasSignals(tile)) {
- TrackBits tracks = GetTrackBits(tile);
- do { // there may be two tracks with signals for TRACK_BIT_HORZ and TRACK_BIT_VERT
- Track track = RemoveFirstTrack(&tracks);
- if (HasSignalOnTrack(tile, track)) AddTrackToSignalBuffer(tile, track, new_owner);
- } while (tracks != TRACK_BIT_NONE);
- } else if (IsLevelCrossingTile(tile) && IsTileOwner(tile, new_owner)) {
- UpdateLevelCrossing(tile);
- }
- } while (++tile != MapSize());
+ UpdateAllBlockSignals(new_owner);
+ } else if (_settings_game.sharing.sharing_rail) {
+ /* tracks are being removed while sharing is enabled.
+ * Thus, update all signals and crossings. */
+ UpdateAllBlockSignals();
}
-
- /* update signals in buffer */
+ /* Update any signals in the buffer */
UpdateSignalsInBuffer();
}
diff -r c43adf6620c6 src/infrastructure.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/infrastructure.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -0,0 +1,335 @@
+/* $Id$ */
+
+/*
+ * 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 .
+ */
+
+/** @file infrastructure.cpp Implementation of infrastructure sharing */
+
+#include "stdafx.h"
+#include "infrastructure_func.h"
+#include "train.h"
+#include "aircraft.h"
+#include "vehicle_func.h"
+#include "station_base.h"
+#include "depot_base.h"
+#include "pbs.h"
+#include "signal_func.h"
+#include "window_func.h"
+#include "gui.h"
+#include "pathfinder/yapf/yapf_cache.h"
+
+#include "table/strings.h"
+
+/**
+ * Helper function for transferring sharing fees
+ * @param v The vehicle involved
+ * @param infra_owner The owner of the infrastructure
+ * @param cost Amount to transfer as money fraction (shifted 8 bits to the left)
+ */
+static void PaySharingFee(Vehicle *v, Owner infra_owner, Money cost)
+{
+ Company *c = Company::Get(v->owner);
+ if (!_settings_game.sharing.payment_in_debt) {
+ /* Do not allow fee payment to drop (money - loan) below 0. */
+ cost = min(cost, (c->money - c->current_loan) << 8);
+ if (cost <= 0) return;
+ }
+ v->profit_this_year -= cost;
+ SubtractMoneyFromCompanyFract(v->owner, CommandCost(v->GetExpenseType(false), cost));
+ SubtractMoneyFromCompanyFract(infra_owner, CommandCost(v->GetExpenseType(true), -cost));
+}
+
+/**
+ * Pay the fee for spending a single tick inside a station.
+ * @param v The vehicle that is using the station.
+ * @param st The station that it uses.
+ */
+void PayStationSharingFee(Vehicle *v, const Station *st)
+{
+ if (v->owner == st->owner || st->owner == OWNER_NONE || v->type == VEH_TRAIN) return;
+ Money cost;
+ switch (v->type) {
+ case VEH_ROAD: cost = _settings_game.sharing.fee_road; break;
+ case VEH_SHIP: cost = _settings_game.sharing.fee_water; break;
+ case VEH_AIRCRAFT: cost = _settings_game.sharing.fee_air; break;
+ default: NOT_REACHED();
+ }
+ PaySharingFee(v, st->owner, (cost << 8) / DAY_TICKS);
+}
+
+/**
+ * Pay the daily fee for trains on foreign tracks.
+ * @param v The vehicle to pay the fee for.
+ */
+void PayDailyTrackSharingFee(Train *v)
+{
+ Owner owner = GetTileOwner(v->tile);
+ if (owner == v->owner) return;
+ Money cost = _settings_game.sharing.fee_rail << 8;
+ /* Cost is calculated per 1000 tonnes */
+ cost = cost * v->tcache.cached_weight / 1000;
+ /* Only pay the required fraction */
+ cost = cost * v->running_ticks / DAY_TICKS;
+ if (cost != 0) PaySharingFee(v, owner, cost);
+}
+
+/**
+ * Check whether a vehicle is in an allowed position.
+ * @param v The vehicle to check.
+ * @param owner Owner whose infrastructure is not allowed, because the company will be removed. Ignored if INVALID_OWNER.
+ * @return True if the vehicle is compeletely in an allowed position.
+ */
+static bool VehiclePositionIsAllowed(const Vehicle *v, Owner owner = INVALID_OWNER)
+{
+ switch (v->type) {
+ case VEH_TRAIN:
+ for (const Vehicle *u = v; u != NULL; u = u->Next()) {
+ if (!IsInfraUsageAllowed(GetTileOwner(u->tile), v->owner, VEH_TRAIN) || GetTileOwner(u->tile) == owner) return false;
+ }
+ return true;
+ case VEH_ROAD:
+ for (const Vehicle *u = v; u != NULL; u = u->Next()) {
+ if (IsRoadDepotTile(u->tile) || IsStandardRoadStopTile(u->tile)) {
+ if (!IsInfraUsageAllowed(GetTileOwner(u->tile), v->owner, VEH_ROAD) || GetTileOwner(u->tile) == owner) return false;
+ }
+ }
+ return true;
+ case VEH_SHIP:
+ if (IsShipDepotTile(v->tile) && v->IsStoppedInDepot()) {
+ return IsInfraUsageAllowed(GetTileOwner(v->tile), v->owner, VEH_SHIP) && GetTileOwner(v->tile) != owner;
+ }
+ return true;
+ case VEH_AIRCRAFT: {
+ const Aircraft *a = Aircraft::From(v);
+ if (a->state != FLYING && Station::IsValidID(a->targetairport)) {
+ Owner station_owner = Station::Get(a->targetairport)->owner;
+ return IsInfraUsageAllowed(station_owner, a->owner, VEH_AIRCRAFT) && station_owner != owner;
+ }
+ return true;
+ }
+ default: return true;
+ }
+}
+
+/**
+ * Check whether an order has a destination that is allowed.
+ * I.e. it refers to a station/depot/waypoint the vehicle is allowed to visit.
+ * @param order The order to check
+ * @param v The vehicle this order belongs to.
+ * @param owner Owner whose infrastructure is not allowed, because the company will be removed. Ignored if INVALID_OWNER.
+ * @return True if the order has an allowed destination.
+ */
+static bool OrderDestinationIsAllowed(const Order *order, const Vehicle *v, Owner owner = INVALID_OWNER)
+{
+ Owner dest_owner;
+ switch (order->GetType()) {
+ case OT_GOTO_STATION:
+ case OT_GOTO_WAYPOINT: dest_owner = BaseStation::Get(order->GetDestination())->owner; break;
+ case OT_GOTO_DEPOT: dest_owner = (v->type == VEH_AIRCRAFT) ? Station::Get(order->GetDestination())->owner : GetTileOwner(Depot::Get(order->GetDestination())->xy); break;
+ case OT_LOADING: dest_owner = Station::Get(v->last_station_visited)->owner; break;
+ default: return true;
+ }
+ return dest_owner != owner && IsInfraUsageAllowed(dest_owner, v->owner, v->type);
+}
+
+/**
+ * Sell a vehicle, no matter where it may be.
+ * @param v The vehicle to sell
+ * @param give_money Do we actually need to give money to the vehicle owner?
+ */
+static void RemoveAndSellVehicle(Vehicle *v, bool give_money)
+{
+ assert(v->Previous() == NULL);
+
+ if (give_money) {
+ /* compute total value and give that to the owner */
+ Money value = 0;
+ for (Vehicle *u = v->First(); u != NULL; u = u->Next()) {
+ value += v->value;
+ }
+ CompanyID old = _current_company;
+ _current_company = v->owner;
+ SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, -value));
+ _current_company = old;
+ }
+
+ /* take special measures for trains, but not when sharing is disabled or when the train is a free wagon chain */
+ if (_settings_game.sharing.sharing_rail && v->type == VEH_TRAIN && Train::From(v)->IsFrontEngine()) {
+ DeleteVisibleTrain(Train::From(v));
+ } else {
+ delete v;
+ }
+}
+
+/**
+ * Check all path reservations, and reserve a new path if the current path is invalid.
+ */
+static void FixAllReservations()
+{
+ /* if this function is called, we can safely assume that sharing of rails is being switched off */
+ assert(!_settings_game.sharing.sharing_rail);
+ Train *v;
+ FOR_ALL_TRAINS(v) {
+ if (!v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0) continue;
+ /* It might happen that the train reserved additional tracks,
+ * but FollowTrainReservation can't detect those because they are no longer reachable.
+ * detect this by first finding the end of the reservation,
+ * then switch sharing on and try again. If these two ends differ,
+ * unreserve the path, switch sharing off and try to reserve a new path */
+ PBSTileInfo end_tile_info = FollowTrainReservation(v);
+
+ /* first do a quick test to determine whether the next tile has any reservation at all */
+ TileIndex next_tile = end_tile_info.tile + TileOffsByDiagDir(TrackdirToExitdir(end_tile_info.trackdir));
+ /* If the next tile doesn't have a reservation at all, the reservation surely ends here. Thus all is well */
+ if (GetReservedTrackbits(next_tile) == TRACK_BIT_NONE) continue;
+
+ /* change sharing setting temporarily */
+ _settings_game.sharing.sharing_rail = true;
+ PBSTileInfo end_tile_info2 = FollowTrainReservation(v);
+ /* if these two reservation ends differ, unreserve the path and try to reserve a new path */
+ if (end_tile_info.tile != end_tile_info2.tile || end_tile_info.trackdir != end_tile_info2.trackdir) {
+ FreeTrainTrackReservation(v);
+ _settings_game.sharing.sharing_rail = false;
+ TryPathReserve(v, true);
+ } else {
+ _settings_game.sharing.sharing_rail = false;
+ }
+ }
+}
+
+/**
+ * Check if a sharing change is possible.
+ * If vehicles are still on others' infrastructure or using others' stations,
+ * The change is not possible and false is returned.
+ * @param type The type of vehicle whose setting will be changed.
+ * @return True if the change can take place, false otherwise.
+ */
+bool CheckSharingChangePossible(VehicleType type)
+{
+ if (type != VEH_AIRCRAFT) YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK);
+ /* Only do something when sharing is being disabled */
+ if (GetSharingSetting(type)) return true;
+
+ StringID error_message = STR_NULL;
+ Vehicle *v;
+ FOR_ALL_VEHICLES(v) {
+ if (type != v->type) continue;
+ if (v->Previous() != NULL) continue;
+
+ /* Check vehicle positiion */
+ if (!VehiclePositionIsAllowed(v)) {
+ error_message = STR_CONFIG_SETTING_SHARING_USED_BY_VEHICLES;
+ /* Break immediately, this error message takes precedence over the others. */
+ break;
+ }
+
+ /* Check current order */
+ if (!OrderDestinationIsAllowed(&v->current_order, v)) {
+ error_message = STR_CONFIG_SETTING_SHARING_ORDERS_TO_OTHERS;
+ }
+
+ /* Check order list */
+ if (v->FirstShared() != v) continue;
+ Order *o;
+ FOR_VEHICLE_ORDERS(v, o) {
+ if (!OrderDestinationIsAllowed(o, v)) {
+ error_message = STR_CONFIG_SETTING_SHARING_ORDERS_TO_OTHERS;
+ }
+ }
+ }
+
+ if (error_message != STR_NULL) {
+ ShowErrorMessage(error_message, INVALID_STRING_ID, 0, 0);
+ return false;
+ }
+
+ if (type == VEH_TRAIN) FixAllReservations();
+
+ return true;
+}
+
+/**
+ * Handle the removal (through reset_company or bankruptcy) of a company.
+ * i.e. remove all vehicles owned by that company or on its infrastructure,
+ * and delete all now-invalid orders.
+ * @param Owner the company to be removed.
+ */
+void HandleSharingCompanyDeletion(Owner owner)
+{
+ YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK);
+
+ Vehicle *v;
+ FOR_ALL_VEHICLES(v) {
+ if (!IsCompanyBuildableVehicleType(v) || v->Previous() != NULL) continue;
+ /* vehicle position */
+ if (v->owner == owner || !VehiclePositionIsAllowed(v, owner)) {
+ RemoveAndSellVehicle(v, v->owner != owner);
+ continue;
+ }
+ /* current order */
+ if (!OrderDestinationIsAllowed(&v->current_order, v, owner)) {
+ if (v->current_order.IsType(OT_LOADING)) {
+ v->LeaveStation();
+ } else {
+ v->current_order.MakeDummy();
+ }
+ SetWindowDirty(WC_VEHICLE_VIEW, v->index);
+ }
+
+ /* order list */
+ if (v->FirstShared() != v) continue;
+
+ Order *o;
+ int id = -1;
+ FOR_VEHICLE_ORDERS(v, o) {
+ id++;
+ if (OrderDestinationIsAllowed(o, v, owner)) continue;
+
+ o->MakeDummy();
+ for (const Vehicle *w = v; w != NULL; w = w->NextShared()) {
+ /* In GUI, simulate by removing the order and adding it back */
+ InvalidateVehicleOrder(w, id | (INVALID_VEH_ORDER_ID << 8));
+ InvalidateVehicleOrder(w, (id << 8) | INVALID_VEH_ORDER_ID);
+ }
+ }
+ }
+}
+
+/**
+ * Update all block signals on the map.
+ * To be called after the setting for sharing of rails changes.
+ * @param owner Owner whose signals to update. If INVALID_OWNER, update everything.
+ */
+void UpdateAllBlockSignals(Owner owner)
+{
+ Owner last_owner = INVALID_OWNER;
+ TileIndex tile = 0;
+ do {
+ if (IsTileType(tile, MP_RAILWAY) && HasSignals(tile)) {
+ Owner track_owner = GetTileOwner(tile);
+ if (owner != INVALID_OWNER && track_owner != owner) continue;
+
+ if (!IsOneSignalBlock(track_owner, last_owner)) {
+ /* Cannot update signals of two different companies in one run,
+ * if these signal blocks are not joined */
+ UpdateSignalsInBuffer();
+ last_owner = track_owner;
+ }
+ TrackBits bits = GetTrackBits(tile);
+ do {
+ Track track = RemoveFirstTrack(&bits);
+ if (HasSignalOnTrack(tile, track)) {
+ AddTrackToSignalBuffer(tile, track, track_owner);
+ }
+ } while (bits != TRACK_BIT_NONE);
+ } else if (IsLevelCrossingTile(tile) && (owner == INVALID_OWNER || GetTileOwner(tile) == owner)) {
+ UpdateLevelCrossing(tile);
+ }
+ } while (++tile != MapSize());
+
+ UpdateSignalsInBuffer();
+}
diff -r c43adf6620c6 src/infrastructure_func.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/infrastructure_func.h Tue Jun 22 17:59:34 2010 +0200
@@ -0,0 +1,115 @@
+/* $Id$ */
+
+/*
+ * 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 .
+ */
+
+/** @file infrastructure_func.h Functions for infrastructure sharing */
+
+#ifndef INFRASTRUCTURE_FUNC_H
+#define INFRASTRUCTURE_FUNC_H
+
+#include "vehicle_base.h"
+#include "functions.h"
+#include "company_func.h"
+
+void PayStationSharingFee(Vehicle *v, const Station *st);
+void PayDailyTrackSharingFee(Train *v);
+bool CheckSharingChangePossible(VehicleType type);
+void HandleSharingCompanyDeletion(Owner owner);
+void UpdateAllBlockSignals(Owner owner = INVALID_OWNER);
+
+/**
+ * Get the value of the sharing setting for a vehicle type.
+ * @param type The type of vehicle.
+ * @return True if sharing is enabled for the given vehicle type.
+ */
+static FORCEINLINE bool GetSharingSetting(VehicleType type)
+{
+ switch (type) {
+ case VEH_TRAIN: return _settings_game.sharing.sharing_rail;
+ case VEH_ROAD: return _settings_game.sharing.sharing_road;
+ case VEH_SHIP: return _settings_game.sharing.sharing_water;
+ case VEH_AIRCRAFT: return _settings_game.sharing.sharing_air;
+ default: NOT_REACHED();
+ }
+}
+
+/**
+ * Check whether a vehicle of a given owner and type can use the infrastrucutre of a given company.
+ * @param infra_owner The owner of the infrastructure.
+ * @param veh_owner Owner of the vehicle in question.
+ * @param type Type of vehicle we are talking about.
+ * @return True if infrastructure usage is allowed, false otherwise.
+ */
+static FORCEINLINE bool IsInfraUsageAllowed(Owner infra_owner, Owner veh_owner, VehicleType type)
+{
+ return infra_owner == veh_owner || infra_owner == OWNER_NONE || GetSharingSetting(type);
+}
+
+/**
+ * Check whether a vehicle of a given owner and type can use the infrastrucutre on a given tile.
+ * @param infra_owner The tile that may or may not be used.
+ * @param veh_owner Owner of the vehicle in question.
+ * @param type Type of vehicle we are talking about.
+ * @return True if infrastructure usage is allowed, false otherwise.
+ */
+static FORCEINLINE bool IsInfraTileUsageAllowed(TileIndex tile, Owner veh_owner, VehicleType type)
+{
+ return IsInfraUsageAllowed(GetTileOwner(tile), veh_owner, type);
+}
+
+/**
+ * Is a vehicle owned by _current_company allowed to use the infrastructure of infra_owner?
+ * @see IsInfraUsageAllowed
+ * @note This function is to be called from DoCommands.
+ * @param infra_owner Owner of the infrastructure.
+ * @param type Type of vehicle.
+ * @return True if infrastructure usage is allowed, false otherwise.
+ */
+static FORCEINLINE bool CheckInfraUsageAllowed(Owner infra_owner, VehicleType type)
+{
+ return infra_owner == OWNER_NONE || GetSharingSetting(type) || CheckOwnership(infra_owner);
+}
+
+/**
+ * Check whether a given company can control this vehicle.
+ * Controlling a vehicle means permission to start, stop or reverse it or to make it ignore signals.
+ * @param v The vehicle which may or may not be controlled.
+ * @param o The company which may or may not control this vehicle.
+ * @return True if the given company is allowed to control this vehicle.
+ */
+static FORCEINLINE bool IsVehicleControlAllowed(const Vehicle *v, Owner o)
+{
+ return v->owner == o || (v->type == VEH_TRAIN && IsTileOwner(v->tile, o));
+}
+
+/**
+ * Check whether _current_company can control this vehicle.
+ * @note This function is to be called from DoCommands.
+ * @see IsVehicleControlAllowed
+ * @param v The vehicle which may or may not be controlled.
+ * @return True if _current_company is allowed to control this vehicle.
+ */
+static FORCEINLINE bool CheckVehicleControlAllowed(const Vehicle *v)
+{
+ return (v->type == VEH_TRAIN && IsTileOwner(v->tile, _current_company)) || CheckOwnership(v->owner);
+}
+
+/**
+ * Do signal states propagate from the tracks of one owner to the other?
+ * @note This function should be consistent, so if it returns true for (a, b) and (b, c),
+ * it should also return true for (a, c).
+ * @param o1 First track owner.
+ * @param o2 Second track owner.
+ * @return True if tracks of the two owners are part of the same signal block.
+ */
+static FORCEINLINE bool IsOneSignalBlock(Owner o1, Owner o2)
+{
+ return o1 == o2 || _settings_game.sharing.sharing_rail;
+}
+
+#endif /* INFRASTRUCTURE_FUNC_H */
diff -r c43adf6620c6 src/lang/english.txt
--- a/src/lang/english.txt Wed Dec 30 18:07:28 2009 +0000
+++ b/src/lang/english.txt Tue Jun 22 17:59:34 2010 +0200
@@ -1224,6 +1224,18 @@
STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :{LTBLUE}Allow AIs in multiplayer: {ORANGE}{STRING1}
STR_CONFIG_SETTING_AI_MAX_OPCODES :{LTBLUE}#opcodes before AI is suspended: {ORANGE}{STRING1}
+STR_CONFIG_SETTING_SHARING_RAIL :{LTBLUE}Enable sharing of railways: {ORANGE}{STRING1}
+STR_CONFIG_SETTING_SHARING_ROAD :{LTBLUE}Enable sharing of road stops and depots: {ORANGE}{STRING1}
+STR_CONFIG_SETTING_SHARING_WATER :{LTBLUE}Enable sharing of docks and ship depots: {ORANGE}{STRING1}
+STR_CONFIG_SETTING_SHARING_AIR :{LTBLUE}Enable sharing of airports: {ORANGE}{STRING1}
+STR_CONFIG_SETTING_SHARING_FEE_RAIL :{LTBLUE}Daily track toll for trains: {ORANGE}{STRING1} per 1000 tonnes
+STR_CONFIG_SETTING_SHARING_FEE_ROAD :{LTBLUE}Stopping fee for road vehicles: {ORANGE}{STRING1} per day
+STR_CONFIG_SETTING_SHARING_FEE_WATER :{LTBLUE}Docking fee for ships: {ORANGE}{STRING1} per day
+STR_CONFIG_SETTING_SHARING_FEE_AIR :{LTBLUE}Terminal fee for aircraft: {ORANGE}{STRING1} per day
+STR_CONFIG_SETTING_SHARING_PAYMENT_IN_DEBT :{LTBLUE}Allow companies in debt to pay sharing fees: {ORANGE}{STRING1}
+STR_CONFIG_SETTING_SHARING_USED_BY_VEHICLES :{WHITE}Can't change this setting, vehicles are using shared infrastructure.
+STR_CONFIG_SETTING_SHARING_ORDERS_TO_OTHERS :{WHITE}Can't change this setting, vehicles have orders to destinations of others.
+
STR_CONFIG_SETTING_SERVINT_ISPERCENT :{LTBLUE}Service intervals are in percents: {ORANGE}{STRING1}
STR_CONFIG_SETTING_SERVINT_TRAINS :{LTBLUE}Default service interval for trains: {ORANGE}{STRING1} days/%
STR_CONFIG_SETTING_SERVINT_TRAINS_DISABLED :{LTBLUE}Default service interval for trains: {ORANGE}disabled
@@ -1301,6 +1313,7 @@
STR_CONFIG_SETTING_CONSTRUCTION_SIGNALS :{ORANGE}Signals
STR_CONFIG_SETTING_STATIONS_CARGOHANDLING :{ORANGE}Cargo handling
STR_CONFIG_SETTING_AI_NPC :{ORANGE}Computer players
+STR_CONFIG_SETTING_SHARING :{ORANGE}Infrastructure sharing
STR_CONFIG_SETTING_VEHICLES_AUTORENEW :{ORANGE}Autorenew
STR_CONFIG_SETTING_VEHICLES_SERVICING :{ORANGE}Servicing
STR_CONFIG_SETTING_VEHICLES_ROUTING :{ORANGE}Routing
diff -r c43adf6620c6 src/order_cmd.cpp
--- a/src/order_cmd.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/order_cmd.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -27,6 +27,7 @@
#include "station_base.h"
#include "waypoint_base.h"
#include "roadstop_base.h"
+#include "infrastructure_func.h"
#include "table/strings.h"
@@ -464,7 +465,7 @@
const Station *st = Station::GetIfValid(new_order.GetDestination());
if (st == NULL) return CMD_ERROR;
- if (st->owner != OWNER_NONE && !CheckOwnership(st->owner)) return CMD_ERROR;
+ if (!CheckInfraUsageAllowed(st->owner, v->type)) return CMD_ERROR;
if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
for (Vehicle *u = v->FirstShared(); u != NULL; u = u->NextShared()) {
@@ -508,7 +509,7 @@
if (v->type == VEH_AIRCRAFT) {
const Station *st = Station::GetIfValid(new_order.GetDestination());
- if (st == NULL || !CheckOwnership(st->owner) ||
+ if (st == NULL || !CheckInfraUsageAllowed(st->owner, v->type) ||
!CanVehicleUseStation(v, st) ||
st->Airport()->nof_depots == 0) {
return CMD_ERROR;
@@ -516,7 +517,7 @@
} else {
const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
- if (dp == NULL || !CheckOwnership(GetTileOwner(dp->xy))) return CMD_ERROR;
+ if (dp == NULL || !CheckInfraUsageAllowed(GetTileOwner(dp->xy), v->type)) return CMD_ERROR;
switch (v->type) {
case VEH_TRAIN:
@@ -554,14 +555,13 @@
case VEH_TRAIN:
if (!(wp->facilities & FACIL_TRAIN)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
- if (!CheckOwnership(wp->owner)) return CMD_ERROR;
break;
case VEH_SHIP:
if (!(wp->facilities & FACIL_DOCK)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
- if (!CheckOwnership(wp->owner) && wp->owner != OWNER_NONE) return CMD_ERROR;
break;
}
+ if (!CheckInfraUsageAllowed(wp->owner, v->type)) return CMD_ERROR;
/* Order flags can be any of the following for waypoints:
* [non-stop]
diff -r c43adf6620c6 src/order_gui.cpp
--- a/src/order_gui.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/order_gui.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -31,6 +31,7 @@
#include "network/network.h"
#include "station_base.h"
#include "waypoint_base.h"
+#include "infrastructure_func.h"
#include "table/sprites.h"
#include "table/strings.h"
@@ -316,7 +317,7 @@
if (_settings_game.order.gotodepot) {
switch (GetTileType(tile)) {
case MP_RAILWAY:
- if (v->type == VEH_TRAIN && IsTileOwner(tile, _local_company)) {
+ if (v->type == VEH_TRAIN && IsInfraTileUsageAllowed(tile, v->owner, VEH_TRAIN)) {
if (IsRailDepot(tile)) {
order.MakeGoToDepot(GetDepotIndex(tile), ODTFB_PART_OF_ORDERS,
_settings_client.gui.new_nonstop ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE);
@@ -327,7 +328,7 @@
break;
case MP_ROAD:
- if (IsRoadDepot(tile) && v->type == VEH_ROAD && IsTileOwner(tile, _local_company)) {
+ if (IsRoadDepot(tile) && v->type == VEH_ROAD && IsInfraTileUsageAllowed(tile, v->owner, VEH_ROAD)) {
order.MakeGoToDepot(GetDepotIndex(tile), ODTFB_PART_OF_ORDERS,
_settings_client.gui.new_nonstop ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE);
if (_ctrl_pressed) order.SetDepotOrderType((OrderDepotTypeFlags)(order.GetDepotOrderType() ^ ODTFB_SERVICE));
@@ -337,7 +338,7 @@
case MP_STATION:
if (v->type != VEH_AIRCRAFT) break;
- if (IsHangar(tile) && IsTileOwner(tile, _local_company)) {
+ if (IsHangar(tile) && IsInfraTileUsageAllowed(tile, v->owner, VEH_AIRCRAFT)) {
order.MakeGoToDepot(GetStationIndex(tile), ODTFB_PART_OF_ORDERS, ONSF_STOP_EVERYWHERE);
if (_ctrl_pressed) order.SetDepotOrderType((OrderDepotTypeFlags)(order.GetDepotOrderType() ^ ODTFB_SERVICE));
return order;
@@ -346,7 +347,7 @@
case MP_WATER:
if (v->type != VEH_SHIP) break;
- if (IsShipDepot(tile) && IsTileOwner(tile, _local_company)) {
+ if (IsShipDepot(tile) && IsInfraTileUsageAllowed(tile, v->owner, VEH_SHIP)) {
order.MakeGoToDepot(GetDepotIndex(tile), ODTFB_PART_OF_ORDERS, ONSF_STOP_EVERYWHERE);
if (_ctrl_pressed) order.SetDepotOrderType((OrderDepotTypeFlags)(order.GetDepotOrderType() ^ ODTFB_SERVICE));
return order;
@@ -360,7 +361,7 @@
/* check waypoint */
if (IsRailWaypointTile(tile) &&
v->type == VEH_TRAIN &&
- IsTileOwner(tile, _local_company)) {
+ IsInfraTileUsageAllowed(tile, v->owner, VEH_TRAIN)) {
order.MakeGoToWaypoint(Waypoint::GetByTile(tile)->index);
if (_settings_client.gui.new_nonstop != _ctrl_pressed) order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
return order;
@@ -375,7 +376,7 @@
StationID st_index = GetStationIndex(tile);
const Station *st = Station::Get(st_index);
- if (st->owner == _local_company || st->owner == OWNER_NONE) {
+ if (IsInfraUsageAllowed(st->owner, v->owner, v->type)) {
byte facil;
(facil = FACIL_DOCK, v->type == VEH_SHIP) ||
(facil = FACIL_TRAIN, v->type == VEH_TRAIN) ||
diff -r c43adf6620c6 src/os/windows/ottdres.rc.in
--- a/src/os/windows/ottdres.rc.in Wed Dec 30 18:07:28 2009 +0000
+++ b/src/os/windows/ottdres.rc.in Tue Jun 22 17:59:34 2010 +0200
@@ -79,8 +79,8 @@
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,0,!!REVISION!!
- PRODUCTVERSION 1,0,0,!!REVISION!!
+ FILEVERSION 1,0,0,18667
+ PRODUCTVERSION 1,0,0,18667
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -98,14 +98,14 @@
VALUE "Comments", "This program is licensed under the GNU General Public License version 2.\0"
VALUE "CompanyName", "OpenTTD Development Team\0"
VALUE "FileDescription", "OpenTTD\0"
- VALUE "FileVersion", "Development !!VERSION!!\0"
+ VALUE "FileVersion", "Development IS2.1.1\0"
VALUE "InternalName", "openttd\0"
VALUE "LegalCopyright", "Copyright \xA9 OpenTTD Developers 2002-2009. All Rights Reserved.\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "openttd.exe\0"
VALUE "PrivateBuild", "\0"
VALUE "ProductName", "OpenTTD\0"
- VALUE "ProductVersion", "Development !!VERSION!!\0"
+ VALUE "ProductVersion", "Development IS2.1.1\0"
VALUE "SpecialBuild", "-\0"
END
END
diff -r c43adf6620c6 src/pathfinder/follow_track.hpp
--- a/src/pathfinder/follow_track.hpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/pathfinder/follow_track.hpp Tue Jun 22 17:59:34 2010 +0200
@@ -19,6 +19,7 @@
#include "../train.h"
#include "../tunnelbridge.h"
#include "../tunnelbridge_map.h"
+#include "../infrastructure_func.h"
#include "pf_performance_timer.hpp"
/** Track follower helper template class (can serve pathfinders and vehicle
@@ -283,6 +284,11 @@
m_err = EC_NO_WAY;
return false;
}
+ /* road stops shouldn't be entered unless allowed to */
+ if (!IsInfraTileUsageAllowed(m_new_tile, m_veh_owner, VEH_ROAD)) {
+ m_err = EC_OWNER;
+ return false;
+ }
}
/* single tram bits can only be entered from one direction */
@@ -301,8 +307,8 @@
m_err = EC_NO_WAY;
return false;
}
- /* don't try to enter other company's depots */
- if (GetTileOwner(m_new_tile) != m_veh_owner) {
+ /* don't try to enter other company's depots if not allowed */
+ if (!IsInfraTileUsageAllowed(m_new_tile, m_veh_owner, VEH_ROAD)) {
m_err = EC_OWNER;
return false;
}
@@ -315,8 +321,8 @@
}
}
- /* rail transport is possible only on tiles with the same owner as vehicle */
- if (IsRailTT() && GetTileOwner(m_new_tile) != m_veh_owner) {
+ /* rail transport is possible only on tiles with the same owner as vehicle if sharing of tracks is disabled */
+ if (IsRailTT() && !IsInfraTileUsageAllowed(m_new_tile, m_veh_owner, VEH_TRAIN)) {
/* different owner */
m_err = EC_NO_WAY;
return false;
diff -r c43adf6620c6 src/pathfinder/npf/npf.cpp
--- a/src/pathfinder/npf/npf.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/pathfinder/npf/npf.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -22,6 +22,7 @@
#include "../../ship.h"
#include "../../train.h"
#include "../../roadstop_base.h"
+#include "../../infrastructure_func.h"
#include "../pathfinder_func.h"
#include "../pathfinder_type.h"
#include "../follow_track.hpp"
@@ -674,25 +675,31 @@
*/
static bool CanEnterTileOwnerCheck(Owner owner, TileIndex tile, DiagDirection enterdir)
{
- if (IsTileType(tile, MP_RAILWAY) || // Rail tile (also rail depot)
- HasStationTileRail(tile) || // Rail station tile/waypoint
- IsRoadDepotTile(tile) || // Road depot tile
- IsStandardRoadStopTile(tile)) { // Road station tile (but not drive-through stops)
- return IsTileOwner(tile, owner); // You need to own these tiles entirely to use them
- }
+ switch (GetTileType(tile)) {
+ case MP_RAILWAY:
+ return IsInfraTileUsageAllowed(tile, owner, VEH_TRAIN); // Rail tile (also rail depot)
- switch (GetTileType(tile)) {
case MP_ROAD:
/* rail-road crossing : are we looking at the railway part? */
if (IsLevelCrossing(tile) &&
DiagDirToAxis(enterdir) != GetCrossingRoadAxis(tile)) {
- return IsTileOwner(tile, owner); // Railway needs owner check, while the street is public
+ return IsInfraTileUsageAllowed(tile, owner, VEH_TRAIN); // Railway needs owner check, while the street is public
+ } else if (IsRoadDepot(tile)) { // Road depot tile
+ return IsInfraTileUsageAllowed(tile, owner, VEH_ROAD);
+ }
+ break;
+
+ case MP_STATION:
+ if (HasStationRail(tile)) { // Rail station tile/waypoint
+ return IsInfraTileUsageAllowed(tile, owner, VEH_TRAIN);
+ } else if (IsStandardRoadStopTile(tile)) { // Road station tile (but not drive-through stops)
+ return IsInfraTileUsageAllowed(tile, owner, VEH_ROAD);
}
break;
case MP_TUNNELBRIDGE:
if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) {
- return IsTileOwner(tile, owner);
+ return IsInfraTileUsageAllowed(tile, owner, VEH_TRAIN);
}
break;
diff -r c43adf6620c6 src/rev.cpp.in
--- a/src/rev.cpp.in Wed Dec 30 18:07:28 2009 +0000
+++ b/src/rev.cpp.in Tue Jun 22 17:59:34 2010 +0200
@@ -27,7 +27,7 @@
* norev000 is for non-releases that are made on systems without
* subversion or sources that are not a checkout of subversion.
*/
-const char _openttd_revision[] = "!!VERSION!!";
+const char _openttd_revision[] = "IS2.1.1";
/**
* The text version of OpenTTD's build date.
@@ -60,11 +60,11 @@
* final release will always have a lower version number than the released
* version, thus making comparisions on specific revisions easy.
*/
-const uint32 _openttd_newgrf_version = 1 << 28 | 0 << 24 | 0 << 20 | 0 << 19 | (!!REVISION!! & ((1 << 19) - 1));
+const uint32 _openttd_newgrf_version = 1 << 28 | 0 << 24 | 0 << 20 | 0 << 19 | (18667 & ((1 << 19) - 1));
#ifdef __MORPHOS__
/**
* Variable used by MorphOS to show the version.
*/
-extern const char morphos_versions_tag[] = "$VER: OpenTTD !!VERSION!! (!!DATE!!) OpenTTD Team [MorphOS, PowerPC]";
+extern const char morphos_versions_tag[] = "$VER: OpenTTD IS2.1.1 (!!DATE!!) OpenTTD Team [MorphOS, PowerPC]";
#endif
diff -r c43adf6620c6 src/roadveh_cmd.cpp
--- a/src/roadveh_cmd.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/roadveh_cmd.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -38,6 +38,7 @@
#include "cargotype.h"
#include "spritecache.h"
#include "debug.h"
+#include "infrastructure_func.h"
#include "table/strings.h"
#include "table/sprites.h"
@@ -209,7 +210,7 @@
/* The ai_new queries the vehicle cost before building the route,
* so we must check against cheaters no sooner than now. --pasky */
if (!IsRoadDepotTile(tile)) return CMD_ERROR;
- if (!IsTileOwner(tile, _current_company)) return CMD_ERROR;
+ if (!CheckInfraUsageAllowed(GetTileOwner(tile), VEH_ROAD)) return CMD_ERROR;
if (HasTileRoadType(tile, ROADTYPE_TRAM) != HasBit(e->info.misc_flags, EF_ROAD_TRAM)) return_cmd_error(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE);
@@ -414,7 +415,7 @@
CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
RoadVehicle *v = RoadVehicle::GetIfValid(p1);
- if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
+ if (v == NULL || !CheckVehicleControlAllowed(v)) return CMD_ERROR;
if ((v->vehstatus & VS_STOPPED) ||
(v->vehstatus & VS_CRASHED) ||
@@ -938,14 +939,14 @@
TrackdirBits trackdirs = TrackStatusToTrackdirBits(ts);
if (IsTileType(tile, MP_ROAD)) {
- if (IsRoadDepot(tile) && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir || (GetRoadTypes(tile) & v->compatible_roadtypes) == 0)) {
+ if (IsRoadDepot(tile) && (!IsInfraTileUsageAllowed(tile, v->owner, VEH_ROAD) || GetRoadDepotDirection(tile) == enterdir || (GetRoadTypes(tile) & v->compatible_roadtypes) == 0)) {
/* Road depot owned by another company or with the wrong orientation */
trackdirs = TRACKDIR_BIT_NONE;
}
} else if (IsTileType(tile, MP_STATION) && IsStandardRoadStopTile(tile)) {
/* Standard road stop (drive-through stops are treated as normal road) */
- if (!IsTileOwner(tile, v->owner) || GetRoadStopDir(tile) == enterdir || v->HasArticulatedPart()) {
+ if (!IsInfraTileUsageAllowed(tile, v->owner, VEH_ROAD) || GetRoadStopDir(tile) == enterdir || v->HasArticulatedPart()) {
/* different station owner or wrong orientation or the vehicle has articulated parts */
trackdirs = TRACKDIR_BIT_NONE;
} else {
@@ -1439,7 +1440,7 @@
/* In case an RV is stopped in a road stop, why not try to load? */
if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
- v->owner == GetTileOwner(v->tile) && !v->current_order.IsType(OT_LEAVESTATION) &&
+ IsInfraTileUsageAllowed(v->tile, v->owner, VEH_ROAD) && !v->current_order.IsType(OT_LEAVESTATION) &&
GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK)) {
Station *st = Station::GetByTile(v->tile);
v->last_station_visited = st->index;
@@ -1473,7 +1474,7 @@
_road_veh_data_1[v->state - RVSB_IN_ROAD_STOP + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)] == v->frame) ||
(IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
- v->owner == GetTileOwner(v->tile) &&
+ IsInfraTileUsageAllowed(v->tile, v->owner, VEH_ROAD) &&
GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK) &&
v->frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
diff -r c43adf6620c6 src/saveload/saveload.cpp
--- a/src/saveload/saveload.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/saveload/saveload.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -47,7 +47,7 @@
#include "saveload_internal.h"
-extern const uint16 SAVEGAME_VERSION = 132;
+extern const uint16 SAVEGAME_VERSION = 133;
SavegameType _savegame_type; ///< type of savegame we are loading
diff -r c43adf6620c6 src/settings.cpp
--- a/src/settings.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/settings.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -64,6 +64,7 @@
#include "void_map.h"
#include "station_base.h"
+#include "infrastructure_func.h"
#include "table/strings.h"
#include "table/settings.h"
@@ -983,6 +984,28 @@
return true;
}
+static bool CheckSharingRail(int32 p1)
+{
+ if (!CheckSharingChangePossible(VEH_TRAIN)) return false;
+ UpdateAllBlockSignals();
+ return true;
+}
+
+static bool CheckSharingRoad(int32 p1)
+{
+ return CheckSharingChangePossible(VEH_ROAD);
+}
+
+static bool CheckSharingWater(int32 p1)
+{
+ return CheckSharingChangePossible(VEH_SHIP);
+}
+
+static bool CheckSharingAir(int32 p1)
+{
+ return CheckSharingChangePossible(VEH_AIRCRAFT);
+}
+
#ifdef ENABLE_NETWORK
static bool UpdateClientName(int32 p1)
diff -r c43adf6620c6 src/settings_gui.cpp
--- a/src/settings_gui.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/settings_gui.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -1387,8 +1387,23 @@
/** Computer players sub-page */
static SettingsPage _settings_ai_npc_page = {_settings_ai_npc, lengthof(_settings_ai_npc)};
+static SettingEntry _settings_sharing[] = {
+ SettingEntry("sharing.sharing_rail"),
+ SettingEntry("sharing.sharing_road"),
+ SettingEntry("sharing.sharing_water"),
+ SettingEntry("sharing.sharing_air"),
+ SettingEntry("sharing.fee_rail"),
+ SettingEntry("sharing.fee_road"),
+ SettingEntry("sharing.fee_water"),
+ SettingEntry("sharing.fee_air"),
+ SettingEntry("sharing.payment_in_debt"),
+};
+/** Infrastructure sharing sub-page */
+static SettingsPage _settings_sharing_page = {_settings_sharing, lengthof(_settings_sharing)};
+
static SettingEntry _settings_ai[] = {
SettingEntry(&_settings_ai_npc_page, STR_CONFIG_SETTING_AI_NPC),
+ SettingEntry(&_settings_sharing_page, STR_CONFIG_SETTING_SHARING),
SettingEntry("economy.give_money"),
SettingEntry("economy.allow_shares"),
};
diff -r c43adf6620c6 src/settings_type.h
--- a/src/settings_type.h Wed Dec 30 18:07:28 2009 +0000
+++ b/src/settings_type.h Tue Jun 22 17:59:34 2010 +0200
@@ -354,6 +354,19 @@
byte station_spread; ///< amount a station may spread
};
+/** Settings related to infrastructure sharing */
+struct SharingSettings {
+ bool sharing_rail; ///< Enable infrastructure sharing for rails, including stations and depots
+ bool sharing_road; ///< Enable infrastructure sharing for road stops and depots
+ bool sharing_water; ///< Enable infrastructure sharing for docks and ship depots
+ bool sharing_air; ///< Enable infrastructure sharing for airports
+ uint fee_rail; ///< Track toll for trains
+ uint fee_road; ///< Loading fee for road vehicles
+ uint fee_water; ///< Loading fee for aircraft
+ uint fee_air; ///< Loading fee for aircraft
+ bool payment_in_debt; ///< Whether to allow fee payment for companies with more loan than money. Switch off to prevent MP exploits.
+};
+
/** Default settings for vehicles. */
struct VehicleDefaultSettings {
bool servint_ispercent; ///< service intervals are in percents
@@ -385,6 +398,7 @@
EconomySettings economy; ///< settings to change the economy
StationSettings station; ///< settings related to station management
LocaleSettings locale; ///< settings related to used currency/unit system in the current game
+ SharingSettings sharing; ///< settings related to infrastructure sharing
};
/** All settings that are only important for the local client. */
diff -r c43adf6620c6 src/ship_cmd.cpp
--- a/src/ship_cmd.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/ship_cmd.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -36,6 +36,7 @@
#include "ai/ai.hpp"
#include "pathfinder/opf/opf_ship.h"
#include "landscape_type.h"
+#include "infrastructure_func.h"
#include "table/strings.h"
#include "table/sprites.h"
@@ -111,7 +112,7 @@
FOR_ALL_DEPOTS(depot) {
TileIndex tile = depot->xy;
- if (IsShipDepotTile(tile) && IsTileOwner(tile, v->owner)) {
+ if (IsShipDepotTile(tile) && IsInfraTileUsageAllowed(tile, v->owner, VEH_SHIP)) {
uint dist = DistanceManhattan(tile, v->tile);
if (dist < best_dist) {
best_dist = dist;
@@ -623,7 +624,7 @@
/* The ai_new queries the vehicle cost before building the route,
* so we must check against cheaters no sooner than now. --pasky */
if (!IsShipDepotTile(tile)) return CMD_ERROR;
- if (!IsTileOwner(tile, _current_company)) return CMD_ERROR;
+ if (!CheckInfraUsageAllowed(GetTileOwner(tile), VEH_SHIP)) return CMD_ERROR;
unit_num = (flags & DC_AUTOREPLACE) ? 0 : GetFreeUnitNumber(VEH_SHIP);
diff -r c43adf6620c6 src/signal.cpp
--- a/src/signal.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/signal.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -16,6 +16,7 @@
#include "vehicle_func.h"
#include "functions.h"
#include "train.h"
+#include "infrastructure_func.h"
/** these are the maximums used for updating signal blocks */
@@ -278,7 +279,7 @@
switch (GetTileType(tile)) {
case MP_RAILWAY: {
- if (GetTileOwner(tile) != owner) continue; // do not propagate signals on others' tiles (remove for tracksharing)
+ if (!IsOneSignalBlock(owner, GetTileOwner(tile))) continue;
if (IsRailDepot(tile)) {
if (enterdir == INVALID_DIAGDIR) { // from 'inside' - train just entered or left the depot
@@ -351,7 +352,7 @@
case MP_STATION:
if (!HasStationRail(tile)) continue;
- if (GetTileOwner(tile) != owner) continue;
+ if (!IsOneSignalBlock(owner, GetTileOwner(tile))) continue;
if (DiagDirToAxis(enterdir) != GetRailStationAxis(tile)) continue; // different axis
if (IsStationTileBlocked(tile)) continue; // 'eye-candy' station tile
@@ -361,7 +362,7 @@
case MP_ROAD:
if (!IsLevelCrossing(tile)) continue;
- if (GetTileOwner(tile) != owner) continue;
+ if (!IsOneSignalBlock(owner, GetTileOwner(tile))) continue;
if (DiagDirToAxis(enterdir) == GetCrossingRoadAxis(tile)) continue; // different axis
if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
@@ -369,7 +370,7 @@
break;
case MP_TUNNELBRIDGE: {
- if (GetTileOwner(tile) != owner) continue;
+ if (!IsOneSignalBlock(owner, GetTileOwner(tile))) continue;
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
DiagDirection dir = GetTunnelBridgeDirection(tile);
@@ -583,8 +584,9 @@
DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE
};
- /* do not allow signal updates for two companies in one run */
- assert(_globset.IsEmpty() || owner == _last_owner);
+ /* do not allow signal updates for two companies in one run,
+ * if these companies are not part of the same signal block */
+ assert(_globset.IsEmpty() || IsOneSignalBlock(owner, _last_owner));
_last_owner = owner;
@@ -608,8 +610,9 @@
*/
void AddSideToSignalBuffer(TileIndex tile, DiagDirection side, Owner owner)
{
- /* do not allow signal updates for two companies in one run */
- assert(_globset.IsEmpty() || owner == _last_owner);
+ /* do not allow signal updates for two companies in one run,
+ * if these companies are not part of the same signal block */
+ assert(_globset.IsEmpty() || IsOneSignalBlock(owner, _last_owner));
_last_owner = owner;
diff -r c43adf6620c6 src/table/settings.h
--- a/src/table/settings.h Wed Dec 30 18:07:28 2009 +0000
+++ b/src/table/settings.h Tue Jun 22 17:59:34 2010 +0200
@@ -34,6 +34,10 @@
static bool ChangeDynamicEngines(int32 p1);
static bool StationCatchmentChanged(int32 p1);
static bool InvalidateVehTimetableWindow(int32 p1);
+static bool CheckSharingRail(int32 p1);
+static bool CheckSharingRoad(int32 p1);
+static bool CheckSharingWater(int32 p1);
+static bool CheckSharingAir(int32 p1);
#ifdef ENABLE_NETWORK
static bool UpdateClientName(int32 p1);
@@ -446,6 +450,16 @@
SDT_BOOL(GameSettings, ai.ai_disable_veh_ship, 0, 0, false, STR_CONFIG_SETTING_AI_BUILDS_SHIPS, NULL),
SDT_CONDVAR(GameSettings, ai.ai_max_opcode_till_suspend, SLE_UINT32,107, SL_MAX_VERSION, 0, NG, 10000, 5000,250000,2500, STR_CONFIG_SETTING_AI_MAX_OPCODES, NULL),
+ SDT_CONDBOOL(GameSettings, sharing.sharing_rail, 133, SL_MAX_VERSION, 0, 0, false, STR_CONFIG_SETTING_SHARING_RAIL, CheckSharingRail),
+ SDT_CONDBOOL(GameSettings, sharing.sharing_road, 133, SL_MAX_VERSION, 0, 0, false, STR_CONFIG_SETTING_SHARING_ROAD, CheckSharingRoad),
+ SDT_CONDBOOL(GameSettings, sharing.sharing_water, 133, SL_MAX_VERSION, 0, 0, false, STR_CONFIG_SETTING_SHARING_WATER, CheckSharingWater),
+ SDT_CONDBOOL(GameSettings, sharing.sharing_air, 133, SL_MAX_VERSION, 0, 0, false, STR_CONFIG_SETTING_SHARING_AIR, CheckSharingAir),
+ SDT_CONDVAR(GameSettings, sharing.fee_rail, SLE_UINT,133, SL_MAX_VERSION, 0,CR, 100, 0, 1000000, 10,STR_CONFIG_SETTING_SHARING_FEE_RAIL, NULL),
+ SDT_CONDVAR(GameSettings, sharing.fee_road, SLE_UINT,133, SL_MAX_VERSION, 0,CR, 100, 0, 1000000, 10,STR_CONFIG_SETTING_SHARING_FEE_ROAD, NULL),
+ SDT_CONDVAR(GameSettings, sharing.fee_water, SLE_UINT,133, SL_MAX_VERSION, 0,CR, 100, 0, 1000000, 10,STR_CONFIG_SETTING_SHARING_FEE_WATER, NULL),
+ SDT_CONDVAR(GameSettings, sharing.fee_air, SLE_UINT,133, SL_MAX_VERSION, 0,CR, 100, 0, 1000000, 10,STR_CONFIG_SETTING_SHARING_FEE_AIR, NULL),
+ SDT_CONDBOOL(GameSettings, sharing.payment_in_debt, 133, SL_MAX_VERSION, 0, 0, false, STR_CONFIG_SETTING_SHARING_PAYMENT_IN_DEBT,NULL),
+
SDT_VAR(GameSettings, vehicle.extend_vehicle_life, SLE_UINT8, 0, 0, 0, 0, 100, 0, STR_NULL, NULL),
SDT_VAR(GameSettings, economy.dist_local_authority, SLE_UINT8, 0, 0, 20, 5, 60, 0, STR_NULL, NULL),
SDT_VAR(GameSettings, pf.wait_oneway_signal, SLE_UINT8, 0, 0, 15, 2, 255, 0, STR_NULL, NULL),
diff -r c43adf6620c6 src/train.h
--- a/src/train.h Wed Dec 30 18:07:28 2009 +0000
+++ b/src/train.h Tue Jun 22 17:59:34 2010 +0200
@@ -55,6 +55,8 @@
void FreeTrainTrackReservation(const Train *v, TileIndex origin = INVALID_TILE, Trackdir orig_td = INVALID_TRACKDIR);
bool TryPathReserve(Train *v, bool mark_as_stuck = false, bool first_tile_okay = false);
+void DeleteVisibleTrain(Train *v);
+
int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, int *station_ahead, int *station_length);
void TrainConsistChanged(Train *v, bool same_length);
diff -r c43adf6620c6 src/train_cmd.cpp
--- a/src/train_cmd.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/train_cmd.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -38,6 +38,7 @@
#include "gamelog.h"
#include "network/network.h"
#include "spritecache.h"
+#include "infrastructure_func.h"
#include "table/strings.h"
#include "table/train_cmd.h"
@@ -851,7 +852,7 @@
/* Check if the train is actually being built in a depot belonging
* to the company. Doesn't matter if only the cost is queried */
if (!IsRailDepotTile(tile)) return CMD_ERROR;
- if (!IsTileOwner(tile, _current_company)) return CMD_ERROR;
+ if (!CheckInfraUsageAllowed(GetTileOwner(tile), VEH_TRAIN)) return CMD_ERROR;
if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags);
@@ -1972,7 +1973,7 @@
CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
Train *v = Train::GetIfValid(p1);
- if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
+ if (v == NULL || !CheckVehicleControlAllowed(v)) return CMD_ERROR;
if (p2 != 0) {
/* turn a single unit around */
@@ -2039,7 +2040,7 @@
CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
Train *t = Train::GetIfValid(p1);
- if (t == NULL || !CheckOwnership(t->owner)) return CMD_ERROR;
+ if (t == NULL || !CheckVehicleControlAllowed(t)) return CMD_ERROR;
if (flags & DC_EXEC) {
/* If we are forced to proceed, cancel that order.
@@ -3083,7 +3084,7 @@
static inline bool CheckCompatibleRail(const Train *v, TileIndex tile)
{
return
- IsTileOwner(tile, v->owner) && (
+ IsInfraTileUsageAllowed(tile, v->owner, VEH_TRAIN) && (
!v->IsFrontEngine() ||
HasBit(v->compatible_railtypes, GetRailType(tile))
);
@@ -4197,6 +4198,9 @@
/* running costs */
CommandCost cost(EXPENSES_TRAIN_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS));
+ /* sharing fee */
+ PayDailyTrackSharingFee(this);
+
this->profit_this_year -= cost.GetCost();
this->running_ticks = 0;
@@ -4227,3 +4231,47 @@
return TrackDirectionToTrackdir(FindFirstTrack(this->track), this->direction);
}
+
+/**
+ * Delete a train while it is visible.
+ * This happens when a company bankrupts when infrastructure sharing is enabled.
+ * @param v The train to delete.
+ */
+void DeleteVisibleTrain(Train *v)
+{
+ FreeTrainTrackReservation(v);
+ TileIndex crossing = TrainApproachingCrossingTile(v);
+
+ /* delete train from back to front */
+ Train *u;
+ Train *prev = v->Last();
+ do {
+ u = prev;
+ prev = u->Previous();
+ if (prev != NULL) prev->SetNext(NULL);
+
+ /* 'u' shouldn't be accessed after it has been deleted */
+ TileIndex tile = u->tile;
+ TrackBits trackbits = u->track;
+
+ delete u;
+
+ if (trackbits == TRACK_BIT_WORMHOLE) {
+ /* Vehicle is inside a wormhole, u->track contains no useful value then. */
+ trackbits = DiagDirToDiagTrackBits(GetTunnelBridgeDirection(tile));
+ }
+
+ Track track = TrackBitsToTrack(trackbits);
+ if (HasReservedTracks(tile, trackbits)) UnreserveRailTrack(tile, track);
+ if (IsLevelCrossingTile(tile)) UpdateLevelCrossing(tile);
+
+ /* Update signals */
+ if (IsTileType(tile, MP_TUNNELBRIDGE) || IsRailDepotTile(tile)) {
+ UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, GetTileOwner(tile));
+ } else {
+ SetSignalsOnBothDir(tile, track, GetTileOwner(tile));
+ }
+ } while (prev != NULL);
+
+ if (crossing != INVALID_TILE) UpdateLevelCrossing(crossing);
+}
diff -r c43adf6620c6 src/vehicle.cpp
--- a/src/vehicle.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/vehicle.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -47,6 +47,7 @@
#include "economy_base.h"
#include "articulated_vehicles.h"
#include "roadstop_base.h"
+#include "infrastructure_func.h"
#include "table/sprites.h"
#include "table/strings.h"
@@ -1585,6 +1586,9 @@
case OT_LOADING: {
uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
+ /* Pay the loading fee for using someone else's station, if appropriate */
+ if (!mode && this->type != VEH_TRAIN) PayStationSharingFee(this, Station::Get(this->last_station_visited));
+
/* Not the first call for this tick, or still loading */
if (mode || !HasBit(this->vehicle_flags, VF_LOADING_FINISHED) ||
(_settings_game.order.timetabling && this->current_order_time < wait_time)) return;
diff -r c43adf6620c6 src/vehicle_cmd.cpp
--- a/src/vehicle_cmd.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/vehicle_cmd.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -27,6 +27,7 @@
#include "string_func.h"
#include "depot_map.h"
#include "vehiclelist.h"
+#include "infrastructure_func.h"
#include "table/strings.h"
@@ -74,7 +75,7 @@
if ((flags & DC_AUTOREPLACE) == 0) SetBit(p2, 0);
Vehicle *v = Vehicle::GetIfValid(p1);
- if (v == NULL || !CheckOwnership(v->owner) || !v->IsPrimaryVehicle()) return CMD_ERROR;
+ if (v == NULL || !CheckVehicleControlAllowed(v) || !v->IsPrimaryVehicle()) return CMD_ERROR;
switch (v->type) {
case VEH_TRAIN:
@@ -217,7 +218,7 @@
VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8);
bool all_or_nothing = HasBit(p2, 0);
- if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
+ if (!IsDepotTile(tile) || !CheckInfraUsageAllowed(GetTileOwner(tile), vehicle_type)) return CMD_ERROR;
/* Get the list of vehicles in the depot */
BuildDepotVehicleList(vehicle_type, tile, &list, &list, true);
diff -r c43adf6620c6 src/vehicle_gui.cpp
--- a/src/vehicle_gui.cpp Wed Dec 30 18:07:28 2009 +0000
+++ b/src/vehicle_gui.cpp Tue Jun 22 17:59:34 2010 +0200
@@ -40,6 +40,7 @@
#include "articulated_vehicles.h"
#include "cargotype.h"
#include "spritecache.h"
+#include "infrastructure_func.h"
#include "table/sprites.h"
#include "table/strings.h"
@@ -1954,6 +1955,7 @@
{
const Vehicle *v = Vehicle::Get(this->window_number);
bool is_localcompany = v->owner == _local_company;
+ bool can_control = IsVehicleControlAllowed(v, _local_company);
bool refitable_and_stopped_in_depot = IsVehicleRefitable(v);
this->SetWidgetDisabledState(VVW_WIDGET_GOTO_DEPOT, !is_localcompany);
@@ -1962,8 +1964,8 @@
if (v->type == VEH_TRAIN) {
this->SetWidgetLoweredState(VVW_WIDGET_FORCE_PROCEED, Train::From(v)->force_proceed == 2);
- this->SetWidgetDisabledState(VVW_WIDGET_FORCE_PROCEED, !is_localcompany);
- this->SetWidgetDisabledState(VVW_WIDGET_TURN_AROUND, !is_localcompany);
+ this->SetWidgetDisabledState(VVW_WIDGET_FORCE_PROCEED, !can_control);
+ this->SetWidgetDisabledState(VVW_WIDGET_TURN_AROUND, !can_control);
}
this->DrawWidgets();