Changeset - r2617:c039ce1e1eeb
[Not reviewed]
master
0 12 0
bjarni - 18 years ago 2005-11-07 23:20:47
bjarni@openttd.org
(svn r3155) -Feature: [autoreplace] autoreplace can now remove cars from too long trains
-Trains will now remember the length of stations it visits and sell cars
when being autoreplaced if they became too long
-If it needs to remove cars, then it starts from the front and sells
all it can find until the train is short enough
-This only works for trains, that knows the station length of the route
so a full uninterrupted run is needed
-a train needs 1-2 runs to detect if the shortest station is expanded
-This feature can be turned on and off in the train replace window
and each company can have it's own setting
-NOTE: minor savegame version bump
12 files changed with 129 insertions and 14 deletions:
0 comments (0 inline, 0 general)
lang/english.txt
Show inline comments
 
@@ -943,6 +943,7 @@ STR_TRAIN_AUTORENEW_FAILED              
 
STR_ROADVEHICLE_AUTORENEW_FAILED                                :{WHITE}Autorenew failed on road vehicle {COMMA} (money limit)
 
STR_SHIP_AUTORENEW_FAILED                                       :{WHITE}Autorenew failed on ship {COMMA} (money limit)
 
STR_AIRCRAFT_AUTORENEW_FAILED                                   :{WHITE}Autorenew failed on aircraft {COMMA} (money limit)
 
STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT							:{WHITE}Train {COMMA} is too long after replacement
 

	
 
STR_CONFIG_PATCHES                                              :{BLACK}Configure Patches
 
STR_CONFIG_PATCHES_TIP                                          :{BLACK}Configure the patches
 
@@ -2752,6 +2753,8 @@ STR_REPLACE_HELP_START_BUTTON           
 
STR_REPLACE_HELP_RAILTYPE                                       :{BLACK}Choose the railtype you want to replace engines for
 
STR_REPLACE_HELP_REPLACE_INFO_TAB                               :{BLACK}Displays which engine the left selected engine is being replaced with, if any
 
STR_REPLACE_HELP                                                :{BLACK}This allows you to replace one engine type with another type, when trains of the original type enter a depot
 
STR_REPLACE_REMOVE_WAGON										:{BLACK}Wagon removal: {ORANGE}{SKIP}{STRING}
 
STR_REPLACE_REMOVE_WAGON_HELP									:{BLACK}Setting this to "On" will make autoreplace remove wagons from trains to make them keep their length if they exceed length of the shortest station in their orders.{}It will remove as many wagons as needed starting from the front
 

	
 
STR_SHORT_DATE                                                  :{WHITE}{DATE_TINY}
 
STR_SIGN_LIST_CAPTION                                           :{WHITE}Sign List - {COMMA} Sign{P "" s}
openttd.c
Show inline comments
 
@@ -1300,6 +1300,23 @@ bool AfterLoadGame(uint version)
 
		}
 
	}
 

	
 
	/* In version 16.1 of the savegame, trains became aware of station lengths
 
		need to initialized to the invalid state
 
		players needs to set renew_keep_length too */
 
	if (version < 0x1001) {
 
		Vehicle *v;
 
		FOR_ALL_PLAYERS(p) {
 
			p->renew_keep_length = false;
 
		}
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			if (v->type == VEH_Train) {
 
				v->u.rail.shortest_platform[0] = 255;
 
				v->u.rail.shortest_platform[1] = 0;
 
			}
 
		}
 
	}
 

	
 
	FOR_ALL_PLAYERS(p) {
 
		p->avail_railtypes = GetPlayerRailtypes(p->index);
 
	}
order_cmd.c
Show inline comments
 
@@ -388,6 +388,7 @@ int32 CmdInsertOrder(int x, int y, uint3
 
			}
 
			/* Update any possible open window of the vehicle */
 
			InvalidateVehicleOrder(u);
 
			if (u->type == VEH_Train) u->u.rail.shortest_platform[1] = 0; // we changed the orders so we invalidate the station length collector
 

	
 
			u = u->next_shared;
 
		}
 
