Changeset - r14021:1aae6a0ffa3b
[Not reviewed]
master
0 3 0
rubidium - 15 years ago 2009-12-20 16:19:47
rubidium@openttd.org
(svn r18574) -Fix [FS#3392] (r18481): manually sending trains and RVs to depots didn't quite work
3 files changed with 14 insertions and 9 deletions:
0 comments (0 inline, 0 general)
src/roadveh_cmd.cpp
Show inline comments
 
@@ -268,194 +268,194 @@ CommandCost CmdBuildRoadVeh(TileIndex ti
 
		v->reliability_spd_dec = e->reliability_spd_dec;
 
		v->max_age = e->GetLifeLengthInDays();
 
		_new_vehicle_id = v->index;
 

	
 
		v->name = NULL;
 

	
 
		v->service_interval = Company::Get(v->owner)->settings.vehicle.servint_roadveh;
 

	
 
		v->date_of_last_service = _date;
 
		v->build_year = _cur_year;
 

	
 
		v->cur_image = SPR_IMG_QUERY;
 
		v->random_bits = VehicleRandomBits();
 
		v->SetRoadVehFront();
 

	
 
		v->roadtype = HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
 
		v->compatible_roadtypes = RoadTypeToRoadTypes(v->roadtype);
 
		v->rcache.cached_veh_length = 8;
 

	
 
		v->vehicle_flags = 0;
 
		if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
 

	
 
		AddArticulatedParts(v);
 
		v->InvalidateNewGRFCacheOfChain();
 

	
 
		/* Call various callbacks after the whole consist has been constructed */
 
		for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
 
			u->cargo_cap = GetVehicleCapacity(u);
 
			v->InvalidateNewGRFCache();
 
			u->InvalidateNewGRFCache();
 
		}
 
		RoadVehUpdateCache(v);
 

	
 
		VehicleMove(v, false);
 

	
 
		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
 
		InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
 
		SetWindowDirty(WC_COMPANY, v->owner);
 
		if (IsLocalCompany()) {
 
			InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Road window
 
		}
 

	
 
		Company::Get(_current_company)->num_engines[p1]++;
 

	
 
		CheckConsistencyOfArticulatedVehicle(v);
 
	}
 

	
 
	return cost;
 
}
 

	
 
bool RoadVehicle::IsStoppedInDepot() const
 
{
 
	TileIndex tile = this->tile;
 

	
 
	if (!IsRoadDepotTile(tile)) return false;
 
	if (this->IsRoadVehFront() && !(this->vehstatus & VS_STOPPED)) return false;
 

	
 
	for (const RoadVehicle *v = this; v != NULL; v = v->Next()) {
 
		if (v->state != RVSB_IN_DEPOT || v->tile != tile) return false;
 
	}
 
	return true;
 
}
 

	
 
/** Sell a road vehicle.
 
 * @param tile unused
 
 * @param flags operation to perform
 
 * @param p1 vehicle ID to be sold
 
 * @param p2 unused
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdSellRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	RoadVehicle *v = RoadVehicle::GetIfValid(p1);
 
	if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
 

	
 
	if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_CAN_T_SELL_DESTROYED_VEHICLE);
 

	
 
	if (!v->IsStoppedInDepot()) {
 
		return_cmd_error(STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT);
 
	}
 

	
 
	CommandCost ret(EXPENSES_NEW_VEHICLES, -v->value);
 

	
 
	if (flags & DC_EXEC) {
 
		delete v;
 
	}
 

	
 
	return ret;
 
}
 

	
 
static FindDepotData FindClosestRoadDepot(const RoadVehicle *v, int max_distance)
 
{
 
	if (IsRoadDepotTile(v->tile)) return FindDepotData(v->tile, 0);
 

	
 
	switch (_settings_game.pf.pathfinder_for_roadvehs) {
 
		case VPF_NPF: return NPFRoadVehicleFindNearestDepot(v, _settings_game.pf.npf.maximum_go_to_depot_penalty);
 
		case VPF_YAPF: return YapfRoadVehicleFindNearestDepot(v, _settings_game.pf.yapf.maximum_go_to_depot_penalty);
 
		case VPF_NPF: return NPFRoadVehicleFindNearestDepot(v, max_distance);
 
		case VPF_YAPF: return YapfRoadVehicleFindNearestDepot(v, max_distance);
 

	
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
bool RoadVehicle::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse)
 
{
 
	FindDepotData rfdd = FindClosestRoadDepot(this, 0);
 
	if (rfdd.best_length == UINT_MAX) return false;
 

	
 
	if (location    != NULL) *location    = rfdd.tile;
 
	if (destination != NULL) *destination = GetDepotIndex(rfdd.tile);
 

	
 
	return true;
 
}
 

	
 
/** Send a road vehicle to the depot.
 
 * @param tile unused
 
 * @param flags operation to perform
 
 * @param p1 vehicle ID to send to the depot
 
 * @param p2 various bitmasked elements
 
 * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h)
 
 * - p2 bit 8-10 - VLW flag (for mass goto depot)
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdSendRoadVehToDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	if (p2 & DEPOT_MASS_SEND) {
 
		/* Mass goto depot requested */
 
		if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR;
 
		return SendAllVehiclesToDepot(VEH_ROAD, flags, p2 & DEPOT_SERVICE, _current_company, (p2 & VLW_MASK), p1);
 
	}
 

	
 
	RoadVehicle *v = RoadVehicle::GetIfValid(p1);
 
	if (v == NULL) return CMD_ERROR;
 

	
 
	return v->SendToDepot(flags, (DepotCommand)(p2 & DEPOT_COMMAND_MASK));
 
}
 

	
 
