Changeset - r12160:b49804528c72
[Not reviewed]
master
0 8 0
rubidium - 15 years ago 2009-06-16 13:52:18
rubidium@openttd.org
(svn r16581) -Codechange: unify the access to Engine::lifelength.
8 files changed with 17 insertions and 6 deletions:
0 comments (0 inline, 0 general)
src/ai/api/ai_engine.cpp
Show inline comments
 
@@ -24,193 +24,193 @@
 
	if (!IsValidEngine(engine_id)) return NULL;
 

	
 
	static const int len = 64;
 
	char *engine_name = MallocT<char>(len);
 

	
 
	::SetDParam(0, engine_id);
 
	::GetString(engine_name, STR_ENGINE_NAME, &engine_name[len - 1]);
 
	return engine_name;
 
}
 

	
 
/* static */ CargoID AIEngine::GetCargoType(EngineID engine_id)
 
{
 
	if (!IsValidEngine(engine_id)) return CT_INVALID;
 

	
 
	const Engine *e = ::Engine::Get(engine_id);
 
	if (!e->CanCarryCargo()) return CT_INVALID;
 

	
 
	return e->GetDefaultCargoType();
 
}
 

	
 
/* static */ bool AIEngine::CanRefitCargo(EngineID engine_id, CargoID cargo_id)
 
{
 
	if (!IsValidEngine(engine_id)) return false;
 
	if (!AICargo::IsValidCargo(cargo_id)) return false;
 

	
 
	if (GetCargoType(engine_id) == cargo_id) return true;
 
	if (cargo_id == CT_MAIL && ::Engine::Get(engine_id)->type == VEH_AIRCRAFT) return true;
 
	if (::Engine::Get(engine_id)->type == VEH_SHIP && !ShipVehInfo(engine_id)->refittable) return false;
 
	return ::CanRefitTo(engine_id, cargo_id);
 
}
 

	
 
/* static */ bool AIEngine::CanPullCargo(EngineID engine_id, CargoID cargo_id)
 
{
 
	if (!IsValidEngine(engine_id)) return false;
 
	if (GetVehicleType(engine_id) != AIVehicle::VT_RAIL) return false;
 
	if (!AICargo::IsValidCargo(cargo_id)) return false;
 

	
 
	return (::RailVehInfo(engine_id)->ai_passenger_only != 1) || AICargo::HasCargoClass(cargo_id, AICargo::CC_PASSENGERS);
 
}
 

	
 

	
 
/* static */ int32 AIEngine::GetCapacity(EngineID engine_id)
 