@@ -520,6 +521,7 @@ int32 CmdSkipOrder(int x, int y, uint32 
 
		if (v->current_order.type == OT_LOADING && HASBIT(v->current_order.flags, OFB_NON_STOP))
 
			v->current_order.flags = 0;
 

	
 
		if (v->type == VEH_Train) v->u.rail.shortest_platform[1] = 0; // we changed the orders so we invalidate the station length collector
 
		InvalidateVehicleOrder(v);
 
	}
 

	
 
@@ -663,6 +665,7 @@ int32 CmdCloneOrder(int x, int y, uint32
 
				InvalidateVehicleOrder(src);
 

	
 
				RebuildVehicleLists();
 
				if (dst->type == VEH_Train) dst->u.rail.shortest_platform[1] = 0; // we changed the orders so we invalidate the station length collector
 
			}
 
		} break;
 

	
 
@@ -722,6 +725,7 @@ int32 CmdCloneOrder(int x, int y, uint32
 
				InvalidateVehicleOrder(dst);
 

	
 
				RebuildVehicleLists();
 
				if (dst->type == VEH_Train) dst->u.rail.shortest_platform[1] = 0; // we changed the orders so we invalidate the station length collector
 
			}
 
		} break;
 

	
player.h
Show inline comments
 
@@ -190,6 +190,7 @@ typedef struct Player {
 
	PlayerEconomyEntry old_economy[24];
 
	EngineID engine_replacement[TOTAL_NUM_ENGINES];
 
	bool engine_renew;
 
	bool renew_keep_length;
 
	int16 engine_renew_months;
 
	uint32 engine_renew_money;
 
} Player;
players.c
Show inline comments
 
@@ -497,6 +497,7 @@ Player *DoStartupNewPlayer(bool is_ai)
 
	for (i = 0; i < TOTAL_NUM_ENGINES; i++)
 
		p->engine_replacement[i] = INVALID_ENGINE;
 

	
 
	p->renew_keep_length = false;
 
	p->engine_renew = false;
 
	p->engine_renew_months = -6;
 
	p->engine_renew_money = 100000;
 
@@ -654,6 +655,7 @@ static void DeletePlayerStuff(PlayerID p
 
 * - p1 = 2 - change auto renew money
 
 * - p1 = 3 - change auto renew array
 
 * - p1 = 4 - change bool, months & money all together
 
 * - p1 = 5 - change renew_keep_length
 
 * @param p2 value to set
 
 * if p1 = 0, then:
 
 * - p2 = enable engine renewal
 
@@ -668,6 +670,8 @@ static void DeletePlayerStuff(PlayerID p
 
 * - p1 bit     15 = enable engine renewal
 
 * - p1 bits 16-31 = months left before engine expires to replace it
 
 * - p2 bits  0-31 = minimum amount of money available
 
 * if p1 = 5, then
 
 * - p2 = enable renew_keep_length
 
 */
 
int32 CmdReplaceVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 
{
 
@@ -754,8 +758,19 @@ int32 CmdReplaceVehicle(int x, int y, ui
 
				}
 
			}
 
			break;
 
		case 5:
 
			if (p->renew_keep_length == (bool)GB(p2, 0, 1))
 
				return CMD_ERROR;
 

	
 
			if (flags & DC_EXEC) {
 
				p->renew_keep_length = (bool)GB(p2, 0, 1);
 
				if (IsLocalPlayer()) {
 
					InvalidateWindow(WC_REPLACE_VEHICLE, VEH_Train);
 
				}
 
			}
 
		break;
 

	
 
	}
 

	
 
	return 0;
 
}
 

	
 