/** Turn a roadvehicle around.
 
 * @param tile unused
 
 * @param flags operation to perform
 
 * @param p1 vehicle ID to turn
 
 * @param p2 unused
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	RoadVehicle *v = RoadVehicle::GetIfValid(p1);
 
	if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
 

	
 
	if ((v->vehstatus & VS_STOPPED) ||
 
			(v->vehstatus & VS_CRASHED) ||
 
			v->breakdown_ctr != 0 ||
 
			v->overtaking != 0 ||
 
			v->state == RVSB_WORMHOLE ||
 
			v->IsInDepot() ||
 
			v->cur_speed < 5) {
 
		return CMD_ERROR;
 
	}
 

	
 
	if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) return CMD_ERROR;
 

	
 
	if (IsTileType(v->tile, MP_TUNNELBRIDGE) && DirToDiagDir(v->direction) == GetTunnelBridgeDirection(v->tile)) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) v->reverse_ctr = 180;
 

	
 
	return CommandCost();
 
}
 

	
 

	
 
void RoadVehicle::MarkDirty()
 
{
 
	for (Vehicle *v = this; v != NULL; v = v->Next()) {
 
		v->UpdateViewport(false, false);
 
	}
 
}
 

	
 
void RoadVehicle::UpdateDeltaXY(Direction direction)
 
{
 
#define MKIT(a, b, c, d) ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF) << 0)
 
	static const uint32 _delta_xy_table[8] = {
 
		MKIT(3, 3, -1, -1),
 
		MKIT(3, 7, -1, -3),
 
		MKIT(3, 3, -1, -1),
 
		MKIT(7, 3, -3, -1),
 
		MKIT(3, 3, -1, -1),
 
		MKIT(3, 7, -1, -3),
 
		MKIT(3, 3, -1, -1),
 
		MKIT(7, 3, -3, -1),
 
	};
 
#undef MKIT
 

	
 
	uint32 x = _delta_xy_table[direction];
src/ship_cmd.cpp
Show inline comments
 
@@ -4,232 +4,237 @@
 
 * 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 ship_cmd.cpp Handling of ships. */
 

	
 
#include "stdafx.h"
 
#include "ship.h"
 
#include "landscape.h"
 
#include "timetable.h"
 
#include "command_func.h"
 
#include "news_func.h"
 
#include "company_func.h"
 
#include "pathfinder/npf/npf_func.h"
 
#include "depot_base.h"
 
#include "station_base.h"
 
#include "vehicle_gui.h"
 
#include "newgrf_engine.h"
 
#include "pathfinder/yapf/yapf.h"
 
#include "newgrf_sound.h"
 
#include "spritecache.h"
 
#include "strings_func.h"
 
#include "functions.h"
 
#include "window_func.h"
 
#include "date_func.h"
 
#include "vehicle_func.h"
 
#include "sound_func.h"
 
#include "autoreplace_gui.h"
 
#include "gfx_func.h"
 
#include "effectvehicle_func.h"
 
#include "ai/ai.hpp"
 
#include "pathfinder/opf/opf_ship.h"
 
#include "landscape_type.h"
 

	
 
