|
|
/* $Id$ */
|
|
|
|
|
|
/** @file tunnelbridge_cmd.cpp
|
|
|
* This file deals with tunnels and bridges (non-gui stuff)
|
|
|
* @todo seperate this file into two
|
|
|
*/
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
#include "openttd.h"
|
|
|
#include "bridge_map.h"
|
|
|
#include "rail_map.h"
|
|
|
#include "road_map.h"
|
|
|
#include "table/sprites.h"
|
|
|
#include "table/strings.h"
|
|
|
#include "strings.h"
|
|
|
#include "functions.h"
|
|
|
#include "map.h"
|
|
|
#include "landscape.h"
|
|
|
#include "tile.h"
|
|
|
#include "tunnel_map.h"
|
|
|
#include "unmovable_map.h"
|
|
|
#include "vehicle.h"
|
|
|
#include "viewport.h"
|
|
|
#include "command.h"
|
|
|
#include "player.h"
|
|
|
#include "town.h"
|
|
|
#include "sound.h"
|
|
|
#include "variables.h"
|
|
|
#include "bridge.h"
|
|
|
#include "train.h"
|
|
|
#include "water_map.h"
|
|
|
#include "yapf/yapf.h"
|
|
|
#include "date.h"
|
|
|
#include "newgrf_sound.h"
|
|
|
#include "autoslope.h"
|
|
|
|
|
|
#include "table/bridge_land.h"
|
|
|
|
|
|
const Bridge orig_bridge[] = {
|
|
|
/*
|
|
|
year of availablity
|
|
|
| minimum length
|
|
|
| | maximum length
|
|
|
| | | price
|
|
|
| | | | maximum speed
|
|
|
| | | | | sprite to use in GUI string with description
|
|
|
| | | | | | | */
|
|
|
{ 0, 0, 16, 80, 32, 0xA24, PAL_NONE , STR_5012_WOODEN , NULL, 0 },
|
|
|
{ 0, 0, 2, 112, 48, 0xA26, PALETTE_TO_STRUCT_RED , STR_5013_CONCRETE , NULL, 0 },
|
|
|
{ 1930, 0, 5, 144, 64, 0xA25, PAL_NONE , STR_500F_GIRDER_STEEL , NULL, 0 },
|
|
|
{ 0, 2, 10, 168, 80, 0xA22, PALETTE_TO_STRUCT_CONCRETE, STR_5011_SUSPENSION_CONCRETE, NULL, 0 },
|
|
|
{ 1930, 3, 16, 185, 96, 0xA22, PAL_NONE , STR_500E_SUSPENSION_STEEL , NULL, 0 },
|
|
|
{ 1930, 3, 16, 192, 112, 0xA22, PALETTE_TO_STRUCT_YELLOW , STR_500E_SUSPENSION_STEEL , NULL, 0 },
|
|
|
{ 1930, 3, 7, 224, 160, 0xA23, PAL_NONE , STR_5010_CANTILEVER_STEEL , NULL, 0 },
|
|
|
{ 1930, 3, 8, 232, 208, 0xA23, PALETTE_TO_STRUCT_BROWN , STR_5010_CANTILEVER_STEEL , NULL, 0 },
|
|
|
{ 1930, 3, 9, 248, 240, 0xA23, PALETTE_TO_STRUCT_RED , STR_5010_CANTILEVER_STEEL , NULL, 0 },
|
|
|
{ 1930, 0, 2, 240, 256, 0xA27, PAL_NONE , STR_500F_GIRDER_STEEL , NULL, 0 },
|
|
|
{ 1995, 2, 16, 255, 320, 0xA28, PAL_NONE , STR_5014_TUBULAR_STEEL , NULL, 0 },
|
|
|
{ 2005, 2, 32, 380, 512, 0xA28, PALETTE_TO_STRUCT_YELLOW , STR_5014_TUBULAR_STEEL , NULL, 0 },
|
|
|
{ 2010, 2, 32, 510, 608, 0xA28, PALETTE_TO_STRUCT_GREY , STR_BRIDGE_TUBULAR_SILICON , NULL, 0 }
|
|
|
};
|
|
|
|
|
|
Bridge _bridge[MAX_BRIDGES];
|
|
|
|
|
|
|
|
|
/** calculate the price factor for building a long bridge.
|
|
|
* basically the cost delta is 1,1, 1, 2,2, 3,3,3, 4,4,4,4, 5,5,5,5,5, 6,6,6,6,6,6, 7,7,7,7,7,7,7, 8,8,8,8,8,8,8,8,
|
|
|
*/
|
|
|
int CalcBridgeLenCostFactor(int x)
|
|
|
{
|
|
|
int n;
|
|
|
int r;
|
|
|
|
|
|
if (x < 2) return x;
|
|
|
x -= 2;
|
|
|
for (n = 0, r = 2;; n++) {
|
|
|
if (x <= n) return r + x * n;
|
|
|
r += n * n;
|
|
|
x -= n;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#define M(x) (1 << (x))
|
|
|
enum BridgeFoundation {
|
|
|
/* foundation, whole tile is leveled up --> 3 corners raised */
|
|
|
BRIDGE_FULL_LEVELED_FOUNDATION = M(SLOPE_WSE) | M(SLOPE_NWS) | M(SLOPE_ENW) | M(SLOPE_SEN),
|
|
|
/* foundation, tile is partly leveled up --> 1 corner raised */
|
|
|
BRIDGE_PARTLY_LEVELED_FOUNDATION = M(SLOPE_W) | M(SLOPE_S) | M(SLOPE_E) | M(SLOPE_N),
|
|
|
/* no foundations (X,Y direction) */
|
|
|
BRIDGE_NO_FOUNDATION = M(SLOPE_FLAT) | M(SLOPE_SW) | M(SLOPE_SE) | M(SLOPE_NW) | M(SLOPE_NE),
|
|
|
BRIDGE_HORZ_RAMP = (BRIDGE_PARTLY_LEVELED_FOUNDATION | BRIDGE_NO_FOUNDATION) & ~M(SLOPE_FLAT)
|
|
|
};
|
|
|
#undef M
|
|
|
|
|
|
static inline const PalSpriteID *GetBridgeSpriteTable(int index, byte table)
|
|
|
{
|
|
|
const Bridge *bridge = &_bridge[index];
|
|
|
assert(table < 7);
|
|
|
if (bridge->sprite_table == NULL || bridge->sprite_table[table] == NULL) {
|
|
|
return _bridge_sprite_table[index][table];
|
|
|
} else {
|
|
|
return bridge->sprite_table[table];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
static inline byte GetBridgeFlags(int index) { return _bridge[index].flags;}
|
|
|
|
|
|
|
|
|
/** Check the slope at the bridge ramps in three easy steps:
|
|
|
* - valid slopes without foundation
|
|
|
* - valid slopes with foundation
|
|
|
* - rest is invalid
|
|
|
*/
|
|
|
#define M(x) (1 << (x))
|
|
|
static CommandCost CheckBridgeSlopeNorth(Axis axis, Slope tileh)
|
|
|
{
|
|
|
uint32 valid;
|
|
|
|
|
|
valid = M(SLOPE_FLAT) | (axis == AXIS_X ? M(SLOPE_NE) : M(SLOPE_NW));
|
|
|
if (HASBIT(valid, tileh)) return CommandCost();
|
|
|
|
|
|
valid =
|
|
|
BRIDGE_FULL_LEVELED_FOUNDATION | M(SLOPE_N) | M(SLOPE_STEEP_N) |
|
|
|
(axis == AXIS_X ? M(SLOPE_E) | M(SLOPE_STEEP_E) : M(SLOPE_W) | M(SLOPE_STEEP_W));
|
|
|
if (HASBIT(valid, tileh)) return CommandCost(_price.terraform);
|
|
|
|
|
|
return CMD_ERROR;
|
|
|
}
|
|
|
|
|
|
static CommandCost CheckBridgeSlopeSouth(Axis axis, Slope tileh)
|
|
|
{
|
|
@@ -1323,115 +1324,139 @@ static uint32 VehicleEnter_TunnelBridge(
|
|
|
v->tile = tile;
|
|
|
v->u.rail.track = TRACK_BIT_WORMHOLE;
|
|
|
v->vehstatus |= VS_HIDDEN;
|
|
|
return VETSB_ENTERED_WORMHOLE;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (dir == ReverseDiagDir(vdir) && fc == _tunnel_fractcoord_3[dir] && z == 0) {
|
|
|
/* We're at the tunnel exit ?? */
|
|
|
v->tile = tile;
|
|
|
v->u.rail.track = (TrackBits)_exit_tunnel_track[dir];
|
|
|
assert(v->u.rail.track);
|
|
|
v->vehstatus &= ~VS_HIDDEN;
|
|
|
return VETSB_ENTERED_WORMHOLE;
|
|
|
}
|
|
|
} else if (v->type == VEH_ROAD) {
|
|
|
fc = (x & 0xF) + (y << 4);
|
|
|
dir = GetTunnelDirection(tile);
|
|
|
vdir = DirToDiagDir(v->direction);
|
|
|
|
|
|
/* Enter tunnel? */
|
|
|
if (v->u.road.state != RVSB_WORMHOLE && dir == vdir) {
|
|
|
if (fc == _tunnel_fractcoord_4[dir] ||
|
|
|
fc == _tunnel_fractcoord_5[dir]) {
|
|
|
v->tile = tile;
|
|
|
v->u.road.state = RVSB_WORMHOLE;
|
|
|
v->vehstatus |= VS_HIDDEN;
|
|
|
return VETSB_ENTERED_WORMHOLE;
|
|
|
} else {
|
|
|
return VETSB_CONTINUE;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (dir == ReverseDiagDir(vdir) && (
|
|
|
/* We're at the tunnel exit ?? */
|
|
|
fc == _tunnel_fractcoord_6[dir] ||
|
|
|
fc == _tunnel_fractcoord_7[dir]
|
|
|
) &&
|
|
|
z == 0) {
|
|
|
v->tile = tile;
|
|
|
v->u.road.state = _road_exit_tunnel_state[dir];
|
|
|
v->u.road.frame = _road_exit_tunnel_frame[dir];
|
|
|
v->vehstatus &= ~VS_HIDDEN;
|
|
|
return VETSB_ENTERED_WORMHOLE;
|
|
|
}
|
|
|
}
|
|
|
} else if (IsBridge(tile)) { // XXX is this necessary?
|
|
|
DiagDirection dir;
|
|
|
|
|
|
if (v->IsPrimaryVehicle()) {
|
|
|
/* modify speed of vehicle */
|
|
|
uint16 spd = _bridge[GetBridgeType(tile)].speed;
|
|
|
|
|
|
if (v->type == VEH_ROAD) spd *= 2;
|
|
|
if (v->cur_speed > spd) v->cur_speed = spd;
|
|
|
}
|
|
|
|
|
|
dir = GetBridgeRampDirection(tile);
|
|
|
if (DirToDiagDir(v->direction) == dir) {
|
|
|
switch (dir) {
|
|
|
default: NOT_REACHED();
|
|
|
case DIAGDIR_NE: if ((x & 0xF) != 0) return VETSB_CONTINUE; break;
|
|
|
case DIAGDIR_SE: if ((y & 0xF) != TILE_SIZE - 1) return VETSB_CONTINUE; break;
|
|
|
case DIAGDIR_SW: if ((x & 0xF) != TILE_SIZE - 1) return VETSB_CONTINUE; break;
|
|
|
case DIAGDIR_NW: if ((y & 0xF) != 0) return VETSB_CONTINUE; break;
|
|
|
}
|
|
|
if (v->type == VEH_TRAIN) {
|
|
|
v->u.rail.track = TRACK_BIT_WORMHOLE;
|
|
|
CLRBIT(v->u.rail.flags, VRF_GOINGUP);
|
|
|
CLRBIT(v->u.rail.flags, VRF_GOINGDOWN);
|
|
|
} else {
|
|
|
v->u.road.state = RVSB_WORMHOLE;
|
|
|
}
|
|
|
return VETSB_ENTERED_WORMHOLE;
|
|
|
} else if (DirToDiagDir(v->direction) == ReverseDiagDir(dir)) {
|
|
|
v->tile = tile;
|
|
|
if (v->type == VEH_TRAIN) {
|
|
|
if (v->u.rail.track == TRACK_BIT_WORMHOLE) {
|
|
|
v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? TRACK_BIT_X : TRACK_BIT_Y);
|
|
|
return VETSB_ENTERED_WORMHOLE;
|
|
|
}
|
|
|
} else {
|
|
|
if (v->u.road.state == RVSB_WORMHOLE) {
|
|
|
v->u.road.state = _road_exit_tunnel_state[dir];
|
|
|
v->u.road.frame = 0;
|
|
|
return VETSB_ENTERED_WORMHOLE;
|
|
|
}
|
|
|
}
|
|
|
return VETSB_CONTINUE;
|
|
|
}
|
|
|
}
|
|
|
return VETSB_CONTINUE;
|
|
|
}
|
|
|
|
|
|
static CommandCost TerraformTile_TunnelBridge(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
|
|
|
{
|
|
|
if (_patches.build_on_slopes && AutoslopeEnabled() && IsBridge(tile)) {
|
|
|
DiagDirection direction = GetBridgeRampDirection(tile);
|
|
|
Axis axis = DiagDirToAxis(direction);
|
|
|
CommandCost res;
|
|
|
|
|
|
/* Check if new slope is valid for bridges in general (so we can savely call GetBridgeFoundation()) */
|
|
|
if ((direction == DIAGDIR_NW) || (direction == DIAGDIR_NE)) {
|
|
|
res = CheckBridgeSlopeSouth(axis, tileh_new);
|
|
|
} else {
|
|
|
res = CheckBridgeSlopeNorth(axis, tileh_new);
|
|
|
}
|
|
|
|
|
|
if (!CmdFailed(res)) {
|
|
|
uint z_old;
|
|
|
Slope tileh_old = GetTileSlope(tile, &z_old);
|
|
|
|
|
|
z_old += ApplyFoundationToSlope(GetBridgeFoundation(tileh_old, axis), &tileh_old);
|
|
|
z_new += ApplyFoundationToSlope(GetBridgeFoundation(tileh_new, axis), &tileh_new);
|
|
|
|
|
|
/* Surface slope remains unchanged? */
|
|
|
if ((z_old == z_new) && (tileh_old == tileh_new)) return _price.terraform;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
|
|
|
}
|
|
|
|
|
|
extern const TileTypeProcs _tile_type_tunnelbridge_procs = {
|
|
|
DrawTile_TunnelBridge, /* draw_tile_proc */
|
|
|
GetSlopeZ_TunnelBridge, /* get_slope_z_proc */
|
|
|
ClearTile_TunnelBridge, /* clear_tile_proc */
|
|
|
GetAcceptedCargo_TunnelBridge, /* get_accepted_cargo_proc */
|
|
|
GetTileDesc_TunnelBridge, /* get_tile_desc_proc */
|
|
|
GetTileTrackStatus_TunnelBridge, /* get_tile_track_status_proc */
|
|
|
ClickTile_TunnelBridge, /* click_tile_proc */
|
|
|
AnimateTile_TunnelBridge, /* animate_tile_proc */
|
|
|
TileLoop_TunnelBridge, /* tile_loop_clear */
|
|
|
ChangeTileOwner_TunnelBridge, /* change_tile_owner_clear */
|
|
|
NULL, /* get_produced_cargo_proc */
|
|
|
VehicleEnter_TunnelBridge, /* vehicle_enter_tile_proc */
|
|
|
GetFoundation_TunnelBridge, /* get_foundation_proc */
|
|
|
TerraformTile_TunnelBridge, /* terraform_tile_proc */
|
|
|
};
|