Changeset - r18858:db5888e8ffaa
[Not reviewed]
master
0 1 0
rubidium - 13 years ago 2012-01-02 20:39:18
rubidium@openttd.org
(svn r23717) -Fix [FS#4927]: ships going to wrong dock location when moving the dock while the game is paused
1 file changed with 15 insertions and 0 deletions:
0 comments (0 inline, 0 general)
src/station_cmd.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file station_cmd.cpp Handling of station tiles. */
 

	
 
#include "stdafx.h"
 
#include "aircraft.h"
 
#include "bridge_map.h"
 
#include "cmd_helper.h"
 
#include "viewport_func.h"
 
#include "command_func.h"
 
#include "town.h"
 
#include "news_func.h"
 
#include "train.h"
 
#include "ship.h"
 
#include "roadveh.h"
 
#include "industry.h"
 
#include "newgrf_cargo.h"
 
#include "newgrf_debug.h"
 
#include "newgrf_station.h"
 
#include "newgrf_canal.h" /* For the buoy */
 
#include "pathfinder/yapf/yapf_cache.h"
 
#include "road_internal.h" /* For drawing catenary/checking road removal */
 
#include "autoslope.h"
 
#include "water.h"
 
#include "station_gui.h"
 
#include "strings_func.h"
 
#include "clear_func.h"
 
#include "window_func.h"
 
#include "date_func.h"
 
#include "vehicle_func.h"
 
#include "string_func.h"
 
#include "animated_tile_func.h"
 
#include "elrail_func.h"
 
#include "station_base.h"
 
#include "roadstop_base.h"
 
#include "newgrf_railtype.h"
 
#include "waypoint_base.h"
 
#include "waypoint_func.h"
 
#include "pbs.h"
 
#include "debug.h"
 
#include "core/random_func.hpp"
 
#include "company_base.h"
 
#include "table/airporttile_ids.h"
 
#include "newgrf_airporttiles.h"
 
#include "order_backup.h"
 
#include "newgrf_house.h"
 
#include "company_gui.h"
 

	
 
#include "table/strings.h"
 

	
 
/**
 
 * 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));
 

	
 
	/* If the tile isn't an airport there's no chance it's a hangar. */
 
	if (!IsAirport(t)) return false;
 

	
 
	const Station *st = Station::GetByTile(t);
 
	const AirportSpec *as = st->airport.GetSpec();
 

	
 
	for (uint i = 0; i < as->nof_depots; i++) {
 
		if (st->airport.GetHangarTile(i) == t) return true;
 
	}
 

	
 
	return false;
 
}
 

	
 
/**
 
 * Look for a station around the given tile area.
 
 * @param ta the area to search over
 
 * @param closest_station the closest station found so far
 
 * @param st to 'return' the found station
 
 * @return Succeeded command (if zero or one station found) or failed command (for two or more stations found).
 
 */
 
template <class T>
 
CommandCost GetStationAround(TileArea ta, StationID closest_station, T **st)
 
{
 
	ta.tile -= TileDiffXY(1, 1);
 
	ta.w    += 2;
 
	ta.h    += 2;
 

	
 
	/* check around to see if there's any stations there */
 
	TILE_AREA_LOOP(tile_cur, ta) {
 
		if (IsTileType(tile_cur, MP_STATION)) {
 
			StationID t = GetStationIndex(tile_cur);
 
			if (!T::IsValidID(t)) continue;
 

	
 
			if (closest_station == INVALID_STATION) {
 
				closest_station = t;
 
			} else if (closest_station != t) {
 
				return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING);
 
			}
 
		}
 
	}
 
	*st = (closest_station == INVALID_STATION) ? NULL : T::Get(closest_station);
 
	return CommandCost();
 
}
 

	
 