#include "table/strings.h"
 
#include "table/sprites.h"
 

	
 
static const uint16 _ship_sprites[] = {0x0E5D, 0x0E55, 0x0E65, 0x0E6D};
 

	
 
static inline TrackBits GetTileShipTrackStatus(TileIndex tile)
 
{
 
	return TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0));
 
}
 

	
 
static SpriteID GetShipIcon(EngineID engine)
 
{
 
	const Engine *e = Engine::Get(engine);
 
	uint8 spritenum = e->u.ship.image_index;
 

	
 
	if (is_custom_sprite(spritenum)) {
 
		SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W);
 
		if (sprite != 0) return sprite;
 

	
 
		spritenum = e->original_image_index;
 
	}
 

	
 
	return DIR_W + _ship_sprites[spritenum];
 
}
 

	
 
void DrawShipEngine(int left, int right, int preferred_x, int y, EngineID engine, SpriteID pal)
 
{
 
	SpriteID sprite = GetShipIcon(engine);
 
	const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL);
 
	preferred_x = Clamp(preferred_x, left - real_sprite->x_offs, right - real_sprite->width - real_sprite->x_offs);
 
	DrawSprite(sprite, pal, preferred_x, y);
 
}
 

	
 
/** Get the size of the sprite of a ship sprite heading west (used for lists)
 
 * @param engine The engine to get the sprite from
 
 * @param width The width of the sprite
 
 * @param height The height of the sprite
 
 */
 
void GetShipSpriteSize(EngineID engine, uint &width, uint &height)
 
{
 
	const Sprite *spr = GetSprite(GetShipIcon(engine), ST_NORMAL);
 

	
 
	width  = spr->width;
 
	height = spr->height;
 
}
 

	
 
SpriteID Ship::GetImage(Direction direction) const
 
{
 
	uint8 spritenum = this->spritenum;
 

	
 
	if (is_custom_sprite(spritenum)) {
 
		SpriteID sprite = GetCustomVehicleSprite(this, direction);
 
		if (sprite != 0) return sprite;
 

	
 
		spritenum = Engine::Get(this->engine_type)->original_image_index;
 
	}
 

	
 
	return _ship_sprites[spritenum] + direction;
 
}
 

	
 
static const Depot *FindClosestShipDepot(const Vehicle *v)
 
static const Depot *FindClosestShipDepot(const Vehicle *v, uint max_distance)
 
{
 
	/* Find the closest depot */
 
	const Depot *depot;
 
	const Depot *best_depot = NULL;
 
	uint best_dist = UINT_MAX;
 
	/* If we don't have a maximum distance, i.e. distance = 0,
 
	 * we want to find any depot so the best distance of no
 
	 * depot must be more than any correct distance. On the
 
	 * other hand if we have set a maximum distance, any depot
 
	 * further away than max_distance can safely be ignored. */
 
	uint best_dist = max_distance == 0 ? UINT_MAX : max_distance + 1;
 

	
 
	FOR_ALL_DEPOTS(depot) {
 
		TileIndex tile = depot->xy;
 
		if (IsShipDepotTile(tile) && IsTileOwner(tile, v->owner)) {
 
			uint dist = DistanceManhattan(tile, v->tile);
 
			if (dist < best_dist) {
 
				best_dist = dist;
 
				best_depot = depot;
 
			}
 
		}
 
	}
 

	
 
	return best_depot;
 
}
 

	
 
static void CheckIfShipNeedsService(Vehicle *v)
 