@@ -1131,9 +1146,11 @@ static const SaveLoad _player_desc[] = {
 
	SLE_CONDVAR(Player,engine_renew,         SLE_UINT8,      16, 255),
 
	SLE_CONDVAR(Player,engine_renew_months,  SLE_INT16,      16, 255),
 
	SLE_CONDVAR(Player,engine_renew_money,  SLE_UINT32,      16, 255),
 
	SLE_CONDVAR(Player,renew_keep_length,    SLE_UINT8,       2, 255),	// added with 16.1, but was blank since 2
 

	
 
	// reserve extra space in savegame here. (currently 64 bytes)
 
	SLE_CONDARR(NullStruct,null,SLE_FILE_U64 | SLE_VAR_NULL, 8, 2, 255),
 
	// reserve extra space in savegame here. (currently 63 bytes)
 
	SLE_CONDARR(NullStruct,null,SLE_FILE_U8  | SLE_VAR_NULL, 7, 2, 255),
 
	SLE_CONDARR(NullStruct,null,SLE_FILE_U64 | SLE_VAR_NULL, 7, 2, 255),
 

	
 
	SLE_END()
 
};
saveload.c
Show inline comments
 
@@ -30,7 +30,7 @@
 

	
 
enum {
 
	SAVEGAME_MAJOR_VERSION = 16,
 
	SAVEGAME_MINOR_VERSION = 0,
 
	SAVEGAME_MINOR_VERSION = 1,
 

	
 
	SAVEGAME_LOADABLE_VERSION = (SAVEGAME_MAJOR_VERSION << 8) + SAVEGAME_MINOR_VERSION
 
};
station.h
Show inline comments
 
@@ -320,6 +320,11 @@ static inline bool IsBuoyTile(TileIndex 
 
	return IsTileType(tile, MP_STATION) && _m[tile].m5 == 0x52;
 
}
 

	
 
static inline bool TileBelongsToRailStation(const Station *st, TileIndex tile)
 
{
 
	return IsTileType(tile, MP_STATION) && _m[tile].m2 == st->index && _m[tile].m5 < 8;
 
}
 

	
 
/* Get's the direction the station exit points towards. Ie, returns 0 for a
 
 * station with the exit NE. */
 
static inline byte GetRoadStationDir(TileIndex tile)
station_cmd.c
Show inline comments
 
@@ -1083,11 +1083,6 @@ int32 CmdBuildRailroadStation(int x, int
 
	return cost;
 
}
 

	
 
static bool TileBelongsToRailStation(const Station *st, TileIndex tile)
 
{
 
	return IsTileType(tile, MP_STATION) && _m[tile].m2 == st->index && _m[tile].m5 < 8;
 
}
 

	
 
static void MakeRailwayStationAreaSmaller(Station *st)
 
