Merge branch 'chunnel' into jgrpp
# Conflicts: # src/ground_vehicle.hpp
This commit is contained in:
@@ -404,6 +404,7 @@ transparency.h
|
||||
transparency_gui.h
|
||||
transport_type.h
|
||||
tunnelbridge.h
|
||||
tunnel_base.h
|
||||
vehicle_base.h
|
||||
vehicle_func.h
|
||||
vehicle_gui.h
|
||||
@@ -670,6 +671,7 @@ saveload/strings_sl.cpp
|
||||
saveload/story_sl.cpp
|
||||
saveload/subsidy_sl.cpp
|
||||
saveload/town_sl.cpp
|
||||
saveload/tunnel_sl.cpp
|
||||
saveload/vehicle_sl.cpp
|
||||
saveload/waypoint_sl.cpp
|
||||
saveload/signal_sl.cpp
|
||||
|
@@ -196,6 +196,7 @@ DEFINE_POOL_METHOD(void)::FreeItem(size_t index)
|
||||
DEFINE_POOL_METHOD(void)::CleanPool()
|
||||
{
|
||||
this->cleaning = true;
|
||||
Titem::PreCleanPool();
|
||||
for (size_t i = 0; i < this->first_unused; i++) {
|
||||
delete this->Get(i); // 'delete NULL;' is very valid
|
||||
}
|
||||
|
@@ -286,6 +286,13 @@ struct Pool : PoolBase {
|
||||
* @note it's called only when !CleaningPool()
|
||||
*/
|
||||
static inline void PostDestructor(size_t index) { }
|
||||
|
||||
/**
|
||||
* Dummy function called before a pool is about to be cleaned.
|
||||
* If you want to use it, override it in PoolItem's subclass.
|
||||
* @note it's called only when CleaningPool()
|
||||
*/
|
||||
static inline void PreCleanPool() { }
|
||||
};
|
||||
|
||||
private:
|
||||
|
@@ -13,6 +13,8 @@
|
||||
#include "train.h"
|
||||
#include "roadveh.h"
|
||||
#include "depot_map.h"
|
||||
#include "tunnel_base.h"
|
||||
#include "slope_type.h"
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
@@ -280,6 +282,66 @@ bool GroundVehicle<T, Type>::IsChainInDepot() const
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates vehicle's Z inclination inside a wormhole, where applicable.
|
||||
*/
|
||||
template <class T, VehicleType Type>
|
||||
void GroundVehicle<T, Type>::UpdateZPositionInWormhole()
|
||||
{
|
||||
if (!IsTunnel(this->tile)) return;
|
||||
|
||||
const Tunnel *t = Tunnel::GetByTile(this->tile);
|
||||
if (!t->is_chunnel) return;
|
||||
|
||||
TileIndex pos_tile = TileVirtXY(this->x_pos, this->y_pos);
|
||||
|
||||
ClrBit(this->gv_flags, GVF_GOINGUP_BIT);
|
||||
ClrBit(this->gv_flags, GVF_GOINGDOWN_BIT);
|
||||
|
||||
if (pos_tile == t->tile_n || pos_tile == t->tile_s) {
|
||||
this->z_pos = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
int north_coord, south_coord, pos_coord;
|
||||
bool going_north;
|
||||
Slope slope_north;
|
||||
if (t->tile_s - t->tile_n > MapMaxX()) {
|
||||
// tunnel extends along Y axis (DIAGDIR_SE from north end), has same X values
|
||||
north_coord = TileY(t->tile_n);
|
||||
south_coord = TileY(t->tile_s);
|
||||
pos_coord = TileY(pos_tile);
|
||||
going_north = (this->direction == DIR_NW);
|
||||
slope_north = SLOPE_NW;
|
||||
} else {
|
||||
// tunnel extends along X axis (DIAGDIR_SW from north end), has same Y values
|
||||
north_coord = TileX(t->tile_n);
|
||||
south_coord = TileX(t->tile_s);
|
||||
pos_coord = TileX(pos_tile);
|
||||
going_north = (this->direction == DIR_NE);
|
||||
slope_north = SLOPE_NE;
|
||||
}
|
||||
|
||||
Slope slope = SLOPE_FLAT;
|
||||
|
||||
int delta;
|
||||
if ((delta = pos_coord - north_coord) <= 3) {
|
||||
this->z_pos = TILE_HEIGHT * (delta == 3 ? -2 : -1);
|
||||
if (delta != 2) {
|
||||
slope = slope_north;
|
||||
SetBit(this->gv_flags, going_north ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT);
|
||||
}
|
||||
} else if ((delta = south_coord - pos_coord) <= 3) {
|
||||
this->z_pos = TILE_HEIGHT * (delta == 3 ? -2 : -1);
|
||||
if (delta != 2) {
|
||||
slope = SLOPE_ELEVATED ^ slope_north;
|
||||
SetBit(this->gv_flags, going_north ? GVF_GOINGDOWN_BIT : GVF_GOINGUP_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
if (slope != SLOPE_FLAT) this->z_pos += GetPartialPixelZ(this->x_pos & 0xF, this->y_pos & 0xF, slope);
|
||||
}
|
||||
|
||||
/* Instantiation for Train */
|
||||
template struct GroundVehicle<Train, VEH_TRAIN>;
|
||||
/* Instantiation for RoadVehicle */
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include "vehicle_gui.h"
|
||||
#include "landscape.h"
|
||||
#include "window_func.h"
|
||||
#include "tunnel_map.h"
|
||||
#include "widgets/vehicle_widget.h"
|
||||
|
||||
/** What is the status of our acceleration? */
|
||||
@@ -54,6 +55,7 @@ enum GroundVehicleFlags {
|
||||
GVF_GOINGUP_BIT = 0, ///< Vehicle is currently going uphill. (Cached track information for acceleration)
|
||||
GVF_GOINGDOWN_BIT = 1, ///< Vehicle is currently going downhill. (Cached track information for acceleration)
|
||||
GVF_SUPPRESS_IMPLICIT_ORDERS = 2, ///< Disable insertion and removal of automatic orders until the vehicle completes the real order.
|
||||
GVF_CHUNNEL_BIT = 3, ///< Vehicle may currently be in a chunnel. (Cached track information for inclination changes)
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -228,7 +230,13 @@ struct GroundVehicle : public SpecializedVehicle<T, Type> {
|
||||
#ifdef _DEBUG
|
||||
assert(this->z_pos == GetSlopePixelZ(this->x_pos, this->y_pos));
|
||||
#endif
|
||||
|
||||
if (HasBit(this->gv_flags, GVF_CHUNNEL_BIT) && !IsTunnelTile(this->tile)) {
|
||||
ClrBit(this->gv_flags, GVF_CHUNNEL_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateZPositionInWormhole();
|
||||
|
||||
/**
|
||||
* Checks if the vehicle is in a slope and sets the required flags in that case.
|
||||
@@ -236,11 +244,13 @@ struct GroundVehicle : public SpecializedVehicle<T, Type> {
|
||||
* @param update_delta Indicates to also update the delta.
|
||||
* @return Old height of the vehicle.
|
||||
*/
|
||||
inline int UpdateInclination(bool new_tile, bool update_delta)
|
||||
inline int UpdateInclination(bool new_tile, bool update_delta, bool in_wormhole = false)
|
||||
{
|
||||
int old_z = this->z_pos;
|
||||
|
||||
if (new_tile) {
|
||||
if (in_wormhole) {
|
||||
if (HasBit(this->gv_flags, GVF_CHUNNEL_BIT)) this->UpdateZPositionInWormhole();
|
||||
} else if (new_tile) {
|
||||
this->UpdateZPositionAndInclination();
|
||||
} else {
|
||||
this->UpdateZPosition();
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include "cheat_type.h"
|
||||
#include "genworld.h"
|
||||
#include "tree_map.h"
|
||||
#include "tunnel_map.h"
|
||||
#include "newgrf_cargo.h"
|
||||
#include "newgrf_debug.h"
|
||||
#include "newgrf_industrytiles.h"
|
||||
@@ -1457,6 +1458,11 @@ static CommandCost CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town
|
||||
return_cmd_error(STR_ERROR_CAN_ONLY_BE_BUILT_NEAR_TOWN_CENTER);
|
||||
}
|
||||
|
||||
if (type == IT_OIL_RIG &&
|
||||
(IsTunnelInWay(tile, 0) ||
|
||||
IsTunnelInWay(tile + TileDiffXY(0, 1), 0) ||
|
||||
IsTunnelInWay(tile + TileDiffXY(1, 2), 0))) return_cmd_error(STR_ERROR_NO_DRILLING_ABOVE_CHUNNEL);
|
||||
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
|
@@ -1267,6 +1267,9 @@ STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :When enabled, i
|
||||
STR_CONFIG_SETTING_SHIP_COLLISION_AVOIDANCE :Ships avoid collisions: {STRING2}
|
||||
STR_CONFIG_SETTING_SHIP_COLLISION_AVOIDANCE_HELPTEXT :When enabled, ships try to avoid passing through each other. Requires 90° turns to be forbidden.
|
||||
|
||||
STR_CONFIG_SETTING_CHUNNEL :Allow construction of tunnels under water: {STRING2}
|
||||
STR_CONFIG_SETTING_CHUNNEL_HELPTEXT :When enabled, tunnels can be constructed under bodies of water at sea level. This requires the tunnel ends to be least 3 tiles away from the shore.
|
||||
|
||||
STR_CONFIG_SETTING_NO_TRAIN_CRASH_OTHER_COMPANY :Trains from different companies may not crash into each other: {STRING2}
|
||||
STR_CONFIG_SETTING_NO_TRAIN_CRASH_OTHER_COMPANY_HELPTEXT :This setting is primarily to prevent untrusted players deliberately causing crashes involving other companies' trains in multi-player rail infrastructure sharing games.
|
||||
|
||||
@@ -3042,8 +3045,11 @@ STR_LAI_WATER_DESCRIPTION_SHIP_DEPOT :Ship depot
|
||||
# Industries come directly from their industry names
|
||||
|
||||
STR_LAI_TUNNEL_DESCRIPTION_RAILROAD :Railway tunnel
|
||||
STR_LAI_TUNNEL_DESCRIPTION_RAILROAD_CHUNNEL :Railway tunnel (underwater)
|
||||
STR_LAI_TUNNEL_DESCRIPTION_RAILROAD_SIGNAL :Railway tunnel with signal simulation
|
||||
STR_LAI_TUNNEL_DESCRIPTION_RAILROAD_SIGNAL_CHUNNEL :Railway tunnel with signal simulation (underwater)
|
||||
STR_LAI_TUNNEL_DESCRIPTION_ROAD :Road tunnel
|
||||
STR_LAI_TUNNEL_DESCRIPTION_ROAD_CHUNNEL :Road tunnel (underwater)
|
||||
|
||||
STR_LAI_BRIDGE_DESCRIPTION_RAILROAD_SIGNAL :Railway bridge with signal simulation
|
||||
STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL :Steel suspension rail bridge
|
||||
@@ -5002,6 +5008,11 @@ STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY :{WHITE}Another
|
||||
STR_ERROR_TUNNEL_THROUGH_MAP_BORDER :{WHITE}Tunnel would end out of the map
|
||||
STR_ERROR_UNABLE_TO_EXCAVATE_LAND :{WHITE}Unable to excavate land for other end of tunnel
|
||||
STR_ERROR_TUNNEL_TOO_LONG :{WHITE}... tunnel too long
|
||||
STR_ERROR_TUNNEL_RAMP_TOO_SHORT :{WHITE}... ramp too short, tunnels under water must have a ramp at least three tiles long at both ends.
|
||||
STR_ERROR_TUNNEL_TOO_MANY :{WHITE}... too many tunnels
|
||||
STR_ERROR_NO_DRILLING_ABOVE_CHUNNEL :{WHITE}No oil rigs allowed above underwater tunnels.
|
||||
STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY_FOR_CHUNNEL :{WHITE}Three tiles are needed to pass under the other tunnel.
|
||||
STR_ERROR_CHUNNEL_ONLY_OVER_SEA :{WHITE}Underwater tunnels are only allowed to cross sea...
|
||||
|
||||
# Object related errors
|
||||
STR_ERROR_TOO_MANY_OBJECTS :{WHITE}... too many objects
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include "core/geometry_func.hpp"
|
||||
#include "newgrf_debug.h"
|
||||
#include "zoom_func.h"
|
||||
#include "tunnelbridge_map.h"
|
||||
|
||||
#include "widgets/misc_widget.h"
|
||||
|
||||
@@ -123,6 +124,13 @@ public:
|
||||
# define LANDINFOD_LEVEL 1
|
||||
#endif
|
||||
DEBUG(misc, LANDINFOD_LEVEL, "TILE: %#x (%i,%i)", tile, TileX(tile), TileY(tile));
|
||||
if(IsTunnelTile(tile)) {
|
||||
DEBUG(misc, LANDINFOD_LEVEL, "tunnel pool size: %u", (uint)Tunnel::GetPoolSize());
|
||||
DEBUG(misc, LANDINFOD_LEVEL, "index: %#x" , Tunnel::GetByTile(tile)->index);
|
||||
DEBUG(misc, LANDINFOD_LEVEL, "north tile: %#x" , Tunnel::GetByTile(tile)->tile_n);
|
||||
DEBUG(misc, LANDINFOD_LEVEL, "south tile: %#x" , Tunnel::GetByTile(tile)->tile_s);
|
||||
DEBUG(misc, LANDINFOD_LEVEL, "is chunnel: %u" , Tunnel::GetByTile(tile)->is_chunnel);
|
||||
}
|
||||
DEBUG(misc, LANDINFOD_LEVEL, "type = %#x", _m[tile].type);
|
||||
DEBUG(misc, LANDINFOD_LEVEL, "height = %#x", _m[tile].height);
|
||||
DEBUG(misc, LANDINFOD_LEVEL, "m1 = %#x", _m[tile].m1);
|
||||
|
@@ -1184,6 +1184,7 @@ bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
|
||||
v->x_pos = gp.x;
|
||||
v->y_pos = gp.y;
|
||||
v->UpdatePosition();
|
||||
RoadZPosAffectSpeed(v, v->UpdateInclination(false, false, true));
|
||||
if (v->IsDrawn()) v->Vehicle::UpdateViewport(true);
|
||||
return true;
|
||||
}
|
||||
@@ -1555,7 +1556,7 @@ again:
|
||||
v->x_pos = x;
|
||||
v->y_pos = y;
|
||||
v->UpdatePosition();
|
||||
RoadZPosAffectSpeed(v, v->UpdateInclination(false, true));
|
||||
RoadZPosAffectSpeed(v, v->UpdateInclination(false, true, v->state == RVSB_WORMHOLE));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include "../void_map.h"
|
||||
#include "../signs_base.h"
|
||||
#include "../depot_base.h"
|
||||
#include "../tunnel_base.h"
|
||||
#include "../fios.h"
|
||||
#include "../gamelog_internal.h"
|
||||
#include "../network/network.h"
|
||||
@@ -57,6 +58,7 @@
|
||||
#include "../error.h"
|
||||
#include "../disaster_vehicle.h"
|
||||
#include "../tracerestrict.h"
|
||||
#include "../tunnel_map.h"
|
||||
|
||||
|
||||
#include "saveload_internal.h"
|
||||
@@ -563,6 +565,25 @@ static inline bool MayHaveBridgeAbove(TileIndex t)
|
||||
IsTileType(t, MP_WATER) || IsTileType(t, MP_TUNNELBRIDGE) || IsTileType(t, MP_OBJECT);
|
||||
}
|
||||
|
||||
TileIndex GetOtherTunnelBridgeEndOld(TileIndex tile)
|
||||
{
|
||||
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
||||
TileIndexDiff delta = TileOffsByDiagDir(dir);
|
||||
int z = GetTileZ(tile);
|
||||
|
||||
dir = ReverseDiagDir(dir);
|
||||
do {
|
||||
tile += delta;
|
||||
} while (
|
||||
!IsTunnelTile(tile) ||
|
||||
GetTunnelBridgeDirection(tile) != dir ||
|
||||
GetTileZ(tile) != z
|
||||
);
|
||||
|
||||
return tile;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform a (large) amount of savegame conversion *magic* in order to
|
||||
* load older savegames and to fill the caches for various purposes.
|
||||
@@ -2014,6 +2035,31 @@ bool AfterLoadGame()
|
||||
}
|
||||
}
|
||||
|
||||
/* Tunnel pool has to be initiated before reservations. */
|
||||
if (SlXvIsFeatureMissing(XSLFI_CHUNNEL)) {
|
||||
for (TileIndex t = 0; t < map_size; t++) {
|
||||
if (IsTunnelTile(t)) {
|
||||
DiagDirection dir = GetTunnelBridgeDirection(t);
|
||||
if (dir == DIAGDIR_SE || dir == DIAGDIR_SW) {
|
||||
TileIndex start_tile = t;
|
||||
TileIndex end_tile = GetOtherTunnelBridgeEndOld(start_tile);
|
||||
|
||||
if (!Tunnel::CanAllocateItem()) {
|
||||
SetSaveLoadError(STR_ERROR_TUNNEL_TOO_MANY);
|
||||
/* Restore the signals */
|
||||
ResetSignalHandlers();
|
||||
return false;
|
||||
}
|
||||
|
||||
const Tunnel *t = new Tunnel(start_tile, end_tile, TileHeight(start_tile), false);
|
||||
|
||||
SetTunnelIndex(start_tile, t->index);
|
||||
SetTunnelIndex(end_tile, t->index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Move the signal variant back up one bit for PBS. We don't convert the old PBS
|
||||
* format here, as an old layout wouldn't work properly anyway. To be safe, we
|
||||
* clear any possible PBS reservations as well. */
|
||||
@@ -2648,7 +2694,7 @@ bool AfterLoadGame()
|
||||
} else if (dir == ReverseDiagDir(vdir)) { // Leaving tunnel
|
||||
hidden = frame < TILE_SIZE - _tunnel_visibility_frame[dir];
|
||||
/* v->tile changes at the moment when the vehicle leaves the tunnel. */
|
||||
v->tile = hidden ? GetOtherTunnelBridgeEnd(vtile) : vtile;
|
||||
v->tile = hidden ? GetOtherTunnelBridgeEndOld(vtile) : vtile;
|
||||
} else {
|
||||
/* We could get here in two cases:
|
||||
* - for road vehicles, it is reversing at the end of the tunnel
|
||||
@@ -3335,6 +3381,11 @@ bool AfterLoadGame()
|
||||
_settings_game.economy.town_cargo_scale_factor = _settings_game.economy.old_town_cargo_factor * 10;
|
||||
}
|
||||
|
||||
/* Set day length factor to 1 if loading a pre day length savegame */
|
||||
if (SlXvIsFeatureMissing(XSLFI_VARIABLE_DAY_LENGTH) && SlXvIsFeatureMissing(XSLFI_SPRINGPP)) {
|
||||
_settings_game.economy.day_length_factor = 1;
|
||||
}
|
||||
|
||||
/* Road stops is 'only' updating some caches */
|
||||
AfterLoadRoadStops();
|
||||
AfterLoadLabelMaps();
|
||||
|
@@ -74,6 +74,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
||||
{ XSLFI_EXTENDED_GAMELOG, XSCF_NULL, 1, 1, "extended_gamelog", NULL, NULL, NULL },
|
||||
{ XSLFI_STATION_CATCHMENT_INC, XSCF_NULL, 1, 1, "station_catchment_inc", NULL, NULL, NULL },
|
||||
{ XSLFI_CUSTOM_BRIDGE_HEADS, XSCF_NULL, 1, 1, "custom_bridge_heads", NULL, NULL, NULL },
|
||||
{ XSLFI_CHUNNEL, XSCF_NULL, 1, 1, "chunnel", NULL, NULL, "TUNN" },
|
||||
{ XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker
|
||||
};
|
||||
|
||||
|
@@ -48,6 +48,7 @@ enum SlXvFeatureIndex {
|
||||
XSLFI_EXTENDED_GAMELOG, ///< Extended gamelog
|
||||
XSLFI_STATION_CATCHMENT_INC, ///< Station catchment radius increase
|
||||
XSLFI_CUSTOM_BRIDGE_HEADS, ///< Custom bridge heads
|
||||
XSLFI_CHUNNEL, ///< Tunnels under water (channel tunnel)
|
||||
|
||||
XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit
|
||||
XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk
|
||||
|
@@ -465,6 +465,7 @@ extern const ChunkHandler _plan_chunk_handlers[];
|
||||
extern const ChunkHandler _template_replacement_chunk_handlers[];
|
||||
extern const ChunkHandler _template_vehicle_chunk_handlers[];
|
||||
extern const ChunkHandler _bridge_signal_chunk_handlers[];
|
||||
extern const ChunkHandler _tunnel_chunk_handlers[];
|
||||
|
||||
/** Array of all chunks in a savegame, \c NULL terminated. */
|
||||
static const ChunkHandler * const _chunk_handlers[] = {
|
||||
@@ -508,6 +509,7 @@ static const ChunkHandler * const _chunk_handlers[] = {
|
||||
_template_replacement_chunk_handlers,
|
||||
_template_vehicle_chunk_handlers,
|
||||
_bridge_signal_chunk_handlers,
|
||||
_tunnel_chunk_handlers,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
52
src/saveload/tunnel_sl.cpp
Normal file
52
src/saveload/tunnel_sl.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
/* $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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file tunnel_sl.cpp Code handling saving and loading of tunnels */
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../tunnel_base.h"
|
||||
|
||||
#include "saveload.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
|
||||
static const SaveLoad _tunnel_desc[] = {
|
||||
SLE_CONDVAR(Tunnel, tile_n, SLE_UINT32, 0, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Tunnel, tile_s, SLE_UINT32, 0, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Tunnel, height, SLE_UINT8, 0, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Tunnel, is_chunnel, SLE_BOOL, 0, SL_MAX_VERSION),
|
||||
SLE_END()
|
||||
};
|
||||
|
||||
static void Save_TUNN()
|
||||
{
|
||||
Tunnel *tunnel;
|
||||
|
||||
FOR_ALL_TUNNELS(tunnel) {
|
||||
SlSetArrayIndex(tunnel->index);
|
||||
SlObject(tunnel, _tunnel_desc);
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_TUNN()
|
||||
{
|
||||
int index;
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Tunnel *tunnel = new (index) Tunnel();
|
||||
SlObject(tunnel, _tunnel_desc);
|
||||
tunnel->UpdateIndexes();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern const ChunkHandler _tunnel_chunk_handlers[] = {
|
||||
{ 'TUNN', Save_TUNN, Load_TUNN, NULL, NULL, CH_ARRAY | CH_LAST},
|
||||
};
|
@@ -1701,6 +1701,7 @@ static SettingsContainer &GetSettingsTree()
|
||||
limitations->Add(new SettingEntry("construction.max_bridge_length"));
|
||||
limitations->Add(new SettingEntry("construction.max_bridge_height"));
|
||||
limitations->Add(new SettingEntry("construction.max_tunnel_length"));
|
||||
limitations->Add(new SettingEntry("construction.chunnel"));
|
||||
limitations->Add(new SettingEntry("station.never_expire_airports"));
|
||||
limitations->Add(new SettingEntry("vehicle.never_expire_vehicles"));
|
||||
limitations->Add(new SettingEntry("vehicle.max_trains"));
|
||||
|
@@ -355,6 +355,7 @@ struct ConstructionSettings {
|
||||
byte simulated_wormhole_signals; ///< simulate signals in tunnel
|
||||
bool enable_build_river; ///< enable building rivers in-game
|
||||
uint8 road_custom_bridge_heads; ///< allow construction of road custom bridge heads
|
||||
bool chunnel; ///< allow construction of tunnels under water
|
||||
|
||||
uint32 terraform_per_64k_frames; ///< how many tile heights may, over a long period, be terraformed per 65536 frames?
|
||||
uint16 terraform_frame_burst; ///< how many tile heights may, over a short period, be terraformed?
|
||||
|
@@ -597,6 +597,16 @@ str = STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH
|
||||
strhelp = STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT
|
||||
strval = STR_CONFIG_SETTING_TILE_LENGTH
|
||||
|
||||
[SDT_BOOL]
|
||||
base = GameSettings
|
||||
var = construction.chunnel
|
||||
def = false
|
||||
str = STR_CONFIG_SETTING_CHUNNEL
|
||||
strhelp = STR_CONFIG_SETTING_CHUNNEL_HELPTEXT
|
||||
from = 0
|
||||
cat = SC_BASIC
|
||||
patxname = ""chunnel.construction.chunnel""
|
||||
|
||||
[SDT_VAR]
|
||||
base = GameSettings
|
||||
var = construction.simulated_wormhole_signals
|
||||
|
@@ -270,7 +270,7 @@ CommandCost CmdTerraformLand(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
|
||||
}
|
||||
}
|
||||
/* Check if tunnel would take damage */
|
||||
if (direction == -1 && IsTunnelInWay(tile, z_min)) {
|
||||
if (direction == -1 && IsTunnelInWay(tile, z_min, ITIWF_IGNORE_CHUNNEL)) {
|
||||
_terraform_err_tile = tile; // highlight the tile above the tunnel
|
||||
return_cmd_error(STR_ERROR_EXCAVATION_WOULD_DAMAGE);
|
||||
}
|
||||
|
@@ -1685,6 +1685,7 @@ static void UpdateStatusAfterSwap(Train *v)
|
||||
}
|
||||
|
||||
v->UpdatePosition();
|
||||
if (v->track == TRACK_BIT_WORMHOLE) v->UpdateInclination(false, false, true);
|
||||
v->UpdateViewport(true, true);
|
||||
}
|
||||
|
||||
@@ -3903,6 +3904,15 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
v->x_pos = gp.x;
|
||||
v->y_pos = gp.y;
|
||||
v->UpdatePosition();
|
||||
if (v->track == TRACK_BIT_WORMHOLE) {
|
||||
/* update the Z position of the vehicle */
|
||||
int old_z = v->UpdateInclination(false, false, true);
|
||||
|
||||
if (prev == NULL) {
|
||||
/* This is the first vehicle in the train */
|
||||
AffectSpeedByZChange(v, old_z);
|
||||
}
|
||||
}
|
||||
if (v->IsDrawn()) v->Vehicle::UpdateViewport(true);
|
||||
continue;
|
||||
}
|
||||
@@ -3919,7 +3929,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
}
|
||||
|
||||
/* update the Z position of the vehicle */
|
||||
int old_z = v->UpdateInclination(gp.new_tile != gp.old_tile, false);
|
||||
int old_z = v->UpdateInclination(gp.new_tile != gp.old_tile, false, v->track == TRACK_BIT_WORMHOLE);
|
||||
|
||||
if (prev == NULL) {
|
||||
/* This is the first vehicle in the train */
|
||||
|
51
src/tunnel_base.h
Normal file
51
src/tunnel_base.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* $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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file tunnel_base.h Base for all tunnels */
|
||||
|
||||
#ifndef TUNNEL_BASE_H
|
||||
#define TUNNEL_BASE_H
|
||||
|
||||
#include "tunnel_map.h"
|
||||
#include "core/pool_type.hpp"
|
||||
|
||||
struct Tunnel;
|
||||
|
||||
typedef Pool<Tunnel, TunnelID, 64, 1048576> TunnelPool;
|
||||
extern TunnelPool _tunnel_pool;
|
||||
|
||||
struct Tunnel : TunnelPool::PoolItem<&_tunnel_pool> {
|
||||
|
||||
TileIndex tile_n; // North tile of tunnel.
|
||||
TileIndex tile_s; // South tile of tunnel.
|
||||
uint8 height; // Tunnel height
|
||||
bool is_chunnel; // Whether this tunnel is a chunnel
|
||||
|
||||
Tunnel() {}
|
||||
~Tunnel();
|
||||
|
||||
Tunnel(TileIndex tile_n, TileIndex tile_s, uint8 height, bool is_chunnel) : tile_n(tile_n), tile_s(tile_s), height(height), is_chunnel(is_chunnel)
|
||||
{
|
||||
this->UpdateIndexes();
|
||||
}
|
||||
|
||||
void UpdateIndexes();
|
||||
|
||||
static inline Tunnel *GetByTile(TileIndex tile)
|
||||
{
|
||||
return Tunnel::Get(GetTunnelIndex(tile));
|
||||
}
|
||||
|
||||
static void PreCleanPool();
|
||||
};
|
||||
|
||||
#define FOR_ALL_TUNNELS_FROM(var, start) FOR_ALL_ITEMS_FROM(Tunnel, tunnel_index, var, start)
|
||||
#define FOR_ALL_TUNNELS(var) FOR_ALL_TUNNELS_FROM(var, 0)
|
||||
|
||||
#endif /* TUNNEL_BASE_H */
|
@@ -12,8 +12,84 @@
|
||||
#include "stdafx.h"
|
||||
#include "tunnelbridge_map.h"
|
||||
|
||||
#include "core/pool_func.hpp"
|
||||
#include <unordered_map>
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
/** All tunnel portals tucked away in a pool. */
|
||||
TunnelPool _tunnel_pool("Tunnel");
|
||||
INSTANTIATE_POOL_METHODS(Tunnel)
|
||||
|
||||
static std::unordered_map<TileIndex, TunnelID> tunnel_tile_index_map;
|
||||
static std::unordered_multimap<uint64, Tunnel*> tunnel_axis_height_index;
|
||||
|
||||
static uint64 GetTunnelAxisHeightCacheKey(TileIndex tile, uint8 height, bool y_axis) {
|
||||
if (y_axis) {
|
||||
// tunnel extends along Y axis (DIAGDIR_SE from north end), has same X values
|
||||
return TileX(tile) | (((uint64) height) << 24) | (((uint64) 1) << 32);
|
||||
} else {
|
||||
// tunnel extends along X axis (DIAGDIR_SW from north end), has same Y values
|
||||
return TileY(tile) | (((uint64) height) << 24);
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint64 GetTunnelAxisHeightCacheKey(const Tunnel* t) {
|
||||
return GetTunnelAxisHeightCacheKey(t->tile_n, t->height, t->tile_s - t->tile_n > MapMaxX());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up a tunnel tile
|
||||
*/
|
||||
Tunnel::~Tunnel()
|
||||
{
|
||||
if (CleaningPool()) return;
|
||||
|
||||
if (this->index >= TUNNEL_ID_MAP_LOOKUP) {
|
||||
tunnel_tile_index_map.erase(this->tile_n);
|
||||
tunnel_tile_index_map.erase(this->tile_s);
|
||||
}
|
||||
|
||||
auto range = tunnel_axis_height_index.equal_range(GetTunnelAxisHeightCacheKey(this));
|
||||
bool have_erased = false;
|
||||
for (auto it = range.first; it != range.second; ++it) {
|
||||
if (it->second == this) {
|
||||
tunnel_axis_height_index.erase(it);
|
||||
have_erased = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(have_erased);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update tunnel indexes
|
||||
*/
|
||||
void Tunnel::UpdateIndexes()
|
||||
{
|
||||
if (this->index >= TUNNEL_ID_MAP_LOOKUP) {
|
||||
tunnel_tile_index_map[this->tile_n] = this->index;
|
||||
tunnel_tile_index_map[this->tile_s] = this->index;
|
||||
}
|
||||
|
||||
tunnel_axis_height_index.emplace(GetTunnelAxisHeightCacheKey(this), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tunnel pool is about to be cleaned
|
||||
*/
|
||||
void Tunnel::PreCleanPool()
|
||||
{
|
||||
tunnel_tile_index_map.clear();
|
||||
tunnel_axis_height_index.clear();
|
||||
}
|
||||
|
||||
TunnelID GetTunnelIndexByLookup(TileIndex t)
|
||||
{
|
||||
auto iter = tunnel_tile_index_map.find(t);
|
||||
assert_msg(iter != tunnel_tile_index_map.end(), "tile: 0x%X", t);
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the other end of the tunnel. Where a vehicle would reappear when it
|
||||
@@ -23,52 +99,39 @@
|
||||
*/
|
||||
TileIndex GetOtherTunnelEnd(TileIndex tile)
|
||||
{
|
||||
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
||||
TileIndexDiff delta = TileOffsByDiagDir(dir);
|
||||
int z = GetTileZ(tile);
|
||||
|
||||
dir = ReverseDiagDir(dir);
|
||||
do {
|
||||
tile += delta;
|
||||
} while (
|
||||
!IsTunnelTile(tile) ||
|
||||
GetTunnelBridgeDirection(tile) != dir ||
|
||||
GetTileZ(tile) != z
|
||||
);
|
||||
|
||||
return tile;
|
||||
Tunnel *t = Tunnel::GetByTile(tile);
|
||||
return t->tile_n == tile ? t->tile_s : t->tile_n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Is there a tunnel in the way in the given direction?
|
||||
* @param tile the tile to search from.
|
||||
* @param z the 'z' to search on.
|
||||
* @param dir the direction to start searching to.
|
||||
* @return true if and only if there is a tunnel.
|
||||
*/
|
||||
bool IsTunnelInWayDir(TileIndex tile, int z, DiagDirection dir)
|
||||
static inline bool IsTunnelInWaySingleAxis(TileIndex tile, int z, IsTunnelInWayFlags flags, bool y_axis, TileIndexDiff tile_diff)
|
||||
{
|
||||
TileIndexDiff delta = TileOffsByDiagDir(dir);
|
||||
int height;
|
||||
const auto tunnels = tunnel_axis_height_index.equal_range(GetTunnelAxisHeightCacheKey(tile, z, y_axis));
|
||||
for (auto it = tunnels.first; it != tunnels.second; ++it) {
|
||||
const Tunnel *t = it->second;
|
||||
if (t->tile_n > tile || tile > t->tile_s) continue;
|
||||
|
||||
do {
|
||||
tile -= delta;
|
||||
if (!IsValidTile(tile)) return false;
|
||||
height = GetTileZ(tile);
|
||||
} while (z < height);
|
||||
|
||||
return z == height && IsTunnelTile(tile) && GetTunnelBridgeDirection(tile) == dir;
|
||||
if (!t->is_chunnel && (flags & ITIWF_CHUNNEL_ONLY)) {
|
||||
continue;
|
||||
}
|
||||
if (t->is_chunnel && (flags & ITIWF_IGNORE_CHUNNEL)) {
|
||||
/* Only if tunnel was built over water is terraforming is allowed between portals. */
|
||||
const TileIndexDiff delta = tile_diff * 4; // 4 tiles ramp.
|
||||
if (tile < t->tile_n + delta || t->tile_s - delta < tile) return true;
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is there a tunnel in the way in any direction?
|
||||
* @param tile the tile to search from.
|
||||
* @param z the 'z' to search on.
|
||||
* @param chunnel_allowed True if chunnel mid-parts are allowed, used when terraforming.
|
||||
* @return true if and only if there is a tunnel.
|
||||
*/
|
||||
bool IsTunnelInWay(TileIndex tile, int z)
|
||||
bool IsTunnelInWay(TileIndex tile, int z, IsTunnelInWayFlags flags)
|
||||
{
|
||||
return IsTunnelInWayDir(tile, z, (TileX(tile) > (MapMaxX() / 2)) ? DIAGDIR_NE : DIAGDIR_SW) ||
|
||||
IsTunnelInWayDir(tile, z, (TileY(tile) > (MapMaxY() / 2)) ? DIAGDIR_NW : DIAGDIR_SE);
|
||||
return IsTunnelInWaySingleAxis(tile, z, flags, false, 1) || IsTunnelInWaySingleAxis(tile, z, flags, true, TileOffsByDiagDir(DIAGDIR_SE));
|
||||
}
|
||||
|
@@ -14,6 +14,9 @@
|
||||
|
||||
#include "road_map.h"
|
||||
|
||||
typedef uint32 TunnelID; ///< Type for the unique identifier of tunnels.
|
||||
|
||||
static const TunnelID TUNNEL_ID_MAP_LOOKUP = 0xFFFF; ///< Sentinel ID value to store in m2 to indiciate that the ID should be looked up instead
|
||||
|
||||
/**
|
||||
* Is this a tunnel (entrance)?
|
||||
@@ -37,27 +40,63 @@ static inline bool IsTunnelTile(TileIndex t)
|
||||
return IsTileType(t, MP_TUNNELBRIDGE) && IsTunnel(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of tunnel tile.
|
||||
* @param t the tile
|
||||
* @pre IsTunnelTile(t)
|
||||
* @return TunnelID
|
||||
*/
|
||||
static inline TunnelID GetTunnelIndex(TileIndex t)
|
||||
{
|
||||
extern TunnelID GetTunnelIndexByLookup(TileIndex t);
|
||||
|
||||
assert(IsTunnelTile(t));
|
||||
TunnelID map_id = _m[t].m2;
|
||||
return map_id == TUNNEL_ID_MAP_LOOKUP ? GetTunnelIndexByLookup(t) : map_id;
|
||||
}
|
||||
|
||||
TileIndex GetOtherTunnelEnd(TileIndex);
|
||||
bool IsTunnelInWay(TileIndex, int z);
|
||||
bool IsTunnelInWayDir(TileIndex tile, int z, DiagDirection dir);
|
||||
|
||||
/** Flags for miscellaneous industry tile specialities */
|
||||
enum IsTunnelInWayFlags {
|
||||
ITIWF_NONE = 0,
|
||||
ITIWF_IGNORE_CHUNNEL = 1 << 0, ///< Chunnel mid-parts are ignored, used when terraforming.
|
||||
ITIWF_CHUNNEL_ONLY = 1 << 1, ///< Only check for chunnels
|
||||
};
|
||||
DECLARE_ENUM_AS_BIT_SET(IsTunnelInWayFlags)
|
||||
|
||||
bool IsTunnelInWay(TileIndex, int z, IsTunnelInWayFlags flags = ITIWF_NONE);
|
||||
|
||||
/**
|
||||
* Set the index of tunnel tile.
|
||||
* @param t the tile
|
||||
* @param id the tunnel ID
|
||||
* @pre IsTunnelTile(t)
|
||||
*/
|
||||
static inline void SetTunnelIndex(TileIndex t, TunnelID id)
|
||||
{
|
||||
assert(IsTunnelTile(t));
|
||||
_m[t].m2 = (id >= TUNNEL_ID_MAP_LOOKUP) ? TUNNEL_ID_MAP_LOOKUP : id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a road tunnel entrance
|
||||
* @param t the entrance of the tunnel
|
||||
* @param o the owner of the entrance
|
||||
* @param id the tunnel ID
|
||||
* @param d the direction facing out of the tunnel
|
||||
* @param r the road type used in the tunnel
|
||||
*/
|
||||
static inline void MakeRoadTunnel(TileIndex t, Owner o, DiagDirection d, RoadTypes r)
|
||||
static inline void MakeRoadTunnel(TileIndex t, Owner o, TunnelID id, DiagDirection d, RoadTypes r)
|
||||
{
|
||||
SetTileType(t, MP_TUNNELBRIDGE);
|
||||
SetTileOwner(t, o);
|
||||
_m[t].m2 = 0;
|
||||
_m[t].m3 = 0;
|
||||
_m[t].m4 = 0;
|
||||
_m[t].m5 = TRANSPORT_ROAD << 2 | d;
|
||||
SB(_me[t].m6, 2, 4, 0);
|
||||
_me[t].m7 = 0;
|
||||
SetTunnelIndex(t, id);
|
||||
SetRoadOwner(t, ROADTYPE_ROAD, o);
|
||||
if (o != OWNER_TOWN) SetRoadOwner(t, ROADTYPE_TRAM, o);
|
||||
SetRoadTypes(t, r);
|
||||
@@ -67,14 +106,14 @@ static inline void MakeRoadTunnel(TileIndex t, Owner o, DiagDirection d, RoadTyp
|
||||
* Makes a rail tunnel entrance
|
||||
* @param t the entrance of the tunnel
|
||||
* @param o the owner of the entrance
|
||||
* @param id the tunnel ID
|
||||
* @param d the direction facing out of the tunnel
|
||||
* @param r the rail type used in the tunnel
|
||||
*/
|
||||
static inline void MakeRailTunnel(TileIndex t, Owner o, DiagDirection d, RailType r)
|
||||
static inline void MakeRailTunnel(TileIndex t, Owner o, TunnelID id, DiagDirection d, RailType r)
|
||||
{
|
||||
SetTileType(t, MP_TUNNELBRIDGE);
|
||||
SetTileOwner(t, o);
|
||||
_m[t].m2 = 0;
|
||||
SB(_m[t].m1, 7, 1, GB(r, 4, 1));
|
||||
SB(_m[t].m3, 0, 4, GB(r, 0, 4));
|
||||
SB(_m[t].m3, 4, 4, 0);
|
||||
@@ -82,6 +121,7 @@ static inline void MakeRailTunnel(TileIndex t, Owner o, DiagDirection d, RailTyp
|
||||
_m[t].m5 = TRANSPORT_RAIL << 2 | d;
|
||||
SB(_me[t].m6, 2, 4, 0);
|
||||
_me[t].m7 = 0;
|
||||
SetTunnelIndex(t, id);
|
||||
}
|
||||
|
||||
#endif /* TUNNEL_MAP_H */
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include "autoslope.h"
|
||||
#include "tunnelbridge_map.h"
|
||||
#include "bridge_signal_map.h"
|
||||
#include "tunnel_base.h"
|
||||
#include "strings_func.h"
|
||||
#include "date_func.h"
|
||||
#include "clear_func.h"
|
||||
@@ -43,12 +44,15 @@
|
||||
#include "water.h"
|
||||
#include "company_gui.h"
|
||||
#include "viewport_func.h"
|
||||
#include "station_map.h"
|
||||
#include "industry_map.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
#include "table/bridge_land.h"
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
|
||||
BridgeSpec _bridge[MAX_BRIDGES]; ///< The specification of all bridges.
|
||||
TileIndex _build_tunnel_endtile; ///< The end of a tunnel; as hidden return from the tunnel build command for GUI purposes.
|
||||
|
||||
@@ -661,12 +665,6 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
|
||||
* position, because of increased-cost-by-length: 'cost += cost >> 3' */
|
||||
|
||||
TileIndexDiff delta = TileOffsByDiagDir(direction);
|
||||
DiagDirection tunnel_in_way_dir;
|
||||
if (DiagDirToAxis(direction) == AXIS_Y) {
|
||||
tunnel_in_way_dir = (TileX(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SW : DIAGDIR_NE;
|
||||
} else {
|
||||
tunnel_in_way_dir = (TileY(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SE : DIAGDIR_NW;
|
||||
}
|
||||
|
||||
TileIndex end_tile = start_tile;
|
||||
|
||||
@@ -674,9 +672,15 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
|
||||
int tiles_coef = 3;
|
||||
/* Number of tiles from start of tunnel */
|
||||
int tiles = 0;
|
||||
/* flag for chunnels. */
|
||||
bool is_chunnel = false;
|
||||
/* Number of chunnel head tiles. */
|
||||
int head_tiles = 0;
|
||||
/* Number of tiles at which the cost increase coefficient per tile is halved */
|
||||
int tiles_bump = 25;
|
||||
|
||||
TileIndex found_tunnel_tile = INVALID_TILE;
|
||||
|
||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||
Slope end_tileh;
|
||||
for (;;) {
|
||||
@@ -684,13 +688,90 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
|
||||
if (!IsValidTile(end_tile)) return_cmd_error(STR_ERROR_TUNNEL_THROUGH_MAP_BORDER);
|
||||
end_tileh = GetTileSlope(end_tile, &end_z);
|
||||
|
||||
if (start_z == end_z) break;
|
||||
if (start_z == end_z) {
|
||||
_build_tunnel_endtile = found_tunnel_tile != INVALID_TILE ? found_tunnel_tile : end_tile;
|
||||
|
||||
if (!_cheats.crossing_tunnels.value && IsTunnelInWayDir(end_tile, start_z, tunnel_in_way_dir)) {
|
||||
return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY);
|
||||
/* Test if we are on a shore. */
|
||||
if (end_z == 0 && _settings_game.construction.chunnel &&
|
||||
(IsCoastTile(end_tile) ||
|
||||
(IsValidTile(end_tile + delta) && HasTileWaterGround(end_tile + delta)) ||
|
||||
(IsValidTile(end_tile + delta * 2) && HasTileWaterGround(end_tile + delta * 2)))) {
|
||||
if (!is_chunnel) {
|
||||
/*We are about to pass water for the first time so check if not to close to other tunnel */
|
||||
if (tiles + 1 < head_tiles + 4 && found_tunnel_tile != INVALID_TILE) return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY_FOR_CHUNNEL);
|
||||
if (tiles + 1 < 4) return_cmd_error(STR_ERROR_TUNNEL_RAMP_TOO_SHORT);
|
||||
}
|
||||
} else {/* We are leaving.*/
|
||||
if (is_chunnel) {
|
||||
/* Check if there is enough ramp space to come up. */
|
||||
if (head_tiles < 4 && found_tunnel_tile != INVALID_TILE) return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY_FOR_CHUNNEL);
|
||||
if (head_tiles < 4) return_cmd_error(STR_ERROR_TUNNEL_RAMP_TOO_SHORT);
|
||||
} else {
|
||||
if (found_tunnel_tile != INVALID_TILE) return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* A shore was found so pass the water and find a proper shore tile that potentially
|
||||
* could have a tunnel portal behind. */
|
||||
for (;;) {
|
||||
if (!IsValidTile(end_tile)) return_cmd_error(STR_ERROR_TUNNEL_THROUGH_MAP_BORDER);
|
||||
|
||||
end_tileh = GetTileSlope(end_tile);
|
||||
if(direction == DIAGDIR_NE && (end_tileh & SLOPE_NE) == SLOPE_NE) break;
|
||||
if(direction == DIAGDIR_SE && (end_tileh & SLOPE_SE) == SLOPE_SE) break;
|
||||
if(direction == DIAGDIR_SW && (end_tileh & SLOPE_SW) == SLOPE_SW) break;
|
||||
if(direction == DIAGDIR_NW && (end_tileh & SLOPE_NW) == SLOPE_NW) break;
|
||||
|
||||
/* No drilling under oil rigs.*/
|
||||
if ((IsTileType(end_tile, MP_STATION) && IsOilRig(end_tile)) ||
|
||||
(IsTileType(end_tile, MP_INDUSTRY) &&
|
||||
GetIndustryGfx(end_tile) >= GFX_OILRIG_1 &&
|
||||
GetIndustryGfx(end_tile) <= GFX_OILRIG_5)) {
|
||||
_build_tunnel_endtile = end_tile;
|
||||
return_cmd_error(STR_ERROR_NO_DRILLING_ABOVE_CHUNNEL);
|
||||
}
|
||||
|
||||
end_tile += delta;
|
||||
tiles++;
|
||||
if (IsTileType(end_tile, MP_WATER) && IsSea(end_tile)) is_chunnel = true;
|
||||
}
|
||||
/* The water was passed */
|
||||
if (!is_chunnel) return_cmd_error(STR_ERROR_CHUNNEL_ONLY_OVER_SEA);
|
||||
head_tiles = 0;
|
||||
found_tunnel_tile = INVALID_TILE;
|
||||
}
|
||||
if (!_cheats.crossing_tunnels.value && IsTunnelInWay(end_tile, start_z, ITIWF_IGNORE_CHUNNEL)) {
|
||||
if (found_tunnel_tile == INVALID_TILE || is_chunnel) { // Remember the first or the last when we pass a tunnel.
|
||||
found_tunnel_tile = end_tile;
|
||||
head_tiles = 0;
|
||||
}
|
||||
}
|
||||
head_tiles++;
|
||||
tiles++;
|
||||
}
|
||||
|
||||
if (is_chunnel && !_cheats.crossing_tunnels.value) {
|
||||
/*
|
||||
* Chunnel check: second pass
|
||||
*
|
||||
* Make sure that we don't intersect with any other chunnels
|
||||
*/
|
||||
|
||||
TileIndex check_tile = start_tile;
|
||||
for (;;) {
|
||||
check_tile += delta;
|
||||
if (check_tile == end_tile) break;
|
||||
|
||||
if (IsTunnelInWay(check_tile, start_z, ITIWF_CHUNNEL_ONLY)) {
|
||||
_build_tunnel_endtile = check_tile;
|
||||
return_cmd_error(STR_ERROR_ANOTHER_TUNNEL_IN_THE_WAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The cost of the digging. */
|
||||
for (int i = tiles; i > 0; i--) {
|
||||
if (tiles == tiles_bump) {
|
||||
tiles_coef++;
|
||||
tiles_bump *= 2;
|
||||
@@ -744,13 +825,24 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
|
||||
if (is_chunnel) cost.MultiplyCost(2);
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
Company *c = Company::GetIfValid(company);
|
||||
uint num_pieces = (tiles + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||
|
||||
/* The most northern tile first. */
|
||||
TileIndex tn = start_tile;
|
||||
TileIndex ts = end_tile;
|
||||
if(start_tile > end_tile) Swap(tn, ts);
|
||||
|
||||
if (!Tunnel::CanAllocateItem()) return_cmd_error(STR_ERROR_TUNNEL_TOO_MANY);
|
||||
const Tunnel *t = new Tunnel(tn, ts, TileHeight(tn), is_chunnel);
|
||||
|
||||
if (transport_type == TRANSPORT_RAIL) {
|
||||
if (!IsTunnelTile(start_tile) && c != NULL) c->infrastructure.rail[railtype] += num_pieces;
|
||||
MakeRailTunnel(start_tile, company, direction, railtype);
|
||||
MakeRailTunnel(end_tile, company, ReverseDiagDir(direction), railtype);
|
||||
MakeRailTunnel(start_tile, company, t->index, direction, railtype);
|
||||
MakeRailTunnel(end_tile, company, t->index, ReverseDiagDir(direction), railtype);
|
||||
AddSideToSignalBuffer(start_tile, INVALID_DIAGDIR, company);
|
||||
YapfNotifyTrackLayoutChange(start_tile, DiagDirToDiagTrack(direction));
|
||||
} else {
|
||||
@@ -760,8 +852,8 @@ CommandCost CmdBuildTunnel(TileIndex start_tile, DoCommandFlag flags, uint32 p1,
|
||||
c->infrastructure.road[rt] += num_pieces * 2; // A full diagonal road has two road bits.
|
||||
}
|
||||
}
|
||||
MakeRoadTunnel(start_tile, company, direction, rts);
|
||||
MakeRoadTunnel(end_tile, company, ReverseDiagDir(direction), rts);
|
||||
MakeRoadTunnel(start_tile, company, t->index, direction, rts);
|
||||
MakeRoadTunnel(end_tile, company, t->index, ReverseDiagDir(direction), rts);
|
||||
}
|
||||
DirtyCompanyInfrastructureWindows(company);
|
||||
}
|
||||
@@ -850,6 +942,8 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
|
||||
ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM, flags);
|
||||
}
|
||||
|
||||
const bool is_chunnel = Tunnel::GetByTile(tile)->is_chunnel;
|
||||
|
||||
uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles.
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
@@ -873,6 +967,8 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
|
||||
DirtyCompanyInfrastructureWindows(owner);
|
||||
}
|
||||
|
||||
delete Tunnel::GetByTile(tile);
|
||||
|
||||
DoClearSquare(tile);
|
||||
DoClearSquare(endtile);
|
||||
|
||||
@@ -895,13 +991,15 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
|
||||
}
|
||||
}
|
||||
|
||||
delete Tunnel::GetByTile(tile);
|
||||
|
||||
DoClearSquare(tile);
|
||||
DoClearSquare(endtile);
|
||||
}
|
||||
ViewportMapInvalidateTunnelCacheByTile(tile);
|
||||
ViewportMapInvalidateTunnelCacheByTile(endtile);
|
||||
}
|
||||
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_TUNNEL] * len);
|
||||
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_TUNNEL] * len * (is_chunnel ? 2 : 1));
|
||||
}
|
||||
|
||||
|
||||
@@ -1764,7 +1862,11 @@ static void GetTileDesc_TunnelBridge(TileIndex tile, TileDesc *td)
|
||||
TransportType tt = GetTunnelBridgeTransportType(tile);
|
||||
|
||||
if (IsTunnel(tile)) {
|
||||
if (Tunnel::GetByTile(tile)->is_chunnel) {
|
||||
td->str = (tt == TRANSPORT_RAIL) ? IsTunnelBridgeWithSignalSimulation(tile) ? STR_LAI_TUNNEL_DESCRIPTION_RAILROAD_SIGNAL_CHUNNEL : STR_LAI_TUNNEL_DESCRIPTION_RAILROAD_CHUNNEL : STR_LAI_TUNNEL_DESCRIPTION_ROAD_CHUNNEL;
|
||||
} else {
|
||||
td->str = (tt == TRANSPORT_RAIL) ? IsTunnelBridgeWithSignalSimulation(tile) ? STR_LAI_TUNNEL_DESCRIPTION_RAILROAD_SIGNAL : STR_LAI_TUNNEL_DESCRIPTION_RAILROAD : STR_LAI_TUNNEL_DESCRIPTION_ROAD;
|
||||
}
|
||||
} else { // IsBridge(tile)
|
||||
td->str = (tt == TRANSPORT_WATER) ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : IsTunnelBridgeWithSignalSimulation(tile) ? STR_LAI_BRIDGE_DESCRIPTION_RAILROAD_SIGNAL : GetBridgeSpec(GetBridgeType(tile))->transport_name[tt];
|
||||
}
|
||||
@@ -2027,6 +2129,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
||||
if (frame == _tunnel_visibility_frame[dir]) {
|
||||
t->tile = tile;
|
||||
t->track = TRACK_BIT_WORMHOLE;
|
||||
if (Tunnel::GetByTile(tile)->is_chunnel) SetBit(t->gv_flags, GVF_CHUNNEL_BIT);
|
||||
t->vehstatus |= VS_HIDDEN;
|
||||
return VETSB_ENTERED_WORMHOLE;
|
||||
}
|
||||
@@ -2034,6 +2137,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
||||
|
||||
if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
|
||||
/* We're at the tunnel exit ?? */
|
||||
if (t->tile != tile && GetOtherTunnelEnd(t->tile) != tile) return VETSB_CONTINUE; // In chunnel
|
||||
t->tile = tile;
|
||||
t->track = DiagDirToDiagTrackBits(vdir);
|
||||
assert(t->track);
|
||||
@@ -2051,6 +2155,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
||||
rv->tile = tile;
|
||||
rv->cur_image_valid_dir = INVALID_DIR;
|
||||
rv->state = RVSB_WORMHOLE;
|
||||
if (Tunnel::GetByTile(tile)->is_chunnel) SetBit(rv->gv_flags, GVF_CHUNNEL_BIT);
|
||||
rv->vehstatus |= VS_HIDDEN;
|
||||
return VETSB_ENTERED_WORMHOLE;
|
||||
} else {
|
||||
@@ -2060,6 +2165,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
||||
|
||||
/* We're at the tunnel exit ?? */
|
||||
if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
|
||||
if (rv->tile != tile && GetOtherTunnelEnd(rv->tile) != tile) return VETSB_CONTINUE; // In chunnel
|
||||
rv->tile = tile;
|
||||
rv->cur_image_valid_dir = INVALID_DIR;
|
||||
rv->state = DiagDirToDiagTrackdir(vdir);
|
||||
@@ -2069,6 +2175,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
||||
}
|
||||
}
|
||||
} else { // IsBridge(tile)
|
||||
if (v->vehstatus & VS_HIDDEN) return VETSB_CONTINUE; // Building bridges between chunnel portals allowed.
|
||||
if (v->type != VEH_SHIP) {
|
||||
/* modify speed of vehicle */
|
||||
uint16 spd = GetBridgeSpec(GetBridgeType(tile))->speed;
|
||||
|
@@ -13,7 +13,7 @@
|
||||
#define TUNNELBRIDGE_MAP_H
|
||||
|
||||
#include "bridge_map.h"
|
||||
#include "tunnel_map.h"
|
||||
#include "tunnel_base.h"
|
||||
#include "cmd_helper.h"
|
||||
#include "signal_type.h"
|
||||
|
||||
|
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "depot_type.h"
|
||||
#include "tile_map.h"
|
||||
#include "tree_map.h"
|
||||
|
||||
/**
|
||||
* Bit field layout of m5 for water tiles.
|
||||
@@ -204,7 +205,7 @@ static inline bool IsCoast(TileIndex t)
|
||||
*/
|
||||
static inline bool IsCoastTile(TileIndex t)
|
||||
{
|
||||
return IsTileType(t, MP_WATER) && IsCoast(t);
|
||||
return (IsTileType(t, MP_WATER) && IsCoast(t)) || (IsTileType(t, MP_TREES) && GetTreeGround(t) == TREE_GROUND_SHORE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user