{
 
	if (Company::Get(v->owner)->settings.vehicle.servint_ships == 0 || !v->NeedsAutomaticServicing()) return;
 
	if (v->IsInDepot()) {
 
		VehicleServiceInDepot(v);
 
		return;
 
	}
 

	
 
	uint max_distance;
 
	switch (_settings_game.pf.pathfinder_for_ships) {
 
		case VPF_OPF:  max_distance = 12; break;
 
		case VPF_NPF:  max_distance = _settings_game.pf.npf.maximum_go_to_depot_penalty  / NPF_TILE_LENGTH;  break;
 
		case VPF_YAPF: max_distance = _settings_game.pf.yapf.maximum_go_to_depot_penalty / YAPF_TILE_LENGTH; break;
 
		default: NOT_REACHED();
 
	}
 

	
 
	const Depot *depot = FindClosestShipDepot(v);
 
	const Depot *depot = FindClosestShipDepot(v, max_distance);
 

	
 
	if (depot == NULL || DistanceManhattan(v->tile, depot->xy) > max_distance) {
 
	if (depot == NULL) {
 
		if (v->current_order.IsType(OT_GOTO_DEPOT)) {
 
			v->current_order.MakeDummy();
 
			SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
		}
 
		return;
 
	}
 

	
 
	v->current_order.MakeGoToDepot(depot->index, ODTFB_SERVICE);
 
	v->dest_tile = depot->xy;
 
	SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
 
}
 

	
 
Money Ship::GetRunningCost() const
 
{
 
	const Engine *e = Engine::Get(this->engine_type);
 
	uint cost_factor = GetVehicleProperty(this, PROP_SHIP_RUNNING_COST_FACTOR, e->u.ship.running_cost);
 
	return GetPrice(PR_RUNNING_SHIP, cost_factor, e->grffile);
 
}
 

	
 
void Ship::OnNewDay()
 
{
 
	if ((++this->day_counter & 7) == 0)
 
		DecreaseVehicleValue(this);
 

	
 
	CheckVehicleBreakdown(this);
 
	AgeVehicle(this);
 
	CheckIfShipNeedsService(this);
 

	
 
	CheckOrders(this);
 

	
 
	if (this->running_ticks == 0) return;
 

	
 
	CommandCost cost(EXPENSES_SHIP_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS));
 

	
 
	this->profit_this_year -= cost.GetCost();
 
	this->running_ticks = 0;
 

	
 
	SubtractMoneyFromCompanyFract(this->owner, cost);
 

	
 
	SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
 
	/* we need this for the profit */
 
	SetWindowClassesDirty(WC_SHIPS_LIST);
 
}
 

	
 
Trackdir Ship::GetVehicleTrackdir() const
 
{
 
	if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
 

	
 
	if (this->IsInDepot()) {
 
		/* We'll assume the ship is facing outwards */
 
		return DiagDirToDiagTrackdir(GetShipDepotDirection(this->tile));
 
	}
 

	
 
	if (this->state == TRACK_BIT_WORMHOLE) {
 
		/* ship on aqueduct, so just use his direction and assume a diagonal track */
 
		return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
 
	}
 

	
 
	return TrackDirectionToTrackdir(FindFirstTrack(this->state), this->direction);
 
}
 

	
 
static void HandleBrokenShip(Vehicle *v)
 
{
 
	if (v->breakdown_ctr != 1) {
 
		v->breakdown_ctr = 1;
 
		v->cur_speed = 0;
 

	
 
		if (v->breakdowns_since_last_service != 255)
 
			v->breakdowns_since_last_service++;
 

	
 
		v->MarkDirty();
 
		SetWindowDirty(WC_VEHICLE_VIEW, v->index);
 
		SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
 

	
 
		if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
 
			SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
 
				SND_10_TRAIN_BREAKDOWN : SND_3A_COMEDY_BREAKDOWN_2, v);
 
		}
 

	
 
		if (!(v->vehstatus & VS_HIDDEN)) {
 
			EffectVehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
 
			if (u != NULL) u->animation_state = v->breakdown_delay * 2;
 
		}
 
	}
 

	
 
	if (!(v->tick_counter & 1)) {
 
		if (!--v->breakdown_delay) {
 
			v->breakdown_ctr = 0;
 
			v->MarkDirty();
 
			SetWindowDirty(WC_VEHICLE_VIEW, v->index);
 
		}
 
	}
 
}
 

	
 
void Ship::MarkDirty()
 