{
 
	uint w = st->trainst_w;
train_cmd.c
Show inline comments
 
@@ -752,6 +752,9 @@ int32 CmdBuildRailVehicle(int x, int y, 
 
			v->type = VEH_Train;
 
			v->cur_image = 0xAC2;
 

	
 
			v->u.rail.shortest_platform[0] = 255;
 
			v->u.rail.shortest_platform[1] = 0;
 

	
 
			VehiclePositionChanged(v);
 

	
 
			if (rvi->flags & RVI_MULTIHEAD && !HASBIT(p2, 0)) {
 
@@ -2349,6 +2352,27 @@ static bool ProcessTrainOrder(Vehicle *v
 

	
 
	v->dest_tile = 0;
 

	
 
	// store the station length if no shorter station was visited this order round
 
	if (v->cur_order_index == 0) {
 
		if (v->u.rail.shortest_platform[1] != 0 && v->u.rail.shortest_platform[1] != 255) {
 
			// we went though a whole round of orders without interruptions, so we store the length of the shortest station
 
			v->u.rail.shortest_platform[0] = v->u.rail.shortest_platform[1];
 
		}
 
		// all platforms are shorter than 255, so now we can find the shortest in the next order round. They might have changed size
 
		v->u.rail.shortest_platform[1] = 255;
 
	}
 

	
 
	if (v->last_station_visited != INVALID_STATION) {
 
		Station *st = GetStation(v->last_station_visited);
 
		if (TileBelongsToRailStation(st, v->tile)) {
 
			byte length = GetStationPlatforms(st, v->tile);
 

	
 
			if (length < v->u.rail.shortest_platform[1]) {
 
				v->u.rail.shortest_platform[1] = length;
 
			}
 
		}
 
	}
 

	
 
	result = false;
 
	switch (order->type) {
 
		case OT_GOTO_STATION:
vehicle.c
Show inline comments
 
@@ -1693,6 +1693,8 @@ static int32 ReplaceVehicle(Vehicle **w,
 
			if (old_v->type == VEH_Train){
 
				// move the entire train to the new engine, including the old engine. It will be sold in a moment anyway
 
				DoCommand(0, 0, (new_v->index << 16) | old_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
 
				new_v->u.rail.shortest_platform[0] = old_v->u.rail.shortest_platform[0];
 
				new_v->u.rail.shortest_platform[1] = old_v->u.rail.shortest_platform[1];
 
			}
 
		}
 
	}
 
@@ -1720,6 +1722,7 @@ static void MaybeReplaceVehicle(Vehicle 
 
	byte flags = 0;
 
	int32 cost, temp_cost = 0;
 
	bool stopped = false;
 
	bool train_fits_in_station = false;
 

	
 
	_current_player = v->owner;
 

	
 
@@ -1733,6 +1736,11 @@ static void MaybeReplaceVehicle(Vehicle 
 
		stopped = true;
 
	}
 

	
 
	if (v->type == VEH_Train && v->u.rail.shortest_platform[0]*16 <= v->u.rail.cached_total_length && GetPlayer(v->owner)->renew_keep_length) {
 
		// the train is not too long for the stations it visits. We should try to keep it that way if we change anything
 
		train_fits_in_station = true;
 
	}
 

	
 
	while (true) {
 
		cost = 0;
 
		w = v;
 
@@ -1794,6 +1802,27 @@ static void MaybeReplaceVehicle(Vehicle 
 
		flags |= DC_EXEC;
 
	}
 

	
 
	if (train_fits_in_station) {
 
		// the train fitted in the stations it got in it's orders, so we should make sure that it still do
 
		Vehicle *temp;
 
		w = v;
 
		while (v->u.rail.shortest_platform[0]*16 < v->u.rail.cached_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) ) {
 
				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);
 
			cost += DoCommand(0, 0, temp->index, 0, flags, CMD_SELL_VEH(temp->type));
 
		}
 
	}
 

	
 
	if (IsLocalPlayer()) ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost);
 

	
 
	if (stopped)
 
@@ -2085,8 +2114,10 @@ static const SaveLoad _train_desc[] = {
 
	SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,pbs_status), SLE_UINT8, 2, 255),
 
	SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,pbs_end_tile), SLE_UINT32, 2, 255),
 
	SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,pbs_end_trackdir), SLE_UINT8, 2, 255),
 
	// reserve extra space in savegame here. (currently 7 bytes)
 
	SLE_CONDARR(NullStruct,null,SLE_FILE_U8 | SLE_VAR_NULL, 7, 2, 255),
 
	SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,shortest_platform[0]), SLE_UINT8, 2, 255),	// added with 16.1, but was blank since 2
 
	SLE_CONDVARX(offsetof(Vehicle,u)+offsetof(VehicleRail,shortest_platform[1]), SLE_UINT8, 2, 255),	// added with 16.1, but was blank since 2
 
	// reserve extra space in savegame here. (currently 5 bytes)
 
	SLE_CONDARR(NullStruct,null,SLE_FILE_U8 | SLE_VAR_NULL, 5, 2, 255),
 

	
 
	SLE_END()
 
};
vehicle.h
Show inline comments
 
@@ -85,6 +85,14 @@ typedef struct VehicleRail {
 
	byte pbs_status;
 
	TileIndex pbs_end_tile;
 
	Trackdir pbs_end_trackdir;
 

	
 
	/**
 
	  * stuff to figure out how long a train should be. Used by autoreplace
 
	  * first byte holds the length of the shortest station. Updated each time order 0 is reached
 
	  * last byte is the shortest station reached this round though the orders. It can be invalidated by
 
	  *   skip station and alike by setting it to 0. That way we will ensure that a complete loop is used to find the shortest station
 
	  */
 
	byte shortest_platform[2];
 
} VehicleRail;
 

	
 
