Changeset - r5868:bc3e720ec5f7
[Not reviewed]
master
0 12 0
belugas - 17 years ago 2007-01-30 11:53:35
belugas@openttd.org
(svn r8455) -Codechange: Give a more meaningful name (railveh_type)to member flags of RailVehInfo, as well as changing the code to reflect the fact that it was not a flag but rather a one value only variable. Doing so, some evaluations have been simplified.
-Codechange: Add and use RAILVEH_SINGLEHEAD when railveh_type is set to 0, which was implicit before.
-Cleanup: Remove some extraneous parenthesis.
12 files changed with 89 insertions and 86 deletions:
0 comments (0 inline, 0 general)
src/ai/default/default.cpp
Show inline comments
 
@@ -122,50 +122,50 @@ static void AiStateVehLoop(Player *p)
 
					)) {
 
				p->ai.state = AIS_VEH_CHECK_REPLACE_VEHICLE;
 
				p->ai.cur_veh = v;
 
				return;
 
			}
 
		}
 
	}
 

	
 
	p->ai.state = AIS_WANT_NEW_ROUTE;
 
	p->ai.state_counter = 0;
 
}
 

	
 
static EngineID AiChooseTrainToBuild(RailType railtype, int32 money, byte flag, TileIndex tile)
 
{
 
	EngineID best_veh_index = INVALID_ENGINE;
 
	byte best_veh_score = 0;
 
	int32 ret;
 
	EngineID i;
 

	
 
	for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
 
		const RailVehicleInfo *rvi = RailVehInfo(i);
 
		const Engine* e = GetEngine(i);
 

	
 
		if (!IsCompatibleRail(rvi->railtype, railtype) ||
 
				rvi->flags & RVI_WAGON ||
 
				(rvi->flags & RVI_MULTIHEAD && flag & 1) ||
 
				rvi->railveh_type == RAILVEH_WAGON ||
 
				(rvi->railveh_type == RAILVEH_MULTIHEAD && flag & 1) ||
 
				!HASBIT(e->player_avail, _current_player) ||
 
				e->reliability < 0x8A3D) {
 
			continue;
 
		}
 

	
 
		ret = DoCommand(tile, i, 0, 0, CMD_BUILD_RAIL_VEHICLE);
 
		if (!CmdFailed(ret) && ret <= money && rvi->ai_rank >= best_veh_score) {
 
			best_veh_score = rvi->ai_rank;
 
			best_veh_index = i;
 
		}
 
	}
 

	
 
	return best_veh_index;
 
}
 

	
 
static EngineID AiChooseRoadVehToBuild(CargoID cargo, int32 money, TileIndex tile)
 