{
 
@@ -631,169 +636,169 @@ CommandCost CmdBuildShip(TileIndex tile,
 

	
 
		const ShipVehicleInfo *svi = &e->u.ship;
 

	
 
		Ship *v = new Ship();
 
		v->unitnumber = unit_num;
 

	
 
		v->owner = _current_company;
 
		v->tile = tile;
 
		x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
 
		y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
 
		v->x_pos = x;
 
		v->y_pos = y;
 
		v->z_pos = GetSlopeZ(x, y);
 

	
 
		v->running_ticks = 0;
 

	
 
		v->UpdateDeltaXY(v->direction);
 
		v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
 

	
 
		v->spritenum = svi->image_index;
 
		v->cargo_type = e->GetDefaultCargoType();
 
		v->cargo_subtype = 0;
 
		v->cargo_cap = svi->capacity;
 
		v->value = value.GetCost();
 

	
 
		v->last_station_visited = INVALID_STATION;
 
		v->max_speed = svi->max_speed;
 
		v->engine_type = p1;
 

	
 
		v->reliability = e->reliability;
 
		v->reliability_spd_dec = e->reliability_spd_dec;
 
		v->max_age = e->GetLifeLengthInDays();
 
		_new_vehicle_id = v->index;
 

	
 
		v->name = NULL;
 
		v->state = TRACK_BIT_DEPOT;
 

	
 
		v->service_interval = Company::Get(_current_company)->settings.vehicle.servint_ships;
 
		v->date_of_last_service = _date;
 
		v->build_year = _cur_year;
 
		v->cur_image = SPR_IMG_QUERY;
 
		v->random_bits = VehicleRandomBits();
 

	
 
		v->vehicle_flags = 0;
 
		if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
 

	
 
		v->InvalidateNewGRFCacheOfChain();
 

	
 
		v->cargo_cap = GetVehicleCapacity(v);
 

	
 
		v->InvalidateNewGRFCacheOfChain();
 

	
 
		VehicleMove(v, false);
 

	
 
		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
 
		InvalidateWindowClassesData(WC_SHIPS_LIST, 0);
 
		SetWindowDirty(WC_COMPANY, v->owner);
 
		if (IsLocalCompany())
 
			InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Ship window
 

	
 
		Company::Get(_current_company)->num_engines[p1]++;
 
	}
 

	
 
	return value;
 
}
 

	
 
/** Sell a ship.
 
 * @param tile unused
 
 * @param flags type of operation
 
 * @param p1 vehicle ID to be sold
 
 * @param p2 unused
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdSellShip(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	Ship *v = Ship::GetIfValid(p1);
 
	if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
 

	
 
	if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_CAN_T_SELL_DESTROYED_VEHICLE);
 

	
 
	if (!v->IsStoppedInDepot()) {
 
		return_cmd_error(STR_ERROR_SHIP_MUST_BE_STOPPED_IN_DEPOT);
 
	}
 

	
 
	CommandCost ret(EXPENSES_NEW_VEHICLES, -v->value);
 

	
 
	if (flags & DC_EXEC) {
 
		delete v;
 
	}
 

	
 
	return ret;
 
}
 

	
 
bool Ship::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse)
 
{
 
	const Depot *depot = FindClosestShipDepot(this);
 
	const Depot *depot = FindClosestShipDepot(this, 0);
 

	
 
	if (depot == NULL) return false;
 

	
 
	if (location    != NULL) *location    = depot->xy;
 
	if (destination != NULL) *destination = depot->index;
 

	
 
	return true;
 
}
 

	
 
/** Send a ship to the depot.
 
 * @param tile unused
 
 * @param flags type of operation
 
 * @param p1 vehicle ID to send to the depot
 
 * @param p2 various bitmasked elements
 
 * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h)
 
 * - p2 bit 8-10 - VLW flag (for mass goto depot)
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdSendShipToDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	if (p2 & DEPOT_MASS_SEND) {
 
		/* Mass goto depot requested */
 
		if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR;
 
		return SendAllVehiclesToDepot(VEH_SHIP, flags, p2 & DEPOT_SERVICE, _current_company, (p2 & VLW_MASK), p1);
 
	}
 

	
 
	Ship *v = Ship::GetIfValid(p1);
 
	if (v == NULL) return CMD_ERROR;
 

	
 
	return v->SendToDepot(flags, (DepotCommand)(p2 & DEPOT_COMMAND_MASK));
 
}
 

	
 

	
 
