mirror of https://github.com/OpenTTD/OpenTTD
Compare commits
10 Commits
970bb4a594
...
0b08857238
Author | SHA1 | Date |
---|---|---|
|
0b08857238 | |
|
a8650c6b06 | |
|
5e984eec1a | |
|
a48f491f09 | |
|
3ef5783bf9 | |
|
7f6b5d3103 | |
|
5a1a8adb3f | |
|
1000875f88 | |
|
1f5ae37e2c | |
|
3be979cc05 |
|
@ -454,6 +454,7 @@ add_files(
|
|||
spritecache.cpp
|
||||
spritecache.h
|
||||
spritecache_internal.h
|
||||
spritecache_type.h
|
||||
station.cpp
|
||||
station_base.h
|
||||
station_cmd.cpp
|
||||
|
|
35
src/bridge.h
35
src/bridge.h
|
@ -37,6 +37,30 @@ constexpr uint SPRITES_PER_BRIDGE_PIECE = 32; ///< Number of sprites there are p
|
|||
|
||||
typedef uint BridgeType; ///< Bridge spec number.
|
||||
|
||||
/**
|
||||
* Actions that can be performed when the vehicle enters the depot.
|
||||
*/
|
||||
enum class BridgePiecePillarFlag : uint8_t {
|
||||
BPPF_CORNER_W = 1 << 0,
|
||||
BPPF_CORNER_S = 1 << 1,
|
||||
BPPF_CORNER_E = 1 << 2,
|
||||
BPPF_CORNER_N = 1 << 3,
|
||||
BPPF_ALL_CORNERS = 0xF,
|
||||
BPPF_EDGE_NE = 1 << 4,
|
||||
BPPF_EDGE_SE = 1 << 5,
|
||||
BPPF_EDGE_SW = 1 << 6,
|
||||
BPPF_EDGE_NW = 1 << 7,
|
||||
};
|
||||
using BridgePiecePillarFlags = EnumBitSet<BridgePiecePillarFlag, uint8_t>;
|
||||
|
||||
enum class BridgeSpecCtrlFlag : uint8_t{
|
||||
BSCF_CUSTOM_PILLAR_FLAGS,
|
||||
BSCF_INVALID_PILLAR_FLAGS,
|
||||
BSCF_NOT_AVAILABLE_TOWN,
|
||||
BSCF_NOT_AVAILABLE_AI_GS,
|
||||
};
|
||||
using BridgeSpecCtrlFlags = EnumBitSet<BridgeSpecCtrlFlag, uint8_t>;
|
||||
|
||||
/**
|
||||
* Struct containing information about a single bridge type
|
||||
*/
|
||||
|
@ -52,6 +76,8 @@ struct BridgeSpec {
|
|||
StringID transport_name[2]; ///< description of the bridge, when built for road or rail
|
||||
std::vector<std::vector<PalSpriteID>> sprite_table; ///< table of sprites for drawing the bridge
|
||||
uint8_t flags; ///< bit 0 set: disable drawing of far pillars.
|
||||
BridgeSpecCtrlFlags ctrl_flags; ///< control flags
|
||||
std::array<BridgePiecePillarFlags, 12> pillar_flags; ///< bridge pillar flags: 6 x pairs of x and y flags
|
||||
};
|
||||
|
||||
extern BridgeSpec _bridge[MAX_BRIDGES];
|
||||
|
@ -75,6 +101,15 @@ void DrawBridgeMiddle(const TileInfo *ti);
|
|||
CommandCost CheckBridgeAvailability(BridgeType bridge_type, uint bridge_len, DoCommandFlags flags = {});
|
||||
int CalcBridgeLenCostFactor(int x);
|
||||
|
||||
BridgePiecePillarFlags GetBridgeTilePillarFlags(TileIndex tile, TileIndex northern_bridge_end, TileIndex southern_bridge_end, BridgeType bridge_type, TransportType bridge_transport_type);
|
||||
|
||||
struct BridgePieceDebugInfo {
|
||||
BridgePieces piece;
|
||||
BridgePiecePillarFlags pillar_flags;
|
||||
uint pillar_index;
|
||||
};
|
||||
BridgePieceDebugInfo GetBridgePieceDebugInfo(TileIndex tile);
|
||||
|
||||
void ResetBridges();
|
||||
|
||||
#endif /* BRIDGE_H */
|
||||
|
|
|
@ -382,6 +382,8 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo
|
|||
StringID errmsg = INVALID_STRING_ID;
|
||||
CommandCost ret = Command<CMD_BUILD_BRIDGE>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_BRIDGE>()) | DoCommandFlag::QueryCost, end, start, transport_type, 0, road_rail_type);
|
||||
|
||||
const bool query_per_bridge_type = ret.Failed() && (ret.GetErrorMessage() == STR_ERROR_BRIDGE_TOO_LOW_FOR_STATION || ret.GetErrorMessage() == STR_ERROR_BRIDGE_PILLARS_OBSTRUCT_STATION);
|
||||
|
||||
GUIBridgeList bl;
|
||||
if (ret.Failed()) {
|
||||
errmsg = ret.GetErrorMessage();
|
||||
|
@ -415,11 +417,13 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo
|
|||
}
|
||||
|
||||
bool any_available = false;
|
||||
StringID type_errmsg = INVALID_STRING_ID;
|
||||
CommandCost type_check;
|
||||
/* loop for all bridgetypes */
|
||||
for (BridgeType brd_type = 0; brd_type != MAX_BRIDGES; brd_type++) {
|
||||
type_check = CheckBridgeAvailability(brd_type, bridge_len);
|
||||
if (type_check.Succeeded()) {
|
||||
if (query_per_bridge_type && Command<CMD_BUILD_BRIDGE>::Do(CommandFlagsToDCFlags(GetCommandFlags<CMD_BUILD_BRIDGE>()) | DoCommandFlag::QueryCost, end, start, transport_type, brd_type, road_rail_type).Failed()) continue;
|
||||
/* bridge is accepted, add to list */
|
||||
BuildBridgeData &item = bl.emplace_back();
|
||||
item.index = brd_type;
|
||||
|
@ -428,10 +432,12 @@ void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transpo
|
|||
* bridge itself (not computed with DoCommandFlag::QueryCost) */
|
||||
item.cost = ret.GetCost() + (((int64_t)tot_bridgedata_len * _price[PR_BUILD_BRIDGE] * item.spec->price) >> 8) + infra_cost;
|
||||
any_available = true;
|
||||
} else if (type_check.GetErrorMessage() != INVALID_STRING_ID && !query_per_bridge_type) {
|
||||
type_errmsg = type_check.GetErrorMessage();
|
||||
}
|
||||
}
|
||||
/* give error cause if no bridges available here*/
|
||||
if (!any_available)
|
||||
if (!any_available && type_errmsg != INVALID_STRING_ID) errmsg = type_errmsg;
|
||||
{
|
||||
errmsg = type_check.GetErrorMessage();
|
||||
}
|
||||
|
|
|
@ -5242,6 +5242,8 @@ STR_ERROR_START_AND_END_MUST_BE_IN :{WHITE}Start an
|
|||
STR_ERROR_ENDS_OF_BRIDGE_MUST_BOTH :{WHITE}... ends of bridge must both be on land
|
||||
STR_ERROR_BRIDGE_TOO_LONG :{WHITE}... bridge too long
|
||||
STR_ERROR_BRIDGE_THROUGH_MAP_BORDER :{WHITE}Bridge would end out of the map
|
||||
STR_ERROR_BRIDGE_TOO_LOW_FOR_STATION :{WHITE}Bridge is too low for station
|
||||
STR_ERROR_BRIDGE_PILLARS_OBSTRUCT_STATION :{WHITE}Bridge pillars obstruct station
|
||||
|
||||
# Tunnel related errors
|
||||
STR_ERROR_CAN_T_BUILD_TUNNEL_HERE :{WHITE}Can't build tunnel here...
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#ifndef NEWGRF_ROADSTATION_H
|
||||
#define NEWGRF_ROADSTATION_H
|
||||
|
||||
#include "bridge.h"
|
||||
#include "newgrf_animation_type.h"
|
||||
#include "newgrf_spritegroup.h"
|
||||
#include "newgrf_badge_type.h"
|
||||
|
@ -71,6 +72,12 @@ enum class RoadStopSpecFlag : uint8_t {
|
|||
};
|
||||
using RoadStopSpecFlags = EnumBitSet<RoadStopSpecFlag, uint8_t>;
|
||||
|
||||
enum class RoadStopSpecIntlFlag : uint8_t {
|
||||
BridgeHeightsSet, ///< bridge_height[6] is set.
|
||||
BridgeDisallowedPillarsSet, ///< bridge_disallowed_pillars[6] is set.
|
||||
};
|
||||
using RoadStopSpecIntlFlags = EnumBitSet<RoadStopSpecIntlFlag, uint8_t>;
|
||||
|
||||
enum RoadStopView : uint8_t {
|
||||
RSV_BAY_NE = 0, ///< Bay road stop, facing Northeast
|
||||
RSV_BAY_SE = 1, ///< Bay road stop, facing Southeast
|
||||
|
@ -133,17 +140,20 @@ struct RoadStopSpec : NewGRFSpecBase<RoadStopClassID> {
|
|||
RoadStopDrawModes draw_mode = {RoadStopDrawMode::Road, RoadStopDrawMode::Overlay};
|
||||
RoadStopCallbackMasks callback_mask{};
|
||||
RoadStopSpecFlags flags{};
|
||||
RoadStopSpecIntlFlags internal_flags{};
|
||||
|
||||
CargoTypes cargo_triggers = 0; ///< Bitmask of cargo types which cause trigger re-randomizing
|
||||
|
||||
AnimationInfo<StationAnimationTriggers> animation;
|
||||
|
||||
uint8_t bridge_height[6]; ///< Minimum height for a bridge above, 0 for none
|
||||
uint8_t bridge_disallowed_pillars[6]; ///< Disallowed pillar flags for a bridge above
|
||||
BridgePiecePillarFlags bridge_disallowed_pillars[6]; ///< Disallowed pillar flags for a bridge above
|
||||
|
||||
uint8_t build_cost_multiplier = 16; ///< Build cost multiplier per tile.
|
||||
uint8_t clear_cost_multiplier = 16; ///< Clear cost multiplier per tile.
|
||||
|
||||
uint8_t height; ///< The height of this structure, in heightlevels; max MAX_TILE_HEIGHT.
|
||||
|
||||
std::vector<BadgeID> badges;
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#ifndef NEWGRF_STATION_H
|
||||
#define NEWGRF_STATION_H
|
||||
|
||||
#include "bridge.h"
|
||||
#include "core/enum_type.hpp"
|
||||
#include "newgrf_animation_type.h"
|
||||
#include "newgrf_badge_type.h"
|
||||
|
@ -118,6 +119,12 @@ enum class StationSpecFlag : uint8_t {
|
|||
};
|
||||
using StationSpecFlags = EnumBitSet<StationSpecFlag, uint8_t>;
|
||||
|
||||
enum class StationSpecIntlFlag : uint8_t {
|
||||
BridgeHeightsSet, ///< bridge_height[8] is set.
|
||||
BridgeDisallowedPillarsSet, ///< bridge_disallowed_pillars[8] is set.
|
||||
};
|
||||
using StationSpecIntlFlags = EnumBitSet<StationSpecIntlFlag, uint8_t>;
|
||||
|
||||
/** Station specification. */
|
||||
struct StationSpec : NewGRFSpecBase<StationClassID> {
|
||||
StationSpec() : name(0),
|
||||
|
@ -162,6 +169,12 @@ struct StationSpec : NewGRFSpecBase<StationClassID> {
|
|||
|
||||
StationSpecFlags flags; ///< Bitmask of flags, bit 0: use different sprite set; bit 1: divide cargo about by station size
|
||||
|
||||
struct BridgeAboveFlags {
|
||||
uint8_t height = UINT8_MAX; ///< Minimum height for a bridge above, 0 for none
|
||||
BridgePiecePillarFlags disallowed_pillars = {}; ///< Disallowed pillar flags for a bridge above
|
||||
};
|
||||
std::vector<BridgeAboveFlags> bridge_above_flags; ///< List of bridge above flags.
|
||||
|
||||
enum class TileFlag : uint8_t {
|
||||
Pylons = 0, ///< Tile should contain catenary pylons.
|
||||
NoWires = 1, ///< Tile should NOT contain catenary wires.
|
||||
|
@ -172,10 +185,18 @@ struct StationSpec : NewGRFSpecBase<StationClassID> {
|
|||
|
||||
AnimationInfo<StationAnimationTriggers> animation;
|
||||
|
||||
StationSpecIntlFlags internal_flags{}; ///< Bitmask of internal spec flags
|
||||
|
||||
/** Custom platform layouts, keyed by platform and length combined. */
|
||||
std::unordered_map<uint16_t, std::vector<uint8_t>> layouts;
|
||||
|
||||
std::vector<BadgeID> badges;
|
||||
|
||||
BridgeAboveFlags GetBridgeAboveFlags(uint gfx) const
|
||||
{
|
||||
if (gfx < this->bridge_above_flags.size()) return this->bridge_above_flags[gfx];
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
/** Class containing information relating to station classes. */
|
||||
|
|
|
@ -535,7 +535,7 @@ static void *ReadSprite(const SpriteCache *sc, SpriteID id, SpriteType sprite_ty
|
|||
|
||||
struct GrfSpriteOffset {
|
||||
size_t file_pos;
|
||||
uint8_t control_flags;
|
||||
SpriteCacheCtrlFlags control_flags{};
|
||||
};
|
||||
|
||||
/** Map from sprite numbers to position in the GRF file. */
|
||||
|
@ -565,7 +565,7 @@ void ReadGRFSpriteOffsets(SpriteFile &file)
|
|||
size_t old_pos = file.GetPos();
|
||||
file.SeekTo(data_offset, SEEK_CUR);
|
||||
|
||||
GrfSpriteOffset offset = { 0, 0 };
|
||||
GrfSpriteOffset offset{0};
|
||||
|
||||
/* Loop over all sprite section entries and store the file
|
||||
* offset for each newly encountered ID. */
|
||||
|
@ -574,7 +574,6 @@ void ReadGRFSpriteOffsets(SpriteFile &file)
|
|||
if (id != prev_id) {
|
||||
_grf_sprite_offsets[prev_id] = offset;
|
||||
offset.file_pos = file.GetPos() - 4;
|
||||
offset.control_flags = 0;
|
||||
}
|
||||
prev_id = id;
|
||||
uint length = file.ReadDword();
|
||||
|
@ -585,11 +584,11 @@ void ReadGRFSpriteOffsets(SpriteFile &file)
|
|||
uint8_t zoom = file.ReadByte();
|
||||
length--;
|
||||
if (colour.Any() && zoom == 0) { // ZoomLevel::Normal (normal zoom)
|
||||
SetBit(offset.control_flags, (colour != SpriteComponent::Palette) ? SCCF_ALLOW_ZOOM_MIN_1X_32BPP : SCCF_ALLOW_ZOOM_MIN_1X_PAL);
|
||||
SetBit(offset.control_flags, (colour != SpriteComponent::Palette) ? SCCF_ALLOW_ZOOM_MIN_2X_32BPP : SCCF_ALLOW_ZOOM_MIN_2X_PAL);
|
||||
offset.control_flags.Set((colour != SpriteComponent::Palette) ? SpriteCacheCtrlFlag::AllowZoomMin1x32bpp : SpriteCacheCtrlFlag::AllowZoomMin1xPal);
|
||||
offset.control_flags.Set((colour != SpriteComponent::Palette) ? SpriteCacheCtrlFlag::AllowZoomMin2x32bpp : SpriteCacheCtrlFlag::AllowZoomMin2xPal);
|
||||
}
|
||||
if (colour.Any() && zoom == 2) { // ZoomLevel::In2x (2x zoomed in)
|
||||
SetBit(offset.control_flags, (colour != SpriteComponent::Palette) ? SCCF_ALLOW_ZOOM_MIN_2X_32BPP : SCCF_ALLOW_ZOOM_MIN_2X_PAL);
|
||||
offset.control_flags.Set((colour != SpriteComponent::Palette) ? SpriteCacheCtrlFlag::AllowZoomMin2x32bpp : SpriteCacheCtrlFlag::AllowZoomMin2xPal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -621,7 +620,7 @@ bool LoadNextSprite(SpriteID load_index, SpriteFile &file, uint file_sprite_id)
|
|||
uint8_t grf_type = file.ReadByte();
|
||||
|
||||
SpriteType type;
|
||||
uint8_t control_flags = 0;
|
||||
SpriteCacheCtrlFlags control_flags;
|
||||
if (grf_type == 0xFF) {
|
||||
/* Some NewGRF files have "empty" pseudo-sprites which are 1
|
||||
* byte long. Catch these so the sprites won't be displayed. */
|
||||
|
|
|
@ -11,24 +11,9 @@
|
|||
#define SPRITECACHE_H
|
||||
|
||||
#include "gfx_type.h"
|
||||
#include "spritecache_type.h"
|
||||
#include "spriteloader/spriteloader.hpp"
|
||||
|
||||
/** Data structure describing a sprite. */
|
||||
struct Sprite {
|
||||
uint16_t height; ///< Height of the sprite.
|
||||
uint16_t width; ///< Width of the sprite.
|
||||
int16_t x_offs; ///< Number of pixels to shift the sprite to the right.
|
||||
int16_t y_offs; ///< Number of pixels to shift the sprite downwards.
|
||||
std::byte data[]; ///< Sprite data.
|
||||
};
|
||||
|
||||
enum SpriteCacheCtrlFlags : uint8_t {
|
||||
SCCF_ALLOW_ZOOM_MIN_1X_PAL = 0, ///< Allow use of sprite min zoom setting at 1x in palette mode.
|
||||
SCCF_ALLOW_ZOOM_MIN_1X_32BPP = 1, ///< Allow use of sprite min zoom setting at 1x in 32bpp mode.
|
||||
SCCF_ALLOW_ZOOM_MIN_2X_PAL = 2, ///< Allow use of sprite min zoom setting at 2x in palette mode.
|
||||
SCCF_ALLOW_ZOOM_MIN_2X_32BPP = 3, ///< Allow use of sprite min zoom setting at 2x in 32bpp mode.
|
||||
};
|
||||
|
||||
extern uint _sprite_cache_size;
|
||||
|
||||
/** SpriteAllocator that allocates memory via a unique_ptr array. */
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "core/math_func.hpp"
|
||||
#include "gfx_type.h"
|
||||
#include "spritecache_type.h"
|
||||
#include "spriteloader/spriteloader.hpp"
|
||||
|
||||
#include "table/sprites.h"
|
||||
|
@ -27,7 +28,7 @@ struct SpriteCache {
|
|||
uint32_t lru = 0;
|
||||
SpriteType type = SpriteType::Invalid; ///< In some cases a single sprite is misused by two NewGRFs. Once as real sprite and once as recolour sprite. If the recolour sprite gets into the cache it might be drawn as real sprite which causes enormous trouble.
|
||||
bool warned = false; ///< True iff the user has been warned about incorrect use of this sprite
|
||||
uint8_t control_flags = 0; ///< Control flags, see SpriteCacheCtrlFlags
|
||||
SpriteCacheCtrlFlags control_flags{}; ///< Control flags, see SpriteCacheCtrlFlags
|
||||
|
||||
void ClearSpriteData();
|
||||
};
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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 spritecache_type.h Types related to the sprite cache. */
|
||||
|
||||
#ifndef SPRITECACHE_TYPE_H
|
||||
#define SPRITECACHE_TYPE_H
|
||||
|
||||
#include "core/enum_type.hpp"
|
||||
|
||||
/** Data structure describing a sprite. */
|
||||
struct Sprite {
|
||||
uint16_t height; ///< Height of the sprite.
|
||||
uint16_t width; ///< Width of the sprite.
|
||||
int16_t x_offs; ///< Number of pixels to shift the sprite to the right.
|
||||
int16_t y_offs; ///< Number of pixels to shift the sprite downwards.
|
||||
std::byte data[]; ///< Sprite data.
|
||||
};
|
||||
|
||||
enum class SpriteCacheCtrlFlag : uint8_t {
|
||||
AllowZoomMin1xPal, ///< Allow use of sprite min zoom setting at 1x in palette mode.
|
||||
AllowZoomMin1x32bpp, ///< Allow use of sprite min zoom setting at 1x in 32bpp mode.
|
||||
AllowZoomMin2xPal, ///< Allow use of sprite min zoom setting at 2x in palette mode.
|
||||
AllowZoomMin2x32bpp, ///< Allow use of sprite min zoom setting at 2x in 32bpp mode.
|
||||
};
|
||||
|
||||
using SpriteCacheCtrlFlags = EnumBitSet<SpriteCacheCtrlFlag, uint8_t>;
|
||||
|
||||
#endif /* SPRITECACHE_TYPE_H */
|
|
@ -256,7 +256,7 @@ static ZoomLevels LoadSpriteV1(SpriteLoader::SpriteCollection &sprite, SpriteFil
|
|||
return {};
|
||||
}
|
||||
|
||||
static ZoomLevels LoadSpriteV2(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, uint8_t control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp)
|
||||
static ZoomLevels LoadSpriteV2(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, SpriteCacheCtrlFlags control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp)
|
||||
{
|
||||
static const ZoomLevel zoom_lvl_map[6] = {ZoomLevel::Normal, ZoomLevel::In4x, ZoomLevel::In2x, ZoomLevel::Out2x, ZoomLevel::Out4x, ZoomLevel::Out8x};
|
||||
|
||||
|
@ -295,11 +295,11 @@ static ZoomLevels LoadSpriteV2(SpriteLoader::SpriteCollection &sprite, SpriteFil
|
|||
is_wanted_zoom_lvl = true;
|
||||
ZoomLevel zoom_min = sprite_type == SpriteType::Font ? ZoomLevel::Min : _settings_client.gui.sprite_zoom_min;
|
||||
if (zoom_min >= ZoomLevel::In2x &&
|
||||
HasBit(control_flags, load_32bpp ? SCCF_ALLOW_ZOOM_MIN_2X_32BPP : SCCF_ALLOW_ZOOM_MIN_2X_PAL) && zoom_lvl < ZoomLevel::In2x) {
|
||||
control_flags.Test(load_32bpp ? SpriteCacheCtrlFlag::AllowZoomMin2x32bpp : SpriteCacheCtrlFlag::AllowZoomMin2xPal) && zoom_lvl < ZoomLevel::In2x) {
|
||||
is_wanted_zoom_lvl = false;
|
||||
}
|
||||
if (zoom_min >= ZoomLevel::Normal &&
|
||||
HasBit(control_flags, load_32bpp ? SCCF_ALLOW_ZOOM_MIN_1X_32BPP : SCCF_ALLOW_ZOOM_MIN_1X_PAL) && zoom_lvl < ZoomLevel::Normal) {
|
||||
control_flags.Test(load_32bpp ? SpriteCacheCtrlFlag::AllowZoomMin1x32bpp : SpriteCacheCtrlFlag::AllowZoomMin1xPal) && zoom_lvl < ZoomLevel::Normal) {
|
||||
is_wanted_zoom_lvl = false;
|
||||
}
|
||||
} else {
|
||||
|
@ -359,7 +359,7 @@ static ZoomLevels LoadSpriteV2(SpriteLoader::SpriteCollection &sprite, SpriteFil
|
|||
return loaded_sprites;
|
||||
}
|
||||
|
||||
ZoomLevels SpriteLoaderGrf::LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, uint8_t control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp)
|
||||
ZoomLevels SpriteLoaderGrf::LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, SpriteCacheCtrlFlags control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp)
|
||||
{
|
||||
if (this->container_ver >= 2) {
|
||||
return LoadSpriteV2(sprite, file, file_pos, sprite_type, load_32bpp, control_flags, avail_8bpp, avail_32bpp);
|
||||
|
|
|
@ -17,7 +17,7 @@ class SpriteLoaderGrf : public SpriteLoader {
|
|||
uint8_t container_ver;
|
||||
public:
|
||||
SpriteLoaderGrf(uint8_t container_ver) : container_ver(container_ver) {}
|
||||
ZoomLevels LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, uint8_t control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp) override;
|
||||
ZoomLevels LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, SpriteCacheCtrlFlags control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp) override;
|
||||
};
|
||||
|
||||
#endif /* SPRITELOADER_GRF_HPP */
|
||||
|
|
|
@ -48,7 +48,7 @@ static void Convert32bppTo8bpp(SpriteLoader::Sprite &sprite)
|
|||
}
|
||||
}
|
||||
|
||||
ZoomLevels SpriteLoaderMakeIndexed::LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool, uint8_t control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp)
|
||||
ZoomLevels SpriteLoaderMakeIndexed::LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool, SpriteCacheCtrlFlags control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp)
|
||||
{
|
||||
ZoomLevels avail = this->baseloader.LoadSprite(sprite, file, file_pos, sprite_type, true, control_flags, avail_8bpp, avail_32bpp);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ class SpriteLoaderMakeIndexed : public SpriteLoader {
|
|||
SpriteLoader &baseloader;
|
||||
public:
|
||||
SpriteLoaderMakeIndexed(SpriteLoader &baseloader) : baseloader(baseloader) {}
|
||||
ZoomLevels LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, uint8_t control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp) override;
|
||||
ZoomLevels LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, SpriteCacheCtrlFlags control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp) override;
|
||||
};
|
||||
|
||||
#endif /* SPRITELOADER_MAKEINDEXED_H */
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "../core/alloc_type.hpp"
|
||||
#include "../core/enum_type.hpp"
|
||||
#include "../gfx_type.h"
|
||||
#include "../spritecache_type.h"
|
||||
#include "sprite_file_type.hpp"
|
||||
|
||||
struct Sprite;
|
||||
|
@ -94,7 +95,7 @@ public:
|
|||
* @param[out] avail_32bpp Available 32bpp sprites.
|
||||
* @return Available sprites matching \a load_32bpp.
|
||||
*/
|
||||
virtual ZoomLevels LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, uint8_t control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp) = 0;
|
||||
virtual ZoomLevels LoadSprite(SpriteLoader::SpriteCollection &sprite, SpriteFile &file, size_t file_pos, SpriteType sprite_type, bool load_32bpp, SpriteCacheCtrlFlags control_flags, ZoomLevels &avail_8bpp, ZoomLevels &avail_32bpp) = 0;
|
||||
|
||||
virtual ~SpriteLoader() = default;
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
/** @file station_cmd.cpp Handling of station tiles. */
|
||||
|
||||
#include "core/enum_type.hpp"
|
||||
#include "stdafx.h"
|
||||
#include "core/flatset_type.hpp"
|
||||
#include "aircraft.h"
|
||||
|
@ -949,125 +950,6 @@ static CommandCost CheckFlatLandRailStation(TileIndex tile_cur, TileIndex north_
|
|||
return cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a road stop can be built at the given tile.
|
||||
* @param cur_tile Tile to check.
|
||||
* @param allowed_z Height allowed for the tile. If allowed_z is negative, it will be set to the height of this tile.
|
||||
* @param flags Operation to perform.
|
||||
* @param invalid_dirs Prohibited directions (set of DiagDirections).
|
||||
* @param is_drive_through True if trying to build a drive-through station.
|
||||
* @param station_type Station type (bus, truck or road waypoint).
|
||||
* @param axis Axis of a drive-through road stop.
|
||||
* @param station StationID to be queried and returned if available.
|
||||
* @param rt Road type to build, may be INVALID_ROADTYPE if an existing road is required.
|
||||
* @return The cost in case of success, or an error code if it failed.
|
||||
*/
|
||||
static CommandCost CheckFlatLandRoadStop(TileIndex cur_tile, int &allowed_z, DoCommandFlags flags, DiagDirections invalid_dirs, bool is_drive_through, StationType station_type, Axis axis, StationID *station, RoadType rt)
|
||||
{
|
||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||
|
||||
CommandCost ret = CheckBuildableTile(cur_tile, invalid_dirs, allowed_z, !is_drive_through);
|
||||
if (ret.Failed()) return ret;
|
||||
cost.AddCost(ret.GetCost());
|
||||
|
||||
/* If station is set, then we have special handling to allow building on top of already existing stations.
|
||||
* Station points to StationID::Invalid() if we can build on any station.
|
||||
* Or it points to a station if we're only allowed to build on exactly that station. */
|
||||
if (station != nullptr && IsTileType(cur_tile, MP_STATION)) {
|
||||
if (!IsAnyRoadStop(cur_tile)) {
|
||||
return ClearTile_Station(cur_tile, DoCommandFlag::Auto); // Get error message.
|
||||
} else {
|
||||
if (station_type != GetStationType(cur_tile) ||
|
||||
is_drive_through != IsDriveThroughStopTile(cur_tile)) {
|
||||
return ClearTile_Station(cur_tile, DoCommandFlag::Auto); // Get error message.
|
||||
}
|
||||
/* Drive-through station in the wrong direction. */
|
||||
if (is_drive_through && IsDriveThroughStopTile(cur_tile) && GetDriveThroughStopAxis(cur_tile) != axis) {
|
||||
return CommandCost(STR_ERROR_DRIVE_THROUGH_DIRECTION);
|
||||
}
|
||||
StationID st = GetStationIndex(cur_tile);
|
||||
if (*station == StationID::Invalid()) {
|
||||
*station = st;
|
||||
} else if (*station != st) {
|
||||
return CommandCost(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool build_over_road = is_drive_through && IsNormalRoadTile(cur_tile);
|
||||
/* Road bits in the wrong direction. */
|
||||
RoadBits rb = IsNormalRoadTile(cur_tile) ? GetAllRoadBits(cur_tile) : ROAD_NONE;
|
||||
if (build_over_road && (rb & (axis == AXIS_X ? ROAD_Y : ROAD_X)) != 0) {
|
||||
/* Someone was pedantic and *NEEDED* three fracking different error messages. */
|
||||
switch (CountBits(rb)) {
|
||||
case 1:
|
||||
return CommandCost(STR_ERROR_DRIVE_THROUGH_DIRECTION);
|
||||
|
||||
case 2:
|
||||
if (rb == ROAD_X || rb == ROAD_Y) return CommandCost(STR_ERROR_DRIVE_THROUGH_DIRECTION);
|
||||
return CommandCost(STR_ERROR_DRIVE_THROUGH_CORNER);
|
||||
|
||||
default: // 3 or 4
|
||||
return CommandCost(STR_ERROR_DRIVE_THROUGH_JUNCTION);
|
||||
}
|
||||
}
|
||||
|
||||
if (build_over_road) {
|
||||
/* There is a road, check if we can build road+tram stop over it. */
|
||||
RoadType road_rt = GetRoadType(cur_tile, RTT_ROAD);
|
||||
if (road_rt != INVALID_ROADTYPE) {
|
||||
Owner road_owner = GetRoadOwner(cur_tile, RTT_ROAD);
|
||||
if (road_owner == OWNER_TOWN) {
|
||||
if (!_settings_game.construction.road_stop_on_town_road) return CommandCost(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD);
|
||||
} else if (!_settings_game.construction.road_stop_on_competitor_road && road_owner != OWNER_NONE) {
|
||||
ret = CheckOwnership(road_owner);
|
||||
if (ret.Failed()) return ret;
|
||||
}
|
||||
uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_ROAD));
|
||||
|
||||
if (rt != INVALID_ROADTYPE && RoadTypeIsRoad(rt) && !HasPowerOnRoad(rt, road_rt)) return CommandCost(STR_ERROR_NO_SUITABLE_ROAD);
|
||||
|
||||
if (GetDisallowedRoadDirections(cur_tile) != DRD_NONE && road_owner != OWNER_TOWN) {
|
||||
ret = CheckOwnership(road_owner);
|
||||
if (ret.Failed()) return ret;
|
||||
}
|
||||
|
||||
cost.AddCost(RoadBuildCost(road_rt) * (2 - num_pieces));
|
||||
} else if (rt != INVALID_ROADTYPE && RoadTypeIsRoad(rt)) {
|
||||
cost.AddCost(RoadBuildCost(rt) * 2);
|
||||
}
|
||||
|
||||
/* There is a tram, check if we can build road+tram stop over it. */
|
||||
RoadType tram_rt = GetRoadType(cur_tile, RTT_TRAM);
|
||||
if (tram_rt != INVALID_ROADTYPE) {
|
||||
Owner tram_owner = GetRoadOwner(cur_tile, RTT_TRAM);
|
||||
if (Company::IsValidID(tram_owner) &&
|
||||
(!_settings_game.construction.road_stop_on_competitor_road ||
|
||||
/* Disallow breaking end-of-line of someone else
|
||||
* so trams can still reverse on this tile. */
|
||||
HasExactlyOneBit(GetRoadBits(cur_tile, RTT_TRAM)))) {
|
||||
ret = CheckOwnership(tram_owner);
|
||||
if (ret.Failed()) return ret;
|
||||
}
|
||||
uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_TRAM));
|
||||
|
||||
if (rt != INVALID_ROADTYPE && RoadTypeIsTram(rt) && !HasPowerOnRoad(rt, tram_rt)) return CommandCost(STR_ERROR_NO_SUITABLE_ROAD);
|
||||
|
||||
cost.AddCost(RoadBuildCost(tram_rt) * (2 - num_pieces));
|
||||
} else if (rt != INVALID_ROADTYPE && RoadTypeIsTram(rt)) {
|
||||
cost.AddCost(RoadBuildCost(rt) * 2);
|
||||
}
|
||||
} else if (rt == INVALID_ROADTYPE) {
|
||||
return CommandCost(STR_ERROR_THERE_IS_NO_ROAD);
|
||||
} else {
|
||||
ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, cur_tile);
|
||||
if (ret.Failed()) return ret;
|
||||
cost.AddCost(ret.GetCost());
|
||||
cost.AddCost(RoadBuildCost(rt) * 2);
|
||||
}
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether we can expand the rail part of the given station.
|
||||
|
@ -1324,6 +1206,230 @@ void SetRailStationTileFlags(TileIndex tile, const StationSpec *statspec)
|
|||
SetStationTileHaveWires(tile, !flags.Test(StationSpec::TileFlag::NoWires));
|
||||
}
|
||||
|
||||
CommandCost IsRailStationBridgeAboveOk(TileIndex tile, const StationSpec *statspec, uint8_t layout, TileIndex northern_bridge_end, TileIndex southern_bridge_end, int bridge_height,
|
||||
BridgeType bridge_type, TransportType bridge_transport_type)
|
||||
{
|
||||
if (statspec != nullptr && statspec->internal_flags.Test(StationSpecIntlFlag::BridgeHeightsSet)) {
|
||||
int height_above = statspec->GetBridgeAboveFlags(layout).height;
|
||||
if (height_above == 0) return CommandCost(INVALID_STRING_ID);
|
||||
if (GetTileMaxZ(tile) + height_above > bridge_height) {
|
||||
return CommandCost(STR_ERROR_BRIDGE_TOO_LOW_FOR_STATION);
|
||||
}
|
||||
} else if (!statspec) {
|
||||
/* Default stations/waypoints */
|
||||
const int height = layout < 4 ? 2 : 5;
|
||||
if (GetTileMaxZ(tile) + height > bridge_height) return CommandCost(STR_ERROR_BRIDGE_TOO_LOW_FOR_STATION);
|
||||
} else {
|
||||
return CommandCost(INVALID_STRING_ID);
|
||||
}
|
||||
|
||||
BridgePiecePillarFlags disallowed_pillar_flags;
|
||||
if (statspec != nullptr && statspec->internal_flags.Test(StationSpecIntlFlag::BridgeDisallowedPillarsSet)) {
|
||||
/* Pillar flags set by NewGRF */
|
||||
disallowed_pillar_flags = statspec->GetBridgeAboveFlags(layout).disallowed_pillars;
|
||||
} else if (!statspec) {
|
||||
/* Default stations/waypoints */
|
||||
if (layout < 8) {
|
||||
static const BridgePiecePillarFlags st_flags[8] = {
|
||||
{BridgePiecePillarFlag::BPPF_EDGE_SW, BridgePiecePillarFlag::BPPF_EDGE_NE}, //0x50,
|
||||
{BridgePiecePillarFlag::BPPF_EDGE_NW, BridgePiecePillarFlag::BPPF_EDGE_SE}, //0xA0,
|
||||
{BridgePiecePillarFlag::BPPF_EDGE_SW, BridgePiecePillarFlag::BPPF_EDGE_NE}, //0x50,
|
||||
{BridgePiecePillarFlag::BPPF_EDGE_NW, BridgePiecePillarFlag::BPPF_EDGE_SE}, //0xA0,
|
||||
{BridgePiecePillarFlag::BPPF_EDGE_SW, BridgePiecePillarFlag::BPPF_EDGE_NE, BridgePiecePillarFlag::BPPF_EDGE_SE, BridgePiecePillarFlag::BPPF_CORNER_E, BridgePiecePillarFlag::BPPF_CORNER_S}, //0x50 | 0x26,
|
||||
{BridgePiecePillarFlag::BPPF_EDGE_NW, BridgePiecePillarFlag::BPPF_EDGE_SE, BridgePiecePillarFlag::BPPF_EDGE_NE, BridgePiecePillarFlag::BPPF_CORNER_N, BridgePiecePillarFlag::BPPF_CORNER_E}, //0xA0 | 0x1C,
|
||||
{BridgePiecePillarFlag::BPPF_EDGE_NW, BridgePiecePillarFlag::BPPF_EDGE_SE, BridgePiecePillarFlag::BPPF_EDGE_NW, BridgePiecePillarFlag::BPPF_CORNER_N, BridgePiecePillarFlag::BPPF_CORNER_W}, //0x50 | 0x89,
|
||||
{BridgePiecePillarFlag::BPPF_EDGE_NW, BridgePiecePillarFlag::BPPF_EDGE_SE, BridgePiecePillarFlag::BPPF_EDGE_SW, BridgePiecePillarFlag::BPPF_CORNER_S, BridgePiecePillarFlag::BPPF_CORNER_W} //0xA0 | 0x43
|
||||
};
|
||||
|
||||
disallowed_pillar_flags = st_flags[layout];
|
||||
} else {
|
||||
disallowed_pillar_flags = {};
|
||||
}
|
||||
} else if (GetStationTileFlags(layout, statspec).Test(StationSpec::TileFlag::Blocked)) {
|
||||
/* Non-track station tiles */
|
||||
disallowed_pillar_flags = {};
|
||||
} else {
|
||||
/* Tracked station tiles */
|
||||
const Axis axis = HasBit(layout, 0) ? AXIS_Y : AXIS_X;
|
||||
disallowed_pillar_flags = axis == AXIS_X ? BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_EDGE_SW, BridgePiecePillarFlag::BPPF_EDGE_NE}) : BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_EDGE_NW, BridgePiecePillarFlag::BPPF_EDGE_SE}); //0x50, 0xA0
|
||||
}
|
||||
|
||||
if (!(GetBridgeTilePillarFlags(tile, northern_bridge_end, southern_bridge_end, bridge_type, bridge_transport_type) & disallowed_pillar_flags).Any()) return CommandCost(STR_ERROR_BRIDGE_PILLARS_OBSTRUCT_STATION);
|
||||
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
CommandCost IsRailStationBridgeAboveOk(TileIndex tile, const StationSpec *statspec, uint8_t layout)
|
||||
{
|
||||
if (!IsBridgeAbove(tile)) return CommandCost();
|
||||
|
||||
TileIndex southern_bridge_end = GetSouthernBridgeEnd(tile);
|
||||
TileIndex northern_bridge_end = GetNorthernBridgeEnd(tile);
|
||||
return IsRailStationBridgeAboveOk(tile, statspec, layout, northern_bridge_end, southern_bridge_end, GetBridgeHeight(southern_bridge_end),
|
||||
GetBridgeType(southern_bridge_end), GetTunnelBridgeTransportType(southern_bridge_end));
|
||||
}
|
||||
|
||||
CommandCost IsRoadStopBridgeAboveOK(TileIndex tile, const RoadStopSpec *spec, bool drive_through, DiagDirection entrance,
|
||||
TileIndex northern_bridge_end, TileIndex southern_bridge_end, int bridge_height,
|
||||
BridgeType bridge_type, TransportType bridge_transport_type)
|
||||
{
|
||||
if (spec != nullptr && spec->internal_flags.Test(RoadStopSpecIntlFlag::BridgeHeightsSet)) {
|
||||
int height = spec->bridge_height[drive_through ? (GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET + DiagDirToAxis(entrance)) : entrance];
|
||||
if (height == 0) return CommandCost(INVALID_STRING_ID);
|
||||
if (GetTileMaxZ(tile) + height > bridge_height) {
|
||||
return CommandCost(STR_ERROR_BRIDGE_TOO_LOW_FOR_STATION);
|
||||
}
|
||||
} else {
|
||||
return CommandCost(INVALID_STRING_ID);
|
||||
|
||||
if (GetTileMaxZ(tile) + (drive_through ? 1 : 2) > bridge_height) {
|
||||
return CommandCost(STR_ERROR_BRIDGE_TOO_LOW_FOR_STATION);
|
||||
}
|
||||
}
|
||||
|
||||
BridgePiecePillarFlags disallowed_pillar_flags = {};
|
||||
if (spec != nullptr && spec->internal_flags.Test(RoadStopSpecIntlFlag::BridgeDisallowedPillarsSet)) {
|
||||
disallowed_pillar_flags = spec->bridge_disallowed_pillars[drive_through ? (GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET + DiagDirToAxis(entrance)) : entrance];
|
||||
} else if (drive_through) {
|
||||
disallowed_pillar_flags = DiagDirToAxis(entrance) == AXIS_X ? BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_EDGE_SW, BridgePiecePillarFlag::BPPF_EDGE_NE}) : BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_EDGE_NW, BridgePiecePillarFlag::BPPF_EDGE_SE}); //0x50, 0xA0
|
||||
} else {
|
||||
disallowed_pillar_flags.Set((BridgePiecePillarFlags) (4 + entrance));
|
||||
}
|
||||
if (!(GetBridgeTilePillarFlags(tile, northern_bridge_end, southern_bridge_end, bridge_type, bridge_transport_type) & disallowed_pillar_flags).Any()) return CommandCost(STR_ERROR_BRIDGE_PILLARS_OBSTRUCT_STATION);
|
||||
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a road stop can be built at the given tile.
|
||||
* @param cur_tile Tile to check.
|
||||
* @param allowed_z Height allowed for the tile. If allowed_z is negative, it will be set to the height of this tile.
|
||||
* @param flags Operation to perform.
|
||||
* @param invalid_dirs Prohibited directions (set of DiagDirections).
|
||||
* @param is_drive_through True if trying to build a drive-through station.
|
||||
* @param station_type Station type (bus, truck or road waypoint).
|
||||
* @param axis Axis of a drive-through road stop.
|
||||
* @param station StationID to be queried and returned if available.
|
||||
* @param rt Road type to build, may be INVALID_ROADTYPE if an existing road is required.
|
||||
* @return The cost in case of success, or an error code if it failed.
|
||||
*/
|
||||
static CommandCost CheckFlatLandRoadStop(TileIndex cur_tile, int &allowed_z, const RoadStopSpec *spec, DoCommandFlags flags, DiagDirections invalid_dirs, bool is_drive_through, StationType station_type, Axis axis, StationID *station, RoadType rt)
|
||||
{
|
||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||
|
||||
bool allow_under_bridge = spec != nullptr && spec->internal_flags.Test(RoadStopSpecIntlFlag::BridgeHeightsSet);
|
||||
CommandCost ret = CheckBuildableTile(cur_tile, invalid_dirs, allowed_z, !is_drive_through, true);
|
||||
if (ret.Failed()) return ret;
|
||||
cost.AddCost(ret.GetCost());
|
||||
|
||||
if (allow_under_bridge && IsBridgeAbove(cur_tile)) {
|
||||
TileIndex southern_bridge_end = GetSouthernBridgeEnd(cur_tile);
|
||||
TileIndex northern_bridge_end = GetNorthernBridgeEnd(cur_tile);
|
||||
CommandCost bridge_ret = IsRoadStopBridgeAboveOK(cur_tile, spec, is_drive_through, DiagDirection::DIAGDIR_NE /*obviously wrong, but how do you get the "first bit" from invalid_dirs? and how would that be correct?? */,
|
||||
northern_bridge_end, southern_bridge_end, GetBridgeHeight(southern_bridge_end),
|
||||
GetBridgeType(southern_bridge_end), GetTunnelBridgeTransportType(southern_bridge_end));
|
||||
if (bridge_ret.Failed()) return bridge_ret;
|
||||
}
|
||||
|
||||
/* If station is set, then we have special handling to allow building on top of already existing stations.
|
||||
* Station points to StationID::Invalid() if we can build on any station.
|
||||
* Or it points to a station if we're only allowed to build on exactly that station. */
|
||||
if (station != nullptr && IsTileType(cur_tile, MP_STATION)) {
|
||||
if (!IsAnyRoadStop(cur_tile)) {
|
||||
return ClearTile_Station(cur_tile, DoCommandFlag::Auto); // Get error message.
|
||||
} else {
|
||||
if (station_type != GetStationType(cur_tile) ||
|
||||
is_drive_through != IsDriveThroughStopTile(cur_tile)) {
|
||||
return ClearTile_Station(cur_tile, DoCommandFlag::Auto); // Get error message.
|
||||
}
|
||||
/* Drive-through station in the wrong direction. */
|
||||
if (is_drive_through && IsDriveThroughStopTile(cur_tile) && GetDriveThroughStopAxis(cur_tile) != axis) {
|
||||
return CommandCost(STR_ERROR_DRIVE_THROUGH_DIRECTION);
|
||||
}
|
||||
StationID st = GetStationIndex(cur_tile);
|
||||
if (*station == StationID::Invalid()) {
|
||||
*station = st;
|
||||
} else if (*station != st) {
|
||||
return CommandCost(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool build_over_road = is_drive_through && IsNormalRoadTile(cur_tile);
|
||||
/* Road bits in the wrong direction. */
|
||||
RoadBits rb = IsNormalRoadTile(cur_tile) ? GetAllRoadBits(cur_tile) : ROAD_NONE;
|
||||
if (build_over_road && (rb & (axis == AXIS_X ? ROAD_Y : ROAD_X)) != 0) {
|
||||
/* Someone was pedantic and *NEEDED* three fracking different error messages. */
|
||||
switch (CountBits(rb)) {
|
||||
case 1:
|
||||
return CommandCost(STR_ERROR_DRIVE_THROUGH_DIRECTION);
|
||||
|
||||
case 2:
|
||||
if (rb == ROAD_X || rb == ROAD_Y) return CommandCost(STR_ERROR_DRIVE_THROUGH_DIRECTION);
|
||||
return CommandCost(STR_ERROR_DRIVE_THROUGH_CORNER);
|
||||
|
||||
default: // 3 or 4
|
||||
return CommandCost(STR_ERROR_DRIVE_THROUGH_JUNCTION);
|
||||
}
|
||||
}
|
||||
|
||||
if (build_over_road) {
|
||||
/* There is a road, check if we can build road+tram stop over it. */
|
||||
RoadType road_rt = GetRoadType(cur_tile, RTT_ROAD);
|
||||
if (road_rt != INVALID_ROADTYPE) {
|
||||
Owner road_owner = GetRoadOwner(cur_tile, RTT_ROAD);
|
||||
if (road_owner == OWNER_TOWN) {
|
||||
if (!_settings_game.construction.road_stop_on_town_road) return CommandCost(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD);
|
||||
} else if (!_settings_game.construction.road_stop_on_competitor_road && road_owner != OWNER_NONE) {
|
||||
ret = CheckOwnership(road_owner);
|
||||
if (ret.Failed()) return ret;
|
||||
}
|
||||
uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_ROAD));
|
||||
|
||||
if (rt != INVALID_ROADTYPE && RoadTypeIsRoad(rt) && !HasPowerOnRoad(rt, road_rt)) return CommandCost(STR_ERROR_NO_SUITABLE_ROAD);
|
||||
|
||||
if (GetDisallowedRoadDirections(cur_tile) != DRD_NONE && road_owner != OWNER_TOWN) {
|
||||
ret = CheckOwnership(road_owner);
|
||||
if (ret.Failed()) return ret;
|
||||
}
|
||||
|
||||
cost.AddCost(RoadBuildCost(road_rt) * (2 - num_pieces));
|
||||
} else if (rt != INVALID_ROADTYPE && RoadTypeIsRoad(rt)) {
|
||||
cost.AddCost(RoadBuildCost(rt) * 2);
|
||||
}
|
||||
|
||||
/* There is a tram, check if we can build road+tram stop over it. */
|
||||
RoadType tram_rt = GetRoadType(cur_tile, RTT_TRAM);
|
||||
if (tram_rt != INVALID_ROADTYPE) {
|
||||
Owner tram_owner = GetRoadOwner(cur_tile, RTT_TRAM);
|
||||
if (Company::IsValidID(tram_owner) &&
|
||||
(!_settings_game.construction.road_stop_on_competitor_road ||
|
||||
/* Disallow breaking end-of-line of someone else
|
||||
* so trams can still reverse on this tile. */
|
||||
HasExactlyOneBit(GetRoadBits(cur_tile, RTT_TRAM)))) {
|
||||
ret = CheckOwnership(tram_owner);
|
||||
if (ret.Failed()) return ret;
|
||||
}
|
||||
uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_TRAM));
|
||||
|
||||
if (rt != INVALID_ROADTYPE && RoadTypeIsTram(rt) && !HasPowerOnRoad(rt, tram_rt)) return CommandCost(STR_ERROR_NO_SUITABLE_ROAD);
|
||||
|
||||
cost.AddCost(RoadBuildCost(tram_rt) * (2 - num_pieces));
|
||||
} else if (rt != INVALID_ROADTYPE && RoadTypeIsTram(rt)) {
|
||||
cost.AddCost(RoadBuildCost(rt) * 2);
|
||||
}
|
||||
} else if (rt == INVALID_ROADTYPE) {
|
||||
return CommandCost(STR_ERROR_THERE_IS_NO_ROAD);
|
||||
} else {
|
||||
ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, cur_tile);
|
||||
if (ret.Failed()) return ret;
|
||||
cost.AddCost(ret.GetCost());
|
||||
cost.AddCost(RoadBuildCost(rt) * 2);
|
||||
}
|
||||
}
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build rail station
|
||||
* @param flags operation to perform
|
||||
|
@ -1362,6 +1468,9 @@ CommandCost CmdBuildRailStation(DoCommandFlags flags, TileIndex tile_org, RailTy
|
|||
w_org = numtracks;
|
||||
}
|
||||
|
||||
/* Check if the first tile and the last tile are valid */
|
||||
if (!IsValidTile(tile_org) || TileAddWrap(tile_org, w_org - 1, h_org - 1) == INVALID_TILE) return CMD_ERROR;
|
||||
|
||||
bool reuse = (station_to_join != NEW_STATION);
|
||||
if (!reuse) station_to_join = StationID::Invalid();
|
||||
bool distant_join = (station_to_join != StationID::Invalid());
|
||||
|
@ -1376,6 +1485,7 @@ CommandCost CmdBuildRailStation(DoCommandFlags flags, TileIndex tile_org, RailTy
|
|||
/* Make sure the area below consists of clear tiles. (OR tiles belonging to a certain rail station) */
|
||||
StationID est = StationID::Invalid();
|
||||
std::vector<Train *> affected_vehicles;
|
||||
|
||||
/* Add construction and clearing expenses. */
|
||||
CommandCost cost = CalculateRailStationCost(new_location, flags, axis, &est, rt, affected_vehicles, spec_class, spec_index, plat_len, numtracks);
|
||||
if (cost.Failed()) return cost;
|
||||
|
@ -1423,23 +1533,30 @@ CommandCost CmdBuildRailStation(DoCommandFlags flags, TileIndex tile_org, RailTy
|
|||
st->cached_anim_triggers.Set(statspec->animation.triggers);
|
||||
}
|
||||
|
||||
TileIndexDiff tile_delta = TileOffsByAxis(axis); // offset to go to the next platform tile
|
||||
TileIndexDiff track_delta = TileOffsByAxis(OtherAxis(axis)); // offset to go to the next track
|
||||
Track track = AxisToTrack(axis);
|
||||
|
||||
std::vector<uint8_t> layouts(numtracks * plat_len);
|
||||
GetStationLayout(layouts.data(), numtracks, plat_len, statspec);
|
||||
|
||||
TileIndexDiff tile_delta = TileOffsByAxis(axis); // offset to go to the next platform tile
|
||||
TileIndexDiff track_delta = TileOffsByAxis(OtherAxis(axis)); // offset to go to the next track
|
||||
Track track = AxisToTrack(axis);
|
||||
uint8_t numtracks_orig = numtracks;
|
||||
|
||||
Company *c = Company::Get(st->owner);
|
||||
size_t layout_idx = 0;
|
||||
TileIndex tile_track = tile_org;
|
||||
|
||||
do {
|
||||
TileIndex tile = tile_track;
|
||||
int w = plat_len;
|
||||
do {
|
||||
uint8_t layout = layouts[layout_idx++];
|
||||
|
||||
ret = IsRailStationBridgeAboveOk(tile, statspec, layout);
|
||||
if (ret.Failed()) {
|
||||
//return CommandCost::DualErrorMessage(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST, ret.GetErrorMessage()); //FIXME
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (IsRailStationTile(tile) && HasStationReservation(tile)) {
|
||||
/* Check for trains having a reservation for this tile. */
|
||||
Train *v = GetTrainForReservation(tile, AxisToTrack(GetRailStationAxis(tile)));
|
||||
|
@ -1913,7 +2030,7 @@ static CommandCost FindJoiningRoadStop(StationID existing_stop, StationID statio
|
|||
* @param unit_cost The cost to build one road stop of the current type.
|
||||
* @return The cost in case of success, or an error code if it failed.
|
||||
*/
|
||||
CommandCost CalculateRoadStopCost(TileArea tile_area, DoCommandFlags flags, bool is_drive_through, StationType station_type, Axis axis, DiagDirection ddir, StationID *est, RoadType rt, Money unit_cost)
|
||||
CommandCost CalculateRoadStopCost(TileArea tile_area, DoCommandFlags flags, bool is_drive_through, StationType station_type, const RoadStopSpec *roadstopspec, Axis axis, DiagDirection ddir, StationID *est, RoadType rt, Money unit_cost)
|
||||
{
|
||||
DiagDirections invalid_dirs{};
|
||||
if (is_drive_through) {
|
||||
|
@ -1927,7 +2044,7 @@ CommandCost CalculateRoadStopCost(TileArea tile_area, DoCommandFlags flags, bool
|
|||
int allowed_z = -1;
|
||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||
for (TileIndex cur_tile : tile_area) {
|
||||
CommandCost ret = CheckFlatLandRoadStop(cur_tile, allowed_z, flags, invalid_dirs, is_drive_through, station_type, axis, est, rt);
|
||||
CommandCost ret = CheckFlatLandRoadStop(cur_tile, allowed_z, roadstopspec, flags, invalid_dirs, is_drive_through, station_type, axis, est, rt);
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
bool is_preexisting_roadstop = IsTileType(cur_tile, MP_STATION) && IsAnyRoadStop(cur_tile);
|
||||
|
@ -2008,7 +2125,7 @@ CommandCost CmdBuildRoadStop(DoCommandFlags flags, TileIndex tile, uint8_t width
|
|||
unit_cost = _price[is_truck_stop ? PR_BUILD_STATION_TRUCK : PR_BUILD_STATION_BUS];
|
||||
}
|
||||
StationID est = StationID::Invalid();
|
||||
CommandCost cost = CalculateRoadStopCost(roadstop_area, flags, is_drive_through, is_truck_stop ? StationType::Truck : StationType::Bus, axis, ddir, &est, rt, unit_cost);
|
||||
CommandCost cost = CalculateRoadStopCost(roadstop_area, flags, is_drive_through, is_truck_stop ? StationType::Truck : StationType::Bus, roadstopspec, axis, ddir, &est, rt, unit_cost);
|
||||
if (cost.Failed()) return cost;
|
||||
|
||||
Station *st = nullptr;
|
||||
|
@ -3380,6 +3497,7 @@ draw_default_foundation:
|
|||
}
|
||||
|
||||
DrawRailTileSeq(ti, t, TO_BUILDINGS, total_offset, relocation, palette);
|
||||
DrawBridgeMiddle(ti);
|
||||
}
|
||||
|
||||
void StationPickerDrawSprite(int x, int y, StationType st, RailType railtype, RoadType roadtype, int image)
|
||||
|
|
|
@ -740,8 +740,53 @@ static const std::span<const std::span<const PalSpriteID>> _bridge_sprite_table[
|
|||
* @param nrl description of the rail bridge in query tool
|
||||
* @param nrd description of the road bridge in query tool
|
||||
*/
|
||||
#define MBR(y, mnl, mxl, p, mxs, spr, plt, dsc, nrl, nrd) \
|
||||
{TimerGameCalendar::Year{y}, mnl, mxl, p, mxs, spr, plt, dsc, { nrl, nrd }, {}, 0}
|
||||
#define MBR(y, mnl, mxl, p, mxs, spr, plt, dsc, nrl, nrd, pillars) \
|
||||
{TimerGameCalendar::Year{y}, mnl, mxl, p, mxs, spr, plt, dsc, { nrl, nrd }, {}, 0, BridgeSpecCtrlFlags(), pillars}
|
||||
|
||||
static constexpr std::array<BridgePiecePillarFlags, 12> all_pillars = {
|
||||
BridgePiecePillarFlag::BPPF_ALL_CORNERS, //0x0F,
|
||||
BridgePiecePillarFlag::BPPF_ALL_CORNERS, //0x0F,
|
||||
BridgePiecePillarFlag::BPPF_ALL_CORNERS, //0x0F,
|
||||
BridgePiecePillarFlag::BPPF_ALL_CORNERS, //0x0F,
|
||||
BridgePiecePillarFlag::BPPF_ALL_CORNERS, //0x0F,
|
||||
BridgePiecePillarFlag::BPPF_ALL_CORNERS, //0x0F,
|
||||
BridgePiecePillarFlag::BPPF_ALL_CORNERS, //0x0F,
|
||||
BridgePiecePillarFlag::BPPF_ALL_CORNERS, //0x0F,
|
||||
BridgePiecePillarFlag::BPPF_ALL_CORNERS, //0x0F,
|
||||
BridgePiecePillarFlag::BPPF_ALL_CORNERS, //0x0F,
|
||||
BridgePiecePillarFlag::BPPF_ALL_CORNERS, //0x0F,
|
||||
BridgePiecePillarFlag::BPPF_ALL_CORNERS, //0x0F
|
||||
};
|
||||
|
||||
static constexpr std::array<BridgePiecePillarFlags, 12> susp_pillars = {
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_W, BridgePiecePillarFlag::BPPF_CORNER_S}), //0x03,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_S, BridgePiecePillarFlag::BPPF_CORNER_E}), //0x06,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_E, BridgePiecePillarFlag::BPPF_CORNER_N}), //0x0C,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_W, BridgePiecePillarFlag::BPPF_CORNER_N}), //0x09,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_E, BridgePiecePillarFlag::BPPF_CORNER_N}), //0x0C,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_W, BridgePiecePillarFlag::BPPF_CORNER_N}), //0x09,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_W, BridgePiecePillarFlag::BPPF_CORNER_S}), //0x03,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_S, BridgePiecePillarFlag::BPPF_CORNER_E}), //0x06,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_ALL_CORNERS}), //0x0F,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_ALL_CORNERS}), //0x0F,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag()}), //0x00,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag()}), //0x00
|
||||
};
|
||||
|
||||
static constexpr std::array<BridgePiecePillarFlags, 12> cant_pillars = {
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag()}), //0x00,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag()}), //0x00,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_E, BridgePiecePillarFlag::BPPF_CORNER_N}), //0x0C,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_W, BridgePiecePillarFlag::BPPF_CORNER_N}), //0x09,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_E, BridgePiecePillarFlag::BPPF_CORNER_N}), //0x0C,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_W, BridgePiecePillarFlag::BPPF_CORNER_N}), //0x09,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_E, BridgePiecePillarFlag::BPPF_CORNER_N}), //0x0C,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_W, BridgePiecePillarFlag::BPPF_CORNER_N}), //0x09,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_E, BridgePiecePillarFlag::BPPF_CORNER_N}), //0x0C,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_W, BridgePiecePillarFlag::BPPF_CORNER_N}), //0x09,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_E, BridgePiecePillarFlag::BPPF_CORNER_N}), //0x0C,
|
||||
BridgePiecePillarFlags({BridgePiecePillarFlag::BPPF_CORNER_W, BridgePiecePillarFlag::BPPF_CORNER_N}), //0x09
|
||||
};
|
||||
|
||||
const BridgeSpec _orig_bridge[] = {
|
||||
/*
|
||||
|
@ -755,43 +800,43 @@ const BridgeSpec _orig_bridge[] = {
|
|||
string with description name on rail name on road
|
||||
| | | | */
|
||||
MBR( 0, 0, 0xFFFF, 80, 32, 0xA24, PAL_NONE,
|
||||
STR_BRIDGE_NAME_WOODEN, STR_LAI_BRIDGE_DESCRIPTION_RAIL_WOODEN, STR_LAI_BRIDGE_DESCRIPTION_ROAD_WOODEN),
|
||||
STR_BRIDGE_NAME_WOODEN, STR_LAI_BRIDGE_DESCRIPTION_RAIL_WOODEN, STR_LAI_BRIDGE_DESCRIPTION_ROAD_WOODEN, all_pillars),
|
||||
|
||||
MBR( 0, 0, 2, 112, 48, 0xA26, PALETTE_TO_STRUCT_RED,
|
||||
STR_BRIDGE_NAME_CONCRETE, STR_LAI_BRIDGE_DESCRIPTION_RAIL_CONCRETE, STR_LAI_BRIDGE_DESCRIPTION_ROAD_CONCRETE),
|
||||
STR_BRIDGE_NAME_CONCRETE, STR_LAI_BRIDGE_DESCRIPTION_RAIL_CONCRETE, STR_LAI_BRIDGE_DESCRIPTION_ROAD_CONCRETE, all_pillars),
|
||||
|
||||
MBR(1930, 0, 5, 144, 64, 0xA25, PAL_NONE,
|
||||
STR_BRIDGE_NAME_GIRDER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL),
|
||||
STR_BRIDGE_NAME_GIRDER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL, all_pillars),
|
||||
|
||||
MBR( 0, 2, 10, 168, 80, 0xA22, PALETTE_TO_STRUCT_CONCRETE,
|
||||
STR_BRIDGE_NAME_SUSPENSION_CONCRETE, STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_CONCRETE, STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_CONCRETE),
|
||||
STR_BRIDGE_NAME_SUSPENSION_CONCRETE, STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_CONCRETE, STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_CONCRETE, susp_pillars),
|
||||
|
||||
MBR(1930, 3, 0xFFFF, 185, 96, 0xA22, PAL_NONE,
|
||||
STR_BRIDGE_NAME_SUSPENSION_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL),
|
||||
STR_BRIDGE_NAME_SUSPENSION_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL, susp_pillars),
|
||||
|
||||
MBR(1930, 3, 0xFFFF, 192, 112, 0xA22, PALETTE_TO_STRUCT_YELLOW,
|
||||
STR_BRIDGE_NAME_SUSPENSION_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL),
|
||||
STR_BRIDGE_NAME_SUSPENSION_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_SUSPENSION_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_SUSPENSION_STEEL, susp_pillars),
|
||||
|
||||
MBR(1930, 3, 7, 224, 160, 0xA23, PAL_NONE,
|
||||
STR_BRIDGE_NAME_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL),
|
||||
STR_BRIDGE_NAME_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL, cant_pillars),
|
||||
|
||||
MBR(1930, 3, 8, 232, 208, 0xA23, PALETTE_TO_STRUCT_BROWN,
|
||||
STR_BRIDGE_NAME_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL),
|
||||
STR_BRIDGE_NAME_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL, cant_pillars),
|
||||
|
||||
MBR(1930, 3, 9, 248, 240, 0xA23, PALETTE_TO_STRUCT_RED,
|
||||
STR_BRIDGE_NAME_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL),
|
||||
STR_BRIDGE_NAME_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_CANTILEVER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_CANTILEVER_STEEL, cant_pillars),
|
||||
|
||||
MBR(1930, 0, 2, 240, 256, 0xA27, PAL_NONE,
|
||||
STR_BRIDGE_NAME_GIRDER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL),
|
||||
STR_BRIDGE_NAME_GIRDER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_GIRDER_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_GIRDER_STEEL, all_pillars),
|
||||
|
||||
MBR(1995, 2, 0xFFFF, 255, 320, 0xA28, PAL_NONE,
|
||||
STR_BRIDGE_NAME_TUBULAR_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL),
|
||||
STR_BRIDGE_NAME_TUBULAR_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL, cant_pillars),
|
||||
|
||||
MBR(2005, 2, 0xFFFF, 380, 512, 0xA28, PALETTE_TO_STRUCT_YELLOW,
|
||||
STR_BRIDGE_NAME_TUBULAR_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL),
|
||||
STR_BRIDGE_NAME_TUBULAR_STEEL, STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL, cant_pillars),
|
||||
|
||||
MBR(2010, 2, 0xFFFF, 510, 608, 0xA28, PALETTE_TO_STRUCT_CONCRETE,
|
||||
STR_BRIDGE_TUBULAR_SILICON, STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL)
|
||||
STR_BRIDGE_TUBULAR_SILICON, STR_LAI_BRIDGE_DESCRIPTION_RAIL_TUBULAR_STEEL, STR_LAI_BRIDGE_DESCRIPTION_ROAD_TUBULAR_STEEL, cant_pillars)
|
||||
};
|
||||
|
||||
#undef MBR
|
||||
|
|
|
@ -33,7 +33,7 @@ static bool MockLoadNextSprite(SpriteID load_index)
|
|||
sc->id = 0;
|
||||
sc->type = is_mapgen ? SpriteType::MapGen : SpriteType::Normal;
|
||||
sc->warned = false;
|
||||
sc->control_flags = 0;
|
||||
sc->control_flags = {};
|
||||
|
||||
/* Fill with empty sprites up until the default sprite count. */
|
||||
return load_index < SPR_OPENTTD_BASE + OPENTTD_SPRITE_COUNT;
|
||||
|
|
|
@ -39,10 +39,13 @@
|
|||
#include "object_base.h"
|
||||
#include "water.h"
|
||||
#include "company_gui.h"
|
||||
#include "newgrf_roadstop.h"
|
||||
#include "station_func.h"
|
||||
#include "station_map.h"
|
||||
#include "tunnelbridge_cmd.h"
|
||||
#include "landscape_cmd.h"
|
||||
#include "terraform_cmd.h"
|
||||
#include "newgrf_station.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
#include "table/bridge_land.h"
|
||||
|
@ -55,6 +58,12 @@ TileIndex _build_tunnel_endtile; ///< The end of a tunnel; as hidden return from
|
|||
/** Z position of the bridge sprites relative to bridge height (downwards) */
|
||||
static const int BRIDGE_Z_START = 3;
|
||||
|
||||
extern CommandCost IsRailStationBridgeAboveOk(TileIndex tile, const StationSpec *statspec, uint8_t layout, TileIndex northern_bridge_end, TileIndex southern_bridge_end, int bridge_height,
|
||||
BridgeType bridge_type, TransportType bridge_transport_type);
|
||||
|
||||
extern CommandCost IsRoadStopBridgeAboveOK(TileIndex tile, const RoadStopSpec *spec, bool drive_through, DiagDirection entrance,
|
||||
TileIndex northern_bridge_end, TileIndex southern_bridge_end, int bridge_height,
|
||||
BridgeType bridge_type, TransportType bridge_transport_type);
|
||||
|
||||
/**
|
||||
* Mark bridge tiles dirty.
|
||||
|
@ -391,6 +400,43 @@ CommandCost CmdBuildBridge(DoCommandFlags flags, TileIndex tile_end, TileIndex t
|
|||
/* If bridge belonged to bankrupt company, it has a new owner now */
|
||||
is_new_owner = (owner == OWNER_NONE);
|
||||
if (is_new_owner) owner = company;
|
||||
|
||||
TileIndexDiff delta = (direction == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
|
||||
for (TileIndex tile = tile_start + delta; tile != tile_end; tile += delta) {
|
||||
if (!IsTileType(tile, MP_STATION)) continue;
|
||||
switch (GetStationType(tile)) {
|
||||
case StationType::Rail:
|
||||
case StationType::RailWaypoint: {
|
||||
CommandCost ret = IsRailStationBridgeAboveOk(tile, GetStationSpec(tile), GetStationGfx(tile), tile_start, tile_end, z_start + 1, bridge_type, transport_type);
|
||||
if (ret.Failed()) {
|
||||
if (ret.GetErrorMessage() != INVALID_STRING_ID) return ret;
|
||||
ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
|
||||
if (ret.Failed()) return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case StationType::Bus:
|
||||
case StationType::Truck:
|
||||
case StationType::RoadWaypoint: {
|
||||
CommandCost ret = IsRoadStopBridgeAboveOK(tile, GetRoadStopSpec(tile), IsDriveThroughStopTile(tile), IsDriveThroughStopTile(tile) ? AxisToDiagDir(GetDriveThroughStopAxis(tile)) : GetBayRoadStopDir(tile),
|
||||
tile_start, tile_end, z_start + 1, bridge_type, transport_type);
|
||||
if (ret.Failed()) {
|
||||
if (ret.GetErrorMessage() != INVALID_STRING_ID) return ret;
|
||||
ret = Command<CMD_LANDSCAPE_CLEAR>::Do(flags, tile);
|
||||
if (ret.Failed()) return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case StationType::Buoy:
|
||||
/* Buoys are always allowed */
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Build a new bridge. */
|
||||
|
||||
|
@ -467,6 +513,45 @@ CommandCost CmdBuildBridge(DoCommandFlags flags, TileIndex tile_end, TileIndex t
|
|||
break;
|
||||
}
|
||||
|
||||
case MP_STATION: {
|
||||
switch (GetStationType(tile)) {
|
||||
case StationType::Airport:
|
||||
goto not_valid_below;
|
||||
|
||||
case StationType::Rail:
|
||||
case StationType::RailWaypoint: {
|
||||
CommandCost ret = IsRailStationBridgeAboveOk(tile, GetStationSpec(tile), GetStationGfx(tile), tile_start, tile_end, z_start + 1, bridge_type, transport_type);
|
||||
if (ret.Failed()) {
|
||||
if (ret.GetErrorMessage() != INVALID_STRING_ID) return ret;
|
||||
goto not_valid_below;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case StationType::Bus:
|
||||
case StationType::Truck:
|
||||
case StationType::RoadWaypoint: {
|
||||
CommandCost ret = IsRoadStopBridgeAboveOK(tile, GetRoadStopSpec(tile), IsDriveThroughStopTile(tile), IsDriveThroughStopTile(tile) ? AxisToDiagDir(GetDriveThroughStopAxis(tile)) : GetBayRoadStopDir(tile),
|
||||
tile_start, tile_end, z_start + 1, bridge_type, transport_type);
|
||||
if (ret.Failed()) {
|
||||
if (ret.GetErrorMessage() != INVALID_STRING_ID) return ret;
|
||||
goto not_valid_below;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case StationType::Buoy:
|
||||
/* Buoys are always allowed */
|
||||
break;
|
||||
|
||||
default:
|
||||
//if (!(GetStationType(tile) == StationType::Dock && _settings_game.construction.allow_docks_under_bridges)) goto not_valid_below;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case MP_CLEAR:
|
||||
break;
|
||||
|
||||
|
@ -1517,6 +1602,49 @@ static BridgePieces CalcBridgePiece(uint north, uint south)
|
|||
}
|
||||
}
|
||||
|
||||
BridgePiecePillarFlags GetBridgeTilePillarFlags(TileIndex tile, TileIndex northern_bridge_end, TileIndex southern_bridge_end, BridgeType bridge_type, TransportType bridge_transport_type)
|
||||
{
|
||||
if (bridge_transport_type == TRANSPORT_WATER) return BridgePiecePillarFlag::BPPF_ALL_CORNERS;
|
||||
|
||||
BridgePieces piece = CalcBridgePiece(
|
||||
GetTunnelBridgeLength(tile, northern_bridge_end) + 1,
|
||||
GetTunnelBridgeLength(tile, southern_bridge_end) + 1
|
||||
);
|
||||
assert(piece < BRIDGE_PIECE_HEAD);
|
||||
|
||||
const BridgeSpec *spec = GetBridgeSpec(bridge_type);
|
||||
const Axis axis = TileX(northern_bridge_end) == TileX(southern_bridge_end) ? AXIS_Y : AXIS_X;
|
||||
if (!spec->ctrl_flags.Test(BridgeSpecCtrlFlag::BSCF_INVALID_PILLAR_FLAGS)) {
|
||||
return spec->pillar_flags[piece * 2 + (axis == AXIS_Y ? 1 : 0)];
|
||||
} else {
|
||||
uint base_offset;
|
||||
if (bridge_transport_type == TRANSPORT_RAIL) {
|
||||
base_offset = GetRailTypeInfo(GetRailType(southern_bridge_end))->bridge_offset;
|
||||
} else {
|
||||
base_offset = 8;
|
||||
}
|
||||
|
||||
const PalSpriteID *psid = &GetBridgeSpriteTable(bridge_type, piece)[base_offset];
|
||||
if (axis == AXIS_Y) psid += 4;
|
||||
return psid[2].sprite != 0 ? BridgePiecePillarFlag::BPPF_ALL_CORNERS : BridgePiecePillarFlags();
|
||||
}
|
||||
}
|
||||
|
||||
BridgePieceDebugInfo GetBridgePieceDebugInfo(TileIndex tile)
|
||||
{
|
||||
TileIndex rampnorth = GetNorthernBridgeEnd(tile);
|
||||
TileIndex rampsouth = GetSouthernBridgeEnd(tile);
|
||||
|
||||
BridgePieces piece = CalcBridgePiece(
|
||||
GetTunnelBridgeLength(tile, rampnorth) + 1,
|
||||
GetTunnelBridgeLength(tile, rampsouth) + 1
|
||||
);
|
||||
BridgePiecePillarFlags pillar_flags = GetBridgeTilePillarFlags(tile, rampnorth, rampsouth, GetBridgeType(rampnorth), GetTunnelBridgeTransportType(rampnorth));
|
||||
const Axis axis = TileX(rampnorth) == TileX(rampsouth) ? AXIS_Y : AXIS_X;
|
||||
uint pillar_index = piece * 2 + (axis == AXIS_Y ? 1 : 0);
|
||||
return { piece, pillar_flags, pillar_index };
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the middle bits of a bridge.
|
||||
* @param ti Tile information of the tile to draw it on.
|
||||
|
|
|
@ -182,7 +182,9 @@ static CommandCost IsValidTileForWaypoint(TileIndex tile, Axis axis, StationID *
|
|||
extern void GetStationLayout(uint8_t *layout, uint numtracks, uint plat_len, const StationSpec *statspec);
|
||||
extern CommandCost FindJoiningWaypoint(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Waypoint **wp, bool is_road);
|
||||
extern CommandCost CanExpandRailStation(const BaseStation *st, TileArea &new_ta);
|
||||
extern CommandCost CalculateRoadStopCost(TileArea tile_area, DoCommandFlags flags, bool is_drive_through, StationType station_type, Axis axis, DiagDirection ddir, StationID *est, RoadType rt, Money unit_cost);
|
||||
extern CommandCost CalculateRoadStopCost(TileArea tile_area, DoCommandFlags flags, bool is_drive_through, StationType station_type, const RoadStopSpec *roadstopspec, Axis axis, DiagDirection ddir, StationID *est, RoadType rt, Money unit_cost);
|
||||
extern CommandCost IsRailStationBridgeAboveOk(TileIndex tile, const StationSpec *statspec, uint8_t layout);
|
||||
|
||||
extern CommandCost RemoveRoadWaypointStop(TileIndex tile, DoCommandFlags flags, int replacement_spec_index);
|
||||
|
||||
/**
|
||||
|
@ -220,6 +222,17 @@ CommandCost CmdBuildRailWaypoint(DoCommandFlags flags, TileIndex start_tile, Axi
|
|||
|
||||
if (distant_join && (!_settings_game.station.distant_join_stations || !Waypoint::IsValidID(station_to_join))) return CMD_ERROR;
|
||||
|
||||
const StationSpec *spec = StationClass::Get(spec_class)->GetSpec(spec_index);
|
||||
std::vector<uint8_t> layout_ptr;
|
||||
layout_ptr.resize(count);
|
||||
if (spec == nullptr) {
|
||||
/* The layout must be 0 for the 'normal' waypoints by design. */
|
||||
//memset(layout_ptr, 0, count); //FIXME
|
||||
} else {
|
||||
/* But for NewGRF waypoints we like to have their style. */
|
||||
GetStationLayout(&layout_ptr[0], count, 1, spec);
|
||||
}
|
||||
|
||||
TileArea new_location(start_tile, width, height);
|
||||
|
||||
/* only AddCost for non-existing waypoints */
|
||||
|
@ -237,6 +250,10 @@ CommandCost CmdBuildRailWaypoint(DoCommandFlags flags, TileIndex start_tile, Axi
|
|||
TileIndex tile = start_tile + i * offset;
|
||||
CommandCost ret = IsValidTileForWaypoint(tile, axis, &est);
|
||||
if (ret.Failed()) return ret;
|
||||
ret = IsRailStationBridgeAboveOk(tile, spec, layout_ptr[i]);
|
||||
if (ret.Failed()) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
Waypoint *wp = nullptr;
|
||||
|
@ -364,7 +381,7 @@ CommandCost CmdBuildRoadWaypoint(DoCommandFlags flags, TileIndex start_tile, Axi
|
|||
unit_cost = _price[PR_BUILD_STATION_TRUCK];
|
||||
}
|
||||
StationID est = StationID::Invalid();
|
||||
CommandCost cost = CalculateRoadStopCost(roadstop_area, flags, true, StationType::RoadWaypoint, axis, AxisToDiagDir(axis), &est, INVALID_ROADTYPE, unit_cost);
|
||||
CommandCost cost = CalculateRoadStopCost(roadstop_area, flags, true, StationType::RoadWaypoint, roadstopspec, axis, AxisToDiagDir(axis), &est, INVALID_ROADTYPE, unit_cost);
|
||||
if (cost.Failed()) return cost;
|
||||
|
||||
Waypoint *wp = nullptr;
|
||||
|
|
Loading…
Reference in New Issue