2005-07-24 14:12:37 +00:00
/* $Id$ */
2007-02-23 01:48:53 +00:00
/** @file station_cmd.cpp */
2005-07-28 05:47:54 +00:00
2004-08-09 17:04:08 +00:00
# include "stdafx.h"
2005-06-02 19:30:21 +00:00
# include "openttd.h"
2007-02-20 06:39:09 +00:00
# include "aircraft.h"
2006-12-27 12:38:02 +00:00
# include "bridge_map.h"
2007-02-24 09:42:39 +00:00
# include "cmd_helper.h"
2005-02-05 15:58:59 +00:00
# include "debug.h"
2005-07-22 07:02:20 +00:00
# include "functions.h"
2007-04-12 13:07:15 +00:00
# include "landscape.h"
2006-03-24 08:55:08 +00:00
# include "station_map.h"
2005-02-13 11:18:02 +00:00
# include "table/sprites.h"
2004-11-25 10:47:30 +00:00
# include "table/strings.h"
2004-12-15 22:18:54 +00:00
# include "map.h"
2005-01-29 12:19:05 +00:00
# include "tile.h"
2004-08-09 17:04:08 +00:00
# include "station.h"
# include "gfx.h"
# include "window.h"
# include "viewport.h"
# include "command.h"
# include "town.h"
# include "vehicle.h"
# include "news.h"
# include "saveload.h"
# include "economy.h"
# include "player.h"
# include "airport.h"
2004-11-14 16:42:08 +00:00
# include "sprite.h"
2005-02-06 10:18:47 +00:00
# include "depot.h"
2005-11-18 23:41:03 +00:00
# include "train.h"
2007-06-11 14:00:16 +00:00
# include "roadveh.h"
2006-03-01 21:00:44 +00:00
# include "water_map.h"
2006-04-11 22:09:21 +00:00
# include "industry_map.h"
2006-05-04 20:00:50 +00:00
# include "newgrf_callbacks.h"
# include "newgrf_station.h"
2006-05-27 16:12:16 +00:00
# include "yapf/yapf.h"
2006-08-14 14:21:15 +00:00
# include "date.h"
2007-01-10 18:56:51 +00:00
# include "helpers.hpp"
2007-01-26 11:38:07 +00:00
# include "misc/autoptr.hpp"
2007-02-14 16:37:16 +00:00
# include "road.h"
2007-02-20 22:09:21 +00:00
# include "cargotype.h"
2007-06-27 20:53:25 +00:00
# include "strings.h"
2007-01-14 19:29:21 +00:00
2007-08-01 23:49:06 +00:00
DEFINE_OLD_POOL_GENERIC ( Station , Station )
DEFINE_OLD_POOL_GENERIC ( RoadStop , RoadStop )
2005-02-03 17:22:35 +00:00
2007-07-24 21:48:50 +00:00
/**
* Check whether the given tile is a hangar .
* @ param t the tile to of whether it is a hangar .
* @ pre IsTileType ( t , MP_STATION )
* @ return true if and only if the tile is a hangar .
*/
bool IsHangar ( TileIndex t )
{
assert ( IsTileType ( t , MP_STATION ) ) ;
const Station * st = GetStationByTile ( t ) ;
const AirportFTAClass * apc = st - > Airport ( ) ;
for ( uint i = 0 ; i < apc - > nof_depots ; i + + ) {
if ( st - > airport_tile + ToTileIndexDiff ( apc - > airport_depots [ i ] ) = = t ) return true ;
}
return false ;
}
2007-01-25 10:06:58 +00:00
RoadStop * GetRoadStopByTile ( TileIndex tile , RoadStop : : Type type )
2005-01-29 19:41:44 +00:00
{
2006-03-24 08:55:08 +00:00
const Station * st = GetStationByTile ( tile ) ;
2005-01-29 19:41:44 +00:00
2007-02-18 11:27:09 +00:00
for ( RoadStop * rs = st - > GetPrimaryRoadStop ( type ) ; ; rs = rs - > next ) {
if ( rs - > xy = = tile ) return rs ;
2005-01-29 19:41:44 +00:00
assert ( rs - > next ! = NULL ) ;
2005-11-14 19:48:04 +00:00
}
2005-01-29 19:41:44 +00:00
}
2007-02-02 19:09:54 +00:00
static uint GetNumRoadStopsInStation ( const Station * st , RoadStop : : Type type )
2005-01-29 19:41:44 +00:00
{
2005-10-23 13:04:44 +00:00
uint num = 0 ;
2005-01-29 19:41:44 +00:00
assert ( st ! = NULL ) ;
2007-02-18 11:27:09 +00:00
for ( const RoadStop * rs = st - > GetPrimaryRoadStop ( type ) ; rs ! = NULL ; rs = rs - > next ) {
num + + ;
}
2005-01-29 19:41:44 +00:00
return num ;
}
2004-12-18 13:38:27 +00:00
/* Calculate the radius of the station. Basicly it is the biggest
2006-09-04 20:40:33 +00:00
* radius that is available within the station */
2005-11-15 09:00:02 +00:00
static uint FindCatchmentRadius ( const Station * st )
2004-12-18 13:38:27 +00:00
{
2007-02-17 07:45:18 +00:00
uint ret = CA_NONE ;
if ( st - > bus_stops ! = NULL ) ret = max < uint > ( ret , CA_BUS ) ;
if ( st - > truck_stops ! = NULL ) ret = max < uint > ( ret , CA_TRUCK ) ;
if ( st - > train_tile ! = 0 ) ret = max < uint > ( ret , CA_TRAIN ) ;
if ( st - > dock_tile ! = 0 ) ret = max < uint > ( ret , CA_DOCK ) ;
if ( st - > airport_tile ) ret = max < uint > ( ret , st - > Airport ( ) - > catchment ) ;
2004-12-18 13:38:27 +00:00
return ret ;
}
2004-08-09 17:04:08 +00:00
# define CHECK_STATIONS_ERR ((Station*)-1)
2005-10-07 07:35:15 +00:00
static Station * GetStationAround ( TileIndex tile , int w , int h , StationID closest_station )
2004-08-09 17:04:08 +00:00
{
2007-04-04 01:35:16 +00:00
/* check around to see if there's any stations there */
2005-06-25 16:44:57 +00:00
BEGIN_TILE_LOOP ( tile_cur , w + 2 , h + 2 , tile - TileDiffXY ( 1 , 1 ) )
2005-01-16 11:24:58 +00:00
if ( IsTileType ( tile_cur , MP_STATION ) ) {
2006-03-24 08:55:08 +00:00
StationID t = GetStationIndex ( tile_cur ) ;
2004-08-12 21:11:23 +00:00
2005-10-07 07:35:15 +00:00
if ( closest_station = = INVALID_STATION ) {
2004-08-09 17:04:08 +00:00
closest_station = t ;
} else if ( closest_station ! = t ) {
_error_message = STR_3006_ADJOINS_MORE_THAN_ONE_EXISTING ;
return CHECK_STATIONS_ERR ;
}
}
2005-06-25 16:44:57 +00:00
END_TILE_LOOP ( tile_cur , w + 2 , h + 2 , tile - TileDiffXY ( 1 , 1 ) )
2005-10-07 07:35:15 +00:00
return ( closest_station = = INVALID_STATION ) ? NULL : GetStation ( closest_station ) ;
2004-08-09 17:04:08 +00:00
}
2007-07-24 19:56:43 +00:00
/**
* Function to check whether the given tile matches some criterion .
* @ param tile the tile to check
* @ return true if it matches , false otherwise
*/
typedef bool ( * CMSAMatcher ) ( TileIndex tile ) ;
2004-08-09 17:04:08 +00:00
2006-04-11 22:09:21 +00:00
/**
* Counts the numbers of tiles matching a specific type in the area around
* @ param tile the center tile of the ' count area '
* @ param type the type of tile searched for
* @ param industry when type = = MP_INDUSTRY , the type of the industry ,
* in all other cases this parameter is ignored
2007-03-03 04:04:22 +00:00
* @ return the result the noumber of matching tiles around
2006-04-11 22:09:21 +00:00
*/
2007-07-24 19:56:43 +00:00
static int CountMapSquareAround ( TileIndex tile , CMSAMatcher cmp )
2005-06-24 12:38:35 +00:00
{
2004-08-09 17:04:08 +00:00
int num = 0 ;
2007-02-18 11:27:09 +00:00
for ( int dx = - 3 ; dx < = 3 ; dx + + ) {
for ( int dy = - 3 ; dy < = 3 ; dy + + ) {
2007-07-24 19:56:43 +00:00
if ( cmp ( TILE_MASK ( tile + TileDiffXY ( dx , dy ) ) ) ) num + + ;
2006-04-11 22:09:21 +00:00
}
2004-08-09 17:04:08 +00:00
}
return num ;
}
2007-07-24 19:56:43 +00:00
/**
* Check whether the tile is a mine .
* @ param tile the tile to investigate .
* @ return true if and only if the tile is a mine
*/
static bool CMSAMine ( TileIndex tile )
{
/* No industry */
if ( ! IsTileType ( tile , MP_INDUSTRY ) ) return false ;
const IndustrySpec * indsp = GetIndustrySpec ( GetIndustryByTile ( tile ) - > type ) ;
/* No extractive industry */
if ( ( indsp - > life_type & INDUSTRYLIFE_EXTRACTIVE ) = = 0 ) return false ;
for ( uint i = 0 ; i < lengthof ( indsp - > produced_cargo ) ; i + + ) {
/* The industry extracts something non-liquid, i.e. no oil or plastic, so it is a mine */
if ( indsp - > produced_cargo [ i ] ! = CT_INVALID & & ( GetCargo ( indsp - > produced_cargo [ i ] ) - > classes & CC_LIQUID ) = = 0 ) return true ;
}
return false ;
}
/**
* Check whether the tile is water .
* @ param tile the tile to investigate .
* @ return true if and only if the tile is a mine
*/
static bool CMSAWater ( TileIndex tile )
{
return IsTileType ( tile , MP_WATER ) & & IsWater ( tile ) ;
}
/**
* Check whether the tile is a tree .
* @ param tile the tile to investigate .
* @ return true if and only if the tile is a mine
*/
static bool CMSATree ( TileIndex tile )
{
return IsTileType ( tile , MP_TREES ) ;
}
/**
* Check whether the tile is a forest .
* @ param tile the tile to investigate .
* @ return true if and only if the tile is a mine
*/
static bool CMSAForest ( TileIndex tile )
{
/* No industry */
if ( ! IsTileType ( tile , MP_INDUSTRY ) ) return false ;
const IndustrySpec * indsp = GetIndustrySpec ( GetIndustryByTile ( tile ) - > type ) ;
/* No extractive industry */
if ( ( indsp - > life_type & INDUSTRYLIFE_ORGANIC ) = = 0 ) return false ;
for ( uint i = 0 ; i < lengthof ( indsp - > produced_cargo ) ; i + + ) {
/* The industry produces wood. */
if ( indsp - > produced_cargo [ i ] ! = CT_INVALID & & GetCargo ( indsp - > produced_cargo [ i ] ) - > label = = ' WOOD ' ) return true ;
}
return false ;
}
2004-08-09 17:04:08 +00:00
# define M(x) ((x) - STR_SV_STNAME)
2005-06-24 12:38:35 +00:00
static bool GenerateStationName ( Station * st , TileIndex tile , int flag )
2004-08-09 17:04:08 +00:00
{
static const uint32 _gen_station_name_bits [ ] = {
2005-03-08 00:26:30 +00:00
0 , /* 0 */
1 < < M ( STR_SV_STNAME_AIRPORT ) , /* 1 */
1 < < M ( STR_SV_STNAME_OILFIELD ) , /* 2 */
1 < < M ( STR_SV_STNAME_DOCKS ) , /* 3 */
0x1FF < < M ( STR_SV_STNAME_BUOY_1 ) , /* 4 */
1 < < M ( STR_SV_STNAME_HELIPORT ) , /* 5 */
2004-08-09 17:04:08 +00:00
} ;
Town * t = st - > town ;
uint32 free_names = ( uint32 ) - 1 ;
int found ;
unsigned long tmp ;
{
Station * s ;
FOR_ALL_STATIONS ( s ) {
2007-04-18 22:10:36 +00:00
if ( s ! = st & & s - > town = = t ) {
2004-08-09 17:04:08 +00:00
uint str = M ( s - > string_id ) ;
if ( str < = 0x20 ) {
if ( str = = M ( STR_SV_STNAME_FOREST ) )
str = M ( STR_SV_STNAME_WOODS ) ;
CLRBIT ( free_names , str ) ;
}
}
2004-09-10 19:02:27 +00:00
}
2004-08-09 17:04:08 +00:00
}
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
/* check default names */
tmp = free_names & _gen_station_name_bits [ flag ] ;
if ( tmp ! = 0 ) {
found = FindFirstBit ( tmp ) ;
goto done ;
}
/* check mine? */
if ( HASBIT ( free_names , M ( STR_SV_STNAME_MINES ) ) ) {
2007-07-24 19:56:43 +00:00
if ( CountMapSquareAround ( tile , CMSAMine ) > = 2 ) {
2005-03-08 00:26:30 +00:00
found = M ( STR_SV_STNAME_MINES ) ;
goto done ;
}
2004-08-09 17:04:08 +00:00
}
/* check close enough to town to get central as name? */
2007-04-18 22:10:36 +00:00
if ( DistanceMax ( tile , t - > xy ) < 8 ) {
2004-08-09 17:04:08 +00:00
found = M ( STR_SV_STNAME ) ;
if ( HASBIT ( free_names , M ( STR_SV_STNAME ) ) ) goto done ;
found = M ( STR_SV_STNAME_CENTRAL ) ;
if ( HASBIT ( free_names , M ( STR_SV_STNAME_CENTRAL ) ) ) goto done ;
}
/* Check lakeside */
2005-03-09 19:09:04 +00:00
if ( HASBIT ( free_names , M ( STR_SV_STNAME_LAKESIDE ) ) & &
DistanceFromEdge ( tile ) < 20 & &
2007-07-24 19:56:43 +00:00
CountMapSquareAround ( tile , CMSAWater ) > = 5 ) {
2005-03-08 00:26:30 +00:00
found = M ( STR_SV_STNAME_LAKESIDE ) ;
goto done ;
}
2004-08-09 17:04:08 +00:00
/* Check woods */
2005-03-09 19:09:04 +00:00
if ( HASBIT ( free_names , M ( STR_SV_STNAME_WOODS ) ) & & (
2007-07-24 19:56:43 +00:00
CountMapSquareAround ( tile , CMSATree ) > = 8 | |
CountMapSquareAround ( tile , CMSAForest ) > = 2 )
2005-03-09 19:09:04 +00:00
) {
2007-03-22 03:42:43 +00:00
found = _opt . landscape = = LT_TROPIC ?
2005-03-09 19:09:04 +00:00
M ( STR_SV_STNAME_FOREST ) : M ( STR_SV_STNAME_WOODS ) ;
2005-03-08 00:26:30 +00:00
goto done ;
2004-08-09 17:04:08 +00:00
}
/* check elevation compared to town */
2007-02-18 11:27:09 +00:00
{
uint z = GetTileZ ( tile ) ;
uint z2 = GetTileZ ( t - > xy ) ;
if ( z < z2 ) {
found = M ( STR_SV_STNAME_VALLEY ) ;
if ( HASBIT ( free_names , M ( STR_SV_STNAME_VALLEY ) ) ) goto done ;
} else if ( z > z2 ) {
found = M ( STR_SV_STNAME_HEIGHTS ) ;
if ( HASBIT ( free_names , M ( STR_SV_STNAME_HEIGHTS ) ) ) goto done ;
}
2004-08-09 17:04:08 +00:00
}
/* check direction compared to town */
{
static const int8 _direction_and_table [ ] = {
2007-04-18 22:10:36 +00:00
~ ( ( 1 < < M ( STR_SV_STNAME_WEST ) ) | ( 1 < < M ( STR_SV_STNAME_EAST ) ) | ( 1 < < M ( STR_SV_STNAME_NORTH ) ) ) ,
~ ( ( 1 < < M ( STR_SV_STNAME_SOUTH ) ) | ( 1 < < M ( STR_SV_STNAME_WEST ) ) | ( 1 < < M ( STR_SV_STNAME_NORTH ) ) ) ,
~ ( ( 1 < < M ( STR_SV_STNAME_SOUTH ) ) | ( 1 < < M ( STR_SV_STNAME_EAST ) ) | ( 1 < < M ( STR_SV_STNAME_NORTH ) ) ) ,
~ ( ( 1 < < M ( STR_SV_STNAME_SOUTH ) ) | ( 1 < < M ( STR_SV_STNAME_WEST ) ) | ( 1 < < M ( STR_SV_STNAME_EAST ) ) ) ,
2004-08-09 17:04:08 +00:00
} ;
2004-09-10 19:02:27 +00:00
free_names & = _direction_and_table [
2005-01-07 17:02:43 +00:00
( TileX ( tile ) < TileX ( t - > xy ) ) +
( TileY ( tile ) < TileY ( t - > xy ) ) * 2 ] ;
2004-08-09 17:04:08 +00:00
}
2007-04-18 22:10:36 +00:00
tmp = free_names & ( ( 1 < < 1 ) | ( 1 < < 2 ) | ( 1 < < 3 ) | ( 1 < < 4 ) | ( 1 < < 6 ) | ( 1 < < 7 ) | ( 1 < < 12 ) | ( 1 < < 26 ) | ( 1 < < 27 ) | ( 1 < < 28 ) | ( 1 < < 29 ) | ( 1 < < 30 ) ) ;
2007-06-25 10:22:48 +00:00
found = ( tmp = = 0 ) ? M ( STR_SV_STNAME_FALLBACK ) : FindFirstBit ( tmp ) ;
2004-08-09 17:04:08 +00:00
done :
st - > string_id = found + STR_SV_STNAME ;
return true ;
}
# undef M
2007-02-17 15:59:33 +00:00
static Station * GetClosestStationFromTile ( TileIndex tile )
2004-08-09 17:04:08 +00:00
{
2007-02-17 15:59:33 +00:00
uint threshold = 8 ;
2005-03-05 18:44:26 +00:00
Station * best_station = NULL ;
Station * st ;
2004-08-09 17:04:08 +00:00
FOR_ALL_STATIONS ( st ) {
2007-02-17 15:59:33 +00:00
if ( st - > facilities = = 0 & & st - > owner = = _current_player ) {
2005-03-05 18:44:26 +00:00
uint cur_dist = DistanceManhattan ( tile , st - > xy ) ;
if ( cur_dist < threshold ) {
threshold = cur_dist ;
best_station = st ;
}
2004-08-09 17:04:08 +00:00
}
}
return best_station ;
}
// Update the virtual coords needed to draw the station sign.
// st = Station to update for.
static void UpdateStationVirtCoord ( Station * st )
{
2006-04-03 09:07:21 +00:00
Point pt = RemapCoords2 ( TileX ( st - > xy ) * TILE_SIZE , TileY ( st - > xy ) * TILE_SIZE ) ;
2005-01-29 19:41:44 +00:00
2004-08-09 17:04:08 +00:00
pt . y - = 32 ;
2005-01-29 19:41:44 +00:00
if ( st - > facilities & FACIL_AIRPORT & & st - > airport_type = = AT_OILRIG ) pt . y - = 16 ;
2004-08-09 17:04:08 +00:00
2004-12-02 22:53:07 +00:00
SetDParam ( 0 , st - > index ) ;
SetDParam ( 1 , st - > facilities ) ;
2004-08-09 17:04:08 +00:00
UpdateViewportSignPos ( & st - > sign , pt . x , pt . y , STR_305C_0 ) ;
}
// Update the virtual coords needed to draw the station sign for all stations.
2007-03-07 11:47:46 +00:00
void UpdateAllStationVirtCoord ( )
2004-08-09 17:04:08 +00:00
{
2005-11-14 19:48:04 +00:00
Station * st ;
2004-08-09 17:04:08 +00:00
FOR_ALL_STATIONS ( st ) {
2006-08-22 15:33:35 +00:00
UpdateStationVirtCoord ( st ) ;
2004-08-09 17:04:08 +00:00
}
}
// Update the station virt coords while making the modified parts dirty.
static void UpdateStationVirtCoordDirty ( Station * st )
{
2007-01-14 19:18:50 +00:00
st - > MarkDirty ( ) ;
2004-08-09 17:04:08 +00:00
UpdateStationVirtCoord ( st ) ;
2007-01-14 19:18:50 +00:00
st - > MarkDirty ( ) ;
2004-08-09 17:04:08 +00:00
}
// Get a mask of the cargo types that the station accepts.
2005-03-05 18:44:26 +00:00
static uint GetAcceptanceMask ( const Station * st )
2004-08-09 17:04:08 +00:00
{
uint mask = 0 ;
2005-03-05 18:44:26 +00:00
2007-03-21 13:19:01 +00:00
for ( CargoID i = 0 ; i < NUM_CARGO ; i + + ) {
2007-08-26 13:55:36 +00:00
if ( HASBIT ( st - > goods [ i ] . acceptance_pickup , GoodsEntry : : ACCEPTANCE ) ) mask | = 1 < < i ;
2004-08-09 17:04:08 +00:00
}
return mask ;
}
// Items contains the two cargo names that are to be accepted or rejected.
// msg is the string id of the message to display.
2007-01-16 11:13:00 +00:00
static void ShowRejectOrAcceptNews ( const Station * st , uint num_items , CargoID * cargo , StringID msg )
2004-08-09 17:04:08 +00:00
{
2007-01-16 11:13:00 +00:00
for ( uint i = 0 ; i < num_items ; i + + ) {
2007-02-20 22:09:21 +00:00
SetDParam ( i + 1 , GetCargo ( cargo [ i ] ) - > name ) ;
2004-08-09 17:04:08 +00:00
}
2007-01-16 11:13:00 +00:00
SetDParam ( 0 , st - > index ) ;
2007-04-18 22:10:36 +00:00
AddNewsItem ( msg , NEWS_FLAGS ( NM_SMALL , NF_VIEWPORT | NF_TILE , NT_ACCEPTANCE , 0 ) , st - > xy , 0 ) ;
2004-08-09 17:04:08 +00:00
}
// Get a list of the cargo types being produced around the tile.
2005-03-05 18:44:26 +00:00
void GetProductionAroundTiles ( AcceptedCargo produced , TileIndex tile ,
int w , int h , int rad )
2004-08-09 17:04:08 +00:00
{
2005-07-19 21:49:35 +00:00
memset ( produced , 0 , sizeof ( AcceptedCargo ) ) ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
int x = TileX ( tile ) ;
int y = TileY ( tile ) ;
2004-08-09 17:04:08 +00:00
2005-03-05 18:44:26 +00:00
// expand the region by rad tiles on each side
2004-08-09 17:04:08 +00:00
// while making sure that we remain inside the board.
2007-02-18 11:27:09 +00:00
int x2 = min ( x + w + rad , MapSizeX ( ) ) ;
int x1 = max ( x - rad , 0 ) ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
int y2 = min ( y + h + rad , MapSizeY ( ) ) ;
int y1 = max ( y - rad , 0 ) ;
2004-08-09 17:04:08 +00:00
assert ( x1 < x2 ) ;
assert ( y1 < y2 ) ;
assert ( w > 0 ) ;
assert ( h > 0 ) ;
2007-02-18 11:27:09 +00:00
for ( int yc = y1 ; yc ! = y2 ; yc + + ) {
for ( int xc = x1 ; xc ! = x2 ; xc + + ) {
2004-08-09 17:04:08 +00:00
if ( ! ( IS_INSIDE_1D ( xc , x , w ) & & IS_INSIDE_1D ( yc , y , h ) ) ) {
2005-06-25 16:44:57 +00:00
TileIndex tile = TileXY ( xc , yc ) ;
2005-03-05 18:44:26 +00:00
2007-02-18 11:27:09 +00:00
GetProducedCargoProc * gpc = _tile_type_procs [ GetTileType ( tile ) ] - > get_produced_cargo_proc ;
2004-08-09 17:04:08 +00:00
if ( gpc ! = NULL ) {
2006-03-26 22:23:32 +00:00
CargoID cargos [ 2 ] = { CT_INVALID , CT_INVALID } ;
2005-03-05 18:44:26 +00:00
2004-08-09 17:04:08 +00:00
gpc ( tile , cargos ) ;
2005-03-05 18:44:26 +00:00
if ( cargos [ 0 ] ! = CT_INVALID ) {
2004-08-09 17:04:08 +00:00
produced [ cargos [ 0 ] ] + + ;
2005-03-05 18:44:26 +00:00
if ( cargos [ 1 ] ! = CT_INVALID ) {
2004-08-09 17:04:08 +00:00
produced [ cargos [ 1 ] ] + + ;
}
}
}
}
2005-03-05 18:44:26 +00:00
}
}
2004-08-09 17:04:08 +00:00
}
// Get a list of the cargo types that are accepted around the tile.
2005-03-05 18:44:26 +00:00
void GetAcceptanceAroundTiles ( AcceptedCargo accepts , TileIndex tile ,
int w , int h , int rad )
2004-08-09 17:04:08 +00:00
{
2004-11-21 10:49:40 +00:00
memset ( accepts , 0 , sizeof ( AcceptedCargo ) ) ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
int x = TileX ( tile ) ;
int y = TileY ( tile ) ;
2004-08-09 17:04:08 +00:00
2005-03-05 18:44:26 +00:00
// expand the region by rad tiles on each side
2004-08-09 17:04:08 +00:00
// while making sure that we remain inside the board.
2007-02-18 11:27:09 +00:00
int x2 = min ( x + w + rad , MapSizeX ( ) ) ;
int y2 = min ( y + h + rad , MapSizeY ( ) ) ;
int x1 = max ( x - rad , 0 ) ;
int y1 = max ( y - rad , 0 ) ;
2004-08-09 17:04:08 +00:00
assert ( x1 < x2 ) ;
assert ( y1 < y2 ) ;
assert ( w > 0 ) ;
assert ( h > 0 ) ;
2007-02-18 11:27:09 +00:00
for ( int yc = y1 ; yc ! = y2 ; yc + + ) {
for ( int xc = x1 ; xc ! = x2 ; xc + + ) {
2005-06-25 16:44:57 +00:00
TileIndex tile = TileXY ( xc , yc ) ;
2005-03-05 18:44:26 +00:00
2005-01-16 11:24:58 +00:00
if ( ! IsTileType ( tile , MP_STATION ) ) {
2004-11-21 10:49:40 +00:00
AcceptedCargo ac ;
GetAcceptedCargo ( tile , ac ) ;
2007-02-18 11:27:09 +00:00
for ( uint i = 0 ; i < lengthof ( ac ) ; + + i ) accepts [ i ] + = ac [ i ] ;
2004-08-09 17:04:08 +00:00
}
2005-03-05 18:44:26 +00:00
}
}
2004-08-09 17:04:08 +00:00
}
2007-03-07 12:11:48 +00:00
struct ottd_Rectangle {
2005-03-05 17:41:51 +00:00
uint min_x ;
uint min_y ;
uint max_x ;
uint max_y ;
2007-03-07 12:11:48 +00:00
} ;
2005-03-05 17:41:51 +00:00
2006-11-16 17:59:02 +00:00
static inline void MergePoint ( ottd_Rectangle * rect , TileIndex tile )
2005-03-05 17:41:51 +00:00
{
uint x = TileX ( tile ) ;
uint y = TileY ( tile ) ;
if ( rect - > min_x > x ) rect - > min_x = x ;
if ( rect - > min_y > y ) rect - > min_y = y ;
if ( rect - > max_x < x ) rect - > max_x = x ;
if ( rect - > max_y < y ) rect - > max_y = y ;
}
2004-08-09 17:04:08 +00:00
// Update the acceptance for a station.
// show_msg controls whether to display a message that acceptance was changed.
static void UpdateStationAcceptance ( Station * st , bool show_msg )
{
2007-02-18 11:27:09 +00:00
// Don't update acceptance for a buoy
if ( st - > IsBuoy ( ) ) return ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
ottd_Rectangle rect ;
2005-03-15 12:21:59 +00:00
rect . min_x = MapSizeX ( ) ;
rect . min_y = MapSizeY ( ) ;
2007-02-18 11:27:09 +00:00
rect . max_x = 0 ;
rect . max_y = 0 ;
2004-08-09 17:04:08 +00:00
/* old accepted goods types */
2007-02-18 11:27:09 +00:00
uint old_acc = GetAcceptanceMask ( st ) ;
2004-08-09 17:04:08 +00:00
// Put all the tiles that span an area in the table.
if ( st - > train_tile ! = 0 ) {
2005-03-05 17:41:51 +00:00
MergePoint ( & rect , st - > train_tile ) ;
MergePoint ( & rect ,
2005-06-25 16:44:57 +00:00
st - > train_tile + TileDiffXY ( st - > trainst_w - 1 , st - > trainst_h - 1 )
2005-03-05 17:41:51 +00:00
) ;
2004-08-09 17:04:08 +00:00
}
2005-01-29 19:41:44 +00:00
2004-08-09 17:04:08 +00:00
if ( st - > airport_tile ! = 0 ) {
2007-02-16 09:38:43 +00:00
const AirportFTAClass * afc = st - > Airport ( ) ;
2006-05-20 15:13:27 +00:00
2005-03-05 17:41:51 +00:00
MergePoint ( & rect , st - > airport_tile ) ;
MergePoint ( & rect ,
2006-05-20 15:13:27 +00:00
st - > airport_tile + TileDiffXY ( afc - > size_x - 1 , afc - > size_y - 1 )
2005-03-05 17:41:51 +00:00
) ;
2005-01-29 19:41:44 +00:00
}
2005-03-05 17:41:51 +00:00
if ( st - > dock_tile ! = 0 ) MergePoint ( & rect , st - > dock_tile ) ;
2005-01-29 19:41:44 +00:00
2007-02-18 11:27:09 +00:00
for ( const RoadStop * rs = st - > bus_stops ; rs ! = NULL ; rs = rs - > next ) {
MergePoint ( & rect , rs - > xy ) ;
2004-08-09 17:04:08 +00:00
}
2007-02-18 11:27:09 +00:00
for ( const RoadStop * rs = st - > truck_stops ; rs ! = NULL ; rs = rs - > next ) {
MergePoint ( & rect , rs - > xy ) ;
2004-08-09 17:04:08 +00:00
}
2005-01-29 19:41:44 +00:00
2004-08-09 17:04:08 +00:00
// And retrieve the acceptance.
2007-02-18 11:27:09 +00:00
AcceptedCargo accepts ;
2005-03-05 17:41:51 +00:00
if ( rect . max_x > = rect . min_x ) {
GetAcceptanceAroundTiles (
accepts ,
2005-06-25 16:44:57 +00:00
TileXY ( rect . min_x , rect . min_y ) ,
2005-03-05 17:41:51 +00:00
rect . max_x - rect . min_x + 1 ,
rect . max_y - rect . min_y + 1 ,
2007-02-18 11:27:09 +00:00
_patches . modified_catchment ? FindCatchmentRadius ( st ) : 4
2005-03-05 17:41:51 +00:00
) ;
2004-08-09 17:04:08 +00:00
} else {
memset ( accepts , 0 , sizeof ( accepts ) ) ;
}
// Adjust in case our station only accepts fewer kinds of goods
2007-03-21 13:19:01 +00:00
for ( CargoID i = 0 ; i < NUM_CARGO ; i + + ) {
2004-08-09 17:04:08 +00:00
uint amt = min ( accepts [ i ] , 15 ) ;
// Make sure the station can accept the goods type.
2007-03-18 22:07:44 +00:00
bool is_passengers = IsCargoInClass ( i , CC_PASSENGERS ) ;
if ( ( ! is_passengers & & ! ( st - > facilities & ( byte ) ~ FACIL_BUS_STOP ) ) | |
( is_passengers & & ! ( st - > facilities & ( byte ) ~ FACIL_TRUCK_STOP ) ) )
2004-08-09 17:04:08 +00:00
amt = 0 ;
2007-08-26 13:55:36 +00:00
SB ( st - > goods [ i ] . acceptance_pickup , GoodsEntry : : ACCEPTANCE , 1 , amt > = 8 ) ;
2004-08-09 17:04:08 +00:00
}
// Only show a message in case the acceptance was actually changed.
2007-02-18 11:27:09 +00:00
uint new_acc = GetAcceptanceMask ( st ) ;
2004-08-09 17:04:08 +00:00
if ( old_acc = = new_acc )
return ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
// show a message to report that the acceptance was changed?
if ( show_msg & & st - > owner = = _local_player & & st - > facilities ) {
2007-01-16 11:13:00 +00:00
/* List of accept and reject strings for different number of
* cargo types */
static const StringID accept_msg [ ] = {
STR_3040_NOW_ACCEPTS ,
STR_3041_NOW_ACCEPTS_AND ,
} ;
static const StringID reject_msg [ ] = {
STR_303E_NO_LONGER_ACCEPTS ,
STR_303F_NO_LONGER_ACCEPTS_OR ,
} ;
2004-08-09 17:04:08 +00:00
2007-01-16 11:13:00 +00:00
/* Array of accepted and rejected cargo types */
CargoID accepts [ 2 ] = { CT_INVALID , CT_INVALID } ;
CargoID rejects [ 2 ] = { CT_INVALID , CT_INVALID } ;
uint num_acc = 0 ;
uint num_rej = 0 ;
/* Test each cargo type to see if its acceptange has changed */
for ( CargoID i = 0 ; i < NUM_CARGO ; i + + ) {
if ( HASBIT ( new_acc , i ) ) {
if ( ! HASBIT ( old_acc , i ) & & num_acc < lengthof ( accepts ) ) {
/* New cargo is accepted */
accepts [ num_acc + + ] = i ;
}
2004-08-09 17:04:08 +00:00
} else {
2007-01-16 11:13:00 +00:00
if ( HASBIT ( old_acc , i ) & & num_rej < lengthof ( rejects ) ) {
/* Old cargo is no longer accepted */
rejects [ num_rej + + ] = i ;
}
2004-08-09 17:04:08 +00:00
}
2007-01-16 11:13:00 +00:00
}
2004-08-09 17:04:08 +00:00
2007-01-16 11:13:00 +00:00
/* Show news message if there are any changes */
if ( num_acc > 0 ) ShowRejectOrAcceptNews ( st , num_acc , accepts , accept_msg [ num_acc - 1 ] ) ;
if ( num_rej > 0 ) ShowRejectOrAcceptNews ( st , num_rej , rejects , reject_msg [ num_rej - 1 ] ) ;
2004-08-09 17:04:08 +00:00
}
// redraw the station view since acceptance changed
InvalidateWindowWidget ( WC_STATION_VIEW , st - > index , 4 ) ;
}
2006-11-16 16:18:00 +00:00
static void UpdateStationSignCoord ( Station * st )
{
2007-02-18 11:27:09 +00:00
const StationRect * r = & st - > rect ;
2006-11-16 16:18:00 +00:00
2007-01-14 23:02:12 +00:00
if ( r - > IsEmpty ( ) ) return ; // no tiles belong to this station
2006-11-16 16:18:00 +00:00
2006-12-27 23:11:43 +00:00
// clamp sign coord to be inside the station rect
st - > xy = TileXY ( clampu ( TileX ( st - > xy ) , r - > left , r - > right ) , clampu ( TileY ( st - > xy ) , r - > top , r - > bottom ) ) ;
2006-11-16 16:18:00 +00:00
UpdateStationVirtCoordDirty ( st ) ;
}
2004-08-09 17:04:08 +00:00
// This is called right after a station was deleted.
// It checks if the whole station is free of substations, and if so, the station will be
// deleted after a little while.
2005-11-14 19:48:04 +00:00
static void DeleteStationIfEmpty ( Station * st )
{
2004-08-09 17:04:08 +00:00
if ( st - > facilities = = 0 ) {
st - > delete_ctr = 0 ;
2006-05-11 10:33:58 +00:00
RebuildStationLists ( ) ;
2004-08-09 17:04:08 +00:00
InvalidateWindow ( WC_STATION_LIST , st - > owner ) ;
}
2006-11-16 16:18:00 +00:00
/* station remains but it probably lost some parts - station sign should stay in the station boundaries */
UpdateStationSignCoord ( st ) ;
2004-08-09 17:04:08 +00:00
}
2007-06-18 10:48:15 +00:00
static CommandCost ClearTile_Station ( TileIndex tile , byte flags ) ;
2005-01-10 21:52:35 +00:00
2004-08-09 17:04:08 +00:00
// Tries to clear the given area. Returns the cost in case of success.
// Or an error code if it failed.
2007-06-18 10:48:15 +00:00
CommandCost CheckFlatLandBelow ( TileIndex tile , uint w , uint h , uint flags , uint invalid_dirs , StationID * station , bool check_clear = true )
2004-08-09 17:04:08 +00:00
{
2007-06-18 19:53:50 +00:00
CommandCost cost ;
2005-02-07 10:41:45 +00:00
int allowed_z = - 1 ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
BEGIN_TILE_LOOP ( tile_cur , w , h , tile ) {
2006-12-27 12:38:02 +00:00
if ( MayHaveBridgeAbove ( tile_cur ) & & IsBridgeAbove ( tile_cur ) ) {
return_cmd_error ( STR_5007_MUST_DEMOLISH_BRIDGE_FIRST ) ;
}
2007-06-16 10:10:22 +00:00
if ( ! EnsureNoVehicleOnGround ( tile_cur ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
uint z ;
Slope tileh = GetTileSlope ( tile_cur , & z ) ;
2004-08-09 17:04:08 +00:00
2005-07-16 23:47:37 +00:00
/* Prohibit building if
2006-09-04 20:40:33 +00:00
* 1 ) The tile is " steep " ( i . e . stretches two height levels )
* - OR -
* 2 ) The tile is non - flat if
* a ) the player building is an " old-school " AI
* - OR -
* b ) the build_on_slopes switch is disabled
*/
2006-04-23 13:48:16 +00:00
if ( IsSteepSlope ( tileh ) | |
( ( _is_old_ai_player | | ! _patches . build_on_slopes ) & & tileh ! = SLOPE_FLAT ) ) {
2006-03-12 12:19:25 +00:00
return_cmd_error ( STR_0007_FLAT_LAND_REQUIRED ) ;
2004-08-09 17:04:08 +00:00
}
2007-02-18 11:27:09 +00:00
int flat_z = z ;
2006-04-23 13:48:16 +00:00
if ( tileh ! = SLOPE_FLAT ) {
2004-08-09 17:04:08 +00:00
// need to check so the entrance to the station is not pointing at a slope.
2007-04-18 22:10:36 +00:00
if ( ( invalid_dirs & 1 & & ! ( tileh & SLOPE_NE ) & & ( uint ) w_cur = = w ) | |
( invalid_dirs & 2 & & ! ( tileh & SLOPE_SE ) & & h_cur = = 1 ) | |
( invalid_dirs & 4 & & ! ( tileh & SLOPE_SW ) & & w_cur = = 1 ) | |
( invalid_dirs & 8 & & ! ( tileh & SLOPE_NW ) & & ( uint ) h_cur = = h ) ) {
2006-03-12 12:19:25 +00:00
return_cmd_error ( STR_0007_FLAT_LAND_REQUIRED ) ;
2004-08-09 17:04:08 +00:00
}
2007-06-18 19:53:50 +00:00
cost . AddCost ( _price . terraform ) ;
2006-04-23 19:35:36 +00:00
flat_z + = TILE_HEIGHT ;
2004-08-09 17:04:08 +00:00
}
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
// get corresponding flat level and make sure that all parts of the station have the same level.
if ( allowed_z = = - 1 ) {
// first tile
allowed_z = flat_z ;
} else if ( allowed_z ! = flat_z ) {
2006-03-12 12:19:25 +00:00
return_cmd_error ( STR_0007_FLAT_LAND_REQUIRED ) ;
2004-08-09 17:04:08 +00:00
}
2004-09-10 19:02:27 +00:00
// if station is set, then we have special handling to allow building on top of already existing stations.
2005-10-07 07:35:15 +00:00
// so station points to INVALID_STATION if we can build on any station. or it points to a station if we're only allowed to build
2004-08-09 17:04:08 +00:00
// on exactly that station.
2005-01-16 11:24:58 +00:00
if ( station ! = NULL & & IsTileType ( tile_cur , MP_STATION ) ) {
2006-03-26 14:41:39 +00:00
if ( ! IsRailwayStation ( tile_cur ) ) {
2006-03-12 12:19:25 +00:00
return ClearTile_Station ( tile_cur , DC_AUTO ) ; // get error message
2004-08-09 17:04:08 +00:00
} else {
2006-03-24 08:55:08 +00:00
StationID st = GetStationIndex ( tile_cur ) ;
2005-10-07 07:35:15 +00:00
if ( * station = = INVALID_STATION ) {
2004-08-09 17:04:08 +00:00
* station = st ;
2005-10-07 07:35:15 +00:00
} else if ( * station ! = st ) {
2006-03-12 12:19:25 +00:00
return_cmd_error ( STR_3006_ADJOINS_MORE_THAN_ONE_EXISTING ) ;
2004-08-09 17:04:08 +00:00
}
}
2007-05-27 01:59:07 +00:00
} else if ( check_clear ) {
2007-06-18 10:48:15 +00:00
CommandCost ret = DoCommand ( tile_cur , 0 , 0 , flags , CMD_LANDSCAPE_CLEAR ) ;
2006-03-12 12:19:25 +00:00
if ( CmdFailed ( ret ) ) return ret ;
2007-06-18 19:53:50 +00:00
cost . AddCost ( ret ) ;
2004-08-09 17:04:08 +00:00
}
2007-02-18 11:27:09 +00:00
} END_TILE_LOOP ( tile_cur , w , h , tile )
2004-08-09 17:04:08 +00:00
return cost ;
}
2007-02-18 11:27:09 +00:00
static bool CanExpandRailroadStation ( const Station * st , uint * fin , Axis axis )
2004-08-09 17:04:08 +00:00
{
2007-02-18 11:27:09 +00:00
uint curw = st - > trainst_w ;
uint curh = st - > trainst_h ;
2005-06-24 12:38:35 +00:00
TileIndex tile = fin [ 0 ] ;
2004-08-09 17:04:08 +00:00
uint w = fin [ 1 ] ;
uint h = fin [ 2 ] ;
if ( _patches . nonuniform_stations ) {
// determine new size of train station region..
2005-01-07 17:02:43 +00:00
int x = min ( TileX ( st - > train_tile ) , TileX ( tile ) ) ;
int y = min ( TileY ( st - > train_tile ) , TileY ( tile ) ) ;
curw = max ( TileX ( st - > train_tile ) + curw , TileX ( tile ) + w ) - x ;
curh = max ( TileY ( st - > train_tile ) + curh , TileY ( tile ) + h ) - y ;
2005-06-25 16:44:57 +00:00
tile = TileXY ( x , y ) ;
2004-08-09 17:04:08 +00:00
} else {
2006-03-08 06:55:33 +00:00
// check so the orientation is the same
2006-03-26 14:41:39 +00:00
if ( GetRailStationAxis ( st - > train_tile ) ! = axis ) {
2005-01-27 09:43:24 +00:00
_error_message = STR_306D_NONUNIFORM_STATIONS_DISALLOWED ;
return false ;
}
2004-08-09 17:04:08 +00:00
// check if the new station adjoins the old station in either direction
2005-06-25 16:44:57 +00:00
if ( curw = = w & & st - > train_tile = = tile + TileDiffXY ( 0 , h ) ) {
2004-08-09 17:04:08 +00:00
// above
curh + = h ;
2005-06-25 16:44:57 +00:00
} else if ( curw = = w & & st - > train_tile = = tile - TileDiffXY ( 0 , curh ) ) {
2004-08-09 17:04:08 +00:00
// below
2005-06-25 16:44:57 +00:00
tile - = TileDiffXY ( 0 , curh ) ;
2004-08-09 17:04:08 +00:00
curh + = h ;
2005-06-25 16:44:57 +00:00
} else if ( curh = = h & & st - > train_tile = = tile + TileDiffXY ( w , 0 ) ) {
2004-08-09 17:04:08 +00:00
// to the left
curw + = w ;
2005-06-25 16:44:57 +00:00
} else if ( curh = = h & & st - > train_tile = = tile - TileDiffXY ( curw , 0 ) ) {
2004-08-09 17:04:08 +00:00
// to the right
2005-06-25 16:44:57 +00:00
tile - = TileDiffXY ( curw , 0 ) ;
2004-08-09 17:04:08 +00:00
curw + = w ;
2005-01-27 09:43:24 +00:00
} else {
_error_message = STR_306D_NONUNIFORM_STATIONS_DISALLOWED ;
2004-08-09 17:04:08 +00:00
return false ;
2005-01-27 09:43:24 +00:00
}
2004-08-09 17:04:08 +00:00
}
// make sure the final size is not too big.
2005-01-27 09:43:24 +00:00
if ( curw > _patches . station_spread | | curh > _patches . station_spread ) {
_error_message = STR_306C_STATION_TOO_SPREAD_OUT ;
return false ;
}
2004-08-09 17:04:08 +00:00
// now tile contains the new value for st->train_tile
// curw, curh contain the new value for width and height
fin [ 0 ] = tile ;
fin [ 1 ] = curw ;
fin [ 2 ] = curh ;
return true ;
}
2004-12-03 07:43:00 +00:00
static inline byte * CreateSingle ( byte * layout , int n )
2004-08-09 17:04:08 +00:00
{
int i = n ;
do * layout + + = 0 ; while ( - - i ) ;
2007-04-18 22:10:36 +00:00
layout [ ( ( n - 1 ) > > 1 ) - n ] = 2 ;
2004-08-09 17:04:08 +00:00
return layout ;
}
2004-12-03 07:43:00 +00:00
static inline byte * CreateMulti ( byte * layout , int n , byte b )
2004-08-09 17:04:08 +00:00
{
int i = n ;
do * layout + + = b ; while ( - - i ) ;
if ( n > 4 ) {
2007-04-18 22:10:36 +00:00
layout [ 0 - n ] = 0 ;
layout [ n - 1 - n ] = 0 ;
2004-08-09 17:04:08 +00:00
}
return layout ;
}
2006-04-27 18:28:56 +00:00
static void GetStationLayout ( byte * layout , int numtracks , int plat_len , const StationSpec * statspec )
2004-08-09 17:04:08 +00:00
{
2006-04-27 18:28:56 +00:00
if ( statspec ! = NULL & & statspec - > lengths > = plat_len & &
statspec - > platforms [ plat_len - 1 ] > = numtracks & &
statspec - > layouts [ plat_len - 1 ] [ numtracks - 1 ] ) {
2004-11-17 18:03:33 +00:00
/* Custom layout defined, follow it. */
2006-04-27 18:28:56 +00:00
memcpy ( layout , statspec - > layouts [ plat_len - 1 ] [ numtracks - 1 ] ,
2005-03-09 19:09:04 +00:00
plat_len * numtracks ) ;
2004-11-17 18:03:33 +00:00
return ;
}
2004-08-09 17:04:08 +00:00
if ( plat_len = = 1 ) {
CreateSingle ( layout , numtracks ) ;
} else {
2005-11-14 19:48:04 +00:00
if ( numtracks & 1 ) layout = CreateSingle ( layout , plat_len ) ;
numtracks > > = 1 ;
2004-08-09 17:04:08 +00:00
while ( - - numtracks > = 0 ) {
layout = CreateMulti ( layout , plat_len , 4 ) ;
layout = CreateMulti ( layout , plat_len , 6 ) ;
}
}
}
2005-05-07 10:26:12 +00:00
/** Build railroad station
2006-04-10 07:15:58 +00:00
* @ param tile_org starting position of station dragging / placement
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2005-05-07 10:26:12 +00:00
* @ param p1 various bitstuffed elements
2007-02-24 09:42:39 +00:00
* - p1 = ( bit 0 ) - orientation ( Axis )
2005-07-20 15:29:28 +00:00
* - p1 = ( bit 8 - 15 ) - number of tracks
* - p1 = ( bit 16 - 23 ) - platform length
2007-05-23 17:33:03 +00:00
* - p1 = ( bit 24 ) - allow stations directly adjacent to other stations .
2005-05-07 10:26:12 +00:00
* @ param p2 various bitstuffed elements
* - p2 = ( bit 0 - 3 ) - railtype ( p2 & 0xF )
2006-04-19 07:17:00 +00:00
* - p2 = ( bit 8 - 15 ) - custom station class
* - p2 = ( bit 16 - 23 ) - custom station id
2004-08-09 17:04:08 +00:00
*/
2007-06-18 10:48:15 +00:00
CommandCost CmdBuildRailroadStation ( TileIndex tile_org , uint32 flags , uint32 p1 , uint32 p2 )
2004-08-09 17:04:08 +00:00
{
2005-05-07 10:26:12 +00:00
int w_org , h_org ;
2007-06-18 10:48:15 +00:00
CommandCost ret ;
2004-08-09 17:04:08 +00:00
SET_EXPENSES_TYPE ( EXPENSES_CONSTRUCTION ) ;
/* Does the authority allow this? */
2005-05-07 10:26:12 +00:00
if ( ! ( flags & DC_NO_TOWN_RATING ) & & ! CheckIfAuthorityAllows ( tile_org ) ) return CMD_ERROR ;
if ( ! ValParamRailtype ( p2 & 0xF ) ) return CMD_ERROR ;
/* unpack parameters */
2007-02-24 09:42:39 +00:00
Axis axis = Extract < Axis , 0 > ( p1 ) ;
2007-02-18 11:27:09 +00:00
uint numtracks = GB ( p1 , 8 , 8 ) ;
uint plat_len = GB ( p1 , 16 , 8 ) ;
2006-03-08 06:55:33 +00:00
if ( axis = = AXIS_X ) {
2005-05-07 10:26:12 +00:00
w_org = plat_len ;
h_org = numtracks ;
2006-03-08 06:55:33 +00:00
} else {
h_org = plat_len ;
w_org = numtracks ;
2004-08-09 17:04:08 +00:00
}
2005-05-09 13:26:15 +00:00
if ( h_org > _patches . station_spread | | w_org > _patches . station_spread ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
// these values are those that will be stored in train_tile and station_platforms
2007-02-18 11:27:09 +00:00
uint finalvalues [ 3 ] ;
2004-08-09 17:04:08 +00:00
finalvalues [ 0 ] = tile_org ;
finalvalues [ 1 ] = w_org ;
finalvalues [ 2 ] = h_org ;
// Make sure the area below consists of clear tiles. (OR tiles belonging to a certain rail station)
2007-02-18 11:27:09 +00:00
StationID est = INVALID_STATION ;
2004-09-25 13:58:27 +00:00
// If DC_EXEC is in flag, do not want to pass it to CheckFlatLandBelow, because of a nice bug
// for detail info, see: https://sourceforge.net/tracker/index.php?func=detail&aid=1029064&group_id=103924&atid=636365
2006-03-12 12:19:25 +00:00
ret = CheckFlatLandBelow ( tile_org , w_org , h_org , flags & ~ DC_EXEC , 5 < < axis , _patches . nonuniform_stations ? & est : NULL ) ;
if ( CmdFailed ( ret ) ) return ret ;
2007-06-18 19:53:50 +00:00
CommandCost cost ( ret . GetCost ( ) + ( numtracks * _price . train_station_track + _price . train_station_length ) * plat_len ) ;
2004-08-09 17:04:08 +00:00
2007-05-23 17:33:03 +00:00
Station * st = NULL ;
bool check_surrounding = true ;
if ( _patches . adjacent_stations ) {
if ( est ! = INVALID_STATION ) {
if ( HASBIT ( p1 , 24 ) ) {
/* You can't build an adjacent station over the top of one that
* already exists . */
return_cmd_error ( STR_MUST_REMOVE_RAILWAY_STATION_FIRST ) ;
} else {
/* Extend the current station, and don't check whether it will
* be near any other stations . */
st = GetStation ( est ) ;
check_surrounding = false ;
}
} else {
/* There's no station here. Don't check the tiles surrounding this
* one if the player wanted to build an adjacent station . */
if ( HASBIT ( p1 , 24 ) ) check_surrounding = false ;
}
}
if ( check_surrounding ) {
// Make sure there are no similar stations around us.
st = GetStationAround ( tile_org , w_org , h_org , est ) ;
if ( st = = CHECK_STATIONS_ERR ) return CMD_ERROR ;
}
2004-08-09 17:04:08 +00:00
// See if there is a deleted station close to us.
2007-02-17 15:59:33 +00:00
if ( st = = NULL ) st = GetClosestStationFromTile ( tile_org ) ;
2004-08-09 17:04:08 +00:00
2007-01-14 19:18:50 +00:00
/* In case of new station if DC_EXEC is NOT set we still need to create the station
* to test if everything is OK . In this case we need to delete it before return . */
2007-01-26 11:38:07 +00:00
AutoPtrT < Station > st_auto_delete ;
2007-01-14 19:18:50 +00:00
2004-08-09 17:04:08 +00:00
if ( st ! = NULL ) {
// Reuse an existing station.
2007-02-18 08:37:39 +00:00
if ( st - > owner ! = _current_player )
2004-08-09 17:04:08 +00:00
return_cmd_error ( STR_3009_TOO_CLOSE_TO_ANOTHER_STATION ) ;
if ( st - > train_tile ! = 0 ) {
2004-08-20 09:32:32 +00:00
// check if we want to expanding an already existing station?
2005-09-13 12:19:27 +00:00
if ( _is_old_ai_player | | ! _patches . join_stations )
2004-08-09 17:04:08 +00:00
return_cmd_error ( STR_3005_TOO_CLOSE_TO_ANOTHER_RAILROAD ) ;
2006-03-08 06:55:33 +00:00
if ( ! CanExpandRailroadStation ( st , finalvalues , axis ) )
2005-01-27 09:43:24 +00:00
return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
}
2005-01-27 09:43:24 +00:00
//XXX can't we pack this in the "else" part of the if above?
2007-01-14 23:02:12 +00:00
if ( ! st - > rect . BeforeAddRect ( tile_org , w_org , h_org , StationRect : : ADD_TEST ) ) return CMD_ERROR ;
2006-08-28 18:53:03 +00:00
} else {
2007-01-14 19:18:50 +00:00
/* allocate and initialize new station */
st = new Station ( tile_org ) ;
2007-08-02 08:47:56 +00:00
if ( st = = NULL ) return_cmd_error ( STR_3008_TOO_MANY_STATIONS_LOADING ) ;
2004-09-10 19:02:27 +00:00
2007-01-14 19:18:50 +00:00
/* ensure that in case of error (or no DC_EXEC) the station gets deleted upon return */
2007-01-26 11:38:07 +00:00
st_auto_delete = st ;
2004-08-09 17:04:08 +00:00
2007-01-14 19:18:50 +00:00
st - > town = ClosestTownFromTile ( tile_org , ( uint ) - 1 ) ;
2005-11-14 19:48:04 +00:00
if ( ! GenerateStationName ( st , tile_org , 0 ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
2007-01-14 19:18:50 +00:00
if ( IsValidPlayer ( _current_player ) & & ( flags & DC_EXEC ) ! = 0 ) {
SETBIT ( st - > town - > have_ratings , _current_player ) ;
}
2004-08-09 17:04:08 +00:00
}
2006-04-19 07:17:00 +00:00
/* Check if the given station class is valid */
if ( GB ( p2 , 8 , 8 ) > = STAT_CLASS_MAX ) return CMD_ERROR ;
/* Check if we can allocate a custom stationspec to this station */
2007-02-18 11:27:09 +00:00
const StationSpec * statspec = GetCustomStationSpec ( ( StationClassID ) GB ( p2 , 8 , 8 ) , GB ( p2 , 16 , 8 ) ) ;
int specindex = AllocateSpecToStation ( statspec , st , flags & DC_EXEC ) ;
2006-04-19 07:17:00 +00:00
if ( specindex = = - 1 ) return CMD_ERROR ;
2006-05-04 20:00:50 +00:00
if ( statspec ! = NULL ) {
/* Perform NewStation checks */
/* Check if the station size is permitted */
if ( HASBIT ( statspec - > disallowed_platforms , numtracks - 1 ) | | HASBIT ( statspec - > disallowed_lengths , plat_len - 1 ) ) {
return CMD_ERROR ;
}
/* Check if the station is buildable */
if ( HASBIT ( statspec - > callbackmask , CBM_STATION_AVAIL ) & & GetStationCallback ( CBID_STATION_AVAILABILITY , 0 , 0 , statspec , NULL , INVALID_TILE ) = = 0 ) {
return CMD_ERROR ;
}
}
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
2005-06-24 12:38:35 +00:00
TileIndexDiff tile_delta ;
2004-08-09 17:04:08 +00:00
byte * layout_ptr ;
2006-05-06 22:30:36 +00:00
byte numtracks_orig ;
2006-01-06 17:45:43 +00:00
Track track ;
2004-08-09 17:04:08 +00:00
2004-09-25 13:58:27 +00:00
// Now really clear the land below the station
// It should never return CMD_ERROR.. but you never know ;)
// (a bit strange function name for it, but it really does clear the land, when DC_EXEC is in flags)
2006-03-12 12:19:25 +00:00
ret = CheckFlatLandBelow ( tile_org , w_org , h_org , flags , 5 < < axis , _patches . nonuniform_stations ? & est : NULL ) ;
if ( CmdFailed ( ret ) ) return ret ;
2004-09-25 13:58:27 +00:00
2004-08-09 17:04:08 +00:00
st - > train_tile = finalvalues [ 0 ] ;
2007-01-18 09:34:44 +00:00
st - > AddFacility ( FACIL_TRAIN , finalvalues [ 0 ] ) ;
2004-08-09 17:04:08 +00:00
st - > trainst_w = finalvalues [ 1 ] ;
st - > trainst_h = finalvalues [ 2 ] ;
2004-09-10 19:02:27 +00:00
2007-01-14 23:02:12 +00:00
st - > rect . BeforeAddRect ( tile_org , w_org , h_org , StationRect : : ADD_TRY ) ;
2006-12-27 23:11:43 +00:00
2006-03-08 06:55:33 +00:00
tile_delta = ( axis = = AXIS_X ? TileDiffXY ( 1 , 0 ) : TileDiffXY ( 0 , 1 ) ) ;
2006-07-22 08:59:52 +00:00
track = AxisToTrack ( axis ) ;
2004-09-10 19:02:27 +00:00
2007-01-10 18:56:51 +00:00
layout_ptr = ( byte * ) alloca ( numtracks * plat_len ) ;
2004-11-17 18:03:33 +00:00
GetStationLayout ( layout_ptr , numtracks , plat_len , statspec ) ;
2004-09-10 19:02:27 +00:00
2006-05-06 22:30:36 +00:00
numtracks_orig = numtracks ;
2004-08-09 17:04:08 +00:00
do {
2005-05-07 10:26:12 +00:00
TileIndex tile = tile_org ;
2004-08-09 17:04:08 +00:00
int w = plat_len ;
do {
2006-05-06 22:30:36 +00:00
byte layout = * layout_ptr + + ;
2007-05-01 06:43:18 +00:00
MakeRailStation ( tile , st - > owner , st - > index , axis , layout & ~ 1 , ( RailType ) GB ( p2 , 0 , 4 ) ) ;
2006-04-19 07:17:00 +00:00
SetCustomStationSpecIndex ( tile , specindex ) ;
2006-05-03 21:25:49 +00:00
SetStationTileRandomBits ( tile , GB ( Random ( ) , 0 , 4 ) ) ;
2004-08-09 17:04:08 +00:00
2006-05-04 20:00:50 +00:00
if ( statspec ! = NULL ) {
2006-05-08 06:22:01 +00:00
/* Use a fixed axis for GetPlatformInfo as our platforms / numtracks are always the right way around */
uint32 platinfo = GetPlatformInfo ( AXIS_X , 0 , plat_len , numtracks_orig , plat_len - w , numtracks_orig - numtracks , false ) ;
2006-05-06 22:30:36 +00:00
uint16 callback = GetStationCallback ( CBID_STATION_TILE_LAYOUT , platinfo , 0 , statspec , st , tile ) ;
2007-05-01 06:43:18 +00:00
if ( callback ! = CALLBACK_FAILED & & callback < 8 ) SetStationGfx ( tile , ( callback & ~ 1 ) + axis ) ;
2006-05-04 20:00:50 +00:00
}
2004-08-09 17:04:08 +00:00
tile + = tile_delta ;
} while ( - - w ) ;
2006-01-06 17:45:43 +00:00
SetSignalsOnBothDir ( tile_org , track ) ;
2006-05-27 16:12:16 +00:00
YapfNotifyTrackLayoutChange ( tile_org , track ) ;
2005-06-25 16:44:57 +00:00
tile_org + = tile_delta ^ TileDiffXY ( 1 , 1 ) ; // perpendicular to tile_delta
2004-08-09 17:04:08 +00:00
} while ( - - numtracks ) ;
2007-06-08 09:35:39 +00:00
st - > MarkTilesDirty ( false ) ;
2004-08-09 17:04:08 +00:00
UpdateStationVirtCoordDirty ( st ) ;
UpdateStationAcceptance ( st , false ) ;
2006-05-11 10:33:58 +00:00
RebuildStationLists ( ) ;
2004-08-09 17:04:08 +00:00
InvalidateWindow ( WC_STATION_LIST , st - > owner ) ;
2007-01-14 19:18:50 +00:00
/* success, so don't delete the new station */
2007-07-21 13:45:15 +00:00
st_auto_delete . Detach ( ) ;
2004-08-09 17:04:08 +00:00
}
return cost ;
}
static void MakeRailwayStationAreaSmaller ( Station * st )
{
uint w = st - > trainst_w ;
uint h = st - > trainst_h ;
2005-06-24 12:38:35 +00:00
TileIndex tile = st - > train_tile ;
2004-08-09 17:04:08 +00:00
restart :
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
// too small?
if ( w ! = 0 & & h ! = 0 ) {
// check the left side, x = constant, y changes
2007-02-18 11:27:09 +00:00
for ( uint i = 0 ; ! st - > TileBelongsToRailStation ( tile + TileDiffXY ( 0 , i ) ) ; ) {
2004-08-09 17:04:08 +00:00
// the left side is unused?
2005-06-25 16:44:57 +00:00
if ( + + i = = h ) {
tile + = TileDiffXY ( 1 , 0 ) ;
w - - ;
goto restart ;
}
}
2004-08-09 17:04:08 +00:00
// check the right side, x = constant, y changes
2007-02-18 11:27:09 +00:00
for ( uint i = 0 ; ! st - > TileBelongsToRailStation ( tile + TileDiffXY ( w - 1 , i ) ) ; ) {
2004-08-09 17:04:08 +00:00
// the right side is unused?
2005-06-25 16:44:57 +00:00
if ( + + i = = h ) {
w - - ;
goto restart ;
}
}
2004-08-09 17:04:08 +00:00
// check the upper side, y = constant, x changes
2007-02-18 11:27:09 +00:00
for ( uint i = 0 ; ! st - > TileBelongsToRailStation ( tile + TileDiffXY ( i , 0 ) ) ; ) {
2004-08-09 17:04:08 +00:00
// the left side is unused?
2005-06-25 16:44:57 +00:00
if ( + + i = = w ) {
tile + = TileDiffXY ( 0 , 1 ) ;
h - - ;
goto restart ;
}
}
2004-08-09 17:04:08 +00:00
// check the lower side, y = constant, x changes
2007-02-18 11:27:09 +00:00
for ( uint i = 0 ; ! st - > TileBelongsToRailStation ( tile + TileDiffXY ( i , h - 1 ) ) ; ) {
2004-08-09 17:04:08 +00:00
// the left side is unused?
2005-06-25 16:44:57 +00:00
if ( + + i = = w ) {
h - - ;
goto restart ;
}
}
2004-08-09 17:04:08 +00:00
} else {
tile = 0 ;
}
st - > trainst_w = w ;
st - > trainst_h = h ;
st - > train_tile = tile ;
}
2005-05-09 16:37:40 +00:00
/** Remove a single tile from a railroad station.
* This allows for custom - built station with holes and weird layouts
2006-04-10 07:15:58 +00:00
* @ param tile tile of station piece to remove
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2007-05-07 17:10:30 +00:00
* @ param p1 start_tile
2005-05-09 16:37:40 +00:00
* @ param p2 unused
*/
2007-06-18 10:48:15 +00:00
CommandCost CmdRemoveFromRailroadStation ( TileIndex tile , uint32 flags , uint32 p1 , uint32 p2 )
2004-08-09 17:04:08 +00:00
{
2007-05-07 17:10:30 +00:00
TileIndex start = p1 = = 0 ? tile : p1 ;
/* Count of the number of tiles removed */
int quantity = 0 ;
if ( tile > = MapSize ( ) | | start > = MapSize ( ) ) return CMD_ERROR ;
/* make sure sx,sy are smaller than ex,ey */
int ex = TileX ( tile ) ;
int ey = TileY ( tile ) ;
int sx = TileX ( start ) ;
int sy = TileY ( start ) ;
if ( ex < sx ) Swap ( ex , sx ) ;
if ( ey < sy ) Swap ( ey , sy ) ;
tile = TileXY ( sx , sy ) ;
int size_x = ex - sx + 1 ;
int size_y = ey - sy + 1 ;
2005-01-04 17:11:03 +00:00
SET_EXPENSES_TYPE ( EXPENSES_CONSTRUCTION ) ;
2007-05-07 17:10:30 +00:00
/* Do the action for every tile into the area */
BEGIN_TILE_LOOP ( tile2 , size_x , size_y , tile ) {
/* Make sure the specified tile belongs to the current player, and that it is a railroad station. */
if ( ! IsTileType ( tile2 , MP_STATION ) | | ! IsRailwayStation ( tile2 ) | | ! _patches . nonuniform_stations ) {
continue ;
}
2004-08-09 17:04:08 +00:00
2007-05-07 17:10:30 +00:00
/* Check ownership of station */
Station * st = GetStationByTile ( tile2 ) ;
if ( _current_player ! = OWNER_WATER & & ( ! CheckOwnership ( st - > owner ) | | ! EnsureNoVehicle ( tile2 ) ) ) {
continue ;
}
2004-08-09 17:04:08 +00:00
2007-05-07 17:10:30 +00:00
/* If we reached here, the tile is valid so increase the quantity of tiles we will remove */
quantity + + ;
if ( flags & DC_EXEC ) {
uint specindex = GetCustomStationSpecIndex ( tile2 ) ;
Track track = GetRailStationTrack ( tile2 ) ;
DoClearSquare ( tile2 ) ;
st - > rect . AfterRemoveTile ( st , tile2 ) ;
SetSignalsOnBothDir ( tile2 , track ) ;
YapfNotifyTrackLayoutChange ( tile2 , track ) ;
DeallocateSpecFromStation ( st , specindex ) ;
// now we need to make the "spanned" area of the railway station smaller if we deleted something at the edges.
// we also need to adjust train_tile.
MakeRailwayStationAreaSmaller ( st ) ;
2007-06-08 09:35:39 +00:00
st - > MarkTilesDirty ( false ) ;
2007-05-07 17:10:30 +00:00
UpdateStationSignCoord ( st ) ;
// if we deleted the whole station, delete the train facility.
if ( st - > train_tile = = 0 ) {
st - > facilities & = ~ FACIL_TRAIN ;
UpdateStationVirtCoordDirty ( st ) ;
DeleteStationIfEmpty ( st ) ;
}
2004-08-09 17:04:08 +00:00
}
2007-05-07 17:10:30 +00:00
} END_TILE_LOOP ( tile2 , size_x , size_y , tile )
/* If we've not removed any tiles, give an error */
if ( quantity = = 0 ) return CMD_ERROR ;
2007-06-18 19:53:50 +00:00
return CommandCost ( _price . remove_rail_station * quantity ) ;
2004-08-09 17:04:08 +00:00
}
2006-06-01 09:41:35 +00:00
2007-06-18 10:48:15 +00:00
static CommandCost RemoveRailroadStation ( Station * st , TileIndex tile , uint32 flags )
2004-08-09 17:04:08 +00:00
{
2004-09-03 17:57:27 +00:00
/* if there is flooding and non-uniform stations are enabled, remove platforms tile by tile */
if ( _current_player = = OWNER_WATER & & _patches . nonuniform_stations )
2006-04-10 07:15:58 +00:00
return DoCommand ( tile , 0 , 0 , DC_EXEC , CMD_REMOVE_FROM_RAILROAD_STATION ) ;
2004-09-03 17:57:27 +00:00
2004-08-09 17:04:08 +00:00
/* Current player owns the station? */
if ( _current_player ! = OWNER_WATER & & ! CheckOwnership ( st - > owner ) )
return CMD_ERROR ;
/* determine width and height of platforms */
tile = st - > train_tile ;
2007-02-18 11:27:09 +00:00
int w = st - > trainst_w ;
int h = st - > trainst_h ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
assert ( w ! = 0 & & h ! = 0 ) ;
2007-06-18 19:53:50 +00:00
CommandCost cost ;
2004-08-09 17:04:08 +00:00
/* clear all areas of the station */
do {
int w_bak = w ;
do {
// for nonuniform stations, only remove tiles that are actually train station tiles
2007-01-14 19:18:50 +00:00
if ( st - > TileBelongsToRailStation ( tile ) ) {
2004-08-09 17:04:08 +00:00
if ( ! EnsureNoVehicle ( tile ) )
return CMD_ERROR ;
2007-06-18 19:53:50 +00:00
cost . AddCost ( _price . remove_rail_station ) ;
2006-01-06 17:45:43 +00:00
if ( flags & DC_EXEC ) {
2006-03-26 14:41:39 +00:00
Track track = GetRailStationTrack ( tile ) ;
2004-08-09 17:04:08 +00:00
DoClearSquare ( tile ) ;
2006-01-06 17:45:43 +00:00
SetSignalsOnBothDir ( tile , track ) ;
2006-05-27 16:12:16 +00:00
YapfNotifyTrackLayoutChange ( tile , track ) ;
2006-01-06 17:45:43 +00:00
}
2004-08-09 17:04:08 +00:00
}
2005-06-25 16:44:57 +00:00
tile + = TileDiffXY ( 1 , 0 ) ;
2004-08-09 17:04:08 +00:00
} while ( - - w ) ;
w = w_bak ;
2005-06-25 16:44:57 +00:00
tile + = TileDiffXY ( - w , 1 ) ;
2004-08-09 17:04:08 +00:00
} while ( - - h ) ;
if ( flags & DC_EXEC ) {
2007-01-14 23:02:12 +00:00
st - > rect . AfterRemoveRect ( st , st - > train_tile , st - > trainst_w , st - > trainst_h ) ;
2006-12-27 23:11:43 +00:00
2004-08-09 17:04:08 +00:00
st - > train_tile = 0 ;
2006-12-27 23:11:43 +00:00
st - > trainst_w = st - > trainst_h = 0 ;
2004-08-09 17:04:08 +00:00
st - > facilities & = ~ FACIL_TRAIN ;
2006-04-19 07:17:00 +00:00
free ( st - > speclist ) ;
st - > num_specs = 0 ;
st - > speclist = NULL ;
2004-08-09 17:04:08 +00:00
UpdateStationVirtCoordDirty ( st ) ;
DeleteStationIfEmpty ( st ) ;
}
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
return cost ;
}
2007-03-24 09:12:03 +00:00
/**
* Switches the rail type at a railway station tile .
* @ param tile The tile on which the railtype is to be convert .
* @ param totype The railtype we want to convert to
* @ param exec Switches between test and execute mode
* @ return The cost and state of the operation
* @ retval CMD_ERROR An error occured during the operation .
*/
2007-06-18 10:48:15 +00:00
CommandCost DoConvertStationRail ( TileIndex tile , RailType totype , bool exec )
2004-08-09 17:04:08 +00:00
{
2006-03-24 08:55:08 +00:00
const Station * st = GetStationByTile ( tile ) ;
2004-08-09 17:04:08 +00:00
if ( ! CheckOwnership ( st - > owner ) | | ! EnsureNoVehicle ( tile ) ) return CMD_ERROR ;
// tile is not a railroad station?
2006-03-26 14:41:39 +00:00
if ( ! IsRailwayStation ( tile ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
2006-03-17 10:10:31 +00:00
if ( GetRailType ( tile ) = = totype ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
2006-11-17 19:31:44 +00:00
// 'hidden' elrails can't be downgraded to normal rail when elrails are disabled
if ( _patches . disable_elrails & & totype = = RAILTYPE_RAIL & & GetRailType ( tile ) = = RAILTYPE_ELECTRIC ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
if ( exec ) {
2006-03-17 10:10:31 +00:00
SetRailType ( tile , totype ) ;
2004-08-09 17:04:08 +00:00
MarkTileDirtyByTile ( tile ) ;
2006-05-27 16:12:16 +00:00
YapfNotifyTrackLayoutChange ( tile , GetRailStationTrack ( tile ) ) ;
2004-08-09 17:04:08 +00:00
}
2007-06-18 19:53:50 +00:00
return CommandCost ( _price . build_rail / 2 ) ;
2004-08-09 17:04:08 +00:00
}
2007-02-02 08:23:48 +00:00
/**
2007-04-18 18:00:33 +00:00
* @ param truck_station Determines whether a stop is RoadStop : : BUS or RoadStop : : TRUCK
* @ param st The Station to do the whole procedure for
2007-02-02 08:23:48 +00:00
* @ return a pointer to where to link a new RoadStop *
2006-09-04 20:40:33 +00:00
*/
2007-02-02 08:23:48 +00:00
static RoadStop * * FindRoadStopSpot ( bool truck_station , Station * st )
2005-01-29 19:41:44 +00:00
{
2006-04-29 09:47:43 +00:00
RoadStop * * primary_stop = ( truck_station ) ? & st - > truck_stops : & st - > bus_stops ;
2005-01-29 19:41:44 +00:00
if ( * primary_stop = = NULL ) {
2007-04-18 18:00:33 +00:00
/* we have no roadstop of the type yet, so write a "primary stop" */
2007-02-02 08:23:48 +00:00
return primary_stop ;
2005-01-29 19:41:44 +00:00
} else {
2007-04-18 18:00:33 +00:00
/* there are stops already, so append to the end of the list */
2007-02-02 08:23:48 +00:00
RoadStop * stop = * primary_stop ;
while ( stop - > next ! = NULL ) stop = stop - > next ;
return & stop - > next ;
2005-01-29 19:41:44 +00:00
}
}
2006-04-29 09:47:43 +00:00
/** Build a bus or truck stop
* @ param tile tile to build the stop at
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2006-03-26 11:08:44 +00:00
* @ param p1 entrance direction ( DiagDirection )
2007-02-14 16:37:16 +00:00
* @ param p2 bit 0 : 0 for Bus stops , 1 for truck stops
* bit 1 : 0 for normal , 1 for drive - through
2007-05-20 19:14:08 +00:00
* bit 2. .4 : the roadtypes
2007-05-23 17:33:03 +00:00
* bit 5 : allow stations directly adjacent to other stations .
2004-08-09 17:04:08 +00:00
*/
2007-06-18 10:48:15 +00:00
CommandCost CmdBuildRoadStop ( TileIndex tile , uint32 flags , uint32 p1 , uint32 p2 )
2004-08-09 17:04:08 +00:00
{
2007-02-14 16:37:16 +00:00
bool type = HASBIT ( p2 , 0 ) ;
bool is_drive_through = HASBIT ( p2 , 1 ) ;
2007-07-29 23:42:59 +00:00
bool build_over_road = is_drive_through & & IsTileType ( tile , MP_ROAD ) & & GetRoadTileType ( tile ) = = ROAD_TILE_NORMAL ;
2007-02-18 11:14:55 +00:00
bool town_owned_road = build_over_road & & IsTileOwner ( tile , OWNER_TOWN ) ;
2007-05-20 19:14:08 +00:00
RoadTypes rts = ( RoadTypes ) GB ( p2 , 2 , 3 ) ;
if ( rts = = ROADTYPES_NONE | | HASBIT ( rts , ROADTYPE_HWAY ) ) return CMD_ERROR ;
2005-01-29 19:41:44 +00:00
2007-05-24 08:52:28 +00:00
/* Trams only have drive through stops */
if ( ! is_drive_through & & HASBIT ( rts , ROADTYPE_TRAM ) ) return CMD_ERROR ;
2005-05-09 16:37:40 +00:00
/* Saveguard the parameters */
2007-01-10 18:56:51 +00:00
if ( ! IsValidDiagDirection ( ( DiagDirection ) p1 ) ) return CMD_ERROR ;
2007-02-14 16:37:16 +00:00
/* If it is a drive-through stop check for valid axis */
if ( is_drive_through & & ! IsValidAxis ( ( Axis ) p1 ) ) return CMD_ERROR ;
2007-02-14 20:58:19 +00:00
/* Road bits in the wrong direction */
2007-05-20 19:14:08 +00:00
if ( build_over_road & & ( GetAllRoadBits ( tile ) & ( ( Axis ) p1 = = AXIS_X ? ROAD_Y : ROAD_X ) ) ! = 0 ) return_cmd_error ( STR_DRIVE_THROUGH_ERROR_DIRECTION ) ;
2007-05-26 14:24:19 +00:00
SET_EXPENSES_TYPE ( EXPENSES_CONSTRUCTION ) ;
if ( ! ( flags & DC_NO_TOWN_RATING ) & & ! CheckIfAuthorityAllows ( tile ) ) return CMD_ERROR ;
2007-06-18 19:53:50 +00:00
CommandCost cost ;
2007-05-26 14:24:19 +00:00
2007-02-14 20:58:19 +00:00
/* Not allowed to build over this road */
2007-03-31 09:53:40 +00:00
if ( build_over_road ) {
if ( IsTileOwner ( tile , OWNER_TOWN ) & & ! _patches . road_stop_on_town_road ) return_cmd_error ( STR_DRIVE_THROUGH_ERROR_ON_TOWN_ROAD ) ;
2007-05-20 19:14:08 +00:00
if ( GetRoadTileType ( tile ) ! = ROAD_TILE_NORMAL ) return CMD_ERROR ;
2007-05-25 22:07:40 +00:00
2007-05-31 07:34:40 +00:00
/* Don't allow building the roadstop when vehicles are already driving on it */
if ( ! EnsureNoVehicleOnGround ( tile ) ) return CMD_ERROR ;
2007-05-25 22:07:40 +00:00
RoadTypes cur_rts = GetRoadTypes ( tile ) ;
2007-05-26 14:24:19 +00:00
if ( GetRoadOwner ( tile , ROADTYPE_ROAD ) ! = OWNER_TOWN & & HASBIT ( cur_rts , ROADTYPE_ROAD ) & & ! CheckOwnership ( GetRoadOwner ( tile , ROADTYPE_ROAD ) ) ) return CMD_ERROR ;
if ( HASBIT ( cur_rts , ROADTYPE_TRAM ) & & ! CheckOwnership ( GetRoadOwner ( tile , ROADTYPE_TRAM ) ) ) return CMD_ERROR ;
2007-05-20 19:14:08 +00:00
/* Do not remove roadtypes! */
2007-05-26 14:24:19 +00:00
rts | = cur_rts ;
2007-03-31 09:53:40 +00:00
}
2007-05-27 01:59:07 +00:00
cost = CheckFlatLandBelow ( tile , 1 , 1 , flags , is_drive_through ? 5 < < p1 : 1 < < p1 , NULL , ! build_over_road ) ;
2007-05-27 01:03:59 +00:00
if ( CmdFailed ( cost ) ) return cost ;
2004-08-09 17:04:08 +00:00
2007-05-23 17:33:03 +00:00
Station * st = NULL ;
if ( ! _patches . adjacent_stations | | ! HASBIT ( p2 , 5 ) ) {
st = GetStationAround ( tile , 1 , 1 , INVALID_STATION ) ;
if ( st = = CHECK_STATIONS_ERR ) return CMD_ERROR ;
}
2004-08-09 17:04:08 +00:00
/* Find a station close to us */
2007-02-17 15:59:33 +00:00
if ( st = = NULL ) st = GetClosestStationFromTile ( tile ) ;
2004-08-09 17:04:08 +00:00
2005-01-29 19:41:44 +00:00
//give us a road stop in the list, and check if something went wrong
2007-02-18 11:27:09 +00:00
RoadStop * road_stop = new RoadStop ( tile ) ;
2006-02-01 06:32:03 +00:00
if ( road_stop = = NULL ) {
return_cmd_error ( type ? STR_3008B_TOO_MANY_TRUCK_STOPS : STR_3008A_TOO_MANY_BUS_STOPS ) ;
}
2005-01-29 19:41:44 +00:00
2007-01-25 01:29:24 +00:00
/* ensure that in case of error (or no DC_EXEC) the new road stop gets deleted upon return */
2007-01-26 11:38:07 +00:00
AutoPtrT < RoadStop > rs_auto_delete ( road_stop ) ;
2007-01-25 01:29:24 +00:00
2006-02-06 09:18:04 +00:00
if ( st ! = NULL & &
2007-01-25 11:11:43 +00:00
GetNumRoadStopsInStation ( st , RoadStop : : BUS ) + GetNumRoadStopsInStation ( st , RoadStop : : TRUCK ) > = RoadStop : : LIMIT ) {
2006-02-01 06:32:03 +00:00
return_cmd_error ( type ? STR_3008B_TOO_MANY_TRUCK_STOPS : STR_3008A_TOO_MANY_BUS_STOPS ) ;
}
2005-01-29 19:41:44 +00:00
2007-01-14 19:18:50 +00:00
/* In case of new station if DC_EXEC is NOT set we still need to create the station
* to test if everything is OK . In this case we need to delete it before return . */
2007-01-26 11:38:07 +00:00
AutoPtrT < Station > st_auto_delete ;
2007-01-14 19:18:50 +00:00
2004-08-09 17:04:08 +00:00
if ( st ! = NULL ) {
2007-02-18 08:37:39 +00:00
if ( st - > owner ! = _current_player ) {
2004-08-09 17:04:08 +00:00
return_cmd_error ( STR_3009_TOO_CLOSE_TO_ANOTHER_STATION ) ;
2006-02-01 06:32:03 +00:00
}
2004-09-10 19:02:27 +00:00
2007-01-14 23:02:12 +00:00
if ( ! st - > rect . BeforeAddTile ( tile , StationRect : : ADD_TEST ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
} else {
2007-01-14 19:18:50 +00:00
/* allocate and initialize new station */
st = new Station ( tile ) ;
2007-08-02 08:47:56 +00:00
if ( st = = NULL ) return_cmd_error ( STR_3008_TOO_MANY_STATIONS_LOADING ) ;
2004-08-09 17:04:08 +00:00
2007-01-14 19:18:50 +00:00
/* ensure that in case of error (or no DC_EXEC) the new station gets deleted upon return */
2007-01-26 11:38:07 +00:00
st_auto_delete = st ;
2007-01-14 19:18:50 +00:00
Town * t = st - > town = ClosestTownFromTile ( tile , ( uint ) - 1 ) ;
if ( ! GenerateStationName ( st , tile , 0 ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
2007-01-14 19:18:50 +00:00
if ( IsValidPlayer ( _current_player ) & & ( flags & DC_EXEC ) ! = 0 ) {
2004-08-09 17:04:08 +00:00
SETBIT ( t - > have_ratings , _current_player ) ;
2006-02-01 06:32:03 +00:00
}
2004-08-09 17:04:08 +00:00
st - > sign . width_1 = 0 ;
}
2007-06-18 19:53:50 +00:00
cost . AddCost ( ( type ) ? _price . build_truck_station : _price . build_bus_station ) ;
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
2007-02-02 08:23:48 +00:00
// Insert into linked list of RoadStops
RoadStop * * currstop = FindRoadStopSpot ( type , st ) ;
2005-01-29 19:41:44 +00:00
* currstop = road_stop ;
//initialize an empty station
2007-01-18 09:34:44 +00:00
st - > AddFacility ( ( type ) ? FACIL_TRUCK_STOP : FACIL_BUS_STOP , tile ) ;
2004-08-09 17:04:08 +00:00
2007-01-14 23:02:12 +00:00
st - > rect . BeforeAddTile ( tile , StationRect : : ADD_TRY ) ;
2006-12-27 23:11:43 +00:00
2007-02-21 19:46:37 +00:00
RoadStop : : Type rs_type = type ? RoadStop : : TRUCK : RoadStop : : BUS ;
if ( is_drive_through ) {
2007-05-20 19:14:08 +00:00
MakeDriveThroughRoadStop ( tile , st - > owner , st - > index , rs_type , rts , ( Axis ) p1 , town_owned_road ) ;
2007-02-21 19:46:37 +00:00
} else {
2007-05-20 19:14:08 +00:00
MakeRoadStop ( tile , st - > owner , st - > index , rs_type , rts , ( DiagDirection ) p1 ) ;
2007-02-21 19:46:37 +00:00
}
2004-08-09 17:04:08 +00:00
UpdateStationVirtCoordDirty ( st ) ;
UpdateStationAcceptance ( st , false ) ;
2006-05-11 10:33:58 +00:00
RebuildStationLists ( ) ;
2004-08-09 17:04:08 +00:00
InvalidateWindow ( WC_STATION_LIST , st - > owner ) ;
2007-01-25 01:29:24 +00:00
/* success, so don't delete the new station and the new road stop */
2007-07-21 13:45:15 +00:00
st_auto_delete . Detach ( ) ;
rs_auto_delete . Detach ( ) ;
2004-08-09 17:04:08 +00:00
}
return cost ;
}
// Remove a bus station
2007-06-18 10:48:15 +00:00
static CommandCost RemoveRoadStop ( Station * st , uint32 flags , TileIndex tile )
2004-08-09 17:04:08 +00:00
{
2006-02-01 06:32:03 +00:00
if ( _current_player ! = OWNER_WATER & & ! CheckOwnership ( st - > owner ) ) {
2004-08-09 17:04:08 +00:00
return CMD_ERROR ;
2006-02-01 06:32:03 +00:00
}
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
bool is_truck = IsTruckStop ( tile ) ;
RoadStop * * primary_stop ;
RoadStop * cur_stop ;
2005-11-14 19:48:04 +00:00
if ( is_truck ) { // truck stop
2005-01-29 19:41:44 +00:00
primary_stop = & st - > truck_stops ;
2007-01-25 10:06:58 +00:00
cur_stop = GetRoadStopByTile ( tile , RoadStop : : TRUCK ) ;
2005-01-29 19:41:44 +00:00
} else {
primary_stop = & st - > bus_stops ;
2007-01-25 10:06:58 +00:00
cur_stop = GetRoadStopByTile ( tile , RoadStop : : BUS ) ;
2004-08-09 17:04:08 +00:00
}
2005-01-29 19:41:44 +00:00
assert ( cur_stop ! = NULL ) ;
2004-08-09 17:04:08 +00:00
2006-02-01 06:32:03 +00:00
if ( ! EnsureNoVehicle ( tile ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
2007-01-28 21:54:40 +00:00
if ( * primary_stop = = cur_stop ) {
// removed the first stop in the list
* primary_stop = cur_stop - > next ;
// removed the only stop?
if ( * primary_stop = = NULL ) {
st - > facilities & = ( is_truck ? ~ FACIL_TRUCK_STOP : ~ FACIL_BUS_STOP ) ;
}
} else {
// tell the predecessor in the list to skip this stop
RoadStop * pred = * primary_stop ;
while ( pred - > next ! = cur_stop ) pred = pred - > next ;
pred - > next = cur_stop - > next ;
2005-01-29 19:41:44 +00:00
}
2004-08-09 17:04:08 +00:00
2007-01-17 11:15:51 +00:00
delete cur_stop ;
2006-08-26 19:14:02 +00:00
DoClearSquare ( tile ) ;
2007-01-14 23:02:12 +00:00
st - > rect . AfterRemoveTile ( st , tile ) ;
2006-08-26 19:14:02 +00:00
2004-08-09 17:04:08 +00:00
UpdateStationVirtCoordDirty ( st ) ;
DeleteStationIfEmpty ( st ) ;
}
2007-06-18 19:53:50 +00:00
return CommandCost ( ( is_truck ) ? _price . remove_truck_station : _price . remove_bus_station ) ;
2004-08-09 17:04:08 +00:00
}
2007-02-14 16:37:16 +00:00
/** Remove a bus or truck stop
* @ param tile tile to remove the stop from
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2007-02-14 16:37:16 +00:00
* @ param p1 not used
* @ param p2 bit 0 : 0 for Bus stops , 1 for truck stops
*/
2007-06-18 10:48:15 +00:00
CommandCost CmdRemoveRoadStop ( TileIndex tile , uint32 flags , uint32 p1 , uint32 p2 )
2007-02-14 16:37:16 +00:00
{
/* Make sure the specified tile is a road stop of the correct type */
if ( ! IsTileType ( tile , MP_STATION ) | | ! IsRoadStop ( tile ) | | ( uint32 ) GetRoadStopType ( tile ) ! = p2 ) return CMD_ERROR ;
2007-02-18 11:27:09 +00:00
Station * st = GetStationByTile ( tile ) ;
2007-02-14 16:37:16 +00:00
/* Save the stop info before it is removed */
2007-02-18 11:27:09 +00:00
bool is_drive_through = IsDriveThroughStopTile ( tile ) ;
2007-05-20 19:14:08 +00:00
RoadTypes rts = GetRoadTypes ( tile ) ;
2007-05-21 16:58:23 +00:00
RoadBits road_bits = IsDriveThroughStopTile ( tile ) ?
( ( GetRoadStopDir ( tile ) = = DIAGDIR_NE ) ? ROAD_X : ROAD_Y ) :
DiagDirToRoadBits ( GetRoadStopDir ( tile ) ) ;
2007-02-18 11:27:09 +00:00
bool is_towns_road = is_drive_through & & GetStopBuiltOnTownRoad ( tile ) ;
2007-02-14 16:37:16 +00:00
2007-06-18 10:48:15 +00:00
CommandCost ret = RemoveRoadStop ( st , flags , tile ) ;
2007-02-14 16:37:16 +00:00
/* If the stop was a drive-through stop replace the road */
2007-06-18 16:42:40 +00:00
if ( ( flags & DC_EXEC ) & & CmdSucceeded ( ret ) & & is_drive_through ) {
2007-05-28 20:46:59 +00:00
/* Rebuild the drive throuhg road stop. As a road stop can only be
* removed by the owner of the roadstop , _current_player is the
* owner of the road stop . */
MakeRoadNormal ( tile , road_bits , rts , is_towns_road ? ClosestTownFromTile ( tile , ( uint ) - 1 ) - > index : 0 ,
is_towns_road ? OWNER_TOWN : _current_player , _current_player , _current_player ) ;
2007-02-14 16:37:16 +00:00
}
2005-01-29 19:41:44 +00:00
2007-02-14 16:37:16 +00:00
return ret ;
}
2005-01-29 19:41:44 +00:00
2004-08-09 17:04:08 +00:00
// FIXME -- need to move to its corresponding Airport variable
// Country Airfield (small)
2006-04-03 13:02:33 +00:00
static const byte _airport_sections_country [ ] = {
2004-08-09 17:04:08 +00:00
54 , 53 , 52 , 65 ,
58 , 57 , 56 , 55 ,
64 , 63 , 63 , 62
} ;
// City Airport (large)
2006-04-03 13:02:33 +00:00
static const byte _airport_sections_town [ ] = {
2005-10-23 13:04:44 +00:00
31 , 9 , 33 , 9 , 9 , 32 ,
27 , 36 , 29 , 34 , 8 , 10 ,
2004-08-09 17:04:08 +00:00
30 , 11 , 35 , 13 , 20 , 21 ,
51 , 12 , 14 , 17 , 19 , 28 ,
38 , 13 , 15 , 16 , 18 , 39 ,
26 , 22 , 23 , 24 , 25 , 26
} ;
// Metropolitain Airport (large) - 2 runways
2006-04-03 13:02:33 +00:00
static const byte _airport_sections_metropolitan [ ] = {
2005-10-23 13:04:44 +00:00
31 , 9 , 33 , 9 , 9 , 32 ,
27 , 36 , 29 , 34 , 8 , 10 ,
30 , 11 , 35 , 13 , 20 , 21 ,
102 , 8 , 8 , 8 , 8 , 28 ,
83 , 84 , 84 , 84 , 84 , 83 ,
26 , 23 , 23 , 23 , 23 , 26
2004-08-09 17:04:08 +00:00
} ;
// International Airport (large) - 2 runways
2006-04-03 13:02:33 +00:00
static const byte _airport_sections_international [ ] = {
2006-04-15 03:08:14 +00:00
88 , 89 , 89 , 89 , 89 , 89 , 88 ,
51 , 8 , 8 , 8 , 8 , 8 , 32 ,
2005-10-23 13:04:44 +00:00
30 , 8 , 11 , 27 , 11 , 8 , 10 ,
2004-08-09 17:04:08 +00:00
32 , 8 , 11 , 27 , 11 , 8 , 114 ,
87 , 8 , 11 , 85 , 11 , 8 , 114 ,
2005-10-23 13:04:44 +00:00
87 , 8 , 8 , 8 , 8 , 8 , 90 ,
26 , 23 , 23 , 23 , 23 , 23 , 26
2004-08-09 17:04:08 +00:00
} ;
2006-06-23 22:05:40 +00:00
// Intercontinental Airport (vlarge) - 4 runways
static const byte _airport_sections_intercontinental [ ] = {
2006-06-27 21:25:53 +00:00
102 , 120 , 89 , 89 , 89 , 89 , 89 , 89 , 118 ,
2007-03-09 10:12:08 +00:00
120 , 23 , 23 , 23 , 23 , 23 , 23 , 119 , 117 ,
2006-06-27 21:25:53 +00:00
87 , 54 , 87 , 8 , 8 , 8 , 8 , 51 , 117 ,
87 , 162 , 87 , 85 , 116 , 116 , 8 , 9 , 10 ,
2006-06-23 22:05:40 +00:00
87 , 8 , 8 , 11 , 31 , 11 , 8 , 160 , 32 ,
32 , 160 , 8 , 11 , 27 , 11 , 8 , 8 , 10 ,
87 , 8 , 8 , 11 , 30 , 11 , 8 , 8 , 10 ,
2006-06-25 13:42:37 +00:00
87 , 142 , 8 , 11 , 29 , 11 , 10 , 163 , 10 ,
87 , 164 , 87 , 8 , 8 , 8 , 10 , 37 , 117 ,
2006-06-27 21:25:53 +00:00
87 , 120 , 89 , 89 , 89 , 89 , 89 , 89 , 119 ,
2007-03-09 10:12:08 +00:00
121 , 23 , 23 , 23 , 23 , 23 , 23 , 119 , 37
2006-06-23 22:05:40 +00:00
} ;
// Commuter Airfield (small)
static const byte _airport_sections_commuter [ ] = {
85 , 30 , 115 , 115 , 32 ,
87 , 8 , 8 , 8 , 10 ,
87 , 11 , 11 , 11 , 10 ,
26 , 23 , 23 , 23 , 26
} ;
2004-08-09 17:04:08 +00:00
// Heliport
2006-04-03 13:02:33 +00:00
static const byte _airport_sections_heliport [ ] = {
2004-08-09 17:04:08 +00:00
66 ,
} ;
2006-06-23 22:05:40 +00:00
// Helidepot
static const byte _airport_sections_helidepot [ ] = {
124 , 32 ,
122 , 123
} ;
// Helistation
static const byte _airport_sections_helistation [ ] = {
32 , 134 , 159 , 158 ,
161 , 142 , 142 , 157
} ;
2006-04-07 09:37:04 +00:00
static const byte * const _airport_sections [ ] = {
2006-06-23 22:05:40 +00:00
_airport_sections_country , // Country Airfield (small)
_airport_sections_town , // City Airport (large)
_airport_sections_heliport , // Heliport
_airport_sections_metropolitan , // Metropolitain Airport (large)
_airport_sections_international , // International Airport (xlarge)
_airport_sections_commuter , // Commuter Airport (small)
_airport_sections_helidepot , // Helidepot
_airport_sections_intercontinental , // Intercontinental Airport (xxlarge)
_airport_sections_helistation // Helistation
2004-08-09 17:04:08 +00:00
} ;
2005-05-09 22:33:00 +00:00
/** Place an Airport.
2006-04-10 07:15:58 +00:00
* @ param tile tile where airport will be built
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2005-05-09 22:33:00 +00:00
* @ param p1 airport type , @ see airport . h
2007-05-23 17:33:03 +00:00
* @ param p2 ( bit 0 ) - allow airports directly adjacent to other airports .
2004-08-09 17:04:08 +00:00
*/
2007-06-18 10:48:15 +00:00
CommandCost CmdBuildAirport ( TileIndex tile , uint32 flags , uint32 p1 , uint32 p2 )
2004-08-09 17:04:08 +00:00
{
2004-09-10 19:02:27 +00:00
bool airport_upgrade = true ;
2004-08-09 17:04:08 +00:00
SET_EXPENSES_TYPE ( EXPENSES_CONSTRUCTION ) ;
2005-05-09 22:33:00 +00:00
/* Check if a valid, buildable airport was chosen for construction */
2006-04-07 09:37:04 +00:00
if ( p1 > lengthof ( _airport_sections ) | | ! HASBIT ( GetValidAirports ( ) , p1 ) ) return CMD_ERROR ;
2005-05-09 22:33:00 +00:00
2004-08-09 17:04:08 +00:00
if ( ! ( flags & DC_NO_TOWN_RATING ) & & ! CheckIfAuthorityAllows ( tile ) )
return CMD_ERROR ;
2007-02-18 11:27:09 +00:00
Town * t = ClosestTownFromTile ( tile , ( uint ) - 1 ) ;
2004-08-09 17:04:08 +00:00
/* Check if local auth refuses a new airport */
{
uint num = 0 ;
2007-02-18 11:27:09 +00:00
const Station * st ;
2004-08-09 17:04:08 +00:00
FOR_ALL_STATIONS ( st ) {
2006-08-22 15:33:35 +00:00
if ( st - > town = = t & & st - > facilities & FACIL_AIRPORT & & st - > airport_type ! = AT_OILRIG )
2004-08-09 17:04:08 +00:00
num + + ;
}
if ( num > = 2 ) {
2004-12-02 22:53:07 +00:00
SetDParam ( 0 , t - > index ) ;
2004-08-09 17:04:08 +00:00
return_cmd_error ( STR_2035_LOCAL_AUTHORITY_REFUSES ) ;
}
}
2007-02-18 11:27:09 +00:00
const AirportFTAClass * afc = GetAirport ( p1 ) ;
int w = afc - > size_x ;
int h = afc - > size_y ;
2004-08-09 17:04:08 +00:00
2007-06-18 10:48:15 +00:00
CommandCost ret = CheckFlatLandBelow ( tile , w , h , flags , 0 , NULL ) ;
2006-03-12 12:19:25 +00:00
if ( CmdFailed ( ret ) ) return ret ;
2007-06-18 19:53:50 +00:00
CommandCost cost ( ret . GetCost ( ) ) ;
2004-08-09 17:04:08 +00:00
2007-05-23 17:33:03 +00:00
Station * st = NULL ;
if ( ! _patches . adjacent_stations | | ! HASBIT ( p2 , 0 ) ) {
st = GetStationAround ( tile , w , h , INVALID_STATION ) ;
if ( st = = CHECK_STATIONS_ERR ) return CMD_ERROR ;
}
2004-08-09 17:04:08 +00:00
/* Find a station close to us */
2007-02-17 15:59:33 +00:00
if ( st = = NULL ) st = GetClosestStationFromTile ( tile ) ;
2004-08-09 17:04:08 +00:00
2007-01-03 22:55:53 +00:00
if ( w > _patches . station_spread | | h > _patches . station_spread ) {
_error_message = STR_306C_STATION_TOO_SPREAD_OUT ;
return CMD_ERROR ;
}
2007-01-14 19:18:50 +00:00
/* In case of new station if DC_EXEC is NOT set we still need to create the station
* to test if everything is OK . In this case we need to delete it before return . */
2007-01-26 11:38:07 +00:00
AutoPtrT < Station > st_auto_delete ;
2007-01-14 19:18:50 +00:00
2004-08-09 17:04:08 +00:00
if ( st ! = NULL ) {
2007-02-18 08:37:39 +00:00
if ( st - > owner ! = _current_player )
2004-08-09 17:04:08 +00:00
return_cmd_error ( STR_3009_TOO_CLOSE_TO_ANOTHER_STATION ) ;
2004-09-10 19:02:27 +00:00
2007-01-14 23:02:12 +00:00
if ( ! st - > rect . BeforeAddRect ( tile , w , h , StationRect : : ADD_TEST ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
if ( st - > airport_tile ! = 0 )
return_cmd_error ( STR_300D_TOO_CLOSE_TO_ANOTHER_AIRPORT ) ;
} else {
airport_upgrade = false ;
2007-01-14 19:18:50 +00:00
/* allocate and initialize new station */
st = new Station ( tile ) ;
2007-08-02 08:47:56 +00:00
if ( st = = NULL ) return_cmd_error ( STR_3008_TOO_MANY_STATIONS_LOADING ) ;
2004-08-09 17:04:08 +00:00
2007-01-14 19:18:50 +00:00
/* ensure that in case of error (or no DC_EXEC) the station gets deleted upon return */
2007-01-26 11:38:07 +00:00
st_auto_delete = st ;
2007-01-14 19:18:50 +00:00
2005-02-02 15:45:53 +00:00
st - > town = t ;
2004-08-09 17:04:08 +00:00
2007-01-14 19:18:50 +00:00
if ( IsValidPlayer ( _current_player ) & & ( flags & DC_EXEC ) ! = 0 ) {
2004-08-09 17:04:08 +00:00
SETBIT ( t - > have_ratings , _current_player ) ;
2007-01-14 19:18:50 +00:00
}
2004-08-09 17:04:08 +00:00
st - > sign . width_1 = 0 ;
2007-02-17 15:03:30 +00:00
/* If only helicopters may use the airport generate a helicopter related (5)
* station name , otherwise generate a normal airport name ( 1 ) */
if ( ! GenerateStationName ( st , tile , ! ( afc - > flags & AirportFTAClass : : AIRPLANES ) ? 5 : 1 ) ) {
2004-08-09 17:04:08 +00:00
return CMD_ERROR ;
2007-02-17 15:03:30 +00:00
}
2004-08-09 17:04:08 +00:00
}
2007-06-18 19:53:50 +00:00
cost . AddCost ( _price . build_airport * w * h ) ;
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
st - > airport_tile = tile ;
2007-01-18 09:34:44 +00:00
st - > AddFacility ( FACIL_AIRPORT , tile ) ;
2004-08-09 17:04:08 +00:00
st - > airport_type = ( byte ) p1 ;
st - > airport_flags = 0 ;
2004-09-10 19:02:27 +00:00
2007-01-14 23:02:12 +00:00
st - > rect . BeforeAddRect ( tile , w , h , StationRect : : ADD_TRY ) ;
2006-12-27 23:11:43 +00:00
2005-11-14 19:48:04 +00:00
/* if airport was demolished while planes were en-route to it, the
* positions can no longer be the same ( v - > u . air . pos ) , since different
* airports have different indexes . So update all planes en - route to this
* airport . Only update if
* 1. airport is upgraded
* 2. airport is added to existing station ( unfortunately unavoideable )
*/
2005-10-23 13:04:44 +00:00
if ( airport_upgrade ) UpdateAirplanesOnNewStation ( st ) ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
{
2006-04-07 09:37:04 +00:00
const byte * b = _airport_sections [ p1 ] ;
2005-10-23 13:04:44 +00:00
2006-02-18 14:41:24 +00:00
BEGIN_TILE_LOOP ( tile_cur , w , h , tile ) {
2007-07-16 23:55:22 +00:00
MakeAirport ( tile_cur , st - > owner , st - > index , * b - ( ( * b < 67 ) ? 8 : 24 ) ) ;
b + + ;
2006-02-18 14:41:24 +00:00
} END_TILE_LOOP ( tile_cur , w , h , tile )
2004-08-09 17:04:08 +00:00
}
UpdateStationVirtCoordDirty ( st ) ;
UpdateStationAcceptance ( st , false ) ;
2006-05-11 10:33:58 +00:00
RebuildStationLists ( ) ;
2004-08-09 17:04:08 +00:00
InvalidateWindow ( WC_STATION_LIST , st - > owner ) ;
2007-01-14 19:18:50 +00:00
/* success, so don't delete the new station */
2007-07-21 13:45:15 +00:00
st_auto_delete . Detach ( ) ;
2004-08-09 17:04:08 +00:00
}
return cost ;
}
2007-06-18 10:48:15 +00:00
static CommandCost RemoveAirport ( Station * st , uint32 flags )
2004-08-09 17:04:08 +00:00
{
if ( _current_player ! = OWNER_WATER & & ! CheckOwnership ( st - > owner ) )
return CMD_ERROR ;
2007-02-18 11:27:09 +00:00
TileIndex tile = st - > airport_tile ;
2004-08-09 17:04:08 +00:00
2007-02-16 09:38:43 +00:00
const AirportFTAClass * afc = st - > Airport ( ) ;
2007-02-18 11:27:09 +00:00
int w = afc - > size_x ;
int h = afc - > size_y ;
2004-08-09 17:04:08 +00:00
2007-06-18 19:53:50 +00:00
CommandCost cost ( w * h * _price . remove_airport ) ;
2004-08-09 17:04:08 +00:00
2007-03-29 13:52:34 +00:00
Vehicle * v ;
FOR_ALL_VEHICLES ( v ) {
if ( ! ( v - > type = = VEH_AIRCRAFT & & IsNormalAircraft ( v ) ) ) continue ;
if ( v - > u . air . targetairport = = st - > index & & v - > u . air . state ! = FLYING ) return CMD_ERROR ;
}
2006-02-18 14:41:24 +00:00
BEGIN_TILE_LOOP ( tile_cur , w , h , tile ) {
if ( ! EnsureNoVehicle ( tile_cur ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
DeleteAnimatedTile ( tile_cur ) ;
DoClearSquare ( tile_cur ) ;
}
2007-04-18 22:10:36 +00:00
} END_TILE_LOOP ( tile_cur , w , h , tile )
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
2007-02-18 11:27:09 +00:00
for ( uint i = 0 ; i < afc - > nof_depots ; + + i ) {
2006-02-18 14:41:24 +00:00
DeleteWindowById (
WC_VEHICLE_DEPOT , tile + ToTileIndexDiff ( afc - > airport_depots [ i ] )
) ;
}
2004-12-21 23:27:58 +00:00
2007-01-14 23:02:12 +00:00
st - > rect . AfterRemoveRect ( st , tile , w , h ) ;
2006-12-27 23:11:43 +00:00
2004-08-09 17:04:08 +00:00
st - > airport_tile = 0 ;
st - > facilities & = ~ FACIL_AIRPORT ;
UpdateStationVirtCoordDirty ( st ) ;
DeleteStationIfEmpty ( st ) ;
}
return cost ;
}
2005-05-09 22:33:00 +00:00
/** Build a buoy.
2006-04-10 07:15:58 +00:00
* @ param tile tile where to place the bouy
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2005-05-09 22:33:00 +00:00
* @ param p1 unused
* @ param p2 unused
2004-08-09 17:04:08 +00:00
*/
2007-06-18 10:48:15 +00:00
CommandCost CmdBuildBuoy ( TileIndex tile , uint32 flags , uint32 p1 , uint32 p2 )
2004-08-09 17:04:08 +00:00
{
SET_EXPENSES_TYPE ( EXPENSES_CONSTRUCTION ) ;
2006-03-30 12:00:35 +00:00
if ( ! IsClearWaterTile ( tile ) | | tile = = 0 ) return_cmd_error ( STR_304B_SITE_UNSUITABLE ) ;
2007-03-14 12:56:09 +00:00
if ( MayHaveBridgeAbove ( tile ) & & IsBridgeAbove ( tile ) ) return_cmd_error ( STR_5007_MUST_DEMOLISH_BRIDGE_FIRST ) ;
2004-08-09 17:04:08 +00:00
2007-01-14 19:18:50 +00:00
/* allocate and initialize new station */
2007-02-18 11:27:09 +00:00
Station * st = new Station ( tile ) ;
2007-08-02 08:47:56 +00:00
if ( st = = NULL ) return_cmd_error ( STR_3008_TOO_MANY_STATIONS_LOADING ) ;
2004-08-09 17:04:08 +00:00
2007-01-14 19:18:50 +00:00
/* ensure that in case of error (or no DC_EXEC) the station gets deleted upon return */
2007-01-26 11:38:07 +00:00
AutoPtrT < Station > st_auto_delete ( st ) ;
2007-01-14 19:18:50 +00:00
2006-02-21 07:41:54 +00:00
st - > town = ClosestTownFromTile ( tile , ( uint ) - 1 ) ;
2004-08-09 17:04:08 +00:00
st - > sign . width_1 = 0 ;
2006-02-21 07:41:54 +00:00
if ( ! GenerateStationName ( st , tile , 4 ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
2006-02-21 07:41:54 +00:00
st - > dock_tile = tile ;
2004-08-09 17:04:08 +00:00
st - > facilities | = FACIL_DOCK ;
2005-05-02 22:13:20 +00:00
/* Buoys are marked in the Station struct by this flag. Yes, it is this
* braindead . . */
2004-08-09 17:04:08 +00:00
st - > had_vehicle_of_type | = HVOT_BUOY ;
st - > owner = OWNER_NONE ;
2004-09-10 19:02:27 +00:00
2004-08-17 08:40:09 +00:00
st - > build_date = _date ;
2004-08-09 17:04:08 +00:00
2006-03-26 14:41:39 +00:00
MakeBuoy ( tile , st - > index ) ;
2004-08-09 17:04:08 +00:00
UpdateStationVirtCoordDirty ( st ) ;
UpdateStationAcceptance ( st , false ) ;
2006-05-11 10:33:58 +00:00
RebuildStationLists ( ) ;
2004-08-09 17:04:08 +00:00
InvalidateWindow ( WC_STATION_LIST , st - > owner ) ;
2007-01-14 19:18:50 +00:00
/* success, so don't delete the new station */
2007-07-21 13:45:15 +00:00
st_auto_delete . Detach ( ) ;
2004-08-09 17:04:08 +00:00
}
2007-06-18 19:53:50 +00:00
return CommandCost ( _price . build_dock ) ;
2004-08-09 17:04:08 +00:00
}
2005-01-20 22:19:34 +00:00
/* Checks if any ship is servicing the buoy specified. Returns yes or no */
static bool CheckShipsOnBuoy ( Station * st )
{
const Vehicle * v ;
FOR_ALL_VEHICLES ( v ) {
2007-03-08 16:27:54 +00:00
if ( v - > type = = VEH_SHIP ) {
2005-01-20 22:19:34 +00:00
const Order * order ;
FOR_VEHICLE_ORDERS ( v , order ) {
2006-09-03 08:25:27 +00:00
if ( order - > type = = OT_GOTO_STATION & & order - > dest = = st - > index ) {
2005-01-20 22:19:34 +00:00
return true ;
}
}
}
}
return false ;
}
2007-06-18 10:48:15 +00:00
static CommandCost RemoveBuoy ( Station * st , uint32 flags )
2004-08-09 17:04:08 +00:00
{
2006-10-14 22:31:18 +00:00
/* XXX: strange stuff */
if ( ! IsValidPlayer ( _current_player ) ) return_cmd_error ( INVALID_STRING_ID ) ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
TileIndex tile = st - > dock_tile ;
2004-08-09 17:04:08 +00:00
2005-11-14 19:48:04 +00:00
if ( CheckShipsOnBuoy ( st ) ) return_cmd_error ( STR_BUOY_IS_IN_USE ) ;
if ( ! EnsureNoVehicle ( tile ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
st - > dock_tile = 0 ;
2005-05-02 22:13:20 +00:00
/* Buoys are marked in the Station struct by this flag. Yes, it is this
* braindead . . */
2004-08-09 17:04:08 +00:00
st - > facilities & = ~ FACIL_DOCK ;
st - > had_vehicle_of_type & = ~ HVOT_BUOY ;
2007-02-07 17:52:21 +00:00
/* We have to set the water tile's state to the same state as before the
* buoy was placed . Otherwise one could plant a buoy on a canal edge ,
* remove it and flood the land ( if the canal edge is at level 0 ) */
Owner o = GetTileOwner ( tile ) ;
if ( o = = OWNER_WATER ) {
MakeWater ( tile ) ;
} else {
MakeCanal ( tile , o ) ;
}
2006-03-01 21:00:44 +00:00
MarkTileDirtyByTile ( tile ) ;
2004-08-09 17:04:08 +00:00
UpdateStationVirtCoordDirty ( st ) ;
DeleteStationIfEmpty ( st ) ;
}
2007-06-18 19:53:50 +00:00
return CommandCost ( _price . remove_truck_station ) ;
2004-08-09 17:04:08 +00:00
}
2005-01-06 11:39:00 +00:00
static const TileIndexDiffC _dock_tileoffs_chkaround [ ] = {
{ - 1 , 0 } ,
{ 0 , 0 } ,
{ 0 , 0 } ,
{ 0 , - 1 }
2004-08-09 17:04:08 +00:00
} ;
2006-08-22 14:38:37 +00:00
static const byte _dock_w_chk [ 4 ] = { 2 , 1 , 2 , 1 } ;
static const byte _dock_h_chk [ 4 ] = { 1 , 2 , 1 , 2 } ;
2004-08-09 17:04:08 +00:00
2005-05-09 22:33:00 +00:00
/** Build a dock/haven.
2006-04-10 07:15:58 +00:00
* @ param tile tile where dock will be built
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2007-05-23 17:33:03 +00:00
* @ param p1 ( bit 0 ) - allow docks directly adjacent to other docks .
2005-05-09 22:33:00 +00:00
* @ param p2 unused
*/
2007-06-18 10:48:15 +00:00
CommandCost CmdBuildDock ( TileIndex tile , uint32 flags , uint32 p1 , uint32 p2 )
2004-08-09 17:04:08 +00:00
{
2007-06-18 10:48:15 +00:00
CommandCost cost ;
2004-08-09 17:04:08 +00:00
SET_EXPENSES_TYPE ( EXPENSES_CONSTRUCTION ) ;
2007-02-18 11:27:09 +00:00
DiagDirection direction ;
2006-02-21 07:41:54 +00:00
switch ( GetTileSlope ( tile , NULL ) ) {
2006-04-23 13:48:16 +00:00
case SLOPE_SW : direction = DIAGDIR_NE ; break ;
case SLOPE_SE : direction = DIAGDIR_NW ; break ;
case SLOPE_NW : direction = DIAGDIR_SE ; break ;
case SLOPE_NE : direction = DIAGDIR_SW ; break ;
2006-02-21 07:41:54 +00:00
default : return_cmd_error ( STR_304B_SITE_UNSUITABLE ) ;
}
2004-08-09 17:04:08 +00:00
2006-09-18 18:02:33 +00:00
if ( ! ( flags & DC_NO_TOWN_RATING ) & & ! CheckIfAuthorityAllows ( tile ) ) return CMD_ERROR ;
2007-03-14 12:56:09 +00:00
if ( MayHaveBridgeAbove ( tile ) & & IsBridgeAbove ( tile ) ) return_cmd_error ( STR_5007_MUST_DEMOLISH_BRIDGE_FIRST ) ;
2006-04-10 07:15:58 +00:00
cost = DoCommand ( tile , 0 , 0 , flags , CMD_LANDSCAPE_CLEAR ) ;
2005-05-09 22:33:00 +00:00
if ( CmdFailed ( cost ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
TileIndex tile_cur = tile + TileOffsByDiagDir ( direction ) ;
2004-08-09 17:04:08 +00:00
2006-04-23 13:48:16 +00:00
if ( ! IsTileType ( tile_cur , MP_WATER ) | | GetTileSlope ( tile_cur , NULL ) ! = SLOPE_FLAT ) {
2006-02-21 07:41:54 +00:00
return_cmd_error ( STR_304B_SITE_UNSUITABLE ) ;
}
2004-08-09 17:04:08 +00:00
2007-03-14 12:56:09 +00:00
if ( MayHaveBridgeAbove ( tile_cur ) & & IsBridgeAbove ( tile_cur ) ) return_cmd_error ( STR_5007_MUST_DEMOLISH_BRIDGE_FIRST ) ;
2006-04-10 07:15:58 +00:00
cost = DoCommand ( tile_cur , 0 , 0 , flags , CMD_LANDSCAPE_CLEAR ) ;
2005-05-09 22:33:00 +00:00
if ( CmdFailed ( cost ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
2006-09-05 23:21:41 +00:00
tile_cur + = TileOffsByDiagDir ( direction ) ;
2006-04-23 13:48:16 +00:00
if ( ! IsTileType ( tile_cur , MP_WATER ) | | GetTileSlope ( tile_cur , NULL ) ! = SLOPE_FLAT ) {
2004-08-09 17:04:08 +00:00
return_cmd_error ( STR_304B_SITE_UNSUITABLE ) ;
2006-02-21 07:41:54 +00:00
}
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
/* middle */
2007-05-23 17:33:03 +00:00
Station * st = NULL ;
if ( ! _patches . adjacent_stations | | ! HASBIT ( p1 , 0 ) ) {
st = GetStationAround (
tile + ToTileIndexDiff ( _dock_tileoffs_chkaround [ direction ] ) ,
_dock_w_chk [ direction ] , _dock_h_chk [ direction ] , INVALID_STATION ) ;
if ( st = = CHECK_STATIONS_ERR ) return CMD_ERROR ;
}
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
/* Find a station close to us */
2007-02-17 15:59:33 +00:00
if ( st = = NULL ) st = GetClosestStationFromTile ( tile ) ;
2004-08-09 17:04:08 +00:00
2007-01-14 19:18:50 +00:00
/* In case of new station if DC_EXEC is NOT set we still need to create the station
* to test if everything is OK . In this case we need to delete it before return . */
2007-01-26 11:38:07 +00:00
AutoPtrT < Station > st_auto_delete ;
2007-01-14 19:18:50 +00:00
2004-08-09 17:04:08 +00:00
if ( st ! = NULL ) {
2007-02-18 08:37:39 +00:00
if ( st - > owner ! = _current_player )
2004-08-09 17:04:08 +00:00
return_cmd_error ( STR_3009_TOO_CLOSE_TO_ANOTHER_STATION ) ;
2004-09-10 19:02:27 +00:00
2007-01-14 23:02:12 +00:00
if ( ! st - > rect . BeforeAddRect ( tile , _dock_w_chk [ direction ] , _dock_h_chk [ direction ] , StationRect : : ADD_TEST ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
2005-05-09 22:33:00 +00:00
if ( st - > dock_tile ! = 0 ) return_cmd_error ( STR_304C_TOO_CLOSE_TO_ANOTHER_DOCK ) ;
2004-08-09 17:04:08 +00:00
} else {
2007-01-14 19:18:50 +00:00
/* allocate and initialize new station */
st = new Station ( tile ) ;
2007-08-02 08:47:56 +00:00
if ( st = = NULL ) return_cmd_error ( STR_3008_TOO_MANY_STATIONS_LOADING ) ;
2004-08-09 17:04:08 +00:00
2007-01-14 19:18:50 +00:00
/* ensure that in case of error (or no DC_EXEC) the station gets deleted upon return */
2007-01-26 11:38:07 +00:00
st_auto_delete = st ;
2007-01-14 19:18:50 +00:00
Town * t = st - > town = ClosestTownFromTile ( tile , ( uint ) - 1 ) ;
2004-08-09 17:04:08 +00:00
2007-01-14 19:18:50 +00:00
if ( IsValidPlayer ( _current_player ) & & ( flags & DC_EXEC ) ! = 0 ) {
2004-08-09 17:04:08 +00:00
SETBIT ( t - > have_ratings , _current_player ) ;
2007-01-14 19:18:50 +00:00
}
2004-08-09 17:04:08 +00:00
st - > sign . width_1 = 0 ;
2005-05-09 22:33:00 +00:00
if ( ! GenerateStationName ( st , tile , 3 ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
}
if ( flags & DC_EXEC ) {
st - > dock_tile = tile ;
2007-01-18 09:34:44 +00:00
st - > AddFacility ( FACIL_DOCK , tile ) ;
2004-08-09 17:04:08 +00:00
2007-01-14 23:02:12 +00:00
st - > rect . BeforeAddRect ( tile , _dock_w_chk [ direction ] , _dock_h_chk [ direction ] , StationRect : : ADD_TRY ) ;
2006-12-27 23:11:43 +00:00
2006-03-26 14:41:39 +00:00
MakeDock ( tile , st - > owner , st - > index , direction ) ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
UpdateStationVirtCoordDirty ( st ) ;
UpdateStationAcceptance ( st , false ) ;
2006-05-11 10:33:58 +00:00
RebuildStationLists ( ) ;
2004-08-09 17:04:08 +00:00
InvalidateWindow ( WC_STATION_LIST , st - > owner ) ;
2007-01-14 19:18:50 +00:00
/* success, so don't delete the new station */
2007-07-21 13:45:15 +00:00
st_auto_delete . Detach ( ) ;
2004-08-09 17:04:08 +00:00
}
2007-06-18 19:53:50 +00:00
return CommandCost ( _price . build_dock ) ;
2004-08-09 17:04:08 +00:00
}
2007-06-18 10:48:15 +00:00
static CommandCost RemoveDock ( Station * st , uint32 flags )
2004-08-09 17:04:08 +00:00
{
2005-11-14 19:48:04 +00:00
if ( ! CheckOwnership ( st - > owner ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
TileIndex tile1 = st - > dock_tile ;
TileIndex tile2 = tile1 + TileOffsByDiagDir ( GetDockDirection ( tile1 ) ) ;
2004-08-09 17:04:08 +00:00
2005-11-14 19:48:04 +00:00
if ( ! EnsureNoVehicle ( tile1 ) ) return CMD_ERROR ;
if ( ! EnsureNoVehicle ( tile2 ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
DoClearSquare ( tile1 ) ;
2006-03-01 21:00:44 +00:00
MakeWater ( tile2 ) ;
2006-12-27 23:11:43 +00:00
2007-01-14 23:02:12 +00:00
st - > rect . AfterRemoveTile ( st , tile1 ) ;
st - > rect . AfterRemoveTile ( st , tile2 ) ;
2006-12-27 23:11:43 +00:00
2006-03-01 21:00:44 +00:00
MarkTileDirtyByTile ( tile2 ) ;
2004-08-09 17:04:08 +00:00
st - > dock_tile = 0 ;
st - > facilities & = ~ FACIL_DOCK ;
UpdateStationVirtCoordDirty ( st ) ;
DeleteStationIfEmpty ( st ) ;
}
2007-06-18 19:53:50 +00:00
return CommandCost ( _price . remove_dock ) ;
2004-08-09 17:04:08 +00:00
}
# include "table/station_land.h"
2007-07-16 23:55:22 +00:00
const DrawTileSprites * GetStationTileLayout ( StationType st , byte gfx )
2006-05-06 20:33:22 +00:00
{
2007-07-16 23:55:22 +00:00
return & _station_display_datas [ st ] [ gfx ] ;
2006-05-06 20:33:22 +00:00
}
2004-08-09 17:04:08 +00:00
2007-02-08 14:04:02 +00:00
/* For drawing canal edges on buoys */
extern void DrawCanalWater ( TileIndex tile ) ;
2004-08-09 17:04:08 +00:00
static void DrawTile_Station ( TileInfo * ti )
{
2004-11-17 18:03:33 +00:00
const DrawTileSprites * t = NULL ;
2007-05-25 22:07:40 +00:00
RailType railtype ;
RoadTypes roadtypes ;
if ( IsRailwayStation ( ti - > tile ) ) {
railtype = GetRailType ( ti - > tile ) ;
roadtypes = ROADTYPES_NONE ;
} else {
roadtypes = GetRoadTypes ( ti - > tile ) ;
railtype = RAILTYPE_BEGIN ;
}
2005-07-31 22:53:57 +00:00
const RailtypeInfo * rti = GetRailTypeInfo ( railtype ) ;
2004-11-17 18:03:33 +00:00
uint32 relocation = 0 ;
2006-05-07 10:58:53 +00:00
const Station * st = NULL ;
const StationSpec * statspec = NULL ;
2006-08-05 17:00:09 +00:00
PlayerID owner = GetTileOwner ( ti - > tile ) ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
SpriteID palette ;
2006-10-14 22:31:18 +00:00
if ( IsValidPlayer ( owner ) ) {
2006-08-05 17:00:09 +00:00
palette = PLAYER_SPRITE_COLOR ( owner ) ;
} else {
// Some stations are not owner by a player, namely oil rigs
palette = PALETTE_TO_GREY ;
2004-08-09 17:04:08 +00:00
}
2006-03-26 14:41:39 +00:00
// don't show foundation for docks
2006-04-23 13:48:16 +00:00
if ( ti - > tileh ! = SLOPE_FLAT & & ! IsDock ( ti - > tile ) )
2007-07-26 16:51:10 +00:00
DrawFoundation ( ti , FOUNDATION_LEVELED ) ;
2004-08-09 17:04:08 +00:00
2006-04-16 17:29:37 +00:00
if ( IsCustomStationSpecIndex ( ti - > tile ) ) {
2004-11-17 18:03:33 +00:00
// look for customization
2006-05-07 10:58:53 +00:00
st = GetStationByTile ( ti - > tile ) ;
statspec = st - > speclist [ GetCustomStationSpecIndex ( ti - > tile ) ] . spec ;
2004-11-17 18:03:33 +00:00
//debug("Cust-o-mized %p", statspec);
if ( statspec ! = NULL ) {
2006-04-17 19:26:18 +00:00
uint tile = GetStationGfx ( ti - > tile ) ;
2004-11-17 18:03:33 +00:00
2006-05-04 19:21:16 +00:00
relocation = GetCustomStationRelocation ( statspec , st , ti - > tile ) ;
2006-04-17 19:26:18 +00:00
2006-05-04 20:00:50 +00:00
if ( HASBIT ( statspec - > callbackmask , CBM_CUSTOM_LAYOUT ) ) {
uint16 callback = GetStationCallback ( CBID_STATION_SPRITE_LAYOUT , 0 , 0 , statspec , st , ti - > tile ) ;
2006-10-18 17:44:46 +00:00
if ( callback ! = CALLBACK_FAILED ) tile = ( callback & ~ 1 ) + GetRailStationAxis ( ti - > tile ) ;
2006-05-04 20:00:50 +00:00
}
2006-04-17 19:26:18 +00:00
/* Ensure the chosen tile layout is valid for this custom station */
2006-05-04 20:00:50 +00:00
if ( statspec - > renderdata ! = NULL ) {
2007-01-10 18:56:51 +00:00
t = & statspec - > renderdata [ tile < statspec - > tiles ? tile : ( uint ) GetRailStationAxis ( ti - > tile ) ] ;
2006-05-04 20:00:50 +00:00
}
2004-11-17 18:03:33 +00:00
}
}
2007-07-16 23:55:22 +00:00
if ( t = = NULL | | t - > seq = = NULL ) t = & _station_display_datas [ GetStationType ( ti - > tile ) ] [ GetStationGfx ( ti - > tile ) ] ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
SpriteID image = t - > ground_sprite ;
2007-01-14 19:57:49 +00:00
if ( HASBIT ( image , SPRITE_MODIFIER_USE_OFFSET ) ) {
2006-05-07 10:58:53 +00:00
image + = GetCustomStationGroundRelocation ( statspec , st , ti - > tile ) ;
image + = rti - > custom_ground_offset ;
} else {
image + = rti - > total_offset ;
}
2004-11-17 18:03:33 +00:00
// station_land array has been increased from 82 elements to 114
// but this is something else. If AI builds station with 114 it looks all weird
2007-01-14 19:57:49 +00:00
DrawGroundSprite ( image , HASBIT ( image , PALETTE_MODIFIER_COLOR ) ? palette : PAL_NONE ) ;
2004-08-09 17:04:08 +00:00
2006-05-08 21:59:36 +00:00
if ( GetRailType ( ti - > tile ) = = RAILTYPE_ELECTRIC & & IsStationTileElectrifiable ( ti - > tile ) ) DrawCatenary ( ti ) ;
2006-03-29 16:30:26 +00:00
2007-05-25 22:07:40 +00:00
if ( HASBIT ( roadtypes , ROADTYPE_TRAM ) ) {
Axis axis = GetRoadStopDir ( ti - > tile ) = = DIAGDIR_NE ? AXIS_X : AXIS_Y ;
DrawGroundSprite ( ( HASBIT ( roadtypes , ROADTYPE_ROAD ) ? SPR_TRAMWAY_OVERLAY : SPR_TRAMWAY_TRAM ) + ( axis ^ 1 ) , PAL_NONE ) ;
DrawTramCatenary ( ti , axis = = AXIS_X ? ROAD_X : ROAD_Y ) ;
}
2007-02-08 14:04:02 +00:00
if ( IsBuoyTile ( ti - > tile ) & & ( ti - > z ! = 0 | | ! IsTileOwner ( ti - > tile , OWNER_WATER ) ) ) DrawCanalWater ( ti - > tile ) ;
2007-02-18 11:27:09 +00:00
const DrawTileSeqStruct * dtss ;
2004-11-14 01:25:05 +00:00
foreach_draw_tile_seq ( dtss , t - > seq ) {
2006-05-07 10:58:53 +00:00
image = dtss - > image ;
2007-01-17 12:57:35 +00:00
if ( relocation = = 0 | | HASBIT ( image , SPRITE_MODIFIER_USE_OFFSET ) ) {
2006-05-07 10:58:53 +00:00
image + = rti - > total_offset ;
} else {
image + = relocation ;
}
2007-02-18 11:27:09 +00:00
SpriteID pal ;
2007-07-26 14:07:11 +00:00
if ( ! HASBIT ( _transparent_opt , TO_BUILDINGS ) & & HASBIT ( image , PALETTE_MODIFIER_COLOR ) ) {
2007-01-14 19:57:49 +00:00
pal = palette ;
} else {
pal = dtss - > pal ;
2004-11-14 01:25:05 +00:00
}
2004-08-09 17:04:08 +00:00
2004-11-14 01:25:05 +00:00
if ( ( byte ) dtss - > delta_z ! = 0x80 ) {
2006-08-06 08:23:19 +00:00
AddSortableSpriteToDraw (
2007-01-14 19:57:49 +00:00
image , pal ,
2006-08-06 08:23:19 +00:00
ti - > x + dtss - > delta_x , ti - > y + dtss - > delta_y ,
dtss - > size_x , dtss - > size_y ,
2007-07-26 14:07:11 +00:00
dtss - > size_z , ti - > z + dtss - > delta_z ,
HASBIT ( _transparent_opt , TO_BUILDINGS )
2006-08-06 08:23:19 +00:00
) ;
2004-08-09 17:04:08 +00:00
} else {
2007-01-14 19:57:49 +00:00
AddChildSpriteScreen ( image , pal , dtss - > delta_x , dtss - > delta_y ) ;
2004-08-09 17:04:08 +00:00
}
}
}
2007-07-16 23:55:22 +00:00
void StationPickerDrawSprite ( int x , int y , StationType st , RailType railtype , RoadType roadtype , int image )
2004-08-09 17:04:08 +00:00
{
2005-07-31 22:53:57 +00:00
const RailtypeInfo * rti = GetRailTypeInfo ( railtype ) ;
2007-02-18 11:27:09 +00:00
SpriteID pal = PLAYER_SPRITE_COLOR ( _local_player ) ;
2007-07-16 23:55:22 +00:00
const DrawTileSprites * t = & _station_display_datas [ st ] [ image ] ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
SpriteID img = t - > ground_sprite ;
2007-01-14 19:57:49 +00:00
DrawSprite ( img + rti - > total_offset , HASBIT ( img , PALETTE_MODIFIER_COLOR ) ? pal : PAL_NONE , x , y ) ;
2004-08-09 17:04:08 +00:00
2007-05-25 22:07:40 +00:00
if ( roadtype = = ROADTYPE_TRAM ) {
DrawSprite ( SPR_TRAMWAY_TRAM + ( t - > ground_sprite = = SPR_ROAD_PAVED_STRAIGHT_X ? 1 : 0 ) , PAL_NONE , x , y ) ;
}
2007-02-18 11:27:09 +00:00
const DrawTileSeqStruct * dtss ;
2004-11-14 01:25:05 +00:00
foreach_draw_tile_seq ( dtss , t - > seq ) {
2004-08-09 17:04:08 +00:00
Point pt = RemapCoords ( dtss - > delta_x , dtss - > delta_y , dtss - > delta_z ) ;
2007-01-14 19:57:49 +00:00
DrawSprite ( dtss - > image + rti - > total_offset , pal , x + pt . x , y + pt . y ) ;
2004-08-09 17:04:08 +00:00
}
}
2006-08-06 16:32:49 +00:00
static uint GetSlopeZ_Station ( TileIndex tile , uint x , uint y )
2004-08-09 17:04:08 +00:00
{
2006-08-06 16:32:49 +00:00
return GetTileMaxZ ( tile ) ;
2004-08-09 17:04:08 +00:00
}
2007-07-26 16:51:10 +00:00
static Foundation GetFoundation_Station ( TileIndex tile , Slope tileh )
2004-08-13 18:27:33 +00:00
{
2007-07-26 16:51:10 +00:00
return FlatteningFoundation ( tileh ) ;
2004-08-13 18:27:33 +00:00
}
2005-06-24 12:38:35 +00:00
static void GetAcceptedCargo_Station ( TileIndex tile , AcceptedCargo ac )
2004-08-09 17:04:08 +00:00
{
/* not used */
}
2005-06-24 12:38:35 +00:00
static void GetTileDesc_Station ( TileIndex tile , TileDesc * td )
2004-08-09 17:04:08 +00:00
{
2005-06-04 11:56:32 +00:00
td - > owner = GetTileOwner ( tile ) ;
2006-03-24 08:55:08 +00:00
td - > build_date = GetStationByTile ( tile ) - > build_date ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
StringID str ;
2006-03-26 14:41:39 +00:00
switch ( GetStationType ( tile ) ) {
default : NOT_REACHED ( ) ;
case STATION_RAIL : str = STR_305E_RAILROAD_STATION ; break ;
2006-05-21 12:01:57 +00:00
case STATION_AIRPORT :
str = ( IsHangar ( tile ) ? STR_305F_AIRCRAFT_HANGAR : STR_3060_AIRPORT ) ;
break ;
2006-03-26 14:41:39 +00:00
case STATION_TRUCK : str = STR_3061_TRUCK_LOADING_AREA ; break ;
case STATION_BUS : str = STR_3062_BUS_STATION ; break ;
case STATION_OILRIG : str = STR_4807_OIL_RIG ; break ;
case STATION_DOCK : str = STR_3063_SHIP_DOCK ; break ;
case STATION_BUOY : str = STR_3069_BUOY ; break ;
}
2004-08-09 17:04:08 +00:00
td - > str = str ;
}
2007-05-24 22:41:50 +00:00
static uint32 GetTileTrackStatus_Station ( TileIndex tile , TransportType mode , uint sub_mode )
2005-06-24 12:38:35 +00:00
{
2005-01-16 09:51:56 +00:00
switch ( mode ) {
case TRANSPORT_RAIL :
2006-06-27 21:25:53 +00:00
if ( IsRailwayStation ( tile ) & & ! IsStationTileBlocked ( tile ) ) {
2006-03-26 14:41:39 +00:00
return TrackToTrackBits ( GetRailStationTrack ( tile ) ) * 0x101 ;
2005-01-16 09:51:56 +00:00
}
break ;
case TRANSPORT_WATER :
// buoy is coded as a station, it is always on open water
2007-02-02 20:20:56 +00:00
if ( IsBuoy ( tile ) ) {
TrackBits ts = TRACK_BIT_ALL ;
// remove tracks that connect NE map edge
if ( TileX ( tile ) = = 0 ) ts & = ~ ( TRACK_BIT_X | TRACK_BIT_UPPER | TRACK_BIT_RIGHT ) ;
// remove tracks that connect NW map edge
if ( TileY ( tile ) = = 0 ) ts & = ~ ( TRACK_BIT_Y | TRACK_BIT_LEFT | TRACK_BIT_UPPER ) ;
return uint32 ( ts ) * 0x101 ;
}
2005-01-16 09:51:56 +00:00
break ;
2006-05-27 16:12:16 +00:00
case TRANSPORT_ROAD :
2007-05-24 22:41:50 +00:00
if ( ( GetRoadTypes ( tile ) & sub_mode ) ! = 0 & & IsRoadStopTile ( tile ) ) {
2006-07-22 08:59:52 +00:00
return AxisToTrackBits ( DiagDirToAxis ( GetRoadStopDir ( tile ) ) ) * 0x101 ;
2006-06-27 21:25:53 +00:00
}
2006-05-27 16:12:16 +00:00
break ;
2005-01-16 09:51:56 +00:00
default :
break ;
2004-08-09 17:04:08 +00:00
}
2005-01-16 09:51:56 +00:00
2006-03-26 14:41:39 +00:00
return 0 ;
2004-08-09 17:04:08 +00:00
}
2005-11-16 12:29:37 +00:00
2005-06-24 12:38:35 +00:00
static void TileLoop_Station ( TileIndex tile )
2004-08-09 17:04:08 +00:00
{
2005-11-16 12:29:37 +00:00
// FIXME -- GetTileTrackStatus_Station -> animated stationtiles
// hardcoded.....not good
2007-07-16 23:55:22 +00:00
switch ( GetStationType ( tile ) ) {
case STATION_AIRPORT :
switch ( GetStationGfx ( tile ) ) {
case GFX_RADAR_LARGE_FIRST :
case GFX_WINDSACK_FIRST : // for small airport
case GFX_RADAR_INTERNATIONAL_FIRST :
case GFX_RADAR_METROPOLITAN_FIRST :
case GFX_RADAR_DISTRICTWE_FIRST : // radar district W-E airport
case GFX_WINDSACK_INTERCON_FIRST : // for intercontinental airport
AddAnimatedTile ( tile ) ;
break ;
}
2005-11-16 12:29:37 +00:00
break ;
2004-08-13 19:52:45 +00:00
2007-07-16 23:55:22 +00:00
case STATION_OILRIG : //(station part)
case STATION_BUOY :
2005-11-16 12:29:37 +00:00
TileLoop_Water ( tile ) ;
break ;
default : break ;
}
2004-08-09 17:04:08 +00:00
}
2005-06-24 12:38:35 +00:00
static void AnimateTile_Station ( TileIndex tile )
2004-08-09 17:04:08 +00:00
{
2007-03-07 12:11:48 +00:00
struct AnimData {
2006-08-31 07:01:26 +00:00
StationGfx from ; // first sprite
StationGfx to ; // last sprite
byte delay ;
2007-03-07 12:11:48 +00:00
} ;
2006-08-31 07:01:26 +00:00
static const AnimData data [ ] = {
{ GFX_RADAR_LARGE_FIRST , GFX_RADAR_LARGE_LAST , 3 } ,
{ GFX_WINDSACK_FIRST , GFX_WINDSACK_LAST , 1 } ,
{ GFX_RADAR_INTERNATIONAL_FIRST , GFX_RADAR_INTERNATIONAL_LAST , 3 } ,
{ GFX_RADAR_METROPOLITAN_FIRST , GFX_RADAR_METROPOLITAN_LAST , 3 } ,
{ GFX_RADAR_DISTRICTWE_FIRST , GFX_RADAR_DISTRICTWE_LAST , 3 } ,
{ GFX_WINDSACK_INTERCON_FIRST , GFX_WINDSACK_INTERCON_LAST , 1 }
} ;
2004-09-10 19:02:27 +00:00
2006-08-31 07:01:26 +00:00
StationGfx gfx = GetStationGfx ( tile ) ;
2006-06-25 13:42:37 +00:00
2007-02-18 11:27:09 +00:00
for ( const AnimData * i = data ; i ! = endof ( data ) ; i + + ) {
2006-08-31 07:01:26 +00:00
if ( i - > from < = gfx & & gfx < = i - > to ) {
if ( ( _tick_counter & i - > delay ) = = 0 ) {
SetStationGfx ( tile , gfx < i - > to ? gfx + 1 : i - > from ) ;
MarkTileDirtyByTile ( tile ) ;
}
break ;
2006-06-25 13:42:37 +00:00
}
2004-08-09 17:04:08 +00:00
}
}
2006-02-18 14:41:24 +00:00
2005-06-24 12:38:35 +00:00
static void ClickTile_Station ( TileIndex tile )
2004-08-09 17:04:08 +00:00
{
2006-03-26 14:41:39 +00:00
if ( IsHangar ( tile ) ) {
2007-03-08 16:27:54 +00:00
ShowDepotWindow ( tile , VEH_AIRCRAFT ) ;
2004-08-09 17:04:08 +00:00
} else {
2006-03-24 08:55:08 +00:00
ShowStationViewWindow ( GetStationIndex ( tile ) ) ;
2004-08-09 17:04:08 +00:00
}
}
static const byte _enter_station_speedtable [ 12 ] = {
215 , 195 , 175 , 155 , 135 , 115 , 95 , 75 , 55 , 35 , 15 , 0
} ;
2005-06-24 12:38:35 +00:00
static uint32 VehicleEnter_Station ( Vehicle * v , TileIndex tile , int x , int y )
2004-08-09 17:04:08 +00:00
{
2007-03-08 16:27:54 +00:00
if ( v - > type = = VEH_TRAIN ) {
2006-03-26 14:41:39 +00:00
if ( IsRailwayStation ( tile ) & & IsFrontEngine ( v ) & &
2006-09-05 23:21:41 +00:00
! IsCompatibleTrainStationTile ( tile + TileOffsByDiagDir ( DirToDiagDir ( v - > direction ) ) , tile ) ) {
2006-03-24 08:55:08 +00:00
StationID station_id = GetStationIndex ( tile ) ;
2004-09-10 19:02:27 +00:00
2004-12-05 12:43:04 +00:00
if ( ( ! ( v - > current_order . flags & OF_NON_STOP ) & & ! _patches . new_nonstop ) | |
2006-09-03 08:25:27 +00:00
( v - > current_order . type = = OT_GOTO_STATION & & v - > current_order . dest = = station_id ) ) {
2004-12-05 12:43:04 +00:00
if ( ! ( _patches . new_nonstop & & v - > current_order . flags & OF_NON_STOP ) & &
v - > current_order . type ! = OT_LEAVESTATION & &
v - > last_station_visited ! = station_id ) {
2006-04-09 08:25:43 +00:00
DiagDirection dir = DirToDiagDir ( v - > direction ) ;
2006-02-06 09:18:04 +00:00
2004-08-09 17:04:08 +00:00
x & = 0xF ;
y & = 0xF ;
2004-09-10 19:02:27 +00:00
2007-02-22 08:43:02 +00:00
if ( DiagDirToAxis ( dir ) ! = AXIS_X ) Swap ( x , y ) ;
2006-04-23 19:35:36 +00:00
if ( y = = TILE_SIZE / 2 ) {
if ( dir ! = DIAGDIR_SE & & dir ! = DIAGDIR_SW ) x = TILE_SIZE - 1 - x ;
2007-02-13 10:26:53 +00:00
if ( x = = 12 ) return VETSB_ENTERED_STATION | ( station_id < < VETS_STATION_ID_OFFSET ) ; /* enter station */
2004-08-09 17:04:08 +00:00
if ( x < 12 ) {
2005-11-14 19:48:04 +00:00
uint16 spd ;
2004-08-09 17:04:08 +00:00
v - > vehstatus | = VS_TRAIN_SLOWING ;
spd = _enter_station_speedtable [ x ] ;
2005-11-14 19:48:04 +00:00
if ( spd < v - > cur_speed ) v - > cur_speed = spd ;
2004-08-09 17:04:08 +00:00
}
}
}
2004-09-10 19:02:27 +00:00
}
2004-08-09 17:04:08 +00:00
}
2007-03-08 16:27:54 +00:00
} else if ( v - > type = = VEH_ROAD ) {
2007-02-19 13:45:13 +00:00
if ( v - > u . road . state < RVSB_IN_ROAD_STOP & & ! IsReversingRoadTrackdir ( ( Trackdir ) v - > u . road . state ) & & v - > u . road . frame = = 0 ) {
2007-06-11 14:00:16 +00:00
if ( IsRoadStop ( tile ) & & IsRoadVehFront ( v ) ) {
2005-11-17 10:12:21 +00:00
/* Attempt to allocate a parking bay in a road stop */
2005-01-29 19:41:44 +00:00
RoadStop * rs = GetRoadStopByTile ( tile , GetRoadStopType ( tile ) ) ;
2004-08-09 17:04:08 +00:00
2007-02-14 16:37:16 +00:00
if ( IsDriveThroughStopTile ( tile ) ) {
/* Vehicles entering a drive-through stop from the 'normal' side use first bay (bay 0). */
byte side = ( ( DirToDiagDir ( v - > direction ) = = ReverseDiagDir ( GetRoadStopDir ( tile ) ) ) = = ( v - > u . road . overtaking = = 0 ) ) ? 0 : 1 ;
if ( ! rs - > IsFreeBay ( side ) ) return VETSB_CANNOT_ENTER ;
/* Check if the vehicle is stopping at this road stop */
2007-03-18 22:07:44 +00:00
if ( GetRoadStopType ( tile ) = = ( IsCargoInClass ( v - > cargo_type , CC_PASSENGERS ) ? RoadStop : : BUS : RoadStop : : TRUCK ) & &
2007-02-14 16:37:16 +00:00
v - > current_order . dest = = GetStationIndex ( tile ) ) {
SETBIT ( v - > u . road . state , RVS_IS_STOPPING ) ;
rs - > AllocateDriveThroughBay ( side ) ;
}
/* Indicate if vehicle is using second bay. */
if ( side = = 1 ) SETBIT ( v - > u . road . state , RVS_USING_SECOND_BAY ) ;
/* Indicate a drive-through stop */
SETBIT ( v - > u . road . state , RVS_IN_DT_ROAD_STOP ) ;
return VETSB_CONTINUE ;
}
/* For normal (non drive-through) road stops */
2007-08-24 19:19:18 +00:00
/* Check if station is busy or if there are no free bays or whether it is a articulated vehicle. */
if ( rs - > IsEntranceBusy ( ) | | ! rs - > HasFreeBay ( ) | | RoadVehHasArticPart ( v ) ) return VETSB_CANNOT_ENTER ;
2004-08-09 17:04:08 +00:00
2007-02-13 22:27:27 +00:00
SETBIT ( v - > u . road . state , RVS_IN_ROAD_STOP ) ;
2005-11-17 10:12:21 +00:00
2007-02-13 00:25:42 +00:00
/* Allocate a bay and update the road state */
uint bay_nr = rs - > AllocateBay ( ) ;
2007-02-13 22:27:27 +00:00
SB ( v - > u . road . state , RVS_USING_SECOND_BAY , 1 , bay_nr ) ;
2005-01-29 19:41:44 +00:00
2007-02-13 00:25:42 +00:00
/* Mark the station entrace as busy */
rs - > SetEntranceBusy ( true ) ;
2004-08-09 17:04:08 +00:00
}
}
}
2004-09-10 19:02:27 +00:00
2007-02-13 10:26:53 +00:00
return VETSB_CONTINUE ;
2004-08-09 17:04:08 +00:00
}
/* this function is called for one station each tick */
static void StationHandleBigTick ( Station * st )
{
UpdateStationAcceptance ( st , true ) ;
2007-01-14 19:18:50 +00:00
if ( st - > facilities = = 0 & & + + st - > delete_ctr > = 8 ) delete st ;
2005-01-30 22:04:14 +00:00
2004-08-09 17:04:08 +00:00
}
2004-11-24 13:19:48 +00:00
static inline void byte_inc_sat ( byte * p ) { byte b = * p + 1 ; if ( b ! = 0 ) * p = b ; }
2004-08-09 17:04:08 +00:00
static void UpdateStationRating ( Station * st )
{
bool waiting_changed = false ;
byte_inc_sat ( & st - > time_since_load ) ;
byte_inc_sat ( & st - > time_since_unload ) ;
2007-02-18 11:27:09 +00:00
GoodsEntry * ge = st - > goods ;
2004-08-09 17:04:08 +00:00
do {
2007-03-08 20:50:27 +00:00
/* Slowly increase the rating back to his original level in the case we
* didn ' t deliver cargo yet to this station . This happens when a bribe
* failed while you didn ' t moved that cargo yet to a station . */
2007-08-26 13:55:36 +00:00
if ( ! HASBIT ( ge - > acceptance_pickup , GoodsEntry : : PICKUP ) & & ge - > rating < INITIAL_STATION_RATING ) {
2007-03-08 20:50:27 +00:00
ge - > rating + + ;
2007-08-26 13:55:36 +00:00
}
2007-03-08 20:50:27 +00:00
/* Only change the rating if we are moving this cargo */
2007-08-26 13:55:36 +00:00
if ( HASBIT ( ge - > acceptance_pickup , GoodsEntry : : PICKUP ) ) {
2004-08-09 17:04:08 +00:00
byte_inc_sat ( & ge - > days_since_pickup ) ;
2007-02-18 11:27:09 +00:00
int rating = 0 ;
2004-08-09 17:04:08 +00:00
{
int b = ge - > last_speed ;
if ( ( b - = 85 ) > = 0 )
rating + = b > > 2 ;
}
{
byte age = ge - > last_age ;
( age > = 3 ) | |
( rating + = 10 , age > = 2 ) | |
( rating + = 10 , age > = 1 ) | |
( rating + = 13 , true ) ;
}
2006-10-14 22:31:18 +00:00
if ( IsValidPlayer ( st - > owner ) & & HASBIT ( st - > town - > statues , st - > owner ) ) rating + = 26 ;
2004-08-09 17:04:08 +00:00
{
byte days = ge - > days_since_pickup ;
2007-03-08 16:27:54 +00:00
if ( st - > last_vehicle_type = = VEH_SHIP )
2004-08-09 17:04:08 +00:00
days > > = 2 ;
( days > 21 ) | |
( rating + = 25 , days > 12 ) | |
( rating + = 25 , days > 6 ) | |
( rating + = 45 , days > 3 ) | |
( rating + = 35 , true ) ;
}
2004-09-10 19:02:27 +00:00
2007-06-22 11:58:59 +00:00
uint waiting = ge - > cargo . Count ( ) ;
2007-02-18 11:27:09 +00:00
( rating - = 90 , waiting > 1500 ) | |
( rating + = 55 , waiting > 1000 ) | |
( rating + = 35 , waiting > 600 ) | |
( rating + = 10 , waiting > 300 ) | |
( rating + = 20 , waiting > 100 ) | |
( rating + = 10 , true ) ;
2004-08-09 17:04:08 +00:00
{
2007-01-10 18:56:51 +00:00
int or_ = ge - > rating ; // old rating
2004-08-09 17:04:08 +00:00
// only modify rating in steps of -2, -1, 0, 1 or 2
2007-01-10 18:56:51 +00:00
ge - > rating = rating = or_ + clamp ( clamp ( rating , 0 , 255 ) - or_ , - 2 , 2 ) ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
// if rating is <= 64 and more than 200 items waiting, remove some random amount of goods from the station
if ( rating < = 64 & & waiting > = 200 ) {
int dec = Random ( ) & 0x1F ;
if ( waiting < 400 ) dec & = 7 ;
waiting - = dec + 1 ;
waiting_changed = true ;
}
// if rating is <= 127 and there are any items waiting, maybe remove some goods.
if ( rating < = 127 & & waiting ! = 0 ) {
uint32 r = Random ( ) ;
2007-01-14 18:38:40 +00:00
if ( rating < = ( int ) GB ( r , 0 , 7 ) ) {
2007-06-22 11:58:59 +00:00
/* Need to have int, otherwise it will just overflow etc. */
waiting = max ( ( int ) waiting - ( int ) GB ( r , 8 , 2 ) - 1 , 0 ) ;
2004-08-09 17:04:08 +00:00
waiting_changed = true ;
}
}
2007-07-13 20:46:53 +00:00
/* At some point we really must cap the cargo. Previously this
* was a strict 4095 , but now we ' ll have a less strict , but
* increasingly agressive truncation of the amount of cargo . */
static const uint WAITING_CARGO_THRESHOLD = 1 < < 12 ;
static const uint WAITING_CARGO_CUT_FACTOR = 1 < < 6 ;
static const uint MAX_WAITING_CARGO = 1 < < 15 ;
if ( waiting > WAITING_CARGO_THRESHOLD ) {
uint difference = waiting - WAITING_CARGO_THRESHOLD ;
waiting - = ( difference / WAITING_CARGO_CUT_FACTOR ) ;
waiting = min ( waiting , MAX_WAITING_CARGO ) ;
waiting_changed = true ;
}
2007-06-22 11:58:59 +00:00
if ( waiting_changed ) ge - > cargo . Truncate ( waiting ) ;
2004-08-09 17:04:08 +00:00
}
}
} while ( + + ge ! = endof ( st - > goods ) ) ;
2004-09-10 19:02:27 +00:00
2007-02-18 11:27:09 +00:00
StationID index = st - > index ;
2006-06-27 21:25:53 +00:00
if ( waiting_changed ) {
2004-08-09 17:04:08 +00:00
InvalidateWindow ( WC_STATION_VIEW , index ) ;
2006-06-27 21:25:53 +00:00
} else {
2004-08-09 17:04:08 +00:00
InvalidateWindowWidget ( WC_STATION_VIEW , index , 5 ) ;
2006-06-27 21:25:53 +00:00
}
2004-08-09 17:04:08 +00:00
}
/* called for every station each tick */
static void StationHandleSmallTick ( Station * st )
{
2005-11-14 19:48:04 +00:00
if ( st - > facilities = = 0 ) return ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
byte b = st - > delete_ctr + 1 ;
2004-08-09 17:04:08 +00:00
if ( b > = 185 ) b = 0 ;
st - > delete_ctr = b ;
2005-11-14 19:48:04 +00:00
if ( b = = 0 ) UpdateStationRating ( st ) ;
2004-08-09 17:04:08 +00:00
}
2007-03-07 11:47:46 +00:00
void OnTick_Station ( )
2004-08-09 17:04:08 +00:00
{
2005-11-14 19:48:04 +00:00
if ( _game_mode = = GM_EDITOR ) return ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
uint i = _station_tick_ctr ;
2006-12-05 13:58:20 +00:00
if ( + + _station_tick_ctr > GetMaxStationIndex ( ) ) _station_tick_ctr = 0 ;
2004-08-09 17:04:08 +00:00
2006-08-22 18:15:17 +00:00
if ( IsValidStationID ( i ) ) StationHandleBigTick ( GetStation ( i ) ) ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
Station * st ;
FOR_ALL_STATIONS ( st ) StationHandleSmallTick ( st ) ;
2004-08-09 17:04:08 +00:00
}
2007-03-07 11:47:46 +00:00
void StationMonthlyLoop ( )
2004-08-09 17:04:08 +00:00
{
}
2005-10-07 07:35:15 +00:00
void ModifyStationRatingAround ( TileIndex tile , PlayerID owner , int amount , uint radius )
2004-08-09 17:04:08 +00:00
{
Station * st ;
FOR_ALL_STATIONS ( st ) {
2006-08-22 15:33:35 +00:00
if ( st - > owner = = owner & &
2005-01-31 07:23:15 +00:00
DistanceManhattan ( tile , st - > xy ) < = radius ) {
2007-03-21 13:19:01 +00:00
for ( CargoID i = 0 ; i < NUM_CARGO ; i + + ) {
2005-10-23 13:04:44 +00:00
GoodsEntry * ge = & st - > goods [ i ] ;
2007-08-26 13:55:36 +00:00
if ( ge - > acceptance_pickup ! = 0 ) {
2004-08-09 17:04:08 +00:00
ge - > rating = clamp ( ge - > rating + amount , 0 , 255 ) ;
}
}
}
}
}
2007-03-21 13:19:01 +00:00
static void UpdateStationWaiting ( Station * st , CargoID type , uint amount )
2004-08-09 17:04:08 +00:00
{
2007-06-22 11:58:59 +00:00
st - > goods [ type ] . cargo . Append ( new CargoPacket ( st - > index , amount ) ) ;
2004-08-09 17:04:08 +00:00
InvalidateWindow ( WC_STATION_VIEW , st - > index ) ;
2007-06-08 09:35:39 +00:00
st - > MarkTilesDirty ( true ) ;
2004-08-09 17:04:08 +00:00
}
2007-06-27 20:53:25 +00:00
static bool IsUniqueStationName ( const char * name )
{
const Station * st ;
char buf [ 512 ] ;
FOR_ALL_STATIONS ( st ) {
SetDParam ( 0 , st - > index ) ;
GetString ( buf , STR_STATION , lastof ( buf ) ) ;
if ( strcmp ( buf , name ) = = 0 ) return false ;
}
return true ;
}
2005-05-11 00:00:27 +00:00
/** Rename a station
2006-04-10 07:15:58 +00:00
* @ param tile unused
2007-04-17 21:09:38 +00:00
* @ param flags operation to perform
2005-05-11 00:00:27 +00:00
* @ param p1 station ID that is to be renamed
* @ param p2 unused
*/
2007-06-18 10:48:15 +00:00
CommandCost CmdRenameStation ( TileIndex tile , uint32 flags , uint32 p1 , uint32 p2 )
2004-08-09 17:04:08 +00:00
{
2007-06-27 20:53:25 +00:00
if ( ! IsValidStationID ( p1 ) | | StrEmpty ( _cmd_text ) ) return CMD_ERROR ;
2007-02-18 11:27:09 +00:00
Station * st = GetStation ( p1 ) ;
2005-05-07 08:14:06 +00:00
2006-08-22 18:15:17 +00:00
if ( ! CheckOwnership ( st - > owner ) ) return CMD_ERROR ;
2005-05-07 08:14:06 +00:00
2007-06-27 20:53:25 +00:00
if ( ! IsUniqueStationName ( _cmd_text ) ) return_cmd_error ( STR_NAME_MUST_BE_UNIQUE ) ;
StringID str = AllocateName ( _cmd_text , 6 ) ;
2005-05-11 00:00:27 +00:00
if ( str = = 0 ) return CMD_ERROR ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
2005-11-14 19:48:04 +00:00
StringID old_str = st - > string_id ;
2004-08-09 17:04:08 +00:00
st - > string_id = str ;
UpdateStationVirtCoord ( st ) ;
DeleteName ( old_str ) ;
2006-05-11 10:33:58 +00:00
ResortStationLists ( ) ;
2004-08-09 17:04:08 +00:00
MarkWholeScreenDirty ( ) ;
} else {
DeleteName ( str ) ;
}
2007-06-18 19:53:50 +00:00
return CommandCost ( ) ;
2004-08-09 17:04:08 +00:00
}
2007-03-21 13:19:01 +00:00
uint MoveGoodsToStation ( TileIndex tile , int w , int h , CargoID type , uint amount )
2004-08-09 17:04:08 +00:00
{
2006-02-09 06:33:37 +00:00
Station * around [ 8 ] ;
2007-02-18 11:27:09 +00:00
for ( uint i = 0 ; i < lengthof ( around ) ; i + + ) around [ i ] = NULL ;
2006-02-09 06:15:12 +00:00
int w_prod ; //width and height of the "producer" of the cargo
int h_prod ;
2004-12-08 15:46:13 +00:00
int max_rad ;
if ( _patches . modified_catchment ) {
w_prod = w ;
h_prod = h ;
2007-08-31 12:45:21 +00:00
w + = 2 * MAX_CATCHMENT ;
h + = 2 * MAX_CATCHMENT ;
max_rad = MAX_CATCHMENT ;
2004-12-08 15:46:13 +00:00
} else {
2006-02-09 06:15:12 +00:00
w_prod = 0 ;
h_prod = 0 ;
w + = 8 ;
h + = 8 ;
2004-12-08 15:46:13 +00:00
max_rad = 4 ;
}
2004-08-09 17:04:08 +00:00
2005-06-25 16:44:57 +00:00
BEGIN_TILE_LOOP ( cur_tile , w , h , tile - TileDiffXY ( max_rad , max_rad ) )
2004-08-09 17:04:08 +00:00
cur_tile = TILE_MASK ( cur_tile ) ;
2006-02-09 06:15:12 +00:00
if ( ! IsTileType ( cur_tile , MP_STATION ) ) continue ;
2007-02-18 11:27:09 +00:00
Station * st = GetStationByTile ( cur_tile ) ;
2006-02-09 06:15:12 +00:00
2007-02-18 11:27:09 +00:00
for ( uint i = 0 ; i ! = lengthof ( around ) ; i + + ) {
2006-02-09 06:33:37 +00:00
if ( around [ i ] = = NULL ) {
2007-02-01 16:48:38 +00:00
if ( ! st - > IsBuoy ( ) & &
2006-02-09 06:15:12 +00:00
( st - > town - > exclusive_counter = = 0 | | st - > town - > exclusivity = = st - > owner ) & & // check exclusive transport rights
2007-08-26 13:55:36 +00:00
st - > goods [ type ] . rating ! = 0 & & // when you've got the lowest rating you can get, it's better not to give cargo anymore
2007-08-31 17:09:13 +00:00
( ! _patches . selectgoods | | HASBIT ( st - > goods [ type ] . acceptance_pickup , GoodsEntry : : PICKUP ) ) & & // we are servicing the station (or cargo is dumped on all stations)
2007-03-18 22:07:44 +00:00
( ( st - > facilities & ~ FACIL_BUS_STOP ) ! = 0 | | IsCargoInClass ( type , CC_PASSENGERS ) ) & & // if we have other fac. than a bus stop, or the cargo is passengers
( ( st - > facilities & ~ FACIL_TRUCK_STOP ) ! = 0 | | ! IsCargoInClass ( type , CC_PASSENGERS ) ) ) { // if we have other fac. than a cargo bay or the cargo is not passengers
2006-02-09 06:24:53 +00:00
if ( _patches . modified_catchment ) {
// min and max coordinates of the producer relative
2007-08-31 12:45:21 +00:00
const int x_min_prod = max_rad + 1 ;
const int x_max_prod = max_rad + w_prod ;
const int y_min_prod = max_rad + 1 ;
const int y_max_prod = max_rad + h_prod ;
2006-02-09 06:24:53 +00:00
2007-02-18 11:45:56 +00:00
int rad = FindCatchmentRadius ( st ) ;
2006-02-09 06:24:53 +00:00
2007-02-18 11:45:56 +00:00
int x_dist = min ( w_cur - x_min_prod , x_max_prod - w_cur ) ;
2006-02-09 06:24:53 +00:00
if ( w_cur < x_min_prod ) {
x_dist = x_min_prod - w_cur ;
} else if ( w_cur > x_max_prod ) {
x_dist = w_cur - x_max_prod ;
2006-02-09 06:15:12 +00:00
}
2006-02-09 06:24:53 +00:00
2007-02-18 11:45:56 +00:00
int y_dist = min ( h_cur - y_min_prod , y_max_prod - h_cur ) ;
2006-02-09 06:24:53 +00:00
if ( h_cur < y_min_prod ) {
y_dist = y_min_prod - h_cur ;
} else if ( h_cur > y_max_prod ) {
y_dist = h_cur - y_max_prod ;
}
2007-02-18 11:45:56 +00:00
if ( x_dist > rad | | y_dist > rad ) break ;
2006-02-09 06:24:53 +00:00
}
2007-02-18 11:45:56 +00:00
around [ i ] = st ;
2006-02-09 06:24:53 +00:00
}
2006-02-09 06:15:12 +00:00
break ;
2006-02-09 06:33:37 +00:00
} else if ( around [ i ] = = st ) {
2006-02-09 06:15:12 +00:00
break ;
2004-08-09 17:04:08 +00:00
}
}
2005-06-25 16:44:57 +00:00
END_TILE_LOOP ( cur_tile , w , h , tile - TileDiffXY ( max_rad , max_rad ) )
2004-08-09 17:04:08 +00:00
/* no stations around at all? */
2006-02-09 06:33:37 +00:00
if ( around [ 0 ] = = NULL ) return 0 ;
2004-08-09 17:04:08 +00:00
2006-02-09 06:33:37 +00:00
if ( around [ 1 ] = = NULL ) {
2004-08-09 17:04:08 +00:00
/* only one station around */
2007-02-18 11:27:09 +00:00
uint moved = ( amount * around [ 0 ] - > goods [ type ] . rating > > 8 ) + 1 ;
2006-02-09 06:33:37 +00:00
UpdateStationWaiting ( around [ 0 ] , type , moved ) ;
2004-08-09 17:04:08 +00:00
return moved ;
}
/* several stations around, find the two with the highest rating */
2007-02-18 11:27:09 +00:00
Station * st1 = NULL ;
Station * st2 = NULL ;
uint best_rating = 0 ;
uint best_rating2 = 0 ;
2005-01-29 19:41:44 +00:00
2007-02-18 11:27:09 +00:00
for ( uint i = 0 ; i ! = lengthof ( around ) & & around [ i ] ! = NULL ; i + + ) {
2006-02-09 06:33:37 +00:00
if ( around [ i ] - > goods [ type ] . rating > = best_rating ) {
2004-08-09 17:04:08 +00:00
best_rating2 = best_rating ;
st2 = st1 ;
2006-02-09 06:33:37 +00:00
best_rating = around [ i ] - > goods [ type ] . rating ;
st1 = around [ i ] ;
} else if ( around [ i ] - > goods [ type ] . rating > = best_rating2 ) {
best_rating2 = around [ i ] - > goods [ type ] . rating ;
st2 = around [ i ] ;
2004-08-09 17:04:08 +00:00
}
}
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
assert ( st1 ! = NULL ) ;
assert ( st2 ! = NULL ) ;
assert ( best_rating ! = 0 | | best_rating2 ! = 0 ) ;
/* the 2nd highest one gets a penalty */
best_rating2 > > = 1 ;
/* amount given to station 1 */
2007-02-18 11:27:09 +00:00
uint t = ( best_rating * ( amount + 1 ) ) / ( best_rating + best_rating2 ) ;
2004-08-09 17:04:08 +00:00
2007-02-18 11:27:09 +00:00
uint moved = 0 ;
2004-08-09 17:04:08 +00:00
if ( t ! = 0 ) {
2006-02-09 06:15:12 +00:00
moved = t * best_rating / 256 + 1 ;
2004-08-09 17:04:08 +00:00
amount - = t ;
2004-09-10 19:02:27 +00:00
UpdateStationWaiting ( st1 , type , moved ) ;
2004-08-09 17:04:08 +00:00
}
if ( amount ! = 0 ) {
2006-02-09 06:15:12 +00:00
amount = amount * best_rating2 / 256 + 1 ;
moved + = amount ;
2004-08-09 17:04:08 +00:00
UpdateStationWaiting ( st2 , type , amount ) ;
}
return moved ;
}
2005-06-24 12:38:35 +00:00
void BuildOilRig ( TileIndex tile )
2004-08-09 17:04:08 +00:00
{
2007-01-14 19:18:50 +00:00
Station * st = new Station ( ) ;
2004-08-09 17:04:08 +00:00
2005-09-14 22:03:27 +00:00
if ( st = = NULL ) {
2006-12-26 17:36:18 +00:00
DEBUG ( misc , 0 , " Can't allocate station for oilrig at 0x%X, reverting to oilrig only " , tile ) ;
2005-09-14 22:03:27 +00:00
return ;
}
if ( ! GenerateStationName ( st , tile , 2 ) ) {
2006-12-26 17:36:18 +00:00
DEBUG ( misc , 0 , " Can't allocate station-name for oilrig at 0x%X, reverting to oilrig only " , tile ) ;
2005-09-14 22:03:27 +00:00
return ;
}
2004-08-09 17:04:08 +00:00
2005-09-14 22:03:27 +00:00
st - > town = ClosestTownFromTile ( tile , ( uint ) - 1 ) ;
st - > sign . width_1 = 0 ;
2006-03-26 14:41:39 +00:00
MakeOilrig ( tile , st - > index ) ;
2005-09-14 22:03:27 +00:00
st - > owner = OWNER_NONE ;
st - > airport_flags = 0 ;
st - > airport_type = AT_OILRIG ;
st - > xy = tile ;
st - > bus_stops = NULL ;
st - > truck_stops = NULL ;
st - > airport_tile = tile ;
st - > dock_tile = tile ;
st - > train_tile = 0 ;
st - > had_vehicle_of_type = 0 ;
st - > time_since_load = 255 ;
st - > time_since_unload = 255 ;
st - > delete_ctr = 0 ;
2007-03-08 16:27:54 +00:00
st - > last_vehicle_type = VEH_INVALID ;
2005-09-14 22:03:27 +00:00
st - > facilities = FACIL_AIRPORT | FACIL_DOCK ;
st - > build_date = _date ;
2007-03-21 13:19:01 +00:00
for ( CargoID j = 0 ; j < NUM_CARGO ; j + + ) {
2007-08-26 13:55:36 +00:00
st - > goods [ j ] . acceptance_pickup = 0 ;
2007-06-22 11:58:59 +00:00
st - > goods [ j ] . days_since_pickup = 255 ;
2007-03-08 20:50:27 +00:00
st - > goods [ j ] . rating = INITIAL_STATION_RATING ;
2005-09-14 22:03:27 +00:00
st - > goods [ j ] . last_speed = 0 ;
st - > goods [ j ] . last_age = 255 ;
2004-08-09 17:04:08 +00:00
}
2005-09-14 22:03:27 +00:00
UpdateStationVirtCoordDirty ( st ) ;
UpdateStationAcceptance ( st , false ) ;
2004-08-09 17:04:08 +00:00
}
2005-06-24 12:38:35 +00:00
void DeleteOilRig ( TileIndex tile )
2004-08-09 17:04:08 +00:00
{
2006-03-24 08:55:08 +00:00
Station * st = GetStationByTile ( tile ) ;
2004-08-09 17:04:08 +00:00
2007-01-31 21:42:58 +00:00
MakeWater ( tile ) ;
2004-08-09 17:04:08 +00:00
st - > dock_tile = 0 ;
st - > airport_tile = 0 ;
st - > facilities & = ~ ( FACIL_AIRPORT | FACIL_DOCK ) ;
st - > airport_flags = 0 ;
UpdateStationVirtCoordDirty ( st ) ;
2007-01-14 19:18:50 +00:00
if ( st - > facilities = = 0 ) delete st ;
2004-08-09 17:04:08 +00:00
}
2005-09-18 20:56:44 +00:00
static void ChangeTileOwner_Station ( TileIndex tile , PlayerID old_player , PlayerID new_player )
2004-08-09 17:04:08 +00:00
{
2005-06-04 11:56:32 +00:00
if ( ! IsTileOwner ( tile , old_player ) ) return ;
2004-08-09 17:04:08 +00:00
2006-10-14 15:49:43 +00:00
if ( new_player ! = PLAYER_SPECTATOR ) {
2006-03-24 08:55:08 +00:00
Station * st = GetStationByTile ( tile ) ;
2005-06-04 12:13:24 +00:00
SetTileOwner ( tile , new_player ) ;
2004-08-09 17:04:08 +00:00
st - > owner = new_player ;
2006-05-11 10:33:58 +00:00
RebuildStationLists ( ) ;
2004-08-16 14:48:35 +00:00
InvalidateWindowClasses ( WC_STATION_LIST ) ;
2004-08-09 17:04:08 +00:00
} else {
2007-02-23 00:17:46 +00:00
if ( IsDriveThroughStopTile ( tile ) & & GetStopBuiltOnTownRoad ( tile ) ) {
/* For a drive-through stop on a town-owned road remove the stop and replace the road */
DoCommand ( tile , 0 , ( GetStationType ( tile ) = = STATION_TRUCK ) ? RoadStop : : TRUCK : RoadStop : : BUS , DC_EXEC , CMD_REMOVE_ROAD_STOP ) ;
} else {
DoCommand ( tile , 0 , 0 , DC_EXEC , CMD_LANDSCAPE_CLEAR ) ;
}
2004-08-09 17:04:08 +00:00
}
}
2007-02-23 00:17:46 +00:00
/**
* Check if a drive - through road stop tile can be cleared .
* Road stops built on town - owned roads check the conditions
* that would allow clearing of the original road .
* @ param tile road stop tile to check
* @ return true if the road can be cleared
*/
static bool CanRemoveRoadWithStop ( TileIndex tile )
{
/* The road can always be cleared if it was not a town-owned road */
if ( ! GetStopBuiltOnTownRoad ( tile ) ) return true ;
bool edge_road ;
2007-05-20 19:14:08 +00:00
return CheckAllowRemoveRoad ( tile , GetAnyRoadBits ( tile , ROADTYPE_ROAD ) , OWNER_TOWN , & edge_road , ROADTYPE_ROAD ) & &
CheckAllowRemoveRoad ( tile , GetAnyRoadBits ( tile , ROADTYPE_TRAM ) , OWNER_TOWN , & edge_road , ROADTYPE_TRAM ) ;
2007-02-23 00:17:46 +00:00
}
2007-06-18 10:48:15 +00:00
static CommandCost ClearTile_Station ( TileIndex tile , byte flags )
2005-06-24 12:38:35 +00:00
{
2004-08-09 17:04:08 +00:00
if ( flags & DC_AUTO ) {
2006-03-26 14:41:39 +00:00
switch ( GetStationType ( tile ) ) {
case STATION_RAIL : return_cmd_error ( STR_300B_MUST_DEMOLISH_RAILROAD ) ;
case STATION_AIRPORT : return_cmd_error ( STR_300E_MUST_DEMOLISH_AIRPORT_FIRST ) ;
2007-05-25 22:07:40 +00:00
case STATION_TRUCK : return_cmd_error ( HASBIT ( GetRoadTypes ( tile ) , ROADTYPE_TRAM ) ? STR_3047_MUST_DEMOLISH_CARGO_TRAM_STATION : STR_3047_MUST_DEMOLISH_TRUCK_STATION ) ;
case STATION_BUS : return_cmd_error ( HASBIT ( GetRoadTypes ( tile ) , ROADTYPE_TRAM ) ? STR_3046_MUST_DEMOLISH_PASSENGER_TRAM_STATION : STR_3046_MUST_DEMOLISH_BUS_STATION ) ;
2006-03-26 14:41:39 +00:00
case STATION_BUOY : return_cmd_error ( STR_306A_BUOY_IN_THE_WAY ) ;
case STATION_DOCK : return_cmd_error ( STR_304D_MUST_DEMOLISH_DOCK_FIRST ) ;
case STATION_OILRIG :
SetDParam ( 0 , STR_4807_OIL_RIG ) ;
return_cmd_error ( STR_4800_IN_THE_WAY ) ;
}
2004-08-09 17:04:08 +00:00
}
2007-02-18 11:27:09 +00:00
Station * st = GetStationByTile ( tile ) ;
2004-08-09 17:04:08 +00:00
2006-03-26 14:41:39 +00:00
switch ( GetStationType ( tile ) ) {
case STATION_RAIL : return RemoveRailroadStation ( st , tile , flags ) ;
case STATION_AIRPORT : return RemoveAirport ( st , flags ) ;
case STATION_TRUCK :
2007-02-23 00:17:46 +00:00
if ( IsDriveThroughStopTile ( tile ) & & ! CanRemoveRoadWithStop ( tile ) )
2007-02-14 16:37:16 +00:00
return_cmd_error ( STR_3047_MUST_DEMOLISH_TRUCK_STATION ) ;
return RemoveRoadStop ( st , flags , tile ) ;
case STATION_BUS :
2007-02-23 00:17:46 +00:00
if ( IsDriveThroughStopTile ( tile ) & & ! CanRemoveRoadWithStop ( tile ) )
2007-02-14 16:37:16 +00:00
return_cmd_error ( STR_3046_MUST_DEMOLISH_BUS_STATION ) ;
return RemoveRoadStop ( st , flags , tile ) ;
2006-03-26 14:41:39 +00:00
case STATION_BUOY : return RemoveBuoy ( st , flags ) ;
case STATION_DOCK : return RemoveDock ( st , flags ) ;
default : break ;
}
2004-08-09 17:04:08 +00:00
return CMD_ERROR ;
}
2007-03-07 11:47:46 +00:00
void InitializeStations ( )
2004-08-09 17:04:08 +00:00
{
2005-02-03 17:22:35 +00:00
/* Clean the station pool and create 1 block in it */
2007-08-02 10:47:43 +00:00
_Station_pool . CleanPool ( ) ;
_Station_pool . AddBlockToPool ( ) ;
2005-01-06 22:31:58 +00:00
2005-02-04 15:31:30 +00:00
/* Clean the roadstop pool and create 1 block in it */
2007-08-02 10:47:43 +00:00
_RoadStop_pool . CleanPool ( ) ;
_RoadStop_pool . AddBlockToPool ( ) ;
2004-09-14 14:19:53 +00:00
2004-08-09 17:04:08 +00:00
_station_tick_ctr = 0 ;
2004-09-14 14:19:53 +00:00
2004-08-09 17:04:08 +00:00
}
2007-03-07 11:47:46 +00:00
void AfterLoadStations ( )
2006-05-06 21:46:26 +00:00
{
/* Update the speclists of all stations to point to the currently loaded custom stations. */
2007-02-18 11:27:09 +00:00
Station * st ;
2006-05-06 21:46:26 +00:00
FOR_ALL_STATIONS ( st ) {
2007-02-18 11:27:09 +00:00
for ( uint i = 0 ; i < st - > num_specs ; i + + ) {
2006-05-06 21:46:26 +00:00
if ( st - > speclist [ i ] . grfid = = 0 ) continue ;
st - > speclist [ i ] . spec = GetCustomStationSpecByGrf ( st - > speclist [ i ] . grfid , st - > speclist [ i ] . localidx ) ;
}
2007-06-22 11:58:59 +00:00
for ( CargoID c = 0 ; c < NUM_CARGO ; c + + ) st - > goods [ c ] . cargo . InvalidateCache ( ) ;
2006-05-06 21:46:26 +00:00
}
}
2007-08-30 17:17:04 +00:00
static CommandCost TerraformTile_Station ( TileIndex tile , uint32 flags , uint z_new , Slope tileh_new )
{
return DoCommand ( tile , 0 , 0 , flags , CMD_LANDSCAPE_CLEAR ) ;
}
2006-05-06 21:46:26 +00:00
2007-01-10 18:56:51 +00:00
extern const TileTypeProcs _tile_type_station_procs = {
2006-04-15 03:08:14 +00:00
DrawTile_Station , /* draw_tile_proc */
GetSlopeZ_Station , /* get_slope_z_proc */
ClearTile_Station , /* clear_tile_proc */
GetAcceptedCargo_Station , /* get_accepted_cargo_proc */
GetTileDesc_Station , /* get_tile_desc_proc */
GetTileTrackStatus_Station , /* get_tile_track_status_proc */
ClickTile_Station , /* click_tile_proc */
AnimateTile_Station , /* animate_tile_proc */
TileLoop_Station , /* tile_loop_clear */
ChangeTileOwner_Station , /* change_tile_owner_clear */
NULL , /* get_produced_cargo_proc */
VehicleEnter_Station , /* vehicle_enter_tile_proc */
2007-07-26 16:51:10 +00:00
GetFoundation_Station , /* get_foundation_proc */
2007-08-30 17:17:04 +00:00
TerraformTile_Station , /* terraform_tile_proc */
2004-08-09 17:04:08 +00:00
} ;
2005-05-30 22:16:05 +00:00
static const SaveLoad _roadstop_desc [ ] = {
2005-01-29 19:41:44 +00:00
SLE_VAR ( RoadStop , xy , SLE_UINT32 ) ,
2007-01-17 22:32:34 +00:00
SLE_CONDNULL ( 1 , 0 , 44 ) ,
2005-01-29 19:41:44 +00:00
SLE_VAR ( RoadStop , status , SLE_UINT8 ) ,
2005-02-04 15:39:10 +00:00
/* Index was saved in some versions, but this is not needed */
2006-03-16 00:20:33 +00:00
SLE_CONDNULL ( 4 , 0 , 8 ) ,
2007-01-17 21:14:17 +00:00
SLE_CONDNULL ( 2 , 0 , 44 ) ,
2006-04-08 13:50:01 +00:00
SLE_CONDNULL ( 1 , 0 , 25 ) ,
2005-01-29 19:41:44 +00:00
SLE_REF ( RoadStop , next , REF_ROADSTOPS ) ,
2007-01-28 21:54:40 +00:00
SLE_CONDNULL ( 2 , 0 , 44 ) ,
2005-01-29 19:41:44 +00:00
2006-04-03 14:25:32 +00:00
SLE_CONDNULL ( 4 , 0 , 24 ) ,
2006-04-08 05:44:37 +00:00
SLE_CONDNULL ( 1 , 25 , 25 ) ,
2005-01-29 19:41:44 +00:00
SLE_END ( )
} ;
2004-08-09 17:04:08 +00:00
2005-05-30 22:16:05 +00:00
static const SaveLoad _station_desc [ ] = {
2006-08-22 14:38:37 +00:00
SLE_CONDVAR ( Station , xy , SLE_FILE_U16 | SLE_VAR_U32 , 0 , 5 ) ,
SLE_CONDVAR ( Station , xy , SLE_UINT32 , 6 , SL_MAX_VERSION ) ,
2007-01-31 06:25:46 +00:00
SLE_CONDNULL ( 4 , 0 , 5 ) , // bus/lorry tile
2006-08-22 14:38:37 +00:00
SLE_CONDVAR ( Station , train_tile , SLE_FILE_U16 | SLE_VAR_U32 , 0 , 5 ) ,
SLE_CONDVAR ( Station , train_tile , SLE_UINT32 , 6 , SL_MAX_VERSION ) ,
SLE_CONDVAR ( Station , airport_tile , SLE_FILE_U16 | SLE_VAR_U32 , 0 , 5 ) ,
SLE_CONDVAR ( Station , airport_tile , SLE_UINT32 , 6 , SL_MAX_VERSION ) ,
SLE_CONDVAR ( Station , dock_tile , SLE_FILE_U16 | SLE_VAR_U32 , 0 , 5 ) ,
SLE_CONDVAR ( Station , dock_tile , SLE_UINT32 , 6 , SL_MAX_VERSION ) ,
SLE_REF ( Station , town , REF_TOWN ) ,
SLE_VAR ( Station , trainst_w , SLE_UINT8 ) ,
SLE_CONDVAR ( Station , trainst_h , SLE_UINT8 , 2 , SL_MAX_VERSION ) ,
2004-08-09 17:04:08 +00:00
// alpha_order was stored here in savegame format 0 - 3
2006-03-16 00:20:33 +00:00
SLE_CONDNULL ( 1 , 0 , 3 ) ,
2004-08-09 17:04:08 +00:00
2006-08-22 14:38:37 +00:00
SLE_VAR ( Station , string_id , SLE_STRINGID ) ,
SLE_VAR ( Station , had_vehicle_of_type , SLE_UINT16 ) ,
2004-08-09 17:04:08 +00:00
2006-08-22 14:38:37 +00:00
SLE_VAR ( Station , time_since_load , SLE_UINT8 ) ,
SLE_VAR ( Station , time_since_unload , SLE_UINT8 ) ,
SLE_VAR ( Station , delete_ctr , SLE_UINT8 ) ,
SLE_VAR ( Station , owner , SLE_UINT8 ) ,
SLE_VAR ( Station , facilities , SLE_UINT8 ) ,
SLE_VAR ( Station , airport_type , SLE_UINT8 ) ,
2005-01-29 19:41:44 +00:00
2007-01-31 05:08:07 +00:00
SLE_CONDNULL ( 2 , 0 , 5 ) , // Truck/bus stop status
2007-01-31 05:01:29 +00:00
SLE_CONDNULL ( 1 , 0 , 4 ) , // Blocked months
2004-08-09 17:04:08 +00:00
2007-02-13 12:34:54 +00:00
SLE_CONDVAR ( Station , airport_flags , SLE_VAR_U64 | SLE_FILE_U16 , 0 , 2 ) ,
SLE_CONDVAR ( Station , airport_flags , SLE_VAR_U64 | SLE_FILE_U32 , 3 , 45 ) ,
SLE_CONDVAR ( Station , airport_flags , SLE_UINT64 , 46 , SL_MAX_VERSION ) ,
2004-08-09 17:04:08 +00:00
2006-04-18 08:50:17 +00:00
SLE_CONDNULL ( 2 , 0 , 25 ) , /* Ex last-vehicle */
2006-08-22 14:38:37 +00:00
SLE_CONDVAR ( Station , last_vehicle_type , SLE_UINT8 , 26 , SL_MAX_VERSION ) ,
2004-08-09 17:04:08 +00:00
2006-04-17 18:47:50 +00:00
// Was custom station class and id
SLE_CONDNULL ( 2 , 3 , 25 ) ,
2006-08-22 14:38:37 +00:00
SLE_CONDVAR ( Station , build_date , SLE_FILE_U16 | SLE_VAR_I32 , 3 , 30 ) ,
SLE_CONDVAR ( Station , build_date , SLE_INT32 , 31 , SL_MAX_VERSION ) ,
2004-08-09 17:04:08 +00:00
2006-08-22 14:38:37 +00:00
SLE_CONDREF ( Station , bus_stops , REF_ROADSTOPS , 6 , SL_MAX_VERSION ) ,
SLE_CONDREF ( Station , truck_stops , REF_ROADSTOPS , 6 , SL_MAX_VERSION ) ,
2005-01-29 19:41:44 +00:00
2006-04-28 20:48:45 +00:00
/* Used by newstations for graphic variations */
2006-08-22 14:38:37 +00:00
SLE_CONDVAR ( Station , random_bits , SLE_UINT16 , 27 , SL_MAX_VERSION ) ,
SLE_CONDVAR ( Station , waiting_triggers , SLE_UINT8 , 27 , SL_MAX_VERSION ) ,
SLE_CONDVAR ( Station , num_specs , SLE_UINT8 , 27 , SL_MAX_VERSION ) ,
2006-04-28 20:48:45 +00:00
2007-04-20 08:00:30 +00:00
SLE_CONDLST ( Station , loading_vehicles , REF_VEHICLE , 57 , SL_MAX_VERSION ) ,
2006-03-16 00:20:33 +00:00
// reserve extra space in savegame here. (currently 32 bytes)
SLE_CONDNULL ( 32 , 2 , SL_MAX_VERSION ) ,
2004-08-09 17:04:08 +00:00
SLE_END ( )
} ;
2007-06-22 11:58:59 +00:00
static uint16 _waiting_acceptance ;
static uint16 _cargo_source ;
static uint32 _cargo_source_xy ;
static uint16 _cargo_days ;
static Money _cargo_feeder_share ;
2006-05-06 21:46:26 +00:00
static const SaveLoad _station_speclist_desc [ ] = {
SLE_CONDVAR ( StationSpecList , grfid , SLE_UINT32 , 27 , SL_MAX_VERSION ) ,
SLE_CONDVAR ( StationSpecList , localidx , SLE_UINT8 , 27 , SL_MAX_VERSION ) ,
SLE_END ( )
} ;
2004-08-09 17:04:08 +00:00
2007-08-30 12:10:32 +00:00
void SaveLoad_STNS ( Station * st )
{
static const SaveLoad _goods_desc [ ] = {
SLEG_CONDVAR ( _waiting_acceptance , SLE_UINT16 , 0 , 67 ) ,
SLE_CONDVAR ( GoodsEntry , acceptance_pickup , SLE_UINT8 , 68 , SL_MAX_VERSION ) ,
SLE_CONDNULL ( 2 , 51 , 67 ) ,
SLE_VAR ( GoodsEntry , days_since_pickup , SLE_UINT8 ) ,
SLE_VAR ( GoodsEntry , rating , SLE_UINT8 ) ,
SLEG_CONDVAR ( _cargo_source , SLE_FILE_U8 | SLE_VAR_U16 , 0 , 6 ) ,
SLEG_CONDVAR ( _cargo_source , SLE_UINT16 , 7 , 67 ) ,
SLEG_CONDVAR ( _cargo_source_xy , SLE_UINT32 , 44 , 67 ) ,
SLEG_CONDVAR ( _cargo_days , SLE_UINT8 , 0 , 67 ) ,
SLE_VAR ( GoodsEntry , last_speed , SLE_UINT8 ) ,
SLE_VAR ( GoodsEntry , last_age , SLE_UINT8 ) ,
SLEG_CONDVAR ( _cargo_feeder_share , SLE_FILE_U32 | SLE_VAR_I64 , 14 , 64 ) ,
SLEG_CONDVAR ( _cargo_feeder_share , SLE_INT64 , 65 , 67 ) ,
SLE_CONDLST ( GoodsEntry , cargo . packets , REF_CARGO_PACKET , 68 , SL_MAX_VERSION ) ,
SLE_END ( )
} ;
2004-08-09 17:04:08 +00:00
SlObject ( st , _station_desc ) ;
2007-04-15 16:20:35 +00:00
2007-06-22 11:58:59 +00:00
_waiting_acceptance = 0 ;
2007-04-15 16:20:35 +00:00
uint num_cargo = CheckSavegameVersion ( 55 ) ? 12 : NUM_CARGO ;
for ( CargoID i = 0 ; i < num_cargo ; i + + ) {
2007-06-22 11:58:59 +00:00
GoodsEntry * ge = & st - > goods [ i ] ;
SlObject ( ge , _goods_desc ) ;
2007-06-22 17:34:04 +00:00
if ( CheckSavegameVersion ( 68 ) ) {
2007-08-26 13:55:36 +00:00
SB ( ge - > acceptance_pickup , GoodsEntry : : ACCEPTANCE , 1 , HASBIT ( _waiting_acceptance , 15 ) ) ;
2007-06-22 11:58:59 +00:00
if ( GB ( _waiting_acceptance , 0 , 12 ) ! = 0 ) {
/* Don't construct the packet with station here, because that'll fail with old savegames */
CargoPacket * cp = new CargoPacket ( ) ;
/* In old versions, enroute_from used 0xFF as INVALID_STATION */
cp - > source = ( CheckSavegameVersion ( 7 ) & & _cargo_source = = 0xFF ) ? INVALID_STATION : _cargo_source ;
cp - > count = GB ( _waiting_acceptance , 0 , 12 ) ;
cp - > days_in_transit = _cargo_days ;
cp - > feeder_share = _cargo_feeder_share ;
cp - > source_xy = _cargo_source_xy ;
cp - > days_in_transit = _cargo_days ;
cp - > feeder_share = _cargo_feeder_share ;
2007-08-26 13:55:36 +00:00
SB ( ge - > acceptance_pickup , GoodsEntry : : PICKUP , 1 , 1 ) ;
2007-06-22 11:58:59 +00:00
ge - > cargo . Append ( cp ) ;
}
}
2005-02-02 16:16:43 +00:00
}
2006-05-06 21:46:26 +00:00
if ( st - > num_specs ! = 0 ) {
/* Allocate speclist memory when loading a game */
2007-01-11 17:29:39 +00:00
if ( st - > speclist = = NULL ) st - > speclist = CallocT < StationSpecList > ( st - > num_specs ) ;
2007-02-18 11:27:09 +00:00
for ( uint i = 0 ; i < st - > num_specs ; i + + ) {
SlObject ( & st - > speclist [ i ] , _station_speclist_desc ) ;
}
2006-05-06 21:46:26 +00:00
}
2004-08-09 17:04:08 +00:00
}
2007-03-07 11:47:46 +00:00
static void Save_STNS ( )
2004-08-09 17:04:08 +00:00
{
Station * st ;
2005-01-06 22:31:58 +00:00
// Write the stations
2004-08-09 17:04:08 +00:00
FOR_ALL_STATIONS ( st ) {
2006-08-22 15:33:35 +00:00
SlSetArrayIndex ( st - > index ) ;
SlAutolength ( ( AutolengthProc * ) SaveLoad_STNS , st ) ;
2004-08-09 17:04:08 +00:00
}
}
2007-03-07 11:47:46 +00:00
static void Load_STNS ( )
2004-08-09 17:04:08 +00:00
{
int index ;
while ( ( index = SlIterateArray ( ) ) ! = - 1 ) {
2007-01-14 19:18:50 +00:00
Station * st = new ( index ) Station ( ) ;
2005-01-06 22:31:58 +00:00
2004-08-09 17:04:08 +00:00
SaveLoad_STNS ( st ) ;
// this means it's an oldstyle savegame without support for nonuniform stations
2005-11-14 19:48:04 +00:00
if ( st - > train_tile ! = 0 & & st - > trainst_h = = 0 ) {
2006-02-18 14:41:24 +00:00
uint w = GB ( st - > trainst_w , 4 , 4 ) ;
uint h = GB ( st - > trainst_w , 0 , 4 ) ;
2005-11-14 19:48:04 +00:00
2007-02-22 08:43:02 +00:00
if ( GetRailStationAxis ( st - > train_tile ) ! = AXIS_X ) Swap ( w , h ) ;
2004-08-09 17:04:08 +00:00
st - > trainst_w = w ;
st - > trainst_h = h ;
}
}
2005-01-06 22:31:58 +00:00
2005-03-09 19:09:04 +00:00
/* This is to ensure all pointers are within the limits of _stations_size */
2006-12-05 13:58:20 +00:00
if ( _station_tick_ctr > GetMaxStationIndex ( ) ) _station_tick_ctr = 0 ;
2004-08-09 17:04:08 +00:00
}
2007-03-07 11:47:46 +00:00
static void Save_ROADSTOP ( )
2005-01-29 19:41:44 +00:00
{
2005-02-04 15:31:30 +00:00
RoadStop * rs ;
2005-01-29 19:41:44 +00:00
2005-02-04 15:31:30 +00:00
FOR_ALL_ROADSTOPS ( rs ) {
2006-08-22 15:33:35 +00:00
SlSetArrayIndex ( rs - > index ) ;
SlObject ( rs , _roadstop_desc ) ;
2005-01-29 19:41:44 +00:00
}
}
2007-03-07 11:47:46 +00:00
static void Load_ROADSTOP ( )
2005-01-29 19:41:44 +00:00
{
int index ;
2005-02-04 15:31:30 +00:00
while ( ( index = SlIterateArray ( ) ) ! = - 1 ) {
2007-01-17 21:14:17 +00:00
RoadStop * rs = new ( index ) RoadStop ( INVALID_TILE ) ;
2005-02-04 15:31:30 +00:00
SlObject ( rs , _roadstop_desc ) ;
}
2005-01-29 19:41:44 +00:00
}
2007-01-10 18:56:51 +00:00
extern const ChunkHandler _station_chunk_handlers [ ] = {
2005-01-29 19:41:44 +00:00
{ ' STNS ' , Save_STNS , Load_STNS , CH_ARRAY } ,
{ ' ROAD ' , Save_ROADSTOP , Load_ROADSTOP , CH_ARRAY | CH_LAST } ,
2004-08-09 17:04:08 +00:00
} ;