{
 
	if (!IsValidEngine(engine_id)) return -1;
 

	
 
	const Engine *e = ::Engine::Get(engine_id);
 
	switch (e->type) {
 
		case VEH_ROAD:
 
		case VEH_TRAIN: {
 
			uint16 *capacities = GetCapacityOfArticulatedParts(engine_id, e->type);
 
			for (CargoID c = 0; c < NUM_CARGO; c++) {
 
				if (capacities[c] == 0) continue;
 
				return capacities[c];
 
			}
 
			return -1;
 
		} break;
 

	
 
		case VEH_SHIP:
 
		case VEH_AIRCRAFT:
 
			return e->GetDisplayDefaultCapacity();
 
			break;
 

	
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
/* static */ int32 AIEngine::GetReliability(EngineID engine_id)
 
{
 
	if (!IsValidEngine(engine_id)) return -1;
 
	if (GetVehicleType(engine_id) == AIVehicle::VT_RAIL && IsWagon(engine_id)) return -1;
 

	
 
	return (::Engine::Get(engine_id)->reliability * 100 >> 16);
 
}
 

	
 
/* static */ int32 AIEngine::GetMaxSpeed(EngineID engine_id)
 
{
 
	if (!IsValidEngine(engine_id)) return -1;
 

	
 
	const Engine *e = ::Engine::Get(engine_id);
 
	int32 max_speed = e->GetDisplayMaxSpeed(); // km-ish/h
 
	if (e->type == VEH_AIRCRAFT) max_speed /= _settings_game.vehicle.plane_speed;
 
	return max_speed;
 
}
 

	
 
/* static */ Money AIEngine::GetPrice(EngineID engine_id)
 
{
 
	if (!IsValidEngine(engine_id)) return -1;
 

	
 
	return ::Engine::Get(engine_id)->GetCost();
 
}
 

	
 
/* static */ int32 AIEngine::GetMaxAge(EngineID engine_id)
 
{
 
	if (!IsValidEngine(engine_id)) return -1;
 
	if (GetVehicleType(engine_id) == AIVehicle::VT_RAIL && IsWagon(engine_id)) return -1;
 

	
 
	return ::Engine::Get(engine_id)->lifelength * DAYS_IN_LEAP_YEAR;
 
	return ::Engine::Get(engine_id)->GetLifeLengthInDays();
 
}
 

	
 
/* static */ Money AIEngine::GetRunningCost(EngineID engine_id)
 
{
 
	if (!IsValidEngine(engine_id)) return -1;
 

	
 
	return ::Engine::Get(engine_id)->GetRunningCost();
 
}
 

	
 
/* static */ int32 AIEngine::GetPower(EngineID engine_id)
 
{
 
	if (!IsValidEngine(engine_id)) return -1;
 
	if (GetVehicleType(engine_id) != AIVehicle::VT_RAIL) return -1;
 
	if (IsWagon(engine_id)) return -1;
 

	
 
	return ::Engine::Get(engine_id)->GetPower();
 
}
 

	
 
/* static */ int32 AIEngine::GetWeight(EngineID engine_id)
 
{
 
	if (!IsValidEngine(engine_id)) return -1;
 
	if (GetVehicleType(engine_id) != AIVehicle::VT_RAIL) return -1;
 

	
 
	return ::Engine::Get(engine_id)->GetDisplayWeight();
 
}
 

	
 
/* static */ int32 AIEngine::GetMaxTractiveEffort(EngineID engine_id)
 
{
 
	if (!IsValidEngine(engine_id)) return -1;
 
	if (GetVehicleType(engine_id) != AIVehicle::VT_RAIL) return -1;
 
	if (IsWagon(engine_id)) return -1;
 

	
 
	return ::Engine::Get(engine_id)->GetDisplayMaxTractiveEffort();
 
}
 

	
 
/* static */ AIVehicle::VehicleType AIEngine::GetVehicleType(EngineID engine_id)
 
{
 
	if (!IsValidEngine(engine_id)) return AIVehicle::VT_INVALID;
 

	
 
	switch (::Engine::Get(engine_id)->type) {
 
		case VEH_ROAD:     return AIVehicle::VT_ROAD;
 
		case VEH_TRAIN:    return AIVehicle::VT_RAIL;
 
		case VEH_SHIP:     return AIVehicle::VT_WATER;
 
		case VEH_AIRCRAFT: return AIVehicle::VT_AIR;
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
/* static */ bool AIEngine::IsWagon(EngineID engine_id)
 
{
 
	if (!IsValidEngine(engine_id)) return false;
 
	if (GetVehicleType(engine_id) != AIVehicle::VT_RAIL) return false;
 

	
 
	return ::RailVehInfo(engine_id)->power == 0;
 
}
 

	
 
/* static */ bool AIEngine::CanRunOnRail(EngineID engine_id, AIRail::RailType track_rail_type)
 
{
 
	if (!IsValidEngine(engine_id)) return false;
 
	if (GetVehicleType(engine_id) != AIVehicle::VT_RAIL) return false;
 
	if (!AIRail::IsRailTypeAvailable(track_rail_type)) return false;
 

	
 
	return ::IsCompatibleRail((::RailType)::RailVehInfo(engine_id)->railtype, (::RailType)track_rail_type);
 
}
 

	
 
/* static */ bool AIEngine::HasPowerOnRail(EngineID engine_id, AIRail::RailType track_rail_type)
 
{
 
	if (!IsValidEngine(engine_id)) return false;
 
	if (GetVehicleType(engine_id) != AIVehicle::VT_RAIL) return false;
 
	if (!AIRail::IsRailTypeAvailable(track_rail_type)) return false;
 

	
 
	return ::HasPowerOnRail((::RailType)::RailVehInfo(engine_id)->railtype, (::RailType)track_rail_type);
 
}
 

	
 
/* static */ AIRoad::RoadType AIEngine::GetRoadType(EngineID engine_id)
 
{
 
	if (!IsValidEngine(engine_id)) return AIRoad::ROADTYPE_INVALID;
 
	if (GetVehicleType(engine_id) != AIVehicle::VT_ROAD) return AIRoad::ROADTYPE_INVALID;
 

	
 
	return HasBit(::EngInfo(engine_id)->misc_flags, EF_ROAD_TRAM) ? AIRoad::ROADTYPE_TRAM : AIRoad::ROADTYPE_ROAD;
 
}
 

	
 
/* static */ AIRail::RailType AIEngine::GetRailType(EngineID engine_id)
 
{
 
	if (!IsValidEngine(engine_id)) return AIRail::RAILTYPE_INVALID;
 
	if (GetVehicleType(engine_id) != AIVehicle::VT_RAIL) return AIRail::RAILTYPE_INVALID;
 

	
 
	return (AIRail::RailType)(uint)::RailVehInfo(engine_id)->railtype;
 
}
 

	
 
/* static */ bool AIEngine::IsArticulated(EngineID engine_id)
 
{
 
	if (!IsValidEngine(engine_id)) return false;
 
	if (GetVehicleType(engine_id) != AIVehicle::VT_ROAD && GetVehicleType(engine_id) != AIVehicle::VT_RAIL) return false;
 

	
 
	return CountArticulatedParts(engine_id, true) != 0;
src/aircraft_cmd.cpp
Show inline comments
 
@@ -241,193 +241,193 @@ uint16 AircraftDefaultCargoCapacity(Carg
 
/** Build an aircraft.
 
 * @param tile tile of depot where aircraft is built
 
 * @param flags for command
 
 * @param p1 aircraft type being built (engine)
 
 * @param p2 unused
 
 * return result of operation.  Could be cost, error
 
 */
 
CommandCost CmdBuildAircraft(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	if (!IsEngineBuildable(p1, VEH_AIRCRAFT, _current_company)) return_cmd_error(STR_AIRCRAFT_NOT_AVAILABLE);
 

	
 
	const AircraftVehicleInfo *avi = AircraftVehInfo(p1);
 
	const Engine *e = Engine::Get(p1);
 
	CommandCost value(EXPENSES_NEW_VEHICLES, e->GetCost());
 

	
 
	/* Engines without valid cargo should not be available */
 
	if (e->GetDefaultCargoType() == CT_INVALID) return CMD_ERROR;
 

	
 
	/* to just query the cost, it is not neccessary to have a valid tile (automation/AI) */
 
	if (flags & DC_QUERY_COST) return value;
 

	
 
	if (!IsHangarTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;
 

	
 
	/* Prevent building aircraft types at places which can't handle them */
 
	if (!CanVehicleUseStation(p1, GetStationByTile(tile))) return CMD_ERROR;
 

	
 
	/* We will need to allocate 2 or 3 vehicle structs, depending on type */
 
	if (!Vehicle::CanAllocateItem(avi->subtype & AIR_CTOL ? 2 : 3)) {
 
		return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
 
	}
 

	
 
	UnitID unit_num = (flags & DC_AUTOREPLACE) ? 0 : GetFreeUnitNumber(VEH_AIRCRAFT);
 
	if (unit_num > _settings_game.vehicle.max_aircraft)
 
		return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
 

	
 
	if (flags & DC_EXEC) {
 
		Aircraft *v = new Aircraft(); // aircraft
 
		Aircraft *u = new Aircraft(); // shadow
 

	
 
		v->unitnumber = unit_num;
 
		v->direction = DIR_SE;
 

	
 
		v->owner = u->owner = _current_company;
 

	
 
		v->tile = tile;
 
//		u->tile = 0;
 

	
 
		uint x = TileX(tile) * TILE_SIZE + 5;
 
		uint y = TileY(tile) * TILE_SIZE + 3;
 

	
 
		v->x_pos = u->x_pos = x;
 
		v->y_pos = u->y_pos = y;
 

	
 
		u->z_pos = GetSlopeZ(x, y);
 
		v->z_pos = u->z_pos + 1;
 

	
 
		v->running_ticks = 0;
 

	
 
//		u->delta_x = u->delta_y = 0;
 

	
 
		v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
 
		u->vehstatus = VS_HIDDEN | VS_UNCLICKABLE | VS_SHADOW;
 

	
 
		v->spritenum = avi->image_index;
 
//		v->cargo_count = u->number_of_pieces = 0;
 

	
 
		v->cargo_cap = avi->passenger_capacity;
 
		u->cargo_cap = avi->mail_capacity;
 

	
 
		v->cargo_type = e->GetDefaultCargoType();
 
		u->cargo_type = CT_MAIL;
 

	
 
		v->cargo_subtype = 0;
 

	
 
		v->name = NULL;
 
//		v->next_order_param = v->next_order = 0;
 

	
 
//		v->load_unload_time_rem = 0;
 
//		v->progress = 0;
 
		v->last_station_visited = INVALID_STATION;
 
//		v->destination_coords = 0;
 

	
 
		v->max_speed = avi->max_speed;
 
		v->acceleration = avi->acceleration;
 
		v->engine_type = p1;
 
		u->engine_type = p1;
 

	
 
		v->subtype = (avi->subtype & AIR_CTOL ? AIR_AIRCRAFT : AIR_HELICOPTER);
 
		v->UpdateDeltaXY(INVALID_DIR);
 
		v->value = value.GetCost();
 

	
 
		u->subtype = AIR_SHADOW;
 
		u->UpdateDeltaXY(INVALID_DIR);
 

	
 
		v->reliability = e->reliability;
 
		v->reliability_spd_dec = e->reliability_spd_dec;
 
		v->max_age = e->lifelength * DAYS_IN_LEAP_YEAR;
 
		v->max_age = e->GetLifeLengthInDays();
 

	
 
		_new_vehicle_id = v->index;
 

	
 
		/* When we click on hangar we know the tile it is on. By that we know
 
		 * its position in the array of depots the airport has.....we can search
 
		 * layout for #th position of depot. Since layout must start with a listing
 
		 * of all depots, it is simple */
 
		for (uint i = 0;; i++) {
 
			const Station *st = GetStationByTile(tile);
 
			const AirportFTAClass *apc = st->Airport();
 

	
 
			assert(i != apc->nof_depots);
 
			if (st->airport_tile + ToTileIndexDiff(apc->airport_depots[i]) == tile) {
 
				assert(apc->layout[i].heading == HANGAR);
 
				v->pos = apc->layout[i].position;
 
				break;
 
			}
 
		}
 

	
 
		v->state = HANGAR;
 
		v->previous_pos = v->pos;
 
		v->targetairport = GetStationIndex(tile);
 
		v->SetNext(u);
 

	
 
		v->service_interval = Company::Get(_current_company)->settings.vehicle.servint_aircraft;
 

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

	
 
		v->cur_image = u->cur_image = SPR_IMG_QUERY;
 

	
 
		v->random_bits = VehicleRandomBits();
 
		u->random_bits = VehicleRandomBits();
 

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

	
 
		v->InvalidateNewGRFCacheOfChain();
 

	
 
		if (v->cargo_type != CT_PASSENGERS) {
 
			uint16 callback = CALLBACK_FAILED;
 

	
 
			if (HasBit(EngInfo(p1)->callbackmask, CBM_VEHICLE_REFIT_CAPACITY)) {
 
				callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
 
			}
 

	
 
			if (callback == CALLBACK_FAILED) {
 
				/* Callback failed, or not executed; use the default cargo capacity */
 
				v->cargo_cap = AircraftDefaultCargoCapacity(v->cargo_type, avi);
 
			} else {
 
				v->cargo_cap = callback;
 
			}
 

	
 
			/* Set the 'second compartent' capacity to none */
 
			u->cargo_cap = 0;
 
		}
 

	
 
		v->InvalidateNewGRFCacheOfChain();
 

	
 
		UpdateAircraftCache(v);
 

	
 
		VehicleMove(v, false);
 
		VehicleMove(u, false);
 

	
 
		/* Aircraft with 3 vehicles (chopper)? */
 
		if (v->subtype == AIR_HELICOPTER) {
 
			Aircraft *w = new Aircraft();
 
			w->engine_type = p1;
 
			w->direction = DIR_N;
 
			w->owner = _current_company;
 
			w->x_pos = v->x_pos;
 
			w->y_pos = v->y_pos;
 
			w->z_pos = v->z_pos + 5;
 
			w->vehstatus = VS_HIDDEN | VS_UNCLICKABLE;
 
			w->spritenum = 0xFF;
 
			w->subtype = AIR_ROTOR;
 
			w->cur_image = SPR_ROTOR_STOPPED;
 
			w->random_bits = VehicleRandomBits();
 
			/* Use rotor's air.state to store the rotor animation frame */
 
			w->state = HRS_ROTOR_STOPPED;
 
			w->UpdateDeltaXY(INVALID_DIR);
 

	
 
			u->SetNext(w);
 
			VehicleMove(w, false);
 
		}
 

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

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

	
 
	return value;
src/build_vehicle_gui.cpp
Show inline comments
 
@@ -583,193 +583,193 @@ static int DrawAircraftPurchaseInfo(int 
 
	}
 
	y += FONT_HEIGHT_NORMAL;
 

	
 
	/* Running cost */
 
	SetDParam(0, e->GetRunningCost());
 
	DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
 
	y += FONT_HEIGHT_NORMAL;
 

	
 
	return y;
 
}
 

	
 
/**
 
 * Display additional text from NewGRF in the purchase information window
 
 * @param left   Left border of text bounding box
 
 * @param right  Right border of text bounding box
 
 * @param y      Top border of text bounding box
 
 * @param engine Engine to query the additional purchase information for
 
 * @return       Bottom border of text bounding box
 
 */
 
static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
 
{
 
	uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, NULL);
 
	if (callback == CALLBACK_FAILED) return y;
 

	
 
	/* STR_BLACK_STRING is used to start the string with {BLACK} */
 
	SetDParam(0, GetGRFStringID(GetEngineGRFID(engine), 0xD000 + callback));
 
	PrepareTextRefStackUsage(0);
 
	uint result = DrawStringMultiLine(left, right, y, INT32_MAX, STR_BLACK_STRING);
 
	StopTextRefStackUsage();
 
	return result;
 
}
 

	
 
/**
 
 * Draw the purchase info details of a vehicle at a given location.
 
 * @param left,right,y location where to draw the info
 
 * @param engine_number the engine of which to draw the info of
 
 * @return y after drawing all the text
 
 */
 
int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number)
 
{
 
	const Engine *e = Engine::Get(engine_number);
 
	YearMonthDay ymd;
 
	ConvertDateToYMD(e->intro_date, &ymd);
 
	bool refittable = IsArticulatedVehicleRefittable(engine_number);
 

	
 
	switch (e->type) {
 
		default: NOT_REACHED();
 
		case VEH_TRAIN: {
 
			const RailVehicleInfo *rvi = RailVehInfo(engine_number);
 
			if (rvi->railveh_type == RAILVEH_WAGON) {
 
				y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, rvi);
 
			} else {
 
				y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, rvi);
 
			}
 

	
 
			/* Cargo type + capacity, or N/A */
 
			int new_y = DrawCargoCapacityInfo(left, right, y, engine_number, VEH_TRAIN, refittable);
 

	
 
			if (new_y == y) {
 
				SetDParam(0, CT_INVALID);
 
				SetDParam(2, STR_EMPTY);
 
				DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
 
				y += FONT_HEIGHT_NORMAL;
 
			} else {
 
				y = new_y;
 
			}
 
			break;
 
		}
 
		case VEH_ROAD: {
 
			y = DrawRoadVehPurchaseInfo(left, right, y, engine_number);
 

	
 
			/* Cargo type + capacity, or N/A */
 
			int new_y = DrawCargoCapacityInfo(left, right, y, engine_number, VEH_ROAD, refittable);
 

	
 
			if (new_y == y) {
 
				SetDParam(0, CT_INVALID);
 
				SetDParam(2, STR_EMPTY);
 
				DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
 
				y += FONT_HEIGHT_NORMAL;
 
			} else {
 
				y = new_y;
 
			}
 
			break;
 
		}
 
		case VEH_SHIP:
 
			y = DrawShipPurchaseInfo(left, right, y, engine_number, ShipVehInfo(engine_number), refittable);
 
			break;
 
		case VEH_AIRCRAFT:
 
			y = DrawAircraftPurchaseInfo(left, right, y, engine_number, AircraftVehInfo(engine_number), refittable);
 
			break;
 
	}
 

	
 
	/* Draw details, that applies to all types except rail wagons */
 
	if (e->type != VEH_TRAIN || RailVehInfo(engine_number)->railveh_type != RAILVEH_WAGON) {
 
		/* Design date - Life length */
 
		SetDParam(0, ymd.year);
 
		SetDParam(1, e->lifelength);
 
		SetDParam(1, e->GetLifeLengthInDays() / DAYS_IN_LEAP_YEAR);
 
		DrawString(left, right, y, STR_PURCHASE_INFO_DESIGNED_LIFE);
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		/* Reliability */
 
		SetDParam(0, e->reliability * 100 >> 16);
 
		DrawString(left, right, y, STR_PURCHASE_INFO_RELIABILITY);
 
		y += FONT_HEIGHT_NORMAL;
 
	}
 

	
 
	/* Additional text from NewGRF */
 
	y = ShowAdditionalText(left, right, y, engine_number);
 
	if (refittable) y = ShowRefitOptionsList(left, right, y, engine_number);
 

	
 
	return y;
 
}
 

	
 
static void DrawVehicleEngine(VehicleType type, int x, int y, EngineID engine, SpriteID pal)
 
{
 
	switch (type) {
 
		case VEH_TRAIN:    DrawTrainEngine(   x, y, engine, pal); break;
 
		case VEH_ROAD:     DrawRoadVehEngine( x, y, engine, pal); break;
 
		case VEH_SHIP:     DrawShipEngine(    x, y, engine, pal); break;
 
		case VEH_AIRCRAFT: DrawAircraftEngine(x, y, engine, pal); break;
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
/** Engine drawing loop
 
 * @param type Type of vehicle (VEH_*)
 
 * @param x,y Where should the list start
 
 * @param eng_list What engines to draw
 
 * @param min where to start in the list
 
 * @param max where in the list to end
 
 * @param selected_id what engine to highlight as selected, if any
 
 * @param count_location Offset to print the engine count (used by autoreplace). 0 means it's off
 
 */
 
void DrawEngineList(VehicleType type, int x, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, int count_location, GroupID selected_group)
 
{
 
	byte step_size = GetVehicleListHeight(type);
 
	byte x_offset = 0;
 
	byte y_offset = 0;
 

	
 
	assert(max <= eng_list->Length());
 

	
 
	switch (type) {
 
		case VEH_TRAIN:
 
			x++; // train and road vehicles use the same offset, except trains are one more pixel to the right
 
			/* Fallthough */
 
		case VEH_ROAD:
 
			x += 26;
 
			x_offset = 30;
 
			y += 2;
 
			y_offset = 4;
 
			break;
 
		case VEH_SHIP:
 
			x += 35;
 
			x_offset = 40;
 
			y += 7;
 
			y_offset = 3;
 
			break;
 
		case VEH_AIRCRAFT:
 
			x += 27;
 
			x_offset = 33;
 
			y += 7;
 
			y_offset = 3;
 
			break;
 
		default: NOT_REACHED();
 
	}
 

	
 
	for (; min < max; min++, y += step_size) {
 
		const EngineID engine = (*eng_list)[min];
 
		/* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */
 
		const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine);
 

	
 
		SetDParam(0, engine);
 
		DrawString(x + x_offset, r, y, STR_ENGINE_NAME, engine == selected_id ? TC_WHITE : TC_BLACK);
 
		DrawVehicleEngine(type, x, y + y_offset, engine, (count_location != 0 && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company));
 
		if (count_location != 0) {
 
			SetDParam(0, num_engines);
 
			DrawString(x, count_location, y + (GetVehicleListHeight(type) == 14 ? 3 : 8), STR_TINY_BLACK, TC_FROMSTRING, SA_RIGHT);
 
		}
 
	}
 
}
 

	
 

	
 
struct BuildVehicleWindow : Window {
 
	VehicleType vehicle_type;
 
	union {
 
		RailTypeByte railtype;
 
		AirportFTAClass::Flags flags;
 
		RoadTypes roadtypes;
 
	} filter;
 
	bool descending_sort_order;
 
	byte sort_criteria;
 
	bool listview_mode;
 
	EngineID sel_engine;
src/engine.cpp
Show inline comments
 
@@ -223,192 +223,202 @@ Money Engine::GetRunningCost() const
 
		case VEH_AIRCRAFT:
 
			return GetEngineProperty(this->index, 0x0E, this->u.air.running_cost) * _price.aircraft_running >> 8;
 

	
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
Money Engine::GetCost() const
 
{
 
	switch (this->type) {
 
		case VEH_ROAD:
 
			return GetEngineProperty(this->index, 0x11, this->u.road.cost_factor) * (_price.roadveh_base >> 3) >> 5;
 

	
 
		case VEH_TRAIN:
 
			if (this->u.rail.railveh_type == RAILVEH_WAGON) {
 
				return (GetEngineProperty(this->index, 0x17, this->u.rail.cost_factor) * _price.build_railwagon) >> 8;
 
			} else {
 
				return GetEngineProperty(this->index, 0x17, this->u.rail.cost_factor) * (_price.build_railvehicle >> 3) >> 5;
 
			}
 
		case VEH_SHIP:
 
			return GetEngineProperty(this->index, 0x0A, this->u.ship.cost_factor) * (_price.ship_base >> 3) >> 5;
 

	
 
		case VEH_AIRCRAFT:
 
			return GetEngineProperty(this->index, 0x0B, this->u.air.cost_factor) * (_price.aircraft_base >> 3) >> 5;
 

	
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
/**
 
 * Returns max speed for display purposes
 
 * @return max speed in km-ish/h
 
 */
 
uint Engine::GetDisplayMaxSpeed() const
 
{
 
	switch (this->type) {
 
		case VEH_TRAIN:
 
			return GetEngineProperty(this->index, 0x09, this->u.rail.max_speed);
 

	
 
		case VEH_ROAD:
 
			return this->u.road.max_speed / 2;
 

	
 
		case VEH_SHIP:
 
			return GetEngineProperty(this->index, 0x0B, this->u.ship.max_speed) / 2;
 

	
 
		case VEH_AIRCRAFT:
 
			return this->u.air.max_speed;
 

	
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
uint Engine::GetPower() const
 
{
 
	/* Currently only trains have 'power' */
 
	switch (this->type) {
 
		case VEH_TRAIN:
 
			return GetEngineProperty(this->index, 0x0B, this->u.rail.power);
 

	
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
/**
 
 * Returns the weight for display purposes.
 
 * For dual-headed train-engines this is the weight of both heads
 
 * @return weight in display units metric tons
 
 */
 
uint Engine::GetDisplayWeight() const
 
{
 
	/* Currently only trains have 'weight' */
 
	switch (this->type) {
 
		case VEH_TRAIN:
 
			return GetEngineProperty(this->index, 0x16, this->u.rail.weight) << (this->u.rail.railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
 

	
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
/**
 
 * Returns the tractive effort for display purposes.
 
 * For dual-headed train-engines this is the tractive effort of both heads
 
 * @return tractive effort in display units kN
 
 */
 
uint Engine::GetDisplayMaxTractiveEffort() const
 
{
 
	/* Currently only trains have 'tractive effort' */
 
	switch (this->type) {
 
		case VEH_TRAIN:
 
			return (10 * this->GetDisplayWeight() * GetEngineProperty(this->index, 0x1F, this->u.rail.tractive_effort)) / 256;
 

	
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
/**
 
 * Returns the vehicle's life length in days.
 
 * @return the life length
 
 */
 
Date Engine::GetLifeLengthInDays() const
 
{
 
	/* Assume leap years; this gives the player a bit more than the given amount of years, but never less. */
 
	return this->lifelength * DAYS_IN_LEAP_YEAR;
 
}
 

	
 
/**
 
 * Initializes the EngineOverrideManager with the default engines.
 
 */
 
void EngineOverrideManager::ResetToDefaultMapping()
 
{
 
	this->Clear();
 
	for (VehicleType type = VEH_TRAIN; type <= VEH_AIRCRAFT; type++) {
 
		for (uint internal_id = 0; internal_id < _engine_counts[type]; internal_id++) {
 
			EngineIDMapping *eid = this->Append();
 
			eid->type            = type;
 
			eid->grfid           = INVALID_GRFID;
 
			eid->internal_id     = internal_id;
 
			eid->substitute_id   = internal_id;
 
		}
 
	}
 
}
 

	
 
/**
 
 * Looks up an EngineID in the EngineOverrideManager
 
 * @param type Vehicle type
 
 * @param grf_local_id The local id in the newgrf
 
 * @param grfid The GrfID that defines the scope of grf_local_id.
 
 *              If a newgrf overrides the engines of another newgrf, the "scope grfid" is the ID of the overridden newgrf.
 
 *              If dynnamic_engines is disabled, all newgrf share the same ID scope identified by INVALID_GRFID.
 
 * @return The engine ID if present, or INVALID_ENGINE if not.
 
 */
 
EngineID EngineOverrideManager::GetID(VehicleType type, uint16 grf_local_id, uint32 grfid)
 
{
 
	const EngineIDMapping *end = this->End();
 
	EngineID index = 0;
 
	for (const EngineIDMapping *eid = this->Begin(); eid != end; eid++, index++) {
 
		if (eid->type == type && eid->grfid == grfid && eid->internal_id == grf_local_id) {
 
			return index;
 
		}
 
	}
 
	return INVALID_ENGINE;
 
}
 

	
 
/** Sets cached values in Company::num_vehicles and Group::num_vehicles
 
 */
 
void SetCachedEngineCounts()
 
{
 
	size_t engines = Engine::GetPoolSize();
 

	
 
	/* Set up the engine count for all companies */
 
	Company *c;
 
	FOR_ALL_COMPANIES(c) {
 
		free(c->num_engines);
 
		c->num_engines = CallocT<EngineID>(engines);
 
	}
 

	
 
	/* Recalculate */
 
	Group *g;
 
	FOR_ALL_GROUPS(g) {
 
		free(g->num_engines);
 
		g->num_engines = CallocT<EngineID>(engines);
 
	}
 

	
 
	const Vehicle *v;
 
	FOR_ALL_VEHICLES(v) {
 
		if (!IsEngineCountable(v)) continue;
 

	
 
		assert(v->engine_type < engines);
 

	
 
		Company::Get(v->owner)->num_engines[v->engine_type]++;
 

	
 
		if (v->group_id == DEFAULT_GROUP) continue;
 

	
 
		g = Group::Get(v->group_id);
 
		assert(v->type == g->vehicle_type);
 
		assert(v->owner == g->owner);
 

	
 
		g->num_engines[v->engine_type]++;
 
	}
 
}
 

	
 
void SetupEngines()
 
{
 
	_engine_pool.CleanPool();
 

	
 
	assert(_engine_mngr.Length() >= _engine_mngr.NUM_DEFAULT_ENGINES);
 
	const EngineIDMapping *end = _engine_mngr.End();
 
	uint index = 0;
 
	for (const EngineIDMapping *eid = _engine_mngr.Begin(); eid != end; eid++, index++) {
 
		const Engine *e = new Engine(eid->type, eid->internal_id);
 
		assert(e->index == index);
 
	}
 
}
 

	
 

	
 
void ShowEnginePreviewWindow(EngineID engine);
 

	
 
/* Determine if an engine type is a wagon (and not a loco) */
 
static bool IsWagon(EngineID index)
 
{
 
	const Engine *e = Engine::Get(index);
 
	return e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON;
src/engine_base.h
Show inline comments
 
/* $Id$ */
 

	
 
/** @file engine_base.h Base class for engines. */
 

	
 
#ifndef ENGINE_BASE_H
 
#define ENGINE_BASE_H
 

	
 
#include "engine_type.h"
 
#include "economy_type.h"
 
#include "core/pool_type.hpp"
 
#include "core/smallvec_type.hpp"
 

	
 
typedef Pool<Engine, EngineID, 64, 64000> EnginePool;
 
extern EnginePool _engine_pool;
 

	
 
struct Engine : EnginePool::PoolItem<&_engine_pool> {
 
	char *name;         ///< Custom name of engine
 
	Date intro_date;
 
	Date age;
 
	uint16 reliability;
 
	uint16 reliability_spd_dec;
 
	uint16 reliability_start, reliability_max, reliability_final;
 
	uint16 duration_phase_1, duration_phase_2, duration_phase_3;
 
	byte lifelength;
 
	byte flags;
 
	uint8 preview_company_rank;
 
	byte preview_wait;
 
	CompanyMask company_avail;
 
	uint8 original_image_index; ///< Original vehicle image index, thus the image index of the overridden vehicle
 
	VehicleType type; ///< type, ie VEH_ROAD, VEH_TRAIN, etc.
 

	
 
	EngineInfo info;
 

	
 
	union {
 
		RailVehicleInfo rail;
 
		RoadVehicleInfo road;
 
		ShipVehicleInfo ship;
 
		AircraftVehicleInfo air;
 
	} u;
 

	
 
	/* NewGRF related data */
 
	const struct GRFFile *grffile;
 
	const struct SpriteGroup *group[NUM_CARGO + 2];
 
	uint16 internal_id;                             ///< ID within the GRF file
 
	uint16 overrides_count;
 
	struct WagonOverride *overrides;
 
	uint16 list_position;
 

	
 
	Engine();
 
	Engine(VehicleType type, EngineID base);
 
	~Engine();
 

	
 
	CargoID GetDefaultCargoType() const;
 
	bool CanCarryCargo() const;
 
	uint GetDisplayDefaultCapacity() const;
 
	Money GetRunningCost() const;
 
	Money GetCost() const;
 
	uint GetDisplayMaxSpeed() const;
 
	uint GetPower() const;
 
	uint GetDisplayWeight() const;
 
	uint GetDisplayMaxTractiveEffort() const;
 
	Date GetLifeLengthInDays() const;
 
};
 

	
 
struct EngineIDMapping {
 
	uint32 grfid;          ///< The GRF ID of the file the entity belongs to
 
	uint16 internal_id;    ///< The internal ID within the GRF file
 
	VehicleTypeByte type;  ///< The engine type
 
	uint8  substitute_id;  ///< The (original) entity ID to use if this GRF is not available (currently not used)
 
};
 

	
 
/**
 
 * Stores the mapping of EngineID to the internal id of newgrfs.
 
 * Note: This is not part of Engine, as the data in the EngineOverrideManager and the engine pool get resetted in different cases.
 
 */
 
struct EngineOverrideManager : SmallVector<EngineIDMapping, 256> {
 
	static const uint NUM_DEFAULT_ENGINES; ///< Number of default entries
 

	
 
	void ResetToDefaultMapping();
 
	EngineID GetID(VehicleType type, uint16 grf_local_id, uint32 grfid);
 
};
 

	
 
extern EngineOverrideManager _engine_mngr;
 

	
 
#define FOR_ALL_ENGINES_FROM(var, start) FOR_ALL_ITEMS_FROM(Engine, engine_index, var, start)
 
#define FOR_ALL_ENGINES(var) FOR_ALL_ENGINES_FROM(var, 0)
 

	
 
#define FOR_ALL_ENGINES_OF_TYPE(e, engine_type) FOR_ALL_ENGINES(e) if (e->type == engine_type)
 

	
 
static inline const EngineInfo *EngInfo(EngineID e)
 
{
 
	return &Engine::Get(e)->info;
 
}
 

	
 
static inline const RailVehicleInfo *RailVehInfo(EngineID e)
 
{
 
	return &Engine::Get(e)->u.rail;
 
}
 

	
 
static inline const RoadVehicleInfo *RoadVehInfo(EngineID e)
 
{
 
	return &Engine::Get(e)->u.road;
 
}
 

	
 
static inline const ShipVehicleInfo *ShipVehInfo(EngineID e)
 
{
 
	return &Engine::Get(e)->u.ship;
 
}
 

	
 
static inline const AircraftVehicleInfo *AircraftVehInfo(EngineID e)
 
{
 
	return &Engine::Get(e)->u.air;
 
}
 

	
 
#endif /* ENGINE_TYPE_H */
src/roadveh_cmd.cpp
Show inline comments
 
@@ -137,193 +137,193 @@ void RoadVehUpdateCache(RoadVehicle *v)
 
	assert(v->type == VEH_ROAD);
 
	assert(IsRoadVehFront(v));
 

	
 
	v->InvalidateNewGRFCacheOfChain();
 

	
 
	for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
 
		/* Check the v->first cache. */
 
		assert(u->First() == v);
 

	
 
		/* Update the 'first engine' */
 
		u->rcache.first_engine = (v == u) ? INVALID_ENGINE : v->engine_type;
 

	
 
		/* Update the length of the vehicle. */
 
		u->rcache.cached_veh_length = GetRoadVehLength(u);
 

	
 
		/* Invalidate the vehicle colour map */
 
		u->colourmap = PAL_NONE;
 
	}
 
}
 

	
 
/** Build a road vehicle.
 
 * @param tile tile of depot where road vehicle is built
 
 * @param flags operation to perform
 
 * @param p1 bus/truck type being built (engine)
 
 * @param p2 unused
 
 */
 
CommandCost CmdBuildRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	if (!IsEngineBuildable(p1, VEH_ROAD, _current_company)) return_cmd_error(STR_ROAD_VEHICLE_NOT_AVAILABLE);
 

	
 
	const Engine *e = Engine::Get(p1);
 
	/* Engines without valid cargo should not be available */
 
	if (e->GetDefaultCargoType() == CT_INVALID) return CMD_ERROR;
 

	
 
	CommandCost cost(EXPENSES_NEW_VEHICLES, e->GetCost());
 
	if (flags & DC_QUERY_COST) return cost;
 

	
 
	/* The ai_new queries the vehicle cost before building the route,
 
	 * so we must check against cheaters no sooner than now. --pasky */
 
	if (!IsRoadDepotTile(tile)) return CMD_ERROR;
 
	if (!IsTileOwner(tile, _current_company)) return CMD_ERROR;
 

	
 
	if (HasTileRoadType(tile, ROADTYPE_TRAM) != HasBit(EngInfo(p1)->misc_flags, EF_ROAD_TRAM)) return_cmd_error(STR_DEPOT_WRONG_DEPOT_TYPE);
 

	
 
	uint num_vehicles = 1 + CountArticulatedParts(p1, false);
 

	
 
	/* Allow for the front and the articulated parts */
 
	if (!Vehicle::CanAllocateItem(num_vehicles)) {
 
		return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
 
	}
 

	
 
	/* find the first free roadveh id */
 
	UnitID unit_num = (flags & DC_AUTOREPLACE) ? 0 : GetFreeUnitNumber(VEH_ROAD);
 
	if (unit_num > _settings_game.vehicle.max_roadveh) {
 
		return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		const RoadVehicleInfo *rvi = RoadVehInfo(p1);
 

	
 
		RoadVehicle *v = new RoadVehicle();
 
		v->unitnumber = unit_num;
 
		v->direction = DiagDirToDir(GetRoadDepotDirection(tile));
 
		v->owner = _current_company;
 

	
 
		v->tile = tile;
 
		int x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
 
		int 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->state = RVSB_IN_DEPOT;
 
		v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
 

	
 
		v->spritenum = rvi->image_index;
 
		v->cargo_type = e->GetDefaultCargoType();
 
//		v->cargo_subtype = 0;
 
		v->cargo_cap = rvi->capacity;
 
//		v->cargo_count = 0;
 
		v->value = cost.GetCost();
 
//		v->day_counter = 0;
 
//		v->next_order_param = v->next_order = 0;
 
//		v->load_unload_time_rem = 0;
 
//		v->progress = 0;
 

	
 
//		v->overtaking = 0;
 

	
 
		v->last_station_visited = INVALID_STATION;
 
		v->max_speed = rvi->max_speed;
 
		v->engine_type = (EngineID)p1;
 

	
 
		v->reliability = e->reliability;
 
		v->reliability_spd_dec = e->reliability_spd_dec;
 
		v->max_age = e->lifelength * DAYS_IN_LEAP_YEAR;
 
		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();
 
		SetRoadVehFront(v);
 

	
 
		v->roadtype = HasBit(EngInfo(v->engine_type)->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);
 

	
 
		v->cargo_cap = rvi->capacity;
 

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

	
 
		/* Call various callbacks after the whole consist has been constructed */
 
		for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
 
			u->rcache.cached_veh_length = GetRoadVehLength(u);
 
			/* Cargo capacity is zero if and only if the vehicle cannot carry anything */
 
			if (u->cargo_cap != 0) u->cargo_cap = GetVehicleProperty(u, 0x0F, u->cargo_cap);
 
			v->InvalidateNewGRFCache();
 
			u->InvalidateNewGRFCache();
 
		}
 

	
 
		VehicleMove(v, false);
 

	
 
		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
 
		InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
 
		InvalidateWindow(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;
 
}
 

	
 
void ClearSlot(RoadVehicle *v)
 
{
 
	RoadStop *rs = v->slot;
 
	if (v->slot == NULL) return;
 

	
 
	v->slot = NULL;
 
	v->slot_age = 0;
 

	
 
	assert(rs->num_vehicles != 0);
 
	rs->num_vehicles--;
 

	
 
	DEBUG(ms, 3, "Clearing slot at 0x%X", rs->xy);
 
}
 

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

	
 
	if (!IsRoadDepotTile(tile)) return false;
 
	if (IsRoadVehFront(this) && !(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
 
 */
 
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_CAN_T_SELL_DESTROYED_VEHICLE);
 

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

	
 
	CommandCost ret(EXPENSES_NEW_VEHICLES, -v->value);
src/ship_cmd.cpp
Show inline comments
 
@@ -706,193 +706,193 @@ static void ShipController(Ship *v)
 
	v->x_pos = gp.x;
 
	v->y_pos = gp.y;
 
	v->z_pos = GetSlopeZ(gp.x, gp.y);
 

	
 
getout:
 
	v->UpdateDeltaXY(dir);
 
	v->cur_image = v->GetImage(dir);
 
	VehicleMove(v, true);
 
	return;
 

	
 
reverse_direction:
 
	dir = ReverseDir(v->direction);
 
	v->direction = dir;
 
	goto getout;
 
}
 

	
 
static void AgeShipCargo(Vehicle *v)
 
{
 
	if (_age_cargo_skip_counter != 0) return;
 
	v->cargo.AgeCargo();
 
}
 

	
 
bool Ship::Tick()
 
{
 
	if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
 

	
 
	AgeShipCargo(this);
 
	ShipController(this);
 

	
 
	return true;
 
}
 

	
 
/** Build a ship.
 
 * @param tile tile of depot where ship is built
 
 * @param flags type of operation
 
 * @param p1 ship type being built (engine)
 
 * @param p2 unused
 
 */
 
CommandCost CmdBuildShip(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	UnitID unit_num;
 

	
 
	if (!IsEngineBuildable(p1, VEH_SHIP, _current_company)) return_cmd_error(STR_SHIP_NOT_AVAILABLE);
 

	
 
	const Engine *e = Engine::Get(p1);
 
	CommandCost value(EXPENSES_NEW_VEHICLES, e->GetCost());
 

	
 
	/* Engines without valid cargo should not be available */
 
	if (e->GetDefaultCargoType() == CT_INVALID) return CMD_ERROR;
 

	
 
	if (flags & DC_QUERY_COST) return value;
 

	
 
	/* The ai_new queries the vehicle cost before building the route,
 
	 * so we must check against cheaters no sooner than now. --pasky */
 
	if (!IsShipDepotTile(tile)) return CMD_ERROR;
 
	if (!IsTileOwner(tile, _current_company)) return CMD_ERROR;
 

	
 
	unit_num = (flags & DC_AUTOREPLACE) ? 0 : GetFreeUnitNumber(VEH_SHIP);
 

	
 
	if (!Vehicle::CanAllocateItem() || unit_num > _settings_game.vehicle.max_ships)
 
		return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
 

	
 
	if (flags & DC_EXEC) {
 
		int x;
 
		int y;
 

	
 
		const ShipVehicleInfo *svi = ShipVehInfo(p1);
 

	
 
		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->lifelength * DAYS_IN_LEAP_YEAR;
 
		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 = GetVehicleProperty(v, 0x0D, svi->capacity);
 

	
 
		v->InvalidateNewGRFCacheOfChain();
 

	
 
		VehicleMove(v, false);
 

	
 
		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
 
		InvalidateWindowClassesData(WC_SHIPS_LIST, 0);
 
		InvalidateWindow(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
 
 */
 
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_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);
 

	
 
	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)
 
 */
 
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.
src/train_cmd.cpp
Show inline comments
 
@@ -776,193 +776,193 @@ static void AddRearEngineToMultiheadedTr
 
	u->track = TRACK_BIT_DEPOT;
 
	u->vehstatus = v->vehstatus & ~VS_STOPPED;
 
//	u->subtype = 0;
 
	u->spritenum = v->spritenum + 1;
 
	u->cargo_type = v->cargo_type;
 
	u->cargo_subtype = v->cargo_subtype;
 
	u->cargo_cap = v->cargo_cap;
 
	u->railtype = v->railtype;
 
	u->engine_type = v->engine_type;
 
	u->build_year = v->build_year;
 
	u->cur_image = SPR_IMG_QUERY;
 
	u->random_bits = VehicleRandomBits();
 
	SetMultiheaded(v);
 
	SetMultiheaded(u);
 
	v->SetNext(u);
 
	VehicleMove(u, false);
 

	
 
	/* Now we need to link the front and rear engines together */
 
	v->other_multiheaded_part = u;
 
	u->other_multiheaded_part = v;
 
}
 

	
 
/** Build a railroad vehicle.
 
 * @param tile tile of the depot where rail-vehicle is built
 
 * @param flags type of operation
 
 * @param p1 engine type id
 
 * @param p2 bit 1 prevents any free cars from being added to the train
 
 */
 
CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	/* Check if the engine-type is valid (for the company) */
 
	if (!IsEngineBuildable(p1, VEH_TRAIN, _current_company)) return_cmd_error(STR_RAIL_VEHICLE_NOT_AVAILABLE);
 

	
 
	const Engine *e = Engine::Get(p1);
 
	CommandCost value(EXPENSES_NEW_VEHICLES, e->GetCost());
 

	
 
	/* Engines with CT_INVALID should not be available */
 
	if (e->GetDefaultCargoType() == CT_INVALID) return CMD_ERROR;
 

	
 
	if (flags & DC_QUERY_COST) return value;
 

	
 
	/* Check if the train is actually being built in a depot belonging
 
	 * to the company. Doesn't matter if only the cost is queried */
 
	if (!IsRailDepotTile(tile)) return CMD_ERROR;
 
	if (!IsTileOwner(tile, _current_company)) return CMD_ERROR;
 

	
 
	const RailVehicleInfo *rvi = RailVehInfo(p1);
 
	if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags);
 

	
 
	uint num_vehicles =
 
		(rvi->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) +
 
		CountArticulatedParts(p1, false);
 

	
 
	/* Check if depot and new engine uses the same kind of tracks *
 
	 * We need to see if the engine got power on the tile to avoid eletric engines in non-electric depots */
 
	if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
 

	
 
	/* Allow for the dual-heads and the articulated parts */
 
	if (!Vehicle::CanAllocateItem(num_vehicles)) {
 
		return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
 
	}
 

	
 
	UnitID unit_num = (flags & DC_AUTOREPLACE) ? 0 : GetFreeUnitNumber(VEH_TRAIN);
 
	if (unit_num > _settings_game.vehicle.max_trains) {
 
		return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		DiagDirection dir = GetRailDepotDirection(tile);
 
		int x = TileX(tile) * TILE_SIZE + _vehicle_initial_x_fract[dir];
 
		int y = TileY(tile) * TILE_SIZE + _vehicle_initial_y_fract[dir];
 

	
 
		Train *v = new Train();
 
		v->unitnumber = unit_num;
 
		v->direction = DiagDirToDir(dir);
 
		v->tile = tile;
 
		v->owner = _current_company;
 
		v->x_pos = x;
 
		v->y_pos = y;
 
		v->z_pos = GetSlopeZ(x, y);
 
//		v->running_ticks = 0;
 
		v->track = TRACK_BIT_DEPOT;
 
		v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
 
		v->spritenum = rvi->image_index;
 
		v->cargo_type = e->GetDefaultCargoType();
 
//		v->cargo_subtype = 0;
 
		v->cargo_cap = rvi->capacity;
 
		v->max_speed = rvi->max_speed;
 
		v->value = value.GetCost();
 
		v->last_station_visited = INVALID_STATION;
 
//		v->dest_tile = 0;
 

	
 
		v->engine_type = p1;
 

	
 
		v->reliability = e->reliability;
 
		v->reliability_spd_dec = e->reliability_spd_dec;
 
		v->max_age = e->lifelength * DAYS_IN_LEAP_YEAR;
 
		v->max_age = e->GetLifeLengthInDays();
 

	
 
		v->name = NULL;
 
		v->railtype = rvi->railtype;
 
		_new_vehicle_id = v->index;
 

	
 
		v->service_interval = Company::Get(_current_company)->settings.vehicle.servint_trains;
 
		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->group_id = DEFAULT_GROUP;
 

	
 
//		v->subtype = 0;
 
		SetFrontEngine(v);
 
		SetTrainEngine(v);
 

	
 
		VehicleMove(v, false);
 

	
 
		if (rvi->railveh_type == RAILVEH_MULTIHEAD) {
 
			AddRearEngineToMultiheadedTrain(v);
 
		} else {
 
			AddArticulatedParts(v, VEH_TRAIN);
 
		}
 

	
 
		TrainConsistChanged(v, false);
 
		UpdateTrainGroupID(v);
 

	
 
		if (!HasBit(p2, 1) && !(flags & DC_AUTOREPLACE)) { // check if the cars should be added to the new vehicle
 
			NormalizeTrainVehInDepot(v);
 
		}
 

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

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

	
 
		CheckConsistencyOfArticulatedVehicle(v);
 
	}
 

	
 
	return value;
 
}
 

	
 

	
 
/* Check if all the wagons of the given train are in a depot, returns the
 
 * number of cars (including loco) then. If not it returns -1 */
 
int CheckTrainInDepot(const Train *v, bool needs_to_be_stopped)
 
{
 
	TileIndex tile = v->tile;
 

	
 
	/* check if stopped in a depot */
 
	if (!IsRailDepotTile(tile) || v->cur_speed != 0) return -1;
 

	
 
	int count = 0;
 
	for (; v != NULL; v = v->Next()) {
 
		/* This count is used by the depot code to determine the number of engines
 
		 * in the consist. Exclude articulated parts so that autoreplacing to
 
		 * engines with more articulated parts than before works correctly.
 
		 *
 
		 * Also skip counting rear ends of multiheaded engines */
 
		if (!IsArticulatedPart(v) && !IsRearDualheaded(v)) count++;
 
		if (v->track != TRACK_BIT_DEPOT || v->tile != tile ||
 
				(IsFrontEngine(v) && needs_to_be_stopped && !(v->vehstatus & VS_STOPPED))) {
 
			return -1;
 
		}
 
	}
 

	
 
	return count;
 
}
 

	
 
/* Used to check if the train is inside the depot and verifying that the VS_STOPPED flag is set */
 
int CheckTrainStoppedInDepot(const Train *v)
 
{
 
	return CheckTrainInDepot(v, true);
 
}
 

	
 
/* Used to check if the train is inside the depot, but not checking the VS_STOPPED flag */
 
inline bool CheckTrainIsInsideDepot(const Train *v)
 
{
 
	return CheckTrainInDepot(v, false) > 0;
 
}
 

	
 
/**
 
 * Unlink a rail wagon from the consist.
 
 * @param v Vehicle to remove.
 
 * @param first The first vehicle of the consist.
 
 * @return The first vehicle of the consist.
 
 */
 
static Train *UnlinkWagon(Train *v, Train *first)
0 comments (0 inline, 0 general)