/**
 
 * 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);
 
@@ -2428,217 +2429,231 @@ CommandCost CmdBuildDock(TileIndex tile,
 
	}
 

	
 
	if (MayHaveBridgeAbove(tile_cur) && IsBridgeAbove(tile_cur)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST);
 

	
 
	/* Get the water class of the water tile before it is cleared.*/
 
	WaterClass wc = GetWaterClass(tile_cur);
 

	
 
	ret = DoCommand(tile_cur, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
	if (ret.Failed()) return ret;
 

	
 
	tile_cur += TileOffsByDiagDir(direction);
 
	if (!IsTileType(tile_cur, MP_WATER) || GetTileSlope(tile_cur) != SLOPE_FLAT) {
 
		return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
 
	}
 

	
 
	/* middle */
 
	Station *st = NULL;
 
	ret = FindJoiningStation(INVALID_STATION, station_to_join, HasBit(p1, 0),
 
			TileArea(tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]),
 
					_dock_w_chk[direction], _dock_h_chk[direction]), &st);
 
	if (ret.Failed()) return ret;
 

	
 
	/* Distant join */
 
	if (st == NULL && distant_join) st = Station::GetIfValid(station_to_join);
 

	
 
	/* Find a deleted station close to us */
 
	if (st == NULL && reuse) st = GetClosestDeletedStation(tile);
 

	
 
	if (st != NULL) {
 
		if (st->owner != _current_company) {
 
			return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION);
 
		}
 

	
 
		CommandCost ret = st->rect.BeforeAddRect(
 
				tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]),
 
				_dock_w_chk[direction], _dock_h_chk[direction], StationRect::ADD_TEST);
 
		if (ret.Failed()) return ret;
 

	
 
		if (st->dock_tile != INVALID_TILE) return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK);
 
	} else {
 
		/* allocate and initialize new station */
 
		if (!Station::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);
 

	
 
		if (flags & DC_EXEC) {
 
			st = new Station(tile);
 

	
 
			st->town = ClosestTownFromTile(tile, UINT_MAX);
 
			st->string_id = GenerateStationName(st, tile, STATIONNAMING_DOCK);
 

	
 
			if (Company::IsValidID(_current_company)) {
 
				SetBit(st->town->have_ratings, _current_company);
 
			}
 
		}
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		st->dock_tile = tile;
 
		st->AddFacility(FACIL_DOCK, tile);
 

	
 
		st->rect.BeforeAddRect(
 
				tile + ToTileIndexDiff(_dock_tileoffs_chkaround[direction]),
 
				_dock_w_chk[direction], _dock_h_chk[direction], StationRect::ADD_TRY);
 

	
 
		/* If the water part of the dock is on a canal, update infrastructure counts.
 
		 * This is needed as we've unconditionally cleared that tile before. */
 
		if (wc == WATER_CLASS_CANAL) {
 
			Company::Get(st->owner)->infrastructure.water++;
 
		}
 
		Company::Get(st->owner)->infrastructure.station += 2;
 
		DirtyCompanyInfrastructureWindows(st->owner);
 

	
 
		MakeDock(tile, st->owner, st->index, direction, wc);
 

	
 
		st->UpdateVirtCoord();
 
		UpdateStationAcceptance(st, false);
 
		st->RecomputeIndustriesNear();
 
		InvalidateWindowData(WC_SELECT_STATION, 0, 0);
 
		InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
 
		SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_SHIPS);
 
	}
 

	
 
	return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_STATION_DOCK]);
 
}
 

	
 
/**
 
 * Remove a dock
 
 * @param tile TileIndex been queried
 
 * @param flags operation to perform
 
 * @return cost or failure of operation
 
 */
 
static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags)
 
{
 
	Station *st = Station::GetByTile(tile);
 
	CommandCost ret = CheckOwnership(st->owner);
 
	if (ret.Failed()) return ret;
 

	
 
	TileIndex docking_location = TILE_ADD(st->dock_tile, ToTileIndexDiff(GetDockOffset(st->dock_tile)));
 

	
 
	TileIndex tile1 = st->dock_tile;
 
	TileIndex tile2 = tile1 + TileOffsByDiagDir(GetDockDirection(tile1));
 

	
 
	ret = EnsureNoVehicleOnGround(tile1);
 
	if (ret.Succeeded()) ret = EnsureNoVehicleOnGround(tile2);
 
	if (ret.Failed()) return ret;
 

	
 
	if (flags & DC_EXEC) {
 
		DoClearSquare(tile1);
 
		MarkTileDirtyByTile(tile1);
 
		MakeWaterKeepingClass(tile2, st->owner);
 

	
 
		st->rect.AfterRemoveTile(st, tile1);
 
		st->rect.AfterRemoveTile(st, tile2);
 

	
 
		st->dock_tile = INVALID_TILE;
 
		st->facilities &= ~FACIL_DOCK;
 

	
 
		Company::Get(st->owner)->infrastructure.station -= 2;
 
		DirtyCompanyInfrastructureWindows(st->owner);
 

	
 
		SetWindowWidgetDirty(WC_STATION_VIEW, st->index, WID_SV_SHIPS);
 
		st->UpdateVirtCoord();
 
		st->RecomputeIndustriesNear();
 
		DeleteStationIfEmpty(st);
 

	
 
		/* All ships that were going to our station, can't go to it anymore.
 
		 * Just clear the order, then automatically the next appropriate order
 
		 * will be selected and in case of no appropriate order it will just
 
		 * wander around the world. */
 
		Ship *s;
 
		FOR_ALL_SHIPS(s) {
 
			if (s->dest_tile == docking_location) {
 
				s->dest_tile = 0;
 
				s->current_order.Free();
 
			}
 
		}
 
	}
 

	
 
	return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_STATION_DOCK]);
 
}
 

	
 