/** Refits a ship to the specified cargo type.
 
 * @param tile unused
 
 * @param flags type of operation
 
 * @param p1 vehicle ID of the ship to refit
 
 * @param p2 various bitstuffed elements
 
 * - p2 = (bit 0-7) - the new cargo type to refit to (p2 & 0xFF)
 
 * - p2 = (bit 8-15) - the new cargo subtype to refit to
 
 * - p2 = (bit 16) - refit only this vehicle (ignored)
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdRefitShip(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	CargoID new_cid = GB(p2, 0, 8); // gets the cargo number
 
	byte new_subtype = GB(p2, 8, 8);
 

	
 
	Ship *v = Ship::GetIfValid(p1);
 

	
 
	if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
 
	if (!v->IsStoppedInDepot()) return_cmd_error(STR_ERROR_SHIP_MUST_BE_STOPPED_IN_DEPOT);
 
	if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_CAN_T_REFIT_DESTROYED_VEHICLE);
 

	
 
	/* Check cargo */
 
	if (new_cid >= NUM_CARGO) return CMD_ERROR;
 

	
 
	CommandCost cost = RefitVehicle(v, true, new_cid, new_subtype, flags);
 

	
 
	if (flags & DC_EXEC) {
 
		v->colourmap = PAL_NONE; // invalidate vehicle colour map
 
		SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
 
		SetWindowDirty(WC_VEHICLE_DEPOT, v->tile);
 
		InvalidateWindowClassesData(WC_SHIPS_LIST, 0);
 
	}
 
	v->InvalidateNewGRFCacheOfChain(); // always invalidate; querycost might have filled it
 

	
 
	return cost;
 

	
 
}
src/train_cmd.cpp
Show inline comments
 
@@ -2014,194 +2014,194 @@ CommandCost CmdReverseTrainDirection(Til
 
			v->force_proceed = 0;
 
			SetWindowDirty(WC_VEHICLE_VIEW, v->index);
 

	
 
			if (_settings_game.vehicle.train_acceleration_model != TAM_ORIGINAL && v->cur_speed != 0) {
 
				ToggleBit(v->flags, VRF_REVERSING);
 
			} else {
 
				v->cur_speed = 0;
 
				SetLastSpeed(v, 0);
 
				HideFillingPercent(&v->fill_percent_te_id);
 
				ReverseTrainDirection(v);
 
			}
 
		}
 
	}
 
	return CommandCost();
 
}
 

	
 
/** Force a train through a red signal
 
 * @param tile unused
 
 * @param flags type of operation
 
 * @param p1 train to ignore the red signal
 
 * @param p2 unused
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	Train *t = Train::GetIfValid(p1);
 
	if (t == NULL || !CheckOwnership(t->owner)) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		/* If we are forced to proceed, cancel that order.
 
		 * If we are marked stuck we would want to force the train
 
		 * to proceed to the next signal. In the other cases we
 
		 * would like to pass the signal at danger and run till the
 
		 * next signal we encounter. */
 
		t->force_proceed = t->force_proceed == 2 ? 0 : HasBit(t->flags, VRF_TRAIN_STUCK) || t->IsInDepot() ? 1 : 2;
 
		SetWindowDirty(WC_VEHICLE_VIEW, t->index);
 
	}
 

	
 
	return CommandCost();
 
}
 

	
 
/** Refits a train to the specified cargo type.
 
 * @param tile unused
 
 * @param flags type of operation
 
 * @param p1 vehicle ID of the train to refit
 
 * @param p2 various bitstuffed elements
 
 * - p2 = (bit 0-7) - the new cargo type to refit to
 
 * - p2 = (bit 8-15) - the new cargo subtype to refit to
 
 * - p2 = (bit 16) - refit only this vehicle
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdRefitRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	CargoID new_cid = GB(p2, 0, 8);
 
	byte new_subtype = GB(p2, 8, 8);
 
	bool only_this = HasBit(p2, 16);
 

	
 
	Train *v = Train::GetIfValid(p1);
 
	if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
 

	
 
	if (!v->IsStoppedInDepot()) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED);
 
	if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_CAN_T_REFIT_DESTROYED_VEHICLE);
 

	
 
	/* Check cargo */
 
	if (new_cid >= NUM_CARGO) return CMD_ERROR;
 

	
 
	CommandCost cost = RefitVehicle(v, only_this, new_cid, new_subtype, flags);
 

	
 
	/* Update the train's cached variables */
 
	if (flags & DC_EXEC) {
 
		Train *front = v->First();
 
		TrainConsistChanged(front, false);
 
		SetWindowDirty(WC_VEHICLE_DETAILS, front->index);
 
		SetWindowDirty(WC_VEHICLE_DEPOT, front->tile);
 
		InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 
	} else {
 
		v->InvalidateNewGRFCacheOfChain(); // always invalidate; querycost might have filled it
 
	}
 

	
 
	return cost;
 
}
 

	
 
/** returns the tile of a depot to goto to. The given vehicle must not be
 
 * crashed! */
 
static FindDepotData FindClosestTrainDepot(Train *v, int max_distance)
 