{
 
	EngineID best_veh_index = INVALID_ENGINE;
 
	int32 best_veh_rating = 0;
 
	EngineID i = ROAD_ENGINES_INDEX;
 
	EngineID end = i + NUM_ROAD_ENGINES;
 

	
 
	for (; i != end; i++) {
 
		const RoadVehicleInfo *rvi = RoadVehInfo(i);
 
@@ -2345,49 +2345,49 @@ static void AiStateBuildRail(Player *p)
 
	p->ai.state_counter = 0;
 
	p->ai.banned_tile_count = 0;
 
}
 

	
 
static StationID AiGetStationIdByDef(TileIndex tile, int id)
 
{
 
	const AiDefaultBlockData *p = _default_rail_track_data[id]->data;
 
	while (p->mode != 1) p++;
 
	return GetStationIndex(TILE_ADD(tile, ToTileIndexDiff(p->tileoffs)));
 
}
 

	
 
static EngineID AiFindBestWagon(CargoID cargo, RailType railtype)
 
{
 
	EngineID best_veh_index = INVALID_ENGINE;
 
	EngineID i;
 
	uint16 best_capacity = 0;
 
	uint16 best_speed    = 0;
 
	uint speed;
 

	
 
	for (i = 0; i < NUM_TRAIN_ENGINES; i++) {
 
		const RailVehicleInfo *rvi = RailVehInfo(i);
 
		const Engine* e = GetEngine(i);
 

	
 
		if (!IsCompatibleRail(rvi->railtype, railtype) ||
 
				!(rvi->flags & RVI_WAGON) ||
 
				rvi->railveh_type != RAILVEH_WAGON ||
 
				!HASBIT(e->player_avail, _current_player)) {
 
			continue;
 
		}
 

	
 
		if (rvi->cargo_type != cargo) continue;
 

	
 
		/* max_speed of 0 indicates no speed limit */
 
		speed = rvi->max_speed == 0 ? 0xFFFF : rvi->max_speed;
 

	
 
		if (rvi->capacity >= best_capacity && speed >= best_speed) {
 
			best_capacity = rvi->capacity;
 
			best_speed    = best_speed;
 
			best_veh_index = i;
 
		}
 
	}
 

	
 
	return best_veh_index;
 
}
 

	
 
static void AiStateBuildRailVeh(Player *p)
 
{
 
	const AiDefaultBlockData *ptr;
 
	TileIndex tile;
 
	EngineID veh;
src/autoreplace_gui.cpp
Show inline comments
 
@@ -42,49 +42,49 @@ static void train_engine_drawing_loop(in
 
	uint8 lines_drawn, bool is_engine, bool show_cars, bool show_outdated, bool show_compatible)
 
{
 
	EngineID j;
 
	byte colour;
 
	const Player *p = GetPlayer(_local_player);
 

	
 
	for (j = 0; j < NUM_TRAIN_ENGINES; j++) {
 
		EngineID i = GetRailVehAtPosition(j);
 
		const Engine *e = GetEngine(i);
 
		const RailVehicleInfo *rvi = RailVehInfo(i);
 
		const EngineInfo *info = EngInfo(i);
 

	
 
		if (!EngineHasReplacementForPlayer(p, i) && p->num_engines[i] == 0 && show_outdated) continue;
 

	
 
		if ((rvi->power == 0 && !show_cars) || (rvi->power != 0 && show_cars))  // show wagons or engines (works since wagons do not have power)
 
			continue;
 

	
 
		if (*sel == 0) *selected_id = j;
 

	
 

	
 
		colour = *sel == 0 ? 0xC : 0x10;
 
		if (!(ENGINE_AVAILABLE && show_outdated && RailVehInfo(i)->power && IsCompatibleRail(rvi->railtype, railtype))) {
 
			if ((!IsCompatibleRail(rvi->railtype, railtype) && show_compatible)
 
				|| (rvi->railtype != railtype && !show_compatible)
 
				|| !(rvi->flags & RVI_WAGON) != is_engine ||
 
				|| (rvi->railveh_type != RAILVEH_WAGON) != is_engine ||
 
				!HASBIT(e->player_avail, _local_player))
 
				continue;
 
#if 0
 
		} else {
 
			// TODO find a nice red colour for vehicles being replaced
 
			if ( _autoreplace_array[i] != i )
 
				colour = *sel == 0 ? 0x44 : 0x45;
 
#endif
 
		}
 

	
 
		if (IS_INT_INSIDE(--*pos, -lines_drawn, 0)) {
 
			DrawString(*x + 59, *y + 2, GetCustomEngineName(i),
 
				colour);
 
			// show_outdated is true only for left side, which is where we show old replacements
 
			DrawTrainEngine(*x + 29, *y + 6, i, (p->num_engines[i] == 0 && show_outdated) ?
 
				PALETTE_CRASH : GetEnginePalette(i, _local_player));
 
			if ( show_outdated ) {
 
				SetDParam(0, p->num_engines[i]);
 
				DrawStringRightAligned(213, *y+5, STR_TINY_BLACK, 0);
 
			}
 
			*y += 14;
 
		}
 
		--*sel;
 
	}
src/build_vehicle_gui.cpp
Show inline comments
 
@@ -166,91 +166,91 @@ static int CDECL EngineReliabilitySorter
 
/* Train sorting functions */
 
static int CDECL TrainEngineCostSorter(const void *a, const void *b)
 
{
 
	int va = RailVehInfo(*(const EngineID*)a)->base_cost;
 
	int vb = RailVehInfo(*(const EngineID*)b)->base_cost;
 
	int r = va - vb;
 

	
 
	return _internal_sort_order ? -r : r;
 
}
 

	
 
static int CDECL TrainEngineSpeedSorter(const void *a, const void *b)
 
{
 
	int va = RailVehInfo(*(const EngineID*)a)->max_speed;
 
	int vb = RailVehInfo(*(const EngineID*)b)->max_speed;
 
	int r = va - vb;
 

	
 
	return _internal_sort_order ? -r : r;
 
}
 

	
 
static int CDECL TrainEnginePowerSorter(const void *a, const void *b)
 
{
 
	const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
 
	const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
 

	
 
	int va = rvi_a->power << (rvi_a->flags & RVI_MULTIHEAD ? 1 : 0);
 
	int vb = rvi_b->power << (rvi_b->flags & RVI_MULTIHEAD ? 1 : 0);
 
	int va = rvi_a->power << (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
 
	int vb = rvi_b->power << (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
 
	int r = va - vb;
 

	
 
	return _internal_sort_order ? -r : r;
 
}
 

	
 
static int CDECL TrainEngineRunningCostSorter(const void *a, const void *b)
 
{
 
	const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
 
	const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
 

	
 
	int va = rvi_a->running_cost_base * _price.running_rail[rvi_a->running_cost_class] * (rvi_a->flags & RVI_MULTIHEAD ? 2 : 1);
 
	int vb = rvi_b->running_cost_base * _price.running_rail[rvi_b->running_cost_class] * (rvi_b->flags & RVI_MULTIHEAD ? 2 : 1);
 
	int va = rvi_a->running_cost_base * _price.running_rail[rvi_a->running_cost_class] * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
 
	int vb = rvi_b->running_cost_base * _price.running_rail[rvi_b->running_cost_class] * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
 
	int r = va - vb;
 

	
 
	return _internal_sort_order ? -r : r;
 
}
 

	
 
static int CDECL TrainEnginePowerVsRunningCostSorter(const void *a, const void *b)
 
{
 
	const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
 
	const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
 

	
 
	/* Here we are using a few tricks to get the right sort.
 
		* We want power/running cost, but since we usually got higher running cost than power and we store the result in an int,
 
		* we will actually calculate cunning cost/power (to make it more than 1).
 
		* Because of this, the return value have to be reversed as well and we return b - a instead of a - b.
 
		* Another thing is that both power and running costs should be doubled for multiheaded engines.
 
		* Since it would be multipling with 2 in both numerator and denumerator, it will even themselves out and we skip checking for multiheaded. */
 
	int va = (rvi_a->running_cost_base * _price.running_rail[rvi_a->running_cost_class]) / max((uint16)1, rvi_a->power);
 
	int vb = (rvi_b->running_cost_base * _price.running_rail[rvi_b->running_cost_class]) / max((uint16)1, rvi_b->power);
 
	int r = vb - va;
 

	
 
	return _internal_sort_order ? -r : r;
 
}
 

	
 
static int CDECL TrainEnginesThenWagonsSorter(const void *a, const void *b)
 
{
 
	EngineID va = *(const EngineID*)a;
 
	EngineID vb = *(const EngineID*)b;
 
	int val_a = ((RailVehInfo(va)->flags & RVI_WAGON) != 0) ? 1 : 0;
 
	int val_b = ((RailVehInfo(vb)->flags & RVI_WAGON) != 0) ? 1 : 0;
 
	int val_a = (RailVehInfo(va)->railveh_type != RAILVEH_WAGON ? 1 : 0);
 
	int val_b = (RailVehInfo(vb)->railveh_type != RAILVEH_WAGON ? 1 : 0);
 
	int r = val_a - val_b;
 

	
 
	/* Use EngineID to sort instead since we want consistent sorting */
 
	if (r == 0) return EngineNumberSorter(a, b);
 

	
 
	return _internal_sort_order ? -r : r;
 
}
 

	
 
/* Aircraft sorting functions */
 

	
 
static int CDECL AircraftEngineCostSorter(const void *a, const void *b)
 
{
 
	const int va = AircraftVehInfo(*(const EngineID*)a)->base_cost;
 
	const int vb = AircraftVehInfo(*(const EngineID*)b)->base_cost;
 
	int r = va - vb;
 

	
 
	return _internal_sort_order ? -r : r;
 
}
 

	
 
static int CDECL AircraftEngineSpeedSorter(const void *a, const void *b)
 
{
 
	const int va = AircraftVehInfo(*(const EngineID*)a)->max_speed;
 
	const int vb = AircraftVehInfo(*(const EngineID*)b)->max_speed;
 
	const int r = va - vb;
 
@@ -367,49 +367,49 @@ static int DrawRailWagonPurchaseInfo(int
 
{
 
	/* Purchase cost */
 
	SetDParam(0, (rvi->base_cost * _price.build_railwagon) >> 8);
 
	DrawString(x, y, STR_PURCHASE_INFO_COST, 0);
 
	y += 10;
 

	
 
	/* Wagon weight - (including cargo) */
 
	SetDParam(0, rvi->weight);
 
	SetDParam(1, (_cargoc.weights[rvi->cargo_type] * rvi->capacity >> 4) + rvi->weight);
 
	DrawString(x, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT, 0);
 
	y += 10;
 

	
 
	/* Wagon speed limit, displayed if above zero */
 
	if (rvi->max_speed > 0 && _patches.wagon_speed_limits) {
 
		SetDParam(0, rvi->max_speed);
 
		DrawString(x,y, STR_PURCHASE_INFO_SPEED, 0);
 
		y += 10;
 
	}
 
	return y;
 
}
 

	
 
/* Draw locomotive specific details */
 
static int DrawRailEnginePurchaseInfo(int x, int y, EngineID engine_number, const RailVehicleInfo *rvi)
 
{
 
	int multihead = (rvi->flags&RVI_MULTIHEAD?1:0);
 
	int multihead = (rvi->railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
 

	
 
	/* Purchase Cost - Engine weight */
 
	SetDParam(0, rvi->base_cost * (_price.build_railvehicle >> 3) >> 5);
 
	SetDParam(1, rvi->weight << multihead);
 
	DrawString(x,y, STR_PURCHASE_INFO_COST_WEIGHT, 0);
 
	y += 10;
 

	
 
	/* Max speed - Engine power */
 
	SetDParam(0, rvi->max_speed);
 
	SetDParam(1, rvi->power << multihead);
 
	DrawString(x,y, STR_PURCHASE_INFO_SPEED_POWER, 0);
 
	y += 10;
 

	
 
	/* Max tractive effort - not applicable if old acceleration or maglev */
 
	if (_patches.realistic_acceleration && rvi->railtype != RAILTYPE_MAGLEV) {
 
		SetDParam(0, ((rvi->weight << multihead) * 10 * rvi->tractive_effort) / 256);
 
		DrawString(x, y, STR_PURCHASE_INFO_MAX_TE, 0);
 
		y += 10;
 
	}
 

	
 
	/* Running cost */
 
	SetDParam(0, (rvi->running_cost_base * _price.running_rail[rvi->running_cost_class] >> 8) << multihead);
 
	DrawString(x,y, STR_PURCHASE_INFO_RUNNINGCOST, 0);
 
	y += 10;
 
@@ -508,127 +508,127 @@ static int DrawAircraftPurchaseInfo(int 
 
	y += 10;
 

	
 
	return y;
 
}
 

	
 
/**
 
 * Draw the purchase info details of a vehicle at a given location.
 
 * @param x,y location where to draw the info
 
 * @param w how wide are the text allowed to be (size of widget/window to Draw in)
 
 * @param engine_number the engine of which to draw the info of
 
 */
 
void DrawVehiclePurchaseInfo(int x, int y, uint w, EngineID engine_number)
 
{
 
	const Engine *e = GetEngine(engine_number);
 
	YearMonthDay ymd;
 
	ConvertDateToYMD(e->intro_date, &ymd);
 
	bool refitable = false;
 

	
 
	switch (e->type) {
 
		case VEH_Train: {
 
			const RailVehicleInfo *rvi = RailVehInfo(engine_number);
 

	
 
			refitable = (EngInfo(engine_number)->refit_mask != 0) && (rvi->capacity > 0);
 

	
 
			if (rvi->flags & RVI_WAGON) {
 
			if (rvi->railveh_type == RAILVEH_WAGON) {
 
				y = DrawRailWagonPurchaseInfo(x, y, engine_number, rvi);
 
			} else {
 
				y = DrawRailEnginePurchaseInfo(x, y, engine_number, rvi);
 
			}
 

	
 
			/* Cargo type + capacity, or N/A */
 
			if (rvi->capacity == 0) {
 
				SetDParam(0, CT_INVALID);
 
				SetDParam(2, STR_EMPTY);
 
			} else {
 
				int multihead = (rvi->flags & RVI_MULTIHEAD ? 1 : 0);
 
				int multihead = (rvi->railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
 

	
 
				SetDParam(0, rvi->cargo_type);
 
				SetDParam(1, (rvi->capacity * (CountArticulatedParts(engine_number) + 1)) << multihead);
 
				SetDParam(2, refitable ? STR_9842_REFITTABLE : STR_EMPTY);
 
			}
 
			DrawString(x,y, STR_PURCHASE_INFO_CAPACITY, 0);
 
			y += 10;
 
		}
 
			break;
 
		case VEH_Road:
 
			y = DrawRoadVehPurchaseInfo(x, y, engine_number, RoadVehInfo(engine_number));
 
			refitable = true;
 
			break;
 
		case VEH_Ship: {
 
			const ShipVehicleInfo *svi = ShipVehInfo(engine_number);
 
			y = DrawShipPurchaseInfo(x, y, engine_number, svi);
 
			refitable = svi->refittable;
 
		} break;
 
		case VEH_Aircraft:
 
			y = DrawAircraftPurchaseInfo(x, y, engine_number, AircraftVehInfo(engine_number));
 
			refitable = true;
 
			break;
 
	}
 

	
 
	/* Draw details, that applies to all types except rail wagons */
 
	if (e->type != VEH_Train || !(RailVehInfo(engine_number)->flags & RVI_WAGON)) {
 
	if (e->type != VEH_Train || RailVehInfo(engine_number)->railveh_type != RAILVEH_WAGON) {
 
		/* Design date - Life length */
 
		SetDParam(0, ymd.year);
 
		SetDParam(1, e->lifelength);
 
		DrawString(x, y, STR_PURCHASE_INFO_DESIGNED_LIFE, 0);
 
		y += 10;
 

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

	
 
	/* Additional text from NewGRF */
 
	y += ShowAdditionalText(x, y, w, engine_number);
 
	if (refitable) y += ShowRefitOptionsList(x, y, w, engine_number);
 
}
 

	
 
/* Figure out what train EngineIDs to put in the list */
 
static void GenerateBuildTrainList(Window *w)
 
{
 
	EngineID eid, sel_id;
 
	int num_engines = 0;
 
	int num_wagons  = 0;
 
	buildvehicle_d *bv = &WP(w, buildvehicle_d);
 

	
 
	bv->filter.railtype = (w->window_number == 0) ? RAILTYPE_END : GetRailType(w->window_number);
 

	
 
	EngList_RemoveAll(&bv->eng_list);
 

	
 
	/* Make list of all available train engines and wagons.
 
		* Also check to see if the previously selected engine is still available,
 
		* and if not, reset selection to INVALID_ENGINE. This could be the case
 
	* when engines become obsolete and are removed */
 
	for (sel_id = INVALID_ENGINE, eid = 0; eid < NUM_TRAIN_ENGINES; eid++) {
 
		const RailVehicleInfo *rvi = RailVehInfo(eid);
 

	
 
		if (bv->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, bv->filter.railtype)) continue;
 
		if (!IsEngineBuildable(eid, VEH_Train, _local_player)) continue;
 

	
 
		EngList_Add(&bv->eng_list, eid);
 
		if ((rvi->flags & RVI_WAGON) == 0) {
 
		if (rvi->railveh_type != RAILVEH_WAGON) {
 
			num_engines++;
 
		} else {
 
			num_wagons++;
 
		}
 

	
 
		if (eid == bv->sel_engine) sel_id = eid;
 
	}
 

	
 
	bv->sel_engine = sel_id;
 

	
 
	// make engines first, and then wagons, sorted by ListPositionOfEngine()
 
	_internal_sort_order = false;
 
	EngList_Sort(&bv->eng_list, TrainEnginesThenWagonsSorter);
 

	
 
	// and then sort engines
 
	_internal_sort_order = bv->descending_sort_order;
 
	EngList_SortPartial(&bv->eng_list, _sorter[0][bv->sort_criteria], 0, num_engines);
 

	
 
	// and finally sort wagons
 
	EngList_SortPartial(&bv->eng_list, _sorter[0][bv->sort_criteria], num_engines, num_wagons);
 
}
 

	
 
/* Figure out what road vehicle EngineIDs to put in the list */
 
static void GenerateBuildRoadVehList(Window *w)
 
@@ -805,49 +805,49 @@ static void BuildVehicleClickEvent(Windo
 
		case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING:
 
			bv->descending_sort_order ^= true;
 
			_last_sort_order[VehTypeToIndex(bv->vehicle_type)] = bv->descending_sort_order;
 
			bv->regenerate_list = true;
 
			SetWindowDirty(w);
 
			break;
 

	
 
		case BUILD_VEHICLE_WIDGET_LIST: {
 
			uint i = (e->we.click.pt.y - 26) / GetVehicleListHeight(bv->vehicle_type) + w->vscroll.pos;
 
			uint num_items = EngList_Count(&bv->eng_list);
 
			bv->sel_engine = (i < num_items) ? bv->eng_list[i] : INVALID_ENGINE;
 
			SetWindowDirty(w);
 
			break;
 
		}
 

	
 
		case BUILD_VEHICLE_WIDGET_SORT_TEXT: case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN: // Select sorting criteria dropdown menu
 
			ShowDropDownMenu(w, _sort_listing[VehTypeToIndex(bv->vehicle_type)], bv->sort_criteria, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN, 0, 0);
 
			break;
 

	
 
		case BUILD_VEHICLE_WIDGET_BUILD: {
 
			EngineID sel_eng = bv->sel_engine;
 
			if (sel_eng != INVALID_ENGINE) {
 
				switch (bv->vehicle_type) {
 
					case VEH_Train:
 
						DoCommandP(w->window_number, sel_eng, 0, (RailVehInfo(sel_eng)->flags & RVI_WAGON) ? CcBuildWagon : CcBuildLoco,
 
						DoCommandP(w->window_number, sel_eng, 0, (RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildLoco,
 
								   CMD_BUILD_RAIL_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE));
 
						break;
 
					case VEH_Road:
 
						DoCommandP(w->window_number, sel_eng, 0, CcBuildRoadVeh, CMD_BUILD_ROAD_VEH | CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE));
 
						break;
 
					case VEH_Ship:
 
						DoCommandP(w->window_number, sel_eng, 0, CcBuildShip, CMD_BUILD_SHIP | CMD_MSG(STR_980D_CAN_T_BUILD_SHIP));
 
						break;
 
					case VEH_Aircraft:
 
						DoCommandP(w->window_number, sel_eng, 0, CcBuildAircraft, CMD_BUILD_AIRCRAFT | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT));
 
						break;
 
				}
 
			}
 
			break;
 
		}
 

	
 
		case BUILD_VEHICLE_WIDGET_RENAME: {
 
			EngineID sel_eng = bv->sel_engine;
 
			if (sel_eng != INVALID_ENGINE) {
 
				StringID str = STR_NULL;
 

	
 
				bv->rename_engine = sel_eng;
 
				switch (bv->vehicle_type) {
 
					case VEH_Train:    str = STR_886A_RENAME_TRAIN_VEHICLE_TYPE; break;
src/engine.cpp
Show inline comments
 
@@ -264,49 +264,49 @@ void EnginesDailyLoop(void)
 
}
 

	
 
/** Accept an engine prototype. XXX - it is possible that the top-player
 
 * changes while you are waiting to accept the offer? Then it becomes invalid
 
 * @param tile unused
 
 * @param p1 engine-prototype offered
 
 * @param p2 unused
 
 */
 
int32 CmdWantEnginePreview(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	Engine *e;
 

	
 
	if (!IsEngineIndex(p1)) return CMD_ERROR;
 
	e = GetEngine(p1);
 
	if (GetBestPlayer(e->preview_player) != _current_player) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) AcceptEnginePreview(p1, _current_player);
 

	
 
	return 0;
 
}
 

	
 
// Determine if an engine type is a wagon (and not a loco)
 
static bool IsWagon(EngineID index)
 
{
 
	return index < NUM_TRAIN_ENGINES && RailVehInfo(index)->flags & RVI_WAGON;
 
	return index < NUM_TRAIN_ENGINES && RailVehInfo(index)->railveh_type == RAILVEH_WAGON;
 
}
 

	
 
static void NewVehicleAvailable(Engine *e)
 
{
 
	Vehicle *v;
 
	Player *p;
 
	EngineID index = e - _engines;
 

	
 
	// In case the player didn't build the vehicle during the intro period,
 
	// prevent that player from getting future intro periods for a while.
 
	if (e->flags & ENGINE_INTRODUCING) {
 
		FOR_ALL_PLAYERS(p) {
 
			uint block_preview = p->block_preview;
 

	
 
			if (!HASBIT(e->player_avail, p->index)) continue;
 

	
 
			/* We assume the user did NOT build it.. prove me wrong ;) */
 
			p->block_preview = 20;
 

	
 
			FOR_ALL_VEHICLES(v) {
 
				if (v->type == VEH_Train || v->type == VEH_Road || v->type == VEH_Ship ||
 
						(v->type == VEH_Aircraft && IsNormalAircraft(v))) {
 
					if (v->owner == p->index && v->engine_type == index) {
 
						/* The user did prove me wrong, so restore old value */
src/engine.h
Show inline comments
 
/* $Id$ */
 

	
 
#ifndef ENGINE_H
 
#define ENGINE_H
 

	
 
/** @file engine.h */
 

	
 
#include "oldpool.h"
 
#include "rail.h"
 
#include "sound.h"
 

	
 
enum RailVehicleTypes {
 
	RAILVEH_SINGLEHEAD,
 
	RAILVEH_MULTIHEAD,
 
	RAILVEH_WAGON,
 
};
 

	
 
typedef struct RailVehicleInfo {
 
	byte image_index;
 
	byte flags; /* 1=multihead engine, 2=wagon */
 
	RailVehicleTypes railveh_type;
 
	byte base_cost;
 
	RailTypeByte railtype;
 
	uint16 max_speed;
 
	uint16 power;
 
	uint16 weight;
 
	byte running_cost_base;
 
	byte running_cost_class;
 
	byte engclass; // 0: steam, 1: diesel, 2: electric
 
	byte capacity;
 
	CargoID cargo_type;
 
	byte ai_rank;
 
	uint16 pow_wag_power;
 
	byte pow_wag_weight;
 
	byte visual_effect; // NOTE: this is not 100% implemented yet, at the moment it is only used as a 'fallback' value
 
	                    //       for when the 'powered wagon' callback fails. But it should really also determine what
 
	                    //       kind of visual effect to generate for a vehicle (default, steam, diesel, electric).
 
	                    //       Same goes for the callback result, which atm is only used to check if a wagon is powered.
 
	byte shorten_factor; // length on main map for this type is 8 - shorten_factor
 
	byte tractive_effort; ///< Tractive effort coefficient
 
	byte user_def_data; ///! Property 0x25: "User-defined bit mask" Used only for (very few) NewGRF vehicles
 
} RailVehicleInfo;
 

	
 
typedef struct ShipVehicleInfo {
 
	byte image_index;
 
@@ -97,53 +103,48 @@ typedef struct Engine {
 
	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;
 
	PlayerByte preview_player;
 
	byte preview_wait;
 
	byte player_avail;
 
	byte type; // type, ie VEH_Road, VEH_Train, etc. Same as in vehicle.h
 
} Engine;
 

	
 
/**
 
 * EngineInfo.misc_flags is a bitmask, with the following values
 
 */
 
enum {
 
	EF_RAIL_TILTS = 0, ///< Rail vehicle tilts in curves (unsupported)
 
	EF_ROAD_TRAM  = 0, ///< Road vehicle is a tram/light rail vehicle (unsup)
 
	EF_USES_2CC   = 1, ///< Vehicle uses two company colours
 
	EF_RAIL_IS_MU = 2, ///< Rail vehicle is a multiple-unit (DMU/EMU)
 
};
 

	
 
enum {
 
	RVI_MULTIHEAD = 1,
 
	RVI_WAGON = 2,
 
};
 

	
 
enum {
 
	NUM_VEHICLE_TYPES = 6
 
};
 

	
 
static const EngineID INVALID_ENGINE = 0xFFFF;
 

	
 

	
 
void AddTypeToEngines(void);
 
void StartupEngines(void);
 

	
 

	
 
void DrawTrainEngine(int x, int y, EngineID engine, SpriteID pal);
 
void DrawRoadVehEngine(int x, int y, EngineID engine, SpriteID pal);
 
void DrawShipEngine(int x, int y, EngineID engine, SpriteID pal);
 
void DrawAircraftEngine(int x, int y, EngineID engine, SpriteID pal);
 

	
 
void LoadCustomEngineNames(void);
 
void DeleteCustomEngineNames(void);
 

	
 
bool IsEngineBuildable(EngineID engine, byte type, PlayerID player);
 

	
 
enum {
 
	NUM_NORMAL_RAIL_ENGINES = 54,
 
	NUM_MONORAIL_ENGINES    = 30,
 
	NUM_MAGLEV_ENGINES      = 32,
src/engine_gui.cpp
Show inline comments
 
@@ -101,49 +101,49 @@ static void EnginePreviewWndProc(Window 
 
				DeleteWindow(w);
 
				break;
 
		}
 
		break;
 
	}
 
}
 

	
 
static const WindowDesc _engine_preview_desc = {
 
	WDP_CENTER, WDP_CENTER, 300, 192,
 
	WC_ENGINE_PREVIEW,0,
 
	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 
	_engine_preview_widgets,
 
	EnginePreviewWndProc
 
};
 

	
 

	
 
void ShowEnginePreviewWindow(EngineID engine)
 
{
 
	AllocateWindowDescFront(&_engine_preview_desc, engine);
 
}
 

	
 
static void DrawTrainEngineInfo(EngineID engine, int x, int y, int maxw)
 
{
 
	const RailVehicleInfo *rvi = RailVehInfo(engine);
 
	uint multihead = (rvi->flags & RVI_MULTIHEAD) ? 1 : 0;
 
	uint multihead = (rvi->railveh_type == RAILVEH_MULTIHEAD) ? 1 : 0;
 

	
 
	SetDParam(0, (_price.build_railvehicle >> 3) * rvi->base_cost >> 5);
 
	SetDParam(2, rvi->max_speed);
 
	SetDParam(3, rvi->power << multihead);
 
	SetDParam(1, rvi->weight << multihead);
 

	
 
	SetDParam(4, rvi->running_cost_base * _price.running_rail[rvi->running_cost_class] >> 8 << multihead);
 

	
 
	if (rvi->capacity != 0) {
 
		SetDParam(5, rvi->cargo_type);
 
		SetDParam(6, rvi->capacity << multihead);
 
	} else {
 
		SetDParam(5, CT_INVALID);
 
	}
 
	DrawStringMultiCenter(x, y, STR_VEHICLE_INFO_COST_WEIGHT_SPEED_POWER, maxw);
 
}
 

	
 
void DrawNewsNewTrainAvail(Window *w)
 
{
 
	EngineID engine;
 

	
 
	DrawNewsBorder(w);
 

	
 
	engine = WP(w,news_d).ni->string_id;
src/newgrf.cpp
Show inline comments
 
@@ -194,161 +194,161 @@ static GRFFile *GetFileByGRFID(uint32 gr
 
}
 

	
 
static GRFFile *GetFileByFilename(const char *filename)
 
{
 
	GRFFile *file;
 

	
 
	for (file = _first_grffile; file != NULL; file = file->next) {
 
		if (strcmp(file->filename, filename) == 0) break;
 
	}
 
	return file;
 
}
 

	
 

	
 
typedef bool (*VCI_Handler)(uint engine, int numinfo, int prop, byte **buf, int len);
 

	
 
#define FOR_EACH_OBJECT for (i = 0; i < numinfo; i++)
 

	
 
static void dewagonize(int condition, int engine)
 
{
 
	EngineInfo *ei = &_engine_info[engine];
 
	RailVehicleInfo *rvi = &_rail_vehicle_info[engine];
 

	
 
	if (condition != 0) {
 
		ei->unk2 &= ~0x80;
 
		rvi->flags &= ~2;
 
		rvi->railveh_type = RAILVEH_SINGLEHEAD;
 
	} else {
 
		ei->unk2 |= 0x80;
 
		rvi->flags |= 2;
 
		rvi->railveh_type = RAILVEH_WAGON;
 
	}
 
}
 

	
 
static bool RailVehicleChangeInfo(uint engine, int numinfo, int prop, byte **bufp, int len)
 
{
 
	EngineInfo *ei = &_engine_info[engine];
 
	RailVehicleInfo *rvi = &_rail_vehicle_info[engine];
 
	byte *buf = *bufp;
 
	int i;
 
	bool ret = false;
 

	
 
	switch (prop) {
 
		case 0x05: /* Track type */
 
			FOR_EACH_OBJECT {
 
				uint8 tracktype = grf_load_byte(&buf);
 

	
 
				switch (tracktype) {
 
					case 0: rvi[i].railtype = rvi[i].engclass == 2 ? RAILTYPE_ELECTRIC : RAILTYPE_RAIL; break;
 
					case 1: rvi[i].railtype = RAILTYPE_MONO; break;
 
					case 2: rvi[i].railtype = RAILTYPE_MAGLEV; break;
 
					default:
 
						grfmsg(1, "RailVehicleChangeInfo: Invalid track type %d specified, ignoring", tracktype);
 
						break;
 
				}
 
			}
 
			break;
 

	
 
		case 0x08: /* AI passenger service */
 
			/* TODO */
 
			FOR_EACH_OBJECT grf_load_byte(&buf);
 
			ret = true;
 
			break;
 

	
 
		case 0x09: /* Speed (1 unit is 1 kmh) */
 
			FOR_EACH_OBJECT {
 
				uint16 speed = grf_load_word(&buf);
 
				if (speed == 0xFFFF) speed = 0;
 

	
 
				rvi[i].max_speed = speed;
 
			}
 
			break;
 

	
 
		case 0x0B: /* Power */
 
			FOR_EACH_OBJECT {
 
				uint16 power = grf_load_word(&buf);
 

	
 
				if (rvi[i].flags & RVI_MULTIHEAD) power /= 2;
 
				if (rvi[i].railveh_type == RAILVEH_MULTIHEAD) power /= 2;
 

	
 
				rvi[i].power = power;
 
				dewagonize(power, engine + i);
 
			}
 
			break;
 

	
 
		case 0x0D: /* Running cost factor */
 
			FOR_EACH_OBJECT {
 
				uint8 runcostfact = grf_load_byte(&buf);
 

	
 
				if (rvi[i].flags & RVI_MULTIHEAD) runcostfact /= 2;
 
				if (rvi[i].railveh_type == RAILVEH_MULTIHEAD) runcostfact /= 2;
 

	
 
				rvi[i].running_cost_base = runcostfact;
 
			}
 
			break;
 

	
 
		case 0x0E: /* Running cost base */
 
			FOR_EACH_OBJECT {
 
				uint32 base = grf_load_dword(&buf);
 

	
 
				switch (base) {
 
					case 0x4C30: rvi[i].running_cost_class = 0; break;
 
					case 0x4C36: rvi[i].running_cost_class = 1; break;
 
					case 0x4C3C: rvi[i].running_cost_class = 2; break;
 
					case 0: break; /* Used by wagons */
 
					default:
 
						grfmsg(1, "RailVehicleChangeInfo: Unsupported running cost base 0x%04X, ignoring", base);
 
						break;
 
				}
 
			}
 
			break;
 

	
 
		case 0x12: /* Sprite ID */
 
			FOR_EACH_OBJECT {
 
				uint8 spriteid = grf_load_byte(&buf);
 

	
 
				/* TTD sprite IDs point to a location in a 16bit array, but we use it
 
				 * as an array index, so we need it to be half the original value. */
 
				if (spriteid < 0xFD) spriteid >>= 1;
 

	
 
				rvi[i].image_index = spriteid;
 
			}
 
			break;
 

	
 
		case 0x13: /* Dual-headed */
 
			FOR_EACH_OBJECT {
 
				uint8 dual = grf_load_byte(&buf);
 

	
 
				if (dual != 0) {
 
					if (!(rvi[i].flags & RVI_MULTIHEAD)) {
 
					if (rvi[i].railveh_type != RAILVEH_MULTIHEAD) {
 
						// adjust power and running cost if needed
 
						rvi[i].power /= 2;
 
						rvi[i].running_cost_base /= 2;
 
					}
 
					rvi[i].flags |= RVI_MULTIHEAD;
 
					rvi[i].railveh_type = RAILVEH_MULTIHEAD;
 
				} else {
 
					if (rvi[i].flags & RVI_MULTIHEAD) {
 
					if (rvi[i].railveh_type == RAILVEH_MULTIHEAD) {
 
						// adjust power and running cost if needed
 
						rvi[i].power *= 2;
 
						rvi[i].running_cost_base *= 2;
 
					}
 
					rvi[i].flags &= ~RVI_MULTIHEAD;
 
					rvi[i].railveh_type = RAILVEH_SINGLEHEAD;
 
				}
 
			}
 
			break;
 

	
 
		case 0x14: /* Cargo capacity */
 
			FOR_EACH_OBJECT rvi[i].capacity = grf_load_byte(&buf);
 
			break;
 

	
 
		case 0x15: /* Cargo type */
 
			FOR_EACH_OBJECT {
 
				uint8 ctype = grf_load_byte(&buf);
 

	
 
				if (ctype < NUM_CARGO) {
 
					rvi[i].cargo_type = ctype;
 
				} else {
 
					grfmsg(2, "RailVehicleChangeInfo: Invalid cargo type %d, ignoring", ctype);
 
				}
 
			}
 
			break;
 

	
 
		case 0x16: /* Weight */
 
			FOR_EACH_OBJECT SB(rvi[i].weight, 0, 8, grf_load_byte(&buf));
 
			break;
 

	
 
@@ -3567,49 +3567,49 @@ static const uint32 _default_refitmasks[
 
/**
 
 * Precalculate refit masks from cargo classes for all vehicles.
 
 */
 
static void CalculateRefitMasks(void)
 
{
 
	EngineID engine;
 

	
 
	for (engine = 0; engine < TOTAL_NUM_ENGINES; engine++) {
 
		uint32 mask = 0;
 
		uint32 not_mask = 0;
 
		uint32 xor_mask = _engine_info[engine].refit_mask;
 
		byte i;
 

	
 
		if (cargo_allowed[engine] != 0) {
 
			// Build up the list of cargo types from the set cargo classes.
 
			for (i = 0; i < lengthof(cargo_classes); i++) {
 
				if (HASBIT(cargo_allowed[engine], i)) mask |= cargo_classes[i];
 
				if (HASBIT(cargo_disallowed[engine], i)) not_mask |= cargo_classes[i];
 
			}
 
		} else {
 
			// Don't apply default refit mask to wagons or engines with no capacity
 
			if (xor_mask == 0 && (
 
						GetEngine(engine)->type != VEH_Train || (
 
							RailVehInfo(engine)->capacity != 0 &&
 
							!(RailVehInfo(engine)->flags & RVI_WAGON)
 
							RailVehInfo(engine)->railveh_type != RAILVEH_WAGON
 
						)
 
					)) {
 
				xor_mask = _default_refitmasks[GetEngine(engine)->type - VEH_Train];
 
			}
 
		}
 
		_engine_info[engine].refit_mask = ((mask & ~not_mask) ^ xor_mask) & _landscape_global_cargo_mask[_opt.landscape];
 
	}
 
}
 

	
 
/* Here we perform initial decoding of some special sprites (as are they
 
 * described at http://www.ttdpatch.net/src/newgrf.txt, but this is only a very
 
 * partial implementation yet). */
 
/* XXX: We consider GRF files trusted. It would be trivial to exploit OTTD by
 
 * a crafted invalid GRF file. We should tell that to the user somehow, or
 
 * better make this more robust in the future. */
 
static void DecodeSpecialSprite(uint num, GrfLoadingStage stage)
 
{
 
	/* XXX: There is a difference between staged loading in TTDPatch and
 
	 * here.  In TTDPatch, for some reason actions 1 and 2 are carried out
 
	 * during stage 1, whilst action 3 is carried out during stage 2 (to
 
	 * "resolve" cargo IDs... wtf). This is a little problem, because cargo
 
	 * IDs are valid only within a given set (action 1) block, and may be
 
	 * overwritten after action 3 associates them. But overwriting happens
 
	 * in an earlier stage than associating, so...  We just process actions
 
@@ -3780,24 +3780,25 @@ void LoadNewGRF(uint load_index, uint fi
 
		_cur_stage = stage;
 
		_cur_spriteid = load_index;
 
		for (c = _grfconfig; c != NULL; c = c->next) {
 
			if (HASBIT(c->flags, GCF_DISABLED) || HASBIT(c->flags, GCF_NOT_FOUND)) continue;
 

	
 
			// TODO usererror()
 
			if (!FioCheckFileExists(c->filename)) error("NewGRF file is missing '%s'", c->filename);
 

	
 
			if (stage == GLS_LABELSCAN) InitNewGRFFile(c, _cur_spriteid);
 
			LoadNewGRFFile(c, slot++, stage);
 
			if (stage == GLS_ACTIVATION) {
 
				ClearTemporaryNewGRFData();
 
				DEBUG(sprite, 2, "Currently %i sprites are loaded", _cur_spriteid);
 
			}
 
		}
 
	}
 

	
 
	// Pre-calculate all refit masks after loading GRF files
 
	CalculateRefitMasks();
 
}
 

	
 

	
 

	
 

	
 

	
src/players.cpp
Show inline comments
 
@@ -635,49 +635,49 @@ void PlayersYearlyLoop(void)
 
	if (_patches.show_finances && _local_player != PLAYER_SPECTATOR) {
 
		ShowPlayerFinances(_local_player);
 
		p = GetPlayer(_local_player);
 
		if (p->num_valid_stat_ent > 5 && p->old_economy[0].performance_history < p->old_economy[4].performance_history) {
 
			SndPlayFx(SND_01_BAD_YEAR);
 
		} else {
 
			SndPlayFx(SND_00_GOOD_YEAR);
 
		}
 
	}
 
}
 

	
 
byte GetPlayerRailtypes(PlayerID p)
 
{
 
	byte rt = 0;
 
	EngineID i;
 

	
 
	for (i = 0; i != TOTAL_NUM_ENGINES; i++) {
 
		const Engine* e = GetEngine(i);
 
		const EngineInfo *ei = EngInfo(i);
 

	
 
		if (e->type == VEH_Train && HASBIT(ei->climates, _opt.landscape) &&
 
				(HASBIT(e->player_avail, p) || _date >= e->intro_date + 365)) {
 
			const RailVehicleInfo *rvi = RailVehInfo(i);
 

	
 
			if (!(rvi->flags & RVI_WAGON)) {
 
			if (rvi->railveh_type != RAILVEH_WAGON) {
 
				assert(rvi->railtype < RAILTYPE_END);
 
				SETBIT(rt, rvi->railtype);
 
			}
 
		}
 
	}
 

	
 
	return rt;
 
}
 

	
 
static void DeletePlayerStuff(PlayerID pi)
 
{
 
	Player *p;
 

	
 
	DeletePlayerWindows(pi);
 
	p = GetPlayer(pi);
 
	DeleteName(p->name_1);
 
	DeleteName(p->president_name_1);
 
	p->name_1 = 0;
 
	p->president_name_1 = 0;
 
}
 

	
 
/** Change engine renewal parameters
 
 * @param tile unused
 
 * @param p1 bits 0-3 command
src/table/engines.h
Show inline comments
 
@@ -308,189 +308,191 @@ const EngineInfo orig_engine_info[] = {
 
#undef A
 
#undef T
 
#undef MK
 
#undef MW
 
#undef MS
 
#undef MA
 

	
 
/** Writes the properties of a rail vehicle into the RailVehicleInfo struct.
 
 * @see RailVehicleInfo
 
 * @param a image_index
 
 * @param b flags
 
 * @param c base_cost
 
 * @param d max_speed (kph)
 
 * @param e power (hp)
 
 * @param f weight
 
 * @param g running_cost_base
 
 * @param h running_cost_class / engclass
 
 * @param i capacity
 
 * @param j cargo_type
 
 * @param k ai_rank
 
 * @param l railtype
 
 * Tractive effort coefficient by default is the same as TTDPatch, 0.30*256=76
 
 */
 
#define RVI(a, b, c, d, e, f, g, h, i, j, k, l) { a, b, c, {l}, d, e, f, g, h, h, i, j, k, 0, 0, 0, 0, 76, 0 }
 
#define M RVI_MULTIHEAD
 
#define W RVI_WAGON
 
#define M RAILVEH_MULTIHEAD
 
#define W RAILVEH_WAGON
 
#define G RAILVEH_SINGLEHEAD
 
#define S 0
 
#define D 1
 
#define E 2
 

	
 
#define R RAILTYPE_RAIL
 
#define C RAILTYPE_ELECTRIC
 
#define O RAILTYPE_MONO
 
#define L RAILTYPE_MAGLEV
 

	
 
const RailVehicleInfo orig_rail_vehicle_info[NUM_TRAIN_ENGINES] = {
 
	//   image_index  max_speed (kph)      running_cost_base
 
	//   |  flags     |        power (hp)  |  running_cost_class & engclass
 
	//   |  |    base_cost     |    weight |  |   capacity
 
	//   |  |    |    |        |    |      |  |   |  cargo_type
 
	//   |  |    |    |        |    |      |  |   |  |
 
	RVI( 2, 0,   7,  64,     300,  47,    50, S,  0, 0              ,  1, R), //   0
 
	RVI(19, 0,   8,  80,     600,  65,    65, D,  0, 0              ,  4, R), //   1
 
	RVI( 2, 0,  10,  72,     400,  85,    90, S,  0, 0              ,  7, R), //   2
 
	RVI( 0, 0,  15,  96,     900, 130,   130, S,  0, 0              , 19, R), //   3
 
	RVI( 1, 0,  19, 112,    1000, 140,   145, S,  0, 0              , 20, R), //   4
 
	RVI(12, 0,  16, 120,    1400,  95,   125, D,  0, 0              , 30, R), //   5
 
	RVI(14, 0,  20, 152,    2000, 120,   135, D,  0, 0              , 31, R), //   6
 
	RVI( 3, 0,  14,  88,    1100, 145,   130, S,  0, 0              , 19, R), //   7
 
	RVI( 0, 0,  13, 112,    1000, 131,   120, S,  0, 0              , 20, R), //   8
 
	RVI( 1, 0,  19, 128,    1200, 162,   140, S,  0, 0              , 21, R), //   9
 
	RVI( 0, 0,  22, 144,    1600, 170,   130, S,  0, 0              , 22, R), //  10
 
	RVI( 2, G,   7,  64,     300,  47,    50, S,  0, 0              ,  1, R), //   0
 
	RVI(19, G,   8,  80,     600,  65,    65, D,  0, 0              ,  4, R), //   1
 
	RVI( 2, G,  10,  72,     400,  85,    90, S,  0, 0              ,  7, R), //   2
 
	RVI( 0, G,  15,  96,     900, 130,   130, S,  0, 0              , 19, R), //   3
 
	RVI( 1, G,  19, 112,    1000, 140,   145, S,  0, 0              , 20, R), //   4
 
	RVI(12, G,  16, 120,    1400,  95,   125, D,  0, 0              , 30, R), //   5
 
	RVI(14, G,  20, 152,    2000, 120,   135, D,  0, 0              , 31, R), //   6
 
	RVI( 3, G,  14,  88,    1100, 145,   130, S,  0, 0              , 19, R), //   7
 
	RVI( 0, G,  13, 112,    1000, 131,   120, S,  0, 0              , 20, R), //   8
 
	RVI( 1, G,  19, 128,    1200, 162,   140, S,  0, 0              , 21, R), //   9
 
	RVI( 0, G,  22, 144,    1600, 170,   130, S,  0, 0              , 22, R), //  10
 
	RVI( 8, M,  11, 112,   600/2,32/2,  85/2, D, 38, CT_PASSENGERS  , 10, R), //  11
 
	RVI(10, M,  14, 120,   700/2,38/2,  70/2, D, 40, CT_PASSENGERS  , 11, R), //  12
 
	RVI( 4, 0,  15, 128,    1250,  72,    95, D,  0, 0              , 30, R), //  13
 
	RVI( 5, 0,  17, 144,    1750, 101,   120, D,  0, 0              , 31, R), //  14
 
	RVI( 4, 0,  18, 160,    2580, 112,   140, D,  0, 0              , 32, R), //  15
 
	RVI(14, 0,  23,  96,    4000, 150,   135, D,  0, 0              , 33, R), //  16
 
	RVI(12, 0,  16, 112,    2400, 120,   105, D,  0, 0              , 34, R), //  17
 
	RVI(13, 0,  30, 112,    6600, 207,   155, D,  0, 0              , 35, R), //  18
 
	RVI(15, 0,  18, 104,    1500, 110,   105, D,  0, 0              , 29, R), //  19
 
	RVI( 4, G,  15, 128,    1250,  72,    95, D,  0, 0              , 30, R), //  13
 
	RVI( 5, G,  17, 144,    1750, 101,   120, D,  0, 0              , 31, R), //  14
 
	RVI( 4, G,  18, 160,    2580, 112,   140, D,  0, 0              , 32, R), //  15
 
	RVI(14, G,  23,  96,    4000, 150,   135, D,  0, 0              , 33, R), //  16
 
	RVI(12, G,  16, 112,    2400, 120,   105, D,  0, 0              , 34, R), //  17
 
	RVI(13, G,  30, 112,    6600, 207,   155, D,  0, 0              , 35, R), //  18
 
	RVI(15, G,  18, 104,    1500, 110,   105, D,  0, 0              , 29, R), //  19
 
	RVI(16, M,  35, 160,  3500/2,95/2, 205/2, D,  0, 0              , 45, R), //  20
 
	RVI(18, 0,  21, 104,    2200, 120,   145, D,  0, 0              , 32, R), //  21
 
	RVI(18, G,  21, 104,    2200, 120,   145, D,  0, 0              , 32, R), //  21
 
	RVI( 6, M,  20, 200,  4500/2,70/2, 190/2, D,  4, CT_MAIL        , 50, R), //  22
 
	RVI(20, 0,  26, 160,    3600,  84,   180, E,  0, 0              , 40, C), //  23
 
	RVI(20, 0,  30, 176,    5000,  82,   205, E,  0, 0              , 41, C), //  24
 
	RVI(20, G,  26, 160,    3600,  84,   180, E,  0, 0              , 40, C), //  23
 
	RVI(20, G,  30, 176,    5000,  82,   205, E,  0, 0              , 41, C), //  24
 
	RVI(21, M,  40, 240,  7000/2,90/2, 240/2, E,  0, 0              , 51, C), //  25
 
	RVI(23, M,  43, 264,  8000/2,95/2, 250/2, E,  0, 0              , 52, C), //  26
 
	RVI(33, W, 247,   0,       0,  25,     0, 0, 40, CT_PASSENGERS  ,  0, R), //  27
 
	RVI(35, W, 228,   0,       0,  21,     0, 0, 30, CT_MAIL        ,  0, R), //  28
 
	RVI(34, W, 176,   0,       0,  18,     0, 0, 30, CT_COAL        ,  0, R), //  29
 
	RVI(36, W, 200,   0,       0,  24,     0, 0, 30, CT_OIL         ,  0, R), //  30
 
	RVI(37, W, 192,   0,       0,  20,     0, 0, 25, CT_LIVESTOCK   ,  0, R), //  31
 
	RVI(38, W, 190,   0,       0,  21,     0, 0, 25, CT_GOODS       ,  0, R), //  32
 
	RVI(39, W, 182,   0,       0,  19,     0, 0, 30, CT_GRAIN       ,  0, R), //  33
 
	RVI(40, W, 181,   0,       0,  16,     0, 0, 30, CT_WOOD        ,  0, R), //  34
 
	RVI(41, W, 179,   0,       0,  19,     0, 0, 30, CT_IRON_ORE    ,  0, R), //  35
 
	RVI(42, W, 196,   0,       0,  18,     0, 0, 20, CT_STEEL       ,  0, R), //  36
 
	RVI(43, W, 255,   0,       0,  30,     0, 0, 20, CT_VALUABLES   ,  0, R), //  37
 
	RVI(44, W, 191,   0,       0,  22,     0, 0, 25, CT_FOOD        ,  0, R), //  38
 
	RVI(45, W, 196,   0,       0,  18,     0, 0, 20, CT_PAPER       ,  0, R), //  39
 
	RVI(46, W, 179,   0,       0,  19,     0, 0, 30, CT_COPPER_ORE  ,  0, R), //  40
 
	RVI(47, W, 199,   0,       0,  25,     0, 0, 25, CT_WATER       ,  0, R), //  41
 
	RVI(48, W, 182,   0,       0,  18,     0, 0, 25, CT_FRUIT       ,  0, R), //  42
 
	RVI(49, W, 185,   0,       0,  19,     0, 0, 21, CT_RUBBER      ,  0, R), //  43
 
	RVI(50, W, 176,   0,       0,  19,     0, 0, 30, CT_SUGAR       ,  0, R), //  44
 
	RVI(51, W, 178,   0,       0,  20,     0, 0, 30, CT_COTTON_CANDY,  0, R), //  45
 
	RVI(52, W, 192,   0,       0,  20,     0, 0, 30, CT_TOFFEE      ,  0, R), //  46
 
	RVI(53, W, 190,   0,       0,  21,     0, 0, 20, CT_BUBBLES     ,  0, R), //  47
 
	RVI(54, W, 182,   0,       0,  24,     0, 0, 25, CT_COLA        ,  0, R), //  48
 
	RVI(55, W, 181,   0,       0,  21,     0, 0, 25, CT_CANDY       ,  0, R), //  49
 
	RVI(56, W, 183,   0,       0,  21,     0, 0, 20, CT_TOYS        ,  0, R), //  50
 
	RVI(57, W, 196,   0,       0,  18,     0, 0, 22, CT_BATTERIES   ,  0, R), //  51
 
	RVI(58, W, 193,   0,       0,  18,     0, 0, 25, CT_FIZZY_DRINKS,  0, R), //  52
 
	RVI(59, W, 191,   0,       0,  18,     0, 0, 30, CT_PLASTIC     ,  0, R), //  53
 
	RVI(25, 0,  52, 304,    9000,  95,   230, E,  0, 0              , 60, O), //  54
 
	RVI(25, G,  52, 304,    9000,  95,   230, E,  0, 0              , 60, O), //  54
 
	RVI(26, M,  60, 336, 10000/2,85/2, 240/2, E, 25, CT_PASSENGERS  , 62, O), //  55
 
	RVI(26, 0,  53, 320,    5000,  95,   230, E,  0, 0              , 63, O), //  56
 
	RVI(26, G,  53, 320,    5000,  95,   230, E,  0, 0              , 63, O), //  56
 
	RVI(60, W, 247,   0,       0,  25,     0, 0, 45, CT_PASSENGERS  ,  0, O), //  57
 
	RVI(62, W, 228,   0,       0,  21,     0, 0, 35, CT_MAIL        ,  0, O), //  58
 
	RVI(61, W, 176,   0,       0,  18,     0, 0, 35, CT_COAL        ,  0, O), //  59
 
	RVI(63, W, 200,   0,       0,  24,     0, 0, 35, CT_OIL         ,  0, O), //  60
 
	RVI(64, W, 192,   0,       0,  20,     0, 0, 30, CT_LIVESTOCK   ,  0, O), //  61
 
	RVI(65, W, 190,   0,       0,  21,     0, 0, 30, CT_GOODS       ,  0, O), //  62
 
	RVI(66, W, 182,   0,       0,  19,     0, 0, 35, CT_GRAIN       ,  0, O), //  63
 
	RVI(67, W, 181,   0,       0,  16,     0, 0, 35, CT_WOOD        ,  0, O), //  64
 
	RVI(68, W, 179,   0,       0,  19,     0, 0, 35, CT_IRON_ORE    ,  0, O), //  65
 
	RVI(69, W, 196,   0,       0,  18,     0, 0, 25, CT_STEEL       ,  0, O), //  66
 
	RVI(70, W, 255,   0,       0,  30,     0, 0, 25, CT_VALUABLES   ,  0, O), //  67
 
	RVI(71, W, 191,   0,       0,  22,     0, 0, 30, CT_FOOD        ,  0, O), //  68
 
	RVI(72, W, 196,   0,       0,  18,     0, 0, 25, CT_PAPER       ,  0, O), //  69
 
	RVI(73, W, 179,   0,       0,  19,     0, 0, 35, CT_COPPER_ORE  ,  0, O), //  70
 
	RVI(47, W, 199,   0,       0,  25,     0, 0, 30, CT_WATER       ,  0, O), //  71
 
	RVI(48, W, 182,   0,       0,  18,     0, 0, 30, CT_FRUIT       ,  0, O), //  72
 
	RVI(49, W, 185,   0,       0,  19,     0, 0, 26, CT_RUBBER      ,  0, O), //  73
 
	RVI(50, W, 176,   0,       0,  19,     0, 0, 35, CT_SUGAR       ,  0, O), //  74
 
	RVI(51, W, 178,   0,       0,  20,     0, 0, 35, CT_COTTON_CANDY,  0, O), //  75
 
	RVI(52, W, 192,   0,       0,  20,     0, 0, 35, CT_TOFFEE      ,  0, O), //  76
 
	RVI(53, W, 190,   0,       0,  21,     0, 0, 25, CT_BUBBLES     ,  0, O), //  77
 
	RVI(54, W, 182,   0,       0,  24,     0, 0, 30, CT_COLA        ,  0, O), //  78
 
	RVI(55, W, 181,   0,       0,  21,     0, 0, 30, CT_CANDY       ,  0, O), //  79
 
	RVI(56, W, 183,   0,       0,  21,     0, 0, 25, CT_TOYS        ,  0, O), //  80
 
	RVI(57, W, 196,   0,       0,  18,     0, 0, 27, CT_BATTERIES   ,  0, O), //  81
 
	RVI(58, W, 193,   0,       0,  18,     0, 0, 30, CT_FIZZY_DRINKS,  0, O), //  82
 
	RVI(59, W, 191,   0,       0,  18,     0, 0, 35, CT_PLASTIC     ,  0, O), //  83
 
	RVI(28, 0,  70, 400,   10000, 105,   250, E,  0, 0              , 70, L), //  84
 
	RVI(29, 0,  74, 448,   12000, 120,   253, E,  0, 0              , 71, L), //  85
 
	RVI(30, 0,  82, 480,   15000, 130,   254, E,  0, 0              , 72, L), //  86
 
	RVI(28, G,  70, 400,   10000, 105,   250, E,  0, 0              , 70, L), //  84
 
	RVI(29, G,  74, 448,   12000, 120,   253, E,  0, 0              , 71, L), //  85
 
	RVI(30, G,  82, 480,   15000, 130,   254, E,  0, 0              , 72, L), //  86
 
	RVI(31, M,  95, 640, 20000/2,150/2,255/2, E,  0, 0              , 73, L), //  87
 
	RVI(28, 0,  70, 480,   10000, 120,   250, E,  0, 0              , 74, L), //  88
 
	RVI(28, G,  70, 480,   10000, 120,   250, E,  0, 0              , 74, L), //  88
 
	RVI(60, W, 247,   0,       0,  25,     0, 0, 47, CT_PASSENGERS  ,  0, L), //  89
 
	RVI(62, W, 228,   0,       0,  21,     0, 0, 37, CT_MAIL        ,  0, L), //  90
 
	RVI(61, W, 176,   0,       0,  18,     0, 0, 37, CT_COAL        ,  0, L), //  91
 
	RVI(63, W, 200,   0,       0,  24,     0, 0, 37, CT_OIL         ,  0, L), //  92
 
	RVI(64, W, 192,   0,       0,  20,     0, 0, 32, CT_LIVESTOCK   ,  0, L), //  93
 
	RVI(65, W, 190,   0,       0,  21,     0, 0, 32, CT_GOODS       ,  0, L), //  94
 
	RVI(66, W, 182,   0,       0,  19,     0, 0, 37, CT_GRAIN       ,  0, L), //  95
 
	RVI(67, W, 181,   0,       0,  16,     0, 0, 37, CT_WOOD        ,  0, L), //  96
 
	RVI(68, W, 179,   0,       0,  19,     0, 0, 37, CT_IRON_ORE    ,  0, L), //  97
 
	RVI(69, W, 196,   0,       0,  18,     0, 0, 27, CT_STEEL       ,  0, L), //  98
 
	RVI(70, W, 255,   0,       0,  30,     0, 0, 27, CT_VALUABLES   ,  0, L), //  99
 
	RVI(71, W, 191,   0,       0,  22,     0, 0, 32, CT_FOOD        ,  0, L), // 100
 
	RVI(72, W, 196,   0,       0,  18,     0, 0, 27, CT_PAPER       ,  0, L), // 101
 
	RVI(73, W, 179,   0,       0,  19,     0, 0, 37, CT_COPPER_ORE  ,  0, L), // 102
 
	RVI(47, W, 199,   0,       0,  25,     0, 0, 32, CT_WATER       ,  0, L), // 103
 
	RVI(48, W, 182,   0,       0,  18,     0, 0, 32, CT_FRUIT       ,  0, L), // 104
 
	RVI(49, W, 185,   0,       0,  19,     0, 0, 28, CT_RUBBER      ,  0, L), // 105
 
	RVI(50, W, 176,   0,       0,  19,     0, 0, 37, CT_SUGAR       ,  0, L), // 106
 
	RVI(51, W, 178,   0,       0,  20,     0, 0, 37, CT_COTTON_CANDY,  0, L), // 107
 
	RVI(52, W, 192,   0,       0,  20,     0, 0, 37, CT_TOFFEE      ,  0, L), // 108
 
	RVI(53, W, 190,   0,       0,  21,     0, 0, 27, CT_BUBBLES     ,  0, L), // 109
 
	RVI(54, W, 182,   0,       0,  24,     0, 0, 32, CT_COLA        ,  0, L), // 110
 
	RVI(55, W, 181,   0,       0,  21,     0, 0, 32, CT_CANDY       ,  0, L), // 111
 
	RVI(56, W, 183,   0,       0,  21,     0, 0, 27, CT_TOYS        ,  0, L), // 112
 
	RVI(57, W, 196,   0,       0,  18,     0, 0, 29, CT_BATTERIES   ,  0, L), // 113
 
	RVI(58, W, 193,   0,       0,  18,     0, 0, 32, CT_FIZZY_DRINKS,  0, L), // 114
 
	RVI(59, W, 191,   0,       0,  18,     0, 0, 37, CT_PLASTIC     ,  0, L), // 115
 
};
 
#undef L
 
#undef O
 
#undef C
 
#undef R
 
#undef E
 
#undef D
 
#undef S
 
#undef G
 
#undef W
 
#undef M
 
#undef RVI
 

	
 
/** Writes the properties of a ship into the ShipVehicleInfo struct.
 
 * @see ShipVehicleInfo
 
 * @param a image_index
 
 * @param b base_cost
 
 * @param c max_speed
 
 * @param d cargo_type
 
 * @param e cargo_amount
 
 * @param f running_cost
 
 * @param g sound effect
 
 * @param h refittable
 
 */
 
#define SVI(a, b, c, d, e, f, g, h) { a, b, c, d, e, f, {g}, h }
 
const ShipVehicleInfo orig_ship_vehicle_info[NUM_SHIP_ENGINES] = {
 
	//   image_index  cargo_type     cargo_amount                 refittable
 
	//   |    base_cost |              |    running_cost          |
 
	//   |    |    max_speed           |    |  sfx                |
 
	//   |    |    |    |              |    |  |                  |
 
	SVI( 1, 160,  48, CT_OIL,        220, 140, SND_06_SHIP_HORN,  0 ), /*  0 */
 
	SVI( 1, 176,  80, CT_OIL,        350, 125, SND_06_SHIP_HORN,  0 ), /*  1 */
 
	SVI( 2,  96,  64, CT_PASSENGERS, 100,  90, SND_07_FERRY_HORN, 0 ), /*  2 */
src/train_cmd.cpp
Show inline comments
 
@@ -173,72 +173,71 @@ void TrainConsistChanged(Vehicle* v)
 
		} else {
 
			if (IsTrainWagon(u) || IsArticulatedPart(u)) {
 
				// Wagons and articulated parts have no effect by default
 
				u->u.rail.cached_vis_effect = 0x40;
 
			} else if (rvi_u->engclass == 0) {
 
				// Steam is offset by -4 units
 
				u->u.rail.cached_vis_effect = 4;
 
			} else {
 
				// Diesel fumes and sparks come from the centre
 
				u->u.rail.cached_vis_effect = 8;
 
			}
 
		}
 

	
 
		if (!IsArticulatedPart(u)) {
 
			// check if its a powered wagon
 
			CLRBIT(u->u.rail.flags, VRF_POWEREDWAGON);
 

	
 
			/* Check powered wagon / visual effect callback */
 
			if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_WAGON_POWER)) {
 
				uint16 callback = GetVehicleCallback(CBID_TRAIN_WAGON_POWER, 0, 0, u->engine_type, u);
 

	
 
				if (callback != CALLBACK_FAILED) u->u.rail.cached_vis_effect = callback;
 
			}
 

	
 
			if ((rvi_v->pow_wag_power != 0) && (rvi_u->flags & RVI_WAGON) && UsesWagonOverride(u)) {
 
				if (u->u.rail.cached_vis_effect < 0x40) {
 
					/* wagon is powered */
 
					SETBIT(u->u.rail.flags, VRF_POWEREDWAGON); // cache 'powered' status
 
				}
 
			if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON &&
 
				UsesWagonOverride(u) && (u->u.rail.cached_vis_effect < 0x40)) {
 
				/* wagon is powered */
 
				SETBIT(u->u.rail.flags, VRF_POWEREDWAGON); // cache 'powered' status
 
			}
 

	
 
			/* Do not count powered wagons for the compatible railtypes, as wagons always
 
			   have railtype normal */
 
			if (rvi_u->power > 0) {
 
				v->u.rail.compatible_railtypes |= GetRailTypeInfo(u->u.rail.railtype)->powered_railtypes;
 
			}
 

	
 
			/* Some electric engines can be allowed to run on normal rail. It happens to all
 
			 * existing electric engines when elrails are disabled and then re-enabled */
 
			if (HASBIT(u->u.rail.flags, VRF_EL_ENGINE_ALLOWED_NORMAL_RAIL)) {
 
				u->u.rail.railtype = RAILTYPE_RAIL;
 
				u->u.rail.compatible_railtypes |= (1 << RAILTYPE_RAIL);
 
			}
 

	
 
			// max speed is the minimum of the speed limits of all vehicles in the consist
 
			if (!(rvi_u->flags & RVI_WAGON) || _patches.wagon_speed_limits)
 
				if (rvi_u->max_speed != 0 && !UsesWagonOverride(u))
 
					max_speed = min(rvi_u->max_speed, max_speed);
 
			if ((rvi_u->railveh_type != RAILVEH_WAGON || _patches.wagon_speed_limits) &&
 
				rvi_u->max_speed != 0 && !UsesWagonOverride(u))
 
				max_speed = min(rvi_u->max_speed, max_speed);
 
		}
 

	
 
		// check the vehicle length (callback)
 
		veh_len = CALLBACK_FAILED;
 
		if (HASBIT(EngInfo(u->engine_type)->callbackmask, CBM_VEHICLE_LENGTH)) {
 
			veh_len = GetVehicleCallback(CBID_TRAIN_VEHICLE_LENGTH, 0, 0, u->engine_type, u);
 
		}
 
		if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor;
 
		veh_len = clamp(veh_len, 0, u->next == NULL ? 7 : 5); // the clamp on vehicles not the last in chain is stricter, as too short wagons can break the 'follow next vehicle' code
 
		u->u.rail.cached_veh_length = 8 - veh_len;
 
		v->u.rail.cached_total_length += u->u.rail.cached_veh_length;
 

	
 
	};
 

	
 
	// store consist weight/max speed in cache
 
	v->u.rail.cached_max_speed = max_speed;
 

	
 
	// recalculate cached weights and power too (we do this *after* the rest, so it is known which wagons are powered and need extra weight added)
 
	TrainCargoChanged(v);
 
}
 

	
 
/* These two arrays are used for realistic acceleration. XXX: How should they
 
 * be interpreted? */
 
static const byte _curve_neighbours45[8][2] = {
 
@@ -469,49 +468,49 @@ int GetTrainImage(const Vehicle* v, Dire
 

	
 
	if (v->cargo_count >= v->cargo_cap / 2) base += _wagon_full_adder[img];
 
	return base;
 
}
 

	
 
void DrawTrainEngine(int x, int y, EngineID engine, SpriteID pal)
 
{
 
	const RailVehicleInfo *rvi = RailVehInfo(engine);
 

	
 
	int img = rvi->image_index;
 
	SpriteID image = 0;
 

	
 
	if (is_custom_sprite(img)) {
 
		image = GetCustomVehicleIcon(engine, DIR_W);
 
		if (image == 0) {
 
			img = orig_rail_vehicle_info[engine].image_index;
 
		} else {
 
			y += _traininfo_vehicle_pitch;
 
		}
 
	}
 
	if (image == 0) {
 
		image = (6 & _engine_sprite_and[img]) + _engine_sprite_base[img];
 
	}
 

	
 
	if (rvi->flags & RVI_MULTIHEAD) {
 
	if (rvi->railveh_type == RAILVEH_MULTIHEAD) {
 
		DrawSprite(image, pal, x - 14, y);
 
		x += 15;
 
		image = 0;
 
		if (is_custom_sprite(img)) {
 
			image = GetCustomVehicleIcon(engine, DIR_E);
 
			if (image == 0) img = orig_rail_vehicle_info[engine].image_index;
 
		}
 
		if (image == 0) {
 
			image =
 
				((6 + _engine_sprite_add[img + 1]) & _engine_sprite_and[img + 1]) +
 
				_engine_sprite_base[img + 1];
 
		}
 
	}
 
	DrawSprite(image, pal, x, y);
 
}
 

	
 
uint CountArticulatedParts(EngineID engine_type)
 
{
 
	uint16 callback;
 
	uint i;
 

	
 
	if (!HASBIT(EngInfo(engine_type)->callbackmask, CBM_ARTIC_ENGINE)) return 0;
 

	
 
	for (i = 1; i < 10; i++) {
 
@@ -744,53 +743,53 @@ int32 CmdBuildRailVehicle(TileIndex tile
 
	const RailVehicleInfo *rvi;
 
	int value;
 
	Vehicle *v;
 
	UnitID unit_num;
 
	uint num_vehicles;
 

	
 
	/* Check if the engine-type is valid (for the player) */
 
	if (!IsEngineBuildable(p1, VEH_Train, _current_player)) return_cmd_error(STR_ENGINE_NOT_BUILDABLE);
 

	
 
	/* Check if the train is actually being built in a depot belonging
 
	 * to the player. Doesn't matter if only the cost is queried */
 
	if (!(flags & DC_QUERY_COST)) {
 
		if (!IsTileDepotType(tile, TRANSPORT_RAIL)) return CMD_ERROR;
 
		if (!IsTileOwner(tile, _current_player)) return CMD_ERROR;
 
	}
 

	
 
	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
 

	
 
	rvi = RailVehInfo(p1);
 

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

	
 
	if (rvi->flags & RVI_WAGON) return CmdBuildRailWagon(p1, tile, flags);
 
	if (rvi->railveh_type == RAILVEH_WAGON) return CmdBuildRailWagon(p1, tile, flags);
 

	
 
	value = EstimateTrainCost(rvi);
 

	
 
	num_vehicles = (rvi->flags & RVI_MULTIHEAD) ? 2 : 1;
 
	num_vehicles = (rvi->railveh_type == RAILVEH_MULTIHEAD) ? 2 : 1;
 
	num_vehicles += CountArticulatedParts(p1);
 

	
 
	if (!(flags & DC_QUERY_COST)) {
 
		Vehicle *vl[12]; // Allow for upto 10 artic parts and dual-heads
 

	
 
		memset(&vl, 0, sizeof(vl));
 

	
 
		if (!AllocateVehicles(vl, num_vehicles) || IsOrderPoolFull())
 
			return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
 

	
 
		v = vl[0];
 

	
 
		unit_num = HASBIT(p2, 0) ? 0 : GetFreeUnitNumber(VEH_Train);
 
		if (unit_num > _patches.max_trains)
 
			return_cmd_error(STR_00E1_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];
 

	
 
			v->unitnumber = unit_num;
 
			v->direction = DiagDirToDir(dir);
 
			v->tile = tile;
 
@@ -813,49 +812,49 @@ int32 CmdBuildRailVehicle(TileIndex tile
 
			v->engine_type = p1;
 

	
 
			const Engine *e = GetEngine(p1);
 
			v->reliability = e->reliability;
 
			v->reliability_spd_dec = e->reliability_spd_dec;
 
			v->max_age = e->lifelength * 366;
 

	
 
			v->string_id = STR_SV_TRAIN_NAME;
 
			v->u.rail.railtype = rvi->railtype;
 
			_new_vehicle_id = v->index;
 

	
 
			v->service_interval = _patches.servint_trains;
 
			v->date_of_last_service = _date;
 
			v->build_year = _cur_year;
 
			v->type = VEH_Train;
 
			v->cur_image = 0xAC2;
 
			v->random_bits = VehicleRandomBits();
 

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

	
 
			VehiclePositionChanged(v);
 

	
 
			if (rvi->flags & RVI_MULTIHEAD) {
 
			if (rvi->railveh_type == RAILVEH_MULTIHEAD) {
 
				SetMultiheaded(v);
 
				AddRearEngineToMultiheadedTrain(vl[0], vl[1], true);
 
				/* Now we need to link the front and rear engines together
 
				 * other_multiheaded_part is the pointer that links to the other half of the engine
 
				 * vl[0] is the front and vl[1] is the rear
 
				 */
 
				vl[0]->u.rail.other_multiheaded_part = vl[1];
 
				vl[1]->u.rail.other_multiheaded_part = vl[0];
 
			} else {
 
				AddArticulatedParts(vl);
 
			}
 

	
 
			TrainConsistChanged(v);
 
			UpdateTrainAcceleration(v);
 

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

	
 
			GetPlayer(_current_player)->num_engines[p1]++;
 
			InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
 
			RebuildVehicleLists();
 
			InvalidateWindow(WC_COMPANY, v->owner);
 
			if (IsLocalPlayer()) {
 
@@ -1336,49 +1335,49 @@ int32 CmdSellRailWagon(TileIndex tile, u
 
	int32 cost = 0;
 

	
 
	if (!IsValidVehicleID(p1) || p2 > 2) return CMD_ERROR;
 

	
 
	v = GetVehicle(p1);
 

	
 
	if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR;
 

	
 
	SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);
 

	
 
	while (IsArticulatedPart(v)) v = GetPrevVehicleInChain(v);
 
	first = GetFirstVehicleInChain(v);
 

	
 
	// make sure the vehicle is stopped in the depot
 
	if (CheckTrainStoppedInDepot(first) < 0) {
 
		return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED);
 
	}
 

	
 
	if (IsMultiheaded(v) && !IsTrainEngine(v)) return_cmd_error(STR_REAR_ENGINE_FOLLOW_FRONT_ERROR);
 

	
 
	if (flags & DC_EXEC) {
 
		if (v == first && IsFrontEngine(first)) {
 
			DeleteWindowById(WC_VEHICLE_VIEW, first->index);
 
		}
 
		if (IsLocalPlayer() && (p1 == 1 || !(RailVehInfo(v->engine_type)->flags & RVI_WAGON))) {
 
		if (IsLocalPlayer() && (p1 == 1 || RailVehInfo(v->engine_type)->railveh_type != RAILVEH_WAGON)) {
 
			InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train);
 
		}
 
		InvalidateWindow(WC_VEHICLE_DEPOT, first->tile);
 
		RebuildVehicleLists();
 
	}
 

	
 
	switch (p2) {
 
		case 0: case 2: { /* Delete given wagon */
 
			bool switch_engine = false;    // update second wagon to engine?
 
			byte ori_subtype = v->subtype; // backup subtype of deleted wagon in case DeleteVehicle() changes
 

	
 
			/* 1. Delete the engine, if it is dualheaded also delete the matching
 
			 * rear engine of the loco (from the point of deletion onwards) */
 
			Vehicle *rear = (IsMultiheaded(v) &&
 
				IsTrainEngine(v)) ? v->u.rail.other_multiheaded_part : NULL;
 

	
 
			if (rear != NULL) {
 
				cost -= rear->value;
 
				if (flags & DC_EXEC) {
 
					UnlinkWagon(rear, first);
 
					DeleteDepotHighlightOfVehicle(rear);
 
					DeleteVehicle(rear);
 
				}
 
			}
 
@@ -2069,49 +2068,49 @@ void OnTick_Train(void)
 
}
 

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

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

	
 
	if (v->vehstatus & VS_TRAIN_SLOWING || v->load_unload_time_rem != 0 || v->cur_speed < 2)
 
		return;
 

	
 
	u = v;
 

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

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

	
 
		// No smoke in depots or tunnels
 
		if (IsTileDepotType(v->tile, TRANSPORT_RAIL) || IsTunnelTile(v->tile)) continue;
 

	
 
		// No sparks for electric vehicles on nonelectrified tracks
 
		if (!HasPowerOnRail(v->u.rail.railtype, GetTileRailType(v->tile, TrackdirToTrack(GetVehicleTrackdir(v))))) continue;
 

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

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

	
 
		if (HASBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION)) {
 
			x = -x;
 
@@ -3731,62 +3730,62 @@ void ConnectMultiheadedTrains(void)
 
/*
 
 *  Converts all trains to the new subtype format introduced in savegame 16.2
 
 *  It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found
 
 */
 
void ConvertOldMultiheadToNew(void)
 
{
 
	Vehicle *v;
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_Train) {
 
			SETBIT(v->subtype, 7); // indicates that it's the old format and needs to be converted in the next loop
 
		}
 
	}
 

	
 
	FOR_ALL_VEHICLES(v) {
 
		if (v->type == VEH_Train) {
 
			if (HASBIT(v->subtype, 7) && ((v->subtype & ~0x80) == 0 || (v->subtype & ~0x80) == 4)) {
 
				Vehicle *u = v;
 

	
 
				BEGIN_ENUM_WAGONS(u) {
 
					const RailVehicleInfo *rvi = RailVehInfo(u->engine_type);
 

	
 
					CLRBIT(u->subtype, 7);
 
					switch (u->subtype) {
 
						case 0: /* TS_Front_Engine */
 
							if (rvi->flags & RVI_MULTIHEAD) SetMultiheaded(u);
 
							if (rvi->railveh_type == RAILVEH_MULTIHEAD) SetMultiheaded(u);
 
							SetFrontEngine(u);
 
							SetTrainEngine(u);
 
							break;
 

	
 
						case 1: /* TS_Artic_Part */
 
							u->subtype = 0;
 
							SetArticulatedPart(u);
 
							break;
 

	
 
						case 2: /* TS_Not_First */
 
							u->subtype = 0;
 
							if (rvi->flags & RVI_WAGON) {
 
							if (rvi->railveh_type == RAILVEH_WAGON) {
 
								// normal wagon
 
								SetTrainWagon(u);
 
								break;
 
							}
 
							if (rvi->flags & RVI_MULTIHEAD && rvi->image_index == u->spritenum - 1) {
 
							if (rvi->railveh_type == RAILVEH_MULTIHEAD && rvi->image_index == u->spritenum - 1) {
 
								// rear end of a multiheaded engine
 
								SetMultiheaded(u);
 
								break;
 
							}
 
							if (rvi->flags & RVI_MULTIHEAD) SetMultiheaded(u);
 
							if (rvi->railveh_type == RAILVEH_MULTIHEAD) SetMultiheaded(u);
 
							SetTrainEngine(u);
 
							break;
 

	
 
						case 4: /* TS_Free_Car */
 
							u->subtype = 0;
 
							SetTrainWagon(u);
 
							SetFreeWagon(u);
 
							break;
 
						default: NOT_REACHED(); break;
 
					}
 
				} END_ENUM_WAGONS(u)
 
			}
 
		}
 
	}
 
}
src/train_gui.cpp
Show inline comments
 
@@ -137,49 +137,49 @@ static void ShowTrainDetailsWindow(const
 

	
 
static void TrainViewWndProc(Window *w, WindowEvent *e)
 
{
 
	switch (e->event) {
 
	case WE_PAINT: {
 
		const Vehicle *v, *u;
 
		StringID str;
 
		bool is_localplayer;
 

	
 
		v = GetVehicle(w->window_number);
 

	
 
		is_localplayer = v->owner == _local_player;
 
		SetWindowWidgetDisabledState(w,  7, !is_localplayer);
 
		SetWindowWidgetDisabledState(w,  8, !is_localplayer);
 
		SetWindowWidgetDisabledState(w,  9, !is_localplayer);
 
		SetWindowWidgetDisabledState(w, 13, !is_localplayer);
 

	
 
		/* Disable cargo refit button, until we know we can enable it below. */
 
		DisableWindowWidget(w, 12);
 

	
 
		if (is_localplayer) {
 
			/* See if any vehicle can be refitted */
 
			for (u = v; u != NULL; u = u->next) {
 
				if (EngInfo(u->engine_type)->refit_mask != 0 ||
 
						(!(RailVehInfo(v->engine_type)->flags & RVI_WAGON) && v->cargo_cap != 0)) {
 
						(RailVehInfo(v->engine_type)->railveh_type != RAILVEH_WAGON && v->cargo_cap != 0)) {
 
					EnableWindowWidget(w, 12);
 
					/* We have a refittable carriage, bail out */
 
					break;
 
				}
 
			}
 
		}
 

	
 
		/* draw widgets & caption */
 
		SetDParam(0, v->string_id);
 
		SetDParam(1, v->unitnumber);
 
		DrawWindowWidgets(w);
 

	
 
		if (v->u.rail.crash_anim_pos != 0) {
 
			str = STR_8863_CRASHED;
 
		} else if (v->breakdown_ctr == 1) {
 
			str = STR_885C_BROKEN_DOWN;
 
		} else if (v->vehstatus & VS_STOPPED) {
 
			if (v->u.rail.last_speed == 0) {
 
				if (v->u.rail.cached_power == 0) {
 
					str = STR_TRAIN_NO_POWER;
 
				} else {
 
					str = STR_8861_STOPPED;
 
				}
 
			} else {
 
@@ -320,49 +320,49 @@ void ShowTrainViewWindow(const Vehicle *
 
		w->caption_color = v->owner;
 
		AssignWindowViewport(w, 3, 17, 0xE2, 0x66, w->window_number | (1 << 31), 0);
 
	}
 
}
 

	
 
static void TrainDetailsCargoTab(const Vehicle *v, int x, int y)
 
{
 
	if (v->cargo_cap != 0) {
 
		uint num = v->cargo_count;
 
		StringID str = STR_8812_EMPTY;
 

	
 
		if (num != 0) {
 
			SetDParam(0, v->cargo_type);
 
			SetDParam(1, num);
 
			SetDParam(2, v->cargo_source);
 
			SetDParam(3, _patches.freight_trains);
 
			str = FreightWagonMult(v->cargo_type) > 1 ? STR_FROM_MULT : STR_8813_FROM;
 
		}
 
		DrawString(x, y, str, 0);
 
	}
 
}
 

	
 
static void TrainDetailsInfoTab(const Vehicle *v, int x, int y)
 
{
 
	if (RailVehInfo(v->engine_type)->flags & RVI_WAGON) {
 
	if (RailVehInfo(v->engine_type)->railveh_type == RAILVEH_WAGON) {
 
		SetDParam(0, GetCustomEngineName(v->engine_type));
 
		SetDParam(1, v->value);
 
		DrawString(x, y, STR_882D_VALUE, 0x10);
 
	} else {
 
		SetDParam(0, GetCustomEngineName(v->engine_type));
 
		SetDParam(1, v->build_year);
 
		SetDParam(2, v->value);
 
		DrawString(x, y, STR_882C_BUILT_VALUE, 0x10);
 
	}
 
}
 

	
 
static void TrainDetailsCapacityTab(const Vehicle *v, int x, int y)
 
{
 
	if (v->cargo_cap != 0) {
 
		SetDParam(0, v->cargo_type);
 
		SetDParam(1, v->cargo_cap);
 
		SetDParam(2, _patches.freight_trains);
 
		DrawString(x, y, FreightWagonMult(v->cargo_type) > 1 ? STR_CAPACITY_MULT : STR_013F_CAPACITY, 0);
 
	}
 
}
 

	
 

	
 
static void DrawTrainDetailsWindow(Window *w)
 
{
src/vehicle.cpp
Show inline comments
 
@@ -766,49 +766,49 @@ CargoID FindFirstRefittableCargo(EngineI
 
	uint32 refit_mask = EngInfo(engine_type)->refit_mask;
 

	
 
	if (refit_mask != 0) {
 
		for (cid = CT_PASSENGERS; cid < NUM_CARGO; cid++) {
 
			if (HASBIT(refit_mask, _global_cargo_id[_opt_ptr->landscape][cid])) return cid;
 
		}
 
	}
 

	
 
	return CT_INVALID;
 
}
 

	
 
/** Learn the price of refitting a certain engine
 
* @param engine Which engine to refit
 
* @return Price for refitting
 
*/
 
int32 GetRefitCost(EngineID engine_type)
 
{
 
	int32 base_cost = 0;
 

	
 
	switch (GetEngine(engine_type)->type) {
 
		case VEH_Ship: base_cost = _price.ship_base; break;
 
		case VEH_Road: base_cost = _price.roadveh_base; break;
 
		case VEH_Aircraft: base_cost = _price.aircraft_base; break;
 
		case VEH_Train:
 
			base_cost = 2 * ((RailVehInfo(engine_type)->flags & RVI_WAGON) ?
 
			base_cost = 2 * ((RailVehInfo(engine_type)->railveh_type == RAILVEH_WAGON) ?
 
							 _price.build_railwagon : _price.build_railvehicle);
 
			break;
 
		default: NOT_REACHED(); break;
 
	}
 
	return (EngInfo(engine_type)->refit_cost * base_cost) >> 10;
 
}
 

	
 
static void DoDrawVehicle(const Vehicle *v)
 
{
 
	SpriteID image = v->cur_image;
 
	SpriteID pal;
 

	
 
	if (v->vehstatus & VS_SHADOW) {
 
		SETBIT(image, PALETTE_MODIFIER_TRANSPARENT);
 
		pal = PALETTE_TO_TRANSPARENT;
 
	} else if (v->vehstatus & VS_DEFPAL) {
 
		pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
 
	} else {
 
		pal = PAL_NONE;
 
	}
 

	
 
	AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
 
		v->sprite_width, v->sprite_height, v->z_height, v->z_pos);
 
}
 
@@ -2222,49 +2222,49 @@ static int32 MaybeReplaceVehicle(Vehicle
 
			}
 
			if (stopped) v->vehstatus &= ~VS_STOPPED;
 
			if (display_costs) _current_player = OWNER_NONE;
 
			return CMD_ERROR;
 
		}
 

	
 
		if (flags & DC_EXEC) {
 
			break; // we are done replacing since the loop ran once with DC_EXEC
 
		} else if (check) {
 
			/* It's a test only and we know that we can do this
 
			 * NOTE: payment for wagon removal is NOT included in this price */
 
			return cost;
 
		}
 
		// now we redo the loop, but this time we actually do stuff since we know that we can do it
 
		flags |= DC_EXEC;
 
	}
 

	
 
	/* If setting is on to try not to exceed the old length of the train with the replacement */
 
	if (v->type == VEH_Train && p->renew_keep_length) {
 
		Vehicle *temp;
 
		w = v;
 

	
 
		while (v->u.rail.cached_total_length > old_total_length) {
 
			// the train is too long. We will remove cars one by one from the start of the train until it's short enough
 
			while (w != NULL && !(RailVehInfo(w->engine_type)->flags&RVI_WAGON) ) {
 
			while (w != NULL && RailVehInfo(w->engine_type)->railveh_type != RAILVEH_WAGON) {
 
				w = GetNextVehicle(w);
 
			}
 
			if (w == NULL) {
 
				// we failed to make the train short enough
 
				SetDParam(0, v->unitnumber);
 
				AddNewsItem(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
 
				break;
 
			}
 
			temp = w;
 
			w = GetNextVehicle(w);
 
			DoCommand(0, (INVALID_VEHICLE << 16) | temp->index, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
 
			MoveVehicleCargo(v, temp);
 
			cost += DoCommand(0, temp->index, 0, DC_EXEC, CMD_SELL_RAIL_WAGON);
 
		}
 
	}
 

	
 
	if (stopped) v->vehstatus &= ~VS_STOPPED;
 
	if (display_costs) {
 
		if (IsLocalPlayer()) ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost);
 
		_current_player = OWNER_NONE;
 
	}
 
	return cost;
 
}
 

	
 
@@ -2829,49 +2829,49 @@ static SpriteID GetEngineColourMap(Engin
 
		/* A return value of 0xC000 is stated to "use the default two-color
 
		 * maps" which happens to be the failure action too... */
 
		if (callback != CALLBACK_FAILED && callback != 0xC000) {
 
			map = GB(callback, 0, 14);
 
			/* If bit 14 is set, then the company colours are applied to the
 
			 * map else it's returned as-is. */
 
			if (!HASBIT(callback, 14)) return map;
 
		}
 
	}
 

	
 
	/* The default livery is always available for use, but its in_use flag determines
 
	 * whether any _other_ liveries are in use. */
 
	if (p->livery[LS_DEFAULT].in_use && (_patches.liveries == 2 || (_patches.liveries == 1 && player == _local_player))) {
 
		/* Determine the livery scheme to use */
 
		switch (GetEngine(engine_type)->type) {
 
			case VEH_Train: {
 
				const RailVehicleInfo *rvi = RailVehInfo(engine_type);
 

	
 
				switch (rvi->railtype) {
 
					default: NOT_REACHED();
 
					case RAILTYPE_RAIL:
 
					case RAILTYPE_ELECTRIC:
 
					{
 
						if (cargo_type == CT_INVALID) cargo_type = rvi->cargo_type;
 
						if (rvi->flags & RVI_WAGON) {
 
						if (rvi->railveh_type == RAILVEH_WAGON) {
 
							if (cargo_type == CT_PASSENGERS || cargo_type == CT_MAIL || cargo_type == CT_VALUABLES) {
 
								if (parent_engine_type == INVALID_ENGINE) {
 
									scheme = LS_PASSENGER_WAGON_STEAM;
 
								} else {
 
									switch (RailVehInfo(parent_engine_type)->engclass) {
 
										case 0: scheme = LS_PASSENGER_WAGON_STEAM; break;
 
										case 1: scheme = LS_PASSENGER_WAGON_DIESEL; break;
 
										case 2: scheme = LS_PASSENGER_WAGON_ELECTRIC; break;
 
									}
 
								}
 
							} else {
 
								scheme = LS_FREIGHT_WAGON;
 
							}
 
						} else {
 
							bool is_mu = HASBIT(_engine_info[engine_type].misc_flags, EF_RAIL_IS_MU);
 

	
 
							switch (rvi->engclass) {
 
								case 0: scheme = LS_STEAM; break;
 
								case 1: scheme = is_mu ? LS_DMU : LS_DIESEL; break;
 
								case 2: scheme = is_mu ? LS_EMU : LS_ELECTRIC; break;
 
							}
 
						}
 
						break;
 
					}
0 comments (0 inline, 0 general)