#include "table/station_land.h"
 

	
 
const DrawTileSprites *GetStationTileLayout(StationType st, byte gfx)
 
{
 
	return &_station_display_datas[st][gfx];
 
}
 

	
 
static void DrawTile_Station(TileInfo *ti)
 
{
 
	const NewGRFSpriteLayout *layout = NULL;
 
	DrawTileSprites tmp_rail_layout;
 
	const DrawTileSprites *t = NULL;
 
	RoadTypes roadtypes;
 
	int32 total_offset;
 
	const RailtypeInfo *rti = NULL;
 
	uint32 relocation = 0;
 
	uint32 ground_relocation = 0;
 
	BaseStation *st = NULL;
 
	const StationSpec *statspec = NULL;
 
	uint tile_layout = 0;
 

	
 
	if (HasStationRail(ti->tile)) {
 
		rti = GetRailTypeInfo(GetRailType(ti->tile));
 
		roadtypes = ROADTYPES_NONE;
 
		total_offset = rti->GetRailtypeSpriteOffset();
 

	
 
		if (IsCustomStationSpecIndex(ti->tile)) {
 
			/* look for customization */
 
			st = BaseStation::GetByTile(ti->tile);
 
			statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec;
 

	
 
			if (statspec != NULL) {
 
				tile_layout = GetStationGfx(ti->tile);
 

	
 
				if (HasBit(statspec->callback_mask, CBM_STATION_SPRITE_LAYOUT)) {
 
					uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile);
 
					if (callback != CALLBACK_FAILED) tile_layout = (callback & ~1) + GetRailStationAxis(ti->tile);
 
				}
 

	
 
				/* Ensure the chosen tile layout is valid for this custom station */
 
				if (statspec->renderdata != NULL) {
 
					layout = &statspec->renderdata[tile_layout < statspec->tiles ? tile_layout : (uint)GetRailStationAxis(ti->tile)];
 
					if (!layout->NeedsPreprocessing()) {
 
						t = layout;
 
						layout = NULL;
 
					}
 
				}
 
			}
 
		}
 
	} else {
 
		roadtypes = IsRoadStop(ti->tile) ? GetRoadTypes(ti->tile) : ROADTYPES_NONE;
 
		total_offset = 0;
 
	}
 

	
 
	StationGfx gfx = GetStationGfx(ti->tile);
 
	if (IsAirport(ti->tile)) {
 
		gfx = GetAirportGfx(ti->tile);
 
		if (gfx >= NEW_AIRPORTTILE_OFFSET) {
 
			const AirportTileSpec *ats = AirportTileSpec::Get(gfx);
 
			if (ats->grf_prop.spritegroup[0] != NULL && DrawNewAirportTile(ti, Station::GetByTile(ti->tile), gfx, ats)) {
 
				return;
 
			}
 
			/* No sprite group (or no valid one) found, meaning no graphics associated.
 
			 * Use the substitute one instead */
 
			assert(ats->grf_prop.subst_id != INVALID_AIRPORTTILE);
 
			gfx = ats->grf_prop.subst_id;
 
		}
 
		switch (gfx) {
 
			case APT_RADAR_GRASS_FENCE_SW:
 
				t = &_station_display_datas_airport_radar_grass_fence_sw[GetAnimationFrame(ti->tile)];
 
				break;
 
			case APT_GRASS_FENCE_NE_FLAG:
 
				t = &_station_display_datas_airport_flag_grass_fence_ne[GetAnimationFrame(ti->tile)];
 
				break;
 
			case APT_RADAR_FENCE_SW:
 
				t = &_station_display_datas_airport_radar_fence_sw[GetAnimationFrame(ti->tile)];
 
				break;
 
			case APT_RADAR_FENCE_NE:
 
				t = &_station_display_datas_airport_radar_fence_ne[GetAnimationFrame(ti->tile)];
 
				break;
 
			case APT_GRASS_FENCE_NE_FLAG_2:
 
				t = &_station_display_datas_airport_flag_grass_fence_ne_2[GetAnimationFrame(ti->tile)];
 
				break;
 
		}
 
	}
 

	
 
	Owner owner = GetTileOwner(ti->tile);
 

	
 
	PaletteID palette;
 
	if (Company::IsValidID(owner)) {
 
		palette = COMPANY_SPRITE_COLOUR(owner);
0 comments (0 inline, 0 general)