enum {
 
@@ -177,7 +185,6 @@ struct Vehicle {
 
	int32 x_pos;			// coordinates
 
	int32 y_pos;
 

	
 
	bool leave_depot_instantly;	// NOSAVE: stores if the vehicle needs to leave the depot it just entered. Used by autoreplace
 
	byte z_pos;
 
	byte direction;		// facing
 

	
 
@@ -248,6 +255,8 @@ struct Vehicle {
 
	byte breakdown_chance;
 
	byte build_year;
 

	
 
	bool leave_depot_instantly;	// NOSAVE: stores if the vehicle needs to leave the depot it just entered. Used by autoreplace
 

	
 
	uint16 load_unload_time_rem;
 

	
 
	int32 profit_this_year;
vehicle_gui.c
Show inline comments
 
@@ -748,10 +748,10 @@ static void DrawEngineArrayInReplaceWind
 
static void ReplaceVehicleWndProc(Window *w, WindowEvent *e)
 
{
 
	static const StringID _vehicle_type_names[4] = {STR_019F_TRAIN, STR_019C_ROAD_VEHICLE, STR_019E_SHIP,STR_019D_AIRCRAFT};
 
	const Player *p = GetPlayer(_local_player);
 

	
 
	switch (e->event) {
 
		case WE_PAINT: {
 
				const Player *p = GetPlayer(_local_player);
 
				int pos = w->vscroll.pos;
 
				int selected_id[2] = {-1,-1};
 
				int x = 1;
 
@@ -839,6 +839,12 @@ static void ReplaceVehicleWndProc(Window
 

	
 
				// now the actual drawing of the window itself takes place
 
				SetDParam(0, _vehicle_type_names[WP(w, replaceveh_d).vehicletype - VEH_Train]);
 

	
 
				if (WP(w, replaceveh_d).vehicletype == VEH_Train) {
 
					// set on/off for renew_keep_length
 
					SetDParam(1, p->renew_keep_length ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
 
				}
 

	
 
				DrawWindowWidgets(w);
 

	
 
				// sets up the string for the vehicle that is being replaced to
 
@@ -925,6 +931,9 @@ static void ReplaceVehicleWndProc(Window
 
					ShowDropDownMenu(w, _rail_types_list, _railtype_selected_in_replace_gui, 15, 0, ~GetPlayer(_local_player)->avail_railtypes);
 
					break;
 
				}
 
				case 17: { /* toggle renew_keep_length */
 
					DoCommandP(0, 5, p->renew_keep_length ? 0 : 1, NULL, CMD_REPLACE_VEHICLE);
 
				} break;
 
				case 4: { /* Start replacing */
 
					EngineID veh_from = WP(w, replaceveh_d).sel_engine[0];
 
					EngineID veh_to = WP(w, replaceveh_d).sel_engine[1];
 
@@ -991,7 +1000,7 @@ static const Widget _replace_rail_vehicl
 
{      WWT_PANEL,     RESIZE_TB,    14,   154,   277,   210,   221, STR_NULL,       STR_REPLACE_HELP_RAILTYPE},
 
{   WWT_CLOSEBOX,     RESIZE_TB,    14,   278,   289,   210,   221, STR_0225,       STR_REPLACE_HELP_RAILTYPE},
 
{      WWT_PANEL,     RESIZE_TB,    14,   290,   305,   210,   221, STR_NULL,       STR_NULL},
 
{      WWT_PANEL,     RESIZE_TB,    14,   317,   455,   198,   209, STR_NULL,       STR_NULL},
 
{ WWT_PUSHTXTBTN,     RESIZE_TB,    14,   317,   455,   198,   209, STR_REPLACE_REMOVE_WAGON,       STR_REPLACE_REMOVE_WAGON_HELP},
 
// end of train specific stuff
 
{  WWT_RESIZEBOX,     RESIZE_TB,    14,   444,   455,   210,   221, STR_NULL,       STR_RESIZE_BUTTON},
 
{   WIDGETS_END},
0 comments (0 inline, 0 general)