{
 
	assert(!(v->vehstatus & VS_CRASHED));
 

	
 
	if (IsRailDepotTile(v->tile)) return FindDepotData(v->tile, 0);
 

	
 
	PBSTileInfo origin = FollowTrainReservation(v);
 
	if (IsRailDepotTile(origin.tile)) return FindDepotData(origin.tile, 0);
 

	
 
	switch (_settings_game.pf.pathfinder_for_trains) {
 
		case VPF_NPF: return NPFTrainFindNearestDepot(v, _settings_game.pf.npf.maximum_go_to_depot_penalty);
 
		case VPF_YAPF: return YapfTrainFindNearestDepot(v, _settings_game.pf.yapf.maximum_go_to_depot_penalty);
 
		case VPF_NPF: return NPFTrainFindNearestDepot(v, max_distance);
 
		case VPF_YAPF: return YapfTrainFindNearestDepot(v, max_distance);
 

	
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
bool Train::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse)
 
{
 
	FindDepotData tfdd = FindClosestTrainDepot(this, 0);
 
	if (tfdd.best_length == UINT_MAX) return false;
 

	
 
	if (location    != NULL) *location    = tfdd.tile;
 
	if (destination != NULL) *destination = GetDepotIndex(tfdd.tile);
 
	if (reverse     != NULL) *reverse     = tfdd.reverse;
 

	
 
	return true;
 
}
 

	
 
/** Send a train to a depot
 
 * @param tile unused
 
 * @param flags type of operation
 
 * @param p1 train to send to the depot
 
 * @param p2 various bitmasked elements
 
 * - p2 bit 0-3 - DEPOT_ flags (see vehicle.h)
 
 * - p2 bit 8-10 - VLW flag (for mass goto depot)
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdSendTrainToDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	if (p2 & DEPOT_MASS_SEND) {
 
		/* Mass goto depot requested */
 
		if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR;
 
		return SendAllVehiclesToDepot(VEH_TRAIN, flags, p2 & DEPOT_SERVICE, _current_company, (p2 & VLW_MASK), p1);
 
	}
 

	
 
	Train *v = Train::GetIfValid(p1);
 
	if (v == NULL) return CMD_ERROR;
 

	
 
	return v->SendToDepot(flags, (DepotCommand)(p2 & DEPOT_COMMAND_MASK));
 
}
 

	
 
static const int8 _vehicle_smoke_pos[8] = {
 
	1, 1, 1, 0, -1, -1, -1, 0
 
};
 

	
 
static void HandleLocomotiveSmokeCloud(const Train *v)
 
{
 
	bool sound = false;
 

	
 
	if ((v->vehstatus & VS_TRAIN_SLOWING) || v->cur_speed < 2) {
 
		return;
 
	}
 

	
 
	const Train *u = v;
 

	
 
	do {
 
		const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
 
		int effect_offset = GB(v->tcache.cached_vis_effect, 0, 4) - 8;
 
		byte effect_type = GB(v->tcache.cached_vis_effect, 4, 2);
 
		bool disable_effect = HasBit(v->tcache.cached_vis_effect, 6);
 

	
 
		/* no smoke? */
 
		if ((rvi->railveh_type == RAILVEH_WAGON && effect_type == 0) ||
 
				disable_effect ||
 
				v->vehstatus & VS_HIDDEN) {
 
			continue;
 
		}
 

	
 
		/* No smoke in depots or tunnels */
 
		if (IsRailDepotTile(v->tile) || IsTunnelTile(v->tile)) continue;
 

	
 
		/* No sparks for electric vehicles on nonelectrified tracks */
 
		if (!HasPowerOnRail(v->railtype, GetTileRailType(v->tile))) continue;
 

	
 
		if (effect_type == 0) {
 
			/* Use default effect type for engine class. */
 
			effect_type = rvi->engclass;
 
		} else {
 
			effect_type--;
 
		}
 

	
 
		int x = _vehicle_smoke_pos[v->direction] * effect_offset;
 
		int y = _vehicle_smoke_pos[(v->direction + 2) % 8] * effect_offset;
 

	
 
		if (HasBit(v->flags, VRF_REVERSE_DIRECTION)) {
 
			x = -x;
 
			y = -y;
 
		}
 

	
 
		switch (effect_type) {
 
			case 0:
 
				/* steam smoke. */
 
				if (GB(v->tick_counter, 0, 4) == 0) {
 
					CreateEffectVehicleRel(v, x, y, 10, EV_STEAM_SMOKE);
 
					sound = true;
 
				}
0 comments (0 inline, 0 general)