(svn r1009) -Feature: per-station vehicle lists
authortron
Fri, 10 Dec 2004 18:16:08 +0000
changeset 588 1b60458bdc29
parent 587 2fa4963eb92c
child 589 f719a093cd84
(svn r1009) -Feature: per-station vehicle lists
This adds a little button per vehicle class to the station window which opens a list of all vehicles that have this station on their schedule.
As side effect this gets rid of some global variables.
aircraft_cmd.c
aircraft_gui.c
gui.h
lang/english.txt
main_gui.c
order_cmd.c
roadveh_cmd.c
roadveh_gui.c
ship_cmd.c
ship_gui.c
station_gui.c
train_cmd.c
train_gui.c
vehicle.c
vehicle_gui.c
vehicle_gui.h
water_cmd.c
window.h
--- a/aircraft_cmd.c	Fri Dec 10 15:12:48 2004 +0000
+++ b/aircraft_cmd.c	Fri Dec 10 18:16:08 2004 +0000
@@ -267,8 +267,7 @@
 		}
 
 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-		_vehicle_sort_dirty[VEHAIRCRAFT] = true; // build aircraft
-		InvalidateWindow(WC_AIRCRAFT_LIST, v->owner);
+		RebuildVehicleLists();
 		InvalidateWindow(WC_COMPANY, v->owner);
 	}
 
@@ -299,8 +298,7 @@
 static void DoDeleteAircraft(Vehicle *v)
 {
 	DeleteWindowById(WC_VEHICLE_VIEW, v->index);
-	_vehicle_sort_dirty[VEHAIRCRAFT] = true; // delete aircraft
-	InvalidateWindow(WC_AIRCRAFT_LIST, v->owner);
+	RebuildVehicleLists();
 	InvalidateWindow(WC_COMPANY, v->owner);
 	DeleteVehicleChain(v);
 }
--- a/aircraft_gui.c	Fri Dec 10 15:12:48 2004 +0000
+++ b/aircraft_gui.c	Fri Dec 10 18:16:08 2004 +0000
@@ -884,158 +884,125 @@
 	}
 }
 
-// used to get a sorted list of the vehicles
-static SortStruct _aircraft_sort[NUM_NORMAL_VEHICLES];
-static uint16 _num_aircraft_sort[MAX_PLAYERS];
-
-static void GlobalSortAircraftList()
-{
-	const Vehicle *v;
-	uint16 *i;
-	uint32 n = 0;
-
-	// reset #-of aircraft to 0 because ++ is used for value-assignment
-	for (i = _num_aircraft_sort; i != endof(_num_aircraft_sort); i++) {*i = 0;}
-
-	FOR_ALL_VEHICLES(v) {
-		if(v->type == VEH_Aircraft && v->subtype <= 2) {
-			_aircraft_sort[n].index = v->index;
-			_aircraft_sort[n++].owner = v->owner;
-			_num_aircraft_sort[v->owner]++; // add number of aircraft of player
-		}
-	}
-
-	// create cumulative aircraft-ownership
-	// aircraft are stored as a cummulative index, eg 25, 41, 43. This means
-	// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2
-	for (i = &_num_aircraft_sort[1]; i != endof(_num_aircraft_sort); i++) {*i += *(i-1);}
-
-	qsort(_aircraft_sort, n, sizeof(_aircraft_sort[0]), GeneralOwnerSorter); // sort by owner
 
-	// since indexes are messed up after adding/removing a station, mark all lists dirty
-	memset(_aircraft_sort_dirty, true, sizeof(_aircraft_sort_dirty));
-	_vehicle_sort_dirty[VEHAIRCRAFT] = false;
-
-	DEBUG(misc, 1) ("Resorting global aircraft list...");	
-}
-
-static void MakeSortedAircraftList(byte owner)
-{
-	SortStruct *firstelement;
-	uint32 n = 0;
+static Widget _player_aircraft_widgets[] = {
+{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_A009_AIRCRAFT,			STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,						STR_SORT_TIP},
+{      WWT_PANEL,    14,    81,   237,    14,    25, 0x0,										STR_SORT_TIP},
+{   WWT_CLOSEBOX,    14,   238,   248,    14,    25, STR_0225,							STR_SORT_TIP},
+{      WWT_PANEL,    14,   249,   259,    14,    25, 0x0,										STR_NULL},
+{     WWT_MATRIX,    14,     0,   248,    26,   169, 0x401,									STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT},
+{  WWT_SCROLLBAR,    14,   249,   259,    26,   169, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHTXTBTN,    14,     0,   129,   170,   181, STR_A003_NEW_AIRCRAFT,	STR_A020_BUILD_NEW_AIRCRAFT_REQUIRES},
+{      WWT_PANEL,    14,   130,   259,   170,   181, 0x0,										STR_NULL},
+{   WIDGETS_END},
+};
 
-	if (owner == 0) { // first element starts at 0th element and has n elements as described above
-		firstelement =	&_aircraft_sort[0];
-		n =							_num_aircraft_sort[0];
-	}	else { // nth element starts at the end of the previous one, and has n elements as described above
-		firstelement =	&_aircraft_sort[_num_aircraft_sort[owner-1]];
-		n =							_num_aircraft_sort[owner] - _num_aircraft_sort[owner-1];
-	}
-
-	_internal_sort_order			= _aircraft_sort_order[owner];
-	_internal_name_sorter_id	= STR_SV_AIRCRAFT_NAME;
-	_last_vehicle_idx = 0; // used for "cache" in namesorting
-	qsort(firstelement, n, sizeof(_aircraft_sort[0]), _vehicle_sorter[_aircraft_sort_type[owner]]);
-
-	_aircraft_sort_dirty[owner] = false;
-
-	DEBUG(misc, 1) ("Resorting Aircraft list player %d...", owner+1);
-}
+static Widget _other_player_aircraft_widgets[] = {
+{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_A009_AIRCRAFT,			STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,						STR_SORT_TIP},
+{      WWT_PANEL,    14,    81,   237,    14,    25, 0x0,										STR_SORT_TIP},
+{   WWT_CLOSEBOX,    14,   238,   248,    14,    25, STR_0225,							STR_SORT_TIP},
+{      WWT_PANEL,    14,   249,   259,    14,    25, 0x0,										STR_NULL},
+{     WWT_MATRIX,    14,     0,   248,    26,   169, 0x401,									STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT},
+{  WWT_SCROLLBAR,    14,   249,   259,    26,   169, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{   WIDGETS_END},
+};
 
 static void PlayerAircraftWndProc(Window *w, WindowEvent *e)
 {
+	int station = (int)w->window_number >> 16;
+	int owner = w->window_number & 0xff;
+	vehiclelist_d *vl = &WP(w, vehiclelist_d);
+
 	switch(e->event) {
 	case WE_PAINT: {
-		uint32 i;
-		const byte window_number = (byte)w->window_number;
-
-		if (_aircraft_sort_type[window_number] == SORT_BY_UNSORTED) // disable 'Sort By' tooltip on Unsorted sorting criteria
-			w->disabled_state |= (1 << 2);
-
-		// resort shipps window if roadvehicles have been added/removed
-		if (_vehicle_sort_dirty[VEHAIRCRAFT])
-			GlobalSortAircraftList();
+		int x = 2;
+		int y = PLY_WND_PRC__OFFSET_TOP_WIDGET;
+		int max;
+		int i;
 
-		if (_aircraft_sort_dirty[window_number]) {
-			MakeSortedAircraftList(window_number);
-			/* reset sorting timeout */
-			w->custom[0] = DAY_TICKS;
-			w->custom[1] = PERIODIC_RESORT_DAYS;
-		}
+		BuildVehicleList(vl, VEH_Aircraft, owner, station);
+		SortVehicleList(vl);
 
-		// aircraft are stored as a cummulative index, eg 25, 41, 43. This means
-		// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2 aircraft
-		i = (window_number == 0) ? 0 : _num_aircraft_sort[window_number-1];
-		SetVScrollCount(w, _num_aircraft_sort[window_number] - i);
+		SetVScrollCount(w, vl->list_length);
+
+		// disable 'Sort By' tooltip on Unsorted sorting criteria
+		if (vl->sort_type == SORT_BY_UNSORTED)
+			w->disabled_state |= (1 << 2);
 
 		/* draw the widgets */
 		{
-			Player *p = DEREF_PLAYER(window_number);
-			/* Company Name -- (###) Aircraft */
-			SetDParam(0, p->name_1);
-			SetDParam(1, p->name_2);
-			SetDParam(2, w->vscroll.count);
+			const Player *p = DEREF_PLAYER(owner);
+			/* XXX hack */
+			if (station == -1) {
+				/* Company Name -- (###) Aircraft */
+				SetDParam(0, p->name_1);
+				SetDParam(1, p->name_2);
+				SetDParam(2, w->vscroll.count);
+				_player_aircraft_widgets[1].unkA = STR_A009_AIRCRAFT;
+				_other_player_aircraft_widgets[1].unkA = STR_A009_AIRCRAFT;
+			} else {
+				/* Station Name -- (###) Aircraft */
+				SetDParam(0, DEREF_STATION(station)->index);
+				SetDParam(1, w->vscroll.count);
+				_player_aircraft_widgets[1].unkA = STR_SCHEDULED_AIRCRAFT;
+				_other_player_aircraft_widgets[1].unkA = STR_SCHEDULED_AIRCRAFT;
+			}
 			DrawWindowWidgets(w);
 		}
 		/* draw sorting criteria string */
-		DrawString(85, 15, _vehicle_sort_listing[_aircraft_sort_type[window_number]], 0x10);
-		/* draw arrow pointing up/down for ascending/descending soring */
-		DoDrawString(_aircraft_sort_order[window_number] & 1 ? "\xAA" : "\xA0", 69, 15, 0x10);
-
-		/* draw the aircraft */
-		{
-			Vehicle *v;
-			int n = 0;
-			const int x = 2;			// offset from left side of widget
-			int y = PLY_WND_PRC__OFFSET_TOP_WIDGET;	// offset from top of widget
-			i += w->vscroll.pos;	// offset from sorted aircraft list of current player
-
-			while (i < _num_aircraft_sort[window_number]) {
-				StringID str;
-				v = DEREF_VEHICLE(_aircraft_sort[i].index);
-
-				assert(v->type == VEH_Aircraft && v->subtype <= 2 && v->owner == window_number);
-
-				DrawAircraftImage(v, x + 19, y + 6, INVALID_VEHICLE);
-				DrawVehicleProfitButton(v, x, y+13);
+		DrawString(85, 15, _vehicle_sort_listing[vl->sort_type], 0x10);
+		/* draw arrow pointing up/down for ascending/descending sorting */
+		DoDrawString(
+			vl->flags & VL_DESC ? "\xAA" : "\xA0", 69, 15, 0x10);
 
-				SetDParam(0, v->unitnumber);
-				if (IsAircraftHangarTile(v->tile)) {
-					str = STR_021F;
-				} else {
-					str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
-				}
-				DrawString(x, y+2, str, 0);
-
+		max = min(w->vscroll.pos + w->vscroll.cap, vl->list_length);
+		for (i = w->vscroll.pos; i < max; ++i) {
+			Vehicle *v = DEREF_VEHICLE(vl->sort_list[i].index);
+			StringID str;
 
-				SetDParam(0, v->profit_this_year);
-				SetDParam(1, v->profit_last_year);
-				DrawString(x+19, y + 28, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
+			assert(v->type == VEH_Aircraft && v->subtype <= 2);
 
-				if (v->string_id != STR_SV_AIRCRAFT_NAME) {
-					SetDParam(0, v->string_id);
-					DrawString(x+19, y, STR_01AB, 0);
-				}
+			DrawAircraftImage(v, x + 19, y + 6, INVALID_VEHICLE);
+			DrawVehicleProfitButton(v, x, y + 13);
 
-				DrawSmallSchedule(v, x+136, y);
+			SetDParam(0, v->unitnumber);
+			if (IsAircraftHangarTile(v->tile))
+				str = STR_021F;
+			else
+				str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
+			DrawString(x, y + 2, str, 0);
 
-				y += PLY_WND_PRC__SIZE_OF_ROW_BIG;
-				i++; // next aircraft
-				if (++n == w->vscroll.cap) { break;} // max number of aircraft in the window
+			SetDParam(0, v->profit_this_year);
+			SetDParam(1, v->profit_last_year);
+			DrawString(x + 19, y + 28, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
+
+			if (v->string_id != STR_SV_AIRCRAFT_NAME) {
+				SetDParam(0, v->string_id);
+				DrawString(x + 19, y, STR_01AB, 0);
 			}
+
+			DrawSmallSchedule(v, x + 136, y);
+
+			y += PLY_WND_PRC__SIZE_OF_ROW_BIG;
 		}
 		}	break;
 
 	case WE_CLICK: {
 		switch(e->click.widget) {
 		case 2: /* Flip sorting method ascending/descending */
-			_aircraft_sort_order[(byte)w->window_number] ^= 1;
-			_aircraft_sort_dirty[(byte)w->window_number] = true;
+			vl->flags ^= VL_DESC;
+			vl->flags |= VL_RESORT;
 			SetWindowDirty(w);
 			break;
+
 		case 3: case 4:/* Select sorting criteria dropdown menu */
-			ShowDropDownMenu(w, _vehicle_sort_listing, _aircraft_sort_type[(byte)w->window_number], 4, 0); // do it for widget 4
+			ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 4, 0);
 			return;
+
 		case 6: { /* Matrix to show vehicles */
 			uint32 id_v = (e->click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / PLY_WND_PRC__SIZE_OF_ROW_BIG;
 
@@ -1044,15 +1011,13 @@
 			id_v += w->vscroll.pos;
 
 			{
-				const byte owner = (byte)w->window_number;
 				Vehicle *v;
-				id_v += (owner == 0) ? 0 : _num_aircraft_sort[owner - 1]; // first element in list
 
-				if (id_v >= _num_aircraft_sort[owner]) { return;} // click out of vehicle bound
+				if (id_v >= vl->list_length) return; // click out of list bound
 
-				v	= DEREF_VEHICLE(_aircraft_sort[id_v].index); // add the offset id_x to that
+				v	= DEREF_VEHICLE(vl->sort_list[id_v].index);
 
-				assert(v->type == VEH_Aircraft && v->subtype <= 2 && v->owner == owner);
+				assert(v->type == VEH_Aircraft && v->subtype <= 2);
 
 				ShowAircraftViewWindow(v);
 			}
@@ -1078,48 +1043,37 @@
 	}	break;
 
 	case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
-		if (_aircraft_sort_type[(byte)w->window_number] != e->dropdown.index) // if value hasn't changed, dont resort list
-			_aircraft_sort_dirty[(byte)w->window_number] = true;
+		if (vl->sort_type != e->dropdown.index) {
+			// value has changed -> resort
+			vl->flags |= VL_RESORT;
+			vl->sort_type = e->dropdown.index;
 
-		_aircraft_sort_type[(byte)w->window_number] = e->dropdown.index;
-
-		if (_aircraft_sort_type[(byte)w->window_number] != SORT_BY_UNSORTED) // enable 'Sort By' if a sorter criteria is chosen
-			w->disabled_state &= ~(1 << 2);
-
+			// enable 'Sort By' if a sorter criteria is chosen
+			if (vl->sort_type != SORT_BY_UNSORTED)
+				w->disabled_state &= ~(1 << 2);
+		}
 		SetWindowDirty(w);
 		break;
+
 	case WE_CREATE: /* set up resort timer */
-		w->custom[0] = DAY_TICKS;
-		w->custom[1] = PERIODIC_RESORT_DAYS;
+		vl->sort_list = NULL;
+		vl->flags = VL_REBUILD;
+		vl->sort_type = SORT_BY_UNSORTED;
+		vl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
 		break;
+
 	case WE_TICK: /* resort the list every 20 seconds orso (10 days) */
-		if (--w->custom[0] == 0) {
-			w->custom[0] = DAY_TICKS;
-			if (--w->custom[1] == 0) {
-				w->custom[1] = PERIODIC_RESORT_DAYS;
-				_aircraft_sort_dirty[(byte)w->window_number] = true;
-				DEBUG(misc, 1) ("Periodic resort Aircraft list player %d...", w->window_number+1);
-				SetWindowDirty(w);
-			}
+		if (--vl->resort_timer == 0) {
+			DEBUG(misc, 1) ("Periodic resort aircraft list player %d station %d",
+				owner, station);
+			vl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
+			vl->flags |= VL_RESORT;
+			SetWindowDirty(w);
 		}
 		break;
 	}
 }
 
-static const Widget _player_aircraft_widgets[] = {
-{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_A009_AIRCRAFT,			STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,						STR_SORT_TIP},
-{      WWT_PANEL,    14,    81,   237,    14,    25, 0x0,										STR_SORT_TIP},
-{   WWT_CLOSEBOX,    14,   238,   248,    14,    25, STR_0225,							STR_SORT_TIP},
-{      WWT_PANEL,    14,   249,   259,    14,    25, 0x0,										STR_NULL},
-{     WWT_MATRIX,    14,     0,   248,    26,   169, 0x401,									STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT},
-{  WWT_SCROLLBAR,    14,   249,   259,    26,   169, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHTXTBTN,    14,     0,   129,   170,   181, STR_A003_NEW_AIRCRAFT,	STR_A020_BUILD_NEW_AIRCRAFT_REQUIRES},
-{      WWT_PANEL,    14,   130,   259,   170,   181, 0x0,										STR_NULL},
-{   WIDGETS_END},
-};
-
 static const WindowDesc _player_aircraft_desc = {
 	-1, -1, 260, 182,
 	WC_AIRCRAFT_LIST,0,
@@ -1128,18 +1082,6 @@
 	PlayerAircraftWndProc
 };
 
-static const Widget _other_player_aircraft_widgets[] = {
-{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_A009_AIRCRAFT,			STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,						STR_SORT_TIP},
-{      WWT_PANEL,    14,    81,   237,    14,    25, 0x0,										STR_SORT_TIP},
-{   WWT_CLOSEBOX,    14,   238,   248,    14,    25, STR_0225,							STR_SORT_TIP},
-{      WWT_PANEL,    14,   249,   259,    14,    25, 0x0,										STR_NULL},
-{     WWT_MATRIX,    14,     0,   248,    26,   169, 0x401,									STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT},
-{  WWT_SCROLLBAR,    14,   249,   259,    26,   169, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{   WIDGETS_END},
-};
-
 static const WindowDesc _other_player_aircraft_desc = {
 	-1, -1, 260, 170,
 	WC_AIRCRAFT_LIST,0,
@@ -1148,14 +1090,14 @@
 	PlayerAircraftWndProc
 };
 
-void ShowPlayerAircraft(int player)
+void ShowPlayerAircraft(int player, int station)
 {
 	Window *w;
 
 	if (player == _local_player) {
-		w = AllocateWindowDescFront(&_player_aircraft_desc, player);
+		w = AllocateWindowDescFront(&_player_aircraft_desc, (station << 16) | player);
 	} else  {
-		w = AllocateWindowDescFront(&_other_player_aircraft_desc, player);
+		w = AllocateWindowDescFront(&_other_player_aircraft_desc, (station << 16) | player);
 	}
 
 	if (w) {
--- a/gui.h	Fri Dec 10 15:12:48 2004 +0000
+++ b/gui.h	Fri Dec 10 18:16:08 2004 +0000
@@ -34,7 +34,7 @@
 void PlaceProc_BuyLand(uint tile);
 
 /* train_gui.c */
-void ShowPlayerTrains(int player);
+void ShowPlayerTrains(int player, int station);
 void ShowTrainViewWindow(Vehicle *v);
 void ShowTrainDetailsWindow(Vehicle *v);
 void ShowOrdersWindow(Vehicle *v);
@@ -44,17 +44,17 @@
 /* road_gui.c */
 void ShowBuildRoadToolbar();
 void ShowBuildRoadScenToolbar();
-void ShowPlayerRoadVehicles(int player);
+void ShowPlayerRoadVehicles(int player, int station);
 
 /* dock_gui.c */
 void ShowBuildDocksToolbar();
-void ShowPlayerShips(int player);
+void ShowPlayerShips(int player, int station);
 
 void ShowShipViewWindow(Vehicle *v);
 
 /* aircraft_gui.c */
 void ShowBuildAirToolbar();
-void ShowPlayerAircraft(int player);
+void ShowPlayerAircraft(int player, int station);
 
 /* terraform_gui.c */
 void PlaceProc_DemolishArea(uint tile);
--- a/lang/english.txt	Fri Dec 10 15:12:48 2004 +0000
+++ b/lang/english.txt	Fri Dec 10 18:16:08 2004 +0000
@@ -2697,3 +2697,13 @@
 STR_NEWGRF_NO_FILES_INSTALLED					:{BLACK}There are currently no newgrf files installed! Please refer to the manual for instructions to install new graphics.
 STR_NEWGRF_FILENAME										:{BLACK}Filename:
 STR_NEWGRF_GRF_ID											:{BLACK}GRF ID:
+
+STR_TRAIN :{BLACK}{TRAIN}
+STR_LORRY :{BLACK}{LORRY}
+STR_PLANE :{BLACK}{PLANE}
+STR_SHIP  :{BLACK}{SHIP}
+
+STR_SCHEDULED_TRAINS								:{WHITE}{STATION} - {COMMA16} Trains
+STR_SCHEDULED_ROAD_VEHICLES					:{WHITE}{STATION} - {COMMA16} Road Vehicles
+STR_SCHEDULED_AIRCRAFT							:{WHITE}{STATION} - {COMMA16} Aircraft
+STR_SCHEDULED_SHIPS									:{WHITE}{STATION} - {COMMA16} Ships
--- a/main_gui.c	Fri Dec 10 15:12:48 2004 +0000
+++ b/main_gui.c	Fri Dec 10 18:16:08 2004 +0000
@@ -292,22 +292,22 @@
 
 static void MenuClickShowTrains(int index)
 {
-	ShowPlayerTrains(index);
+	ShowPlayerTrains(index, -1);
 }
 
 static void MenuClickShowRoad(int index)
 {
-	ShowPlayerRoadVehicles(index);
+	ShowPlayerRoadVehicles(index, -1);
 }
 
 static void MenuClickShowShips(int index)
 {
-	ShowPlayerShips(index);
+	ShowPlayerShips(index, -1);
 }
 
 static void MenuClickShowAir(int index)
 {
-	ShowPlayerAircraft(index);
+	ShowPlayerAircraft(index, -1);
 }
 
 static void MenuClickBuildRail(int index)
@@ -1819,10 +1819,10 @@
 		case WKC_F10:ShowOperatingProfitGraph(); break;
 		case WKC_F11: ShowCompanyLeagueTable(); break;
 		case WKC_F12: ShowBuildIndustryWindow(); break;
-		case WKC_SHIFT | WKC_F1: ShowPlayerTrains(local); break;
-		case WKC_SHIFT | WKC_F2: ShowPlayerRoadVehicles(local); break;
-		case WKC_SHIFT | WKC_F3: ShowPlayerShips(local); break;
-		case WKC_SHIFT | WKC_F4: ShowPlayerAircraft(local); break;
+		case WKC_SHIFT | WKC_F1: ShowPlayerTrains(local, -1); break;
+		case WKC_SHIFT | WKC_F2: ShowPlayerRoadVehicles(local, -1); break;
+		case WKC_SHIFT | WKC_F3: ShowPlayerShips(local, -1); break;
+		case WKC_SHIFT | WKC_F4: ShowPlayerAircraft(local, -1); break;
 		case WKC_SHIFT | WKC_F5: ToolbarZoomInClick(w); break;
 		case WKC_SHIFT | WKC_F6: ToolbarZoomOutClick(w); break;
 		case WKC_SHIFT | WKC_F7: ShowBuildRailToolbar(_last_built_railtype,-1); break;
--- a/order_cmd.c	Fri Dec 10 15:12:48 2004 +0000
+++ b/order_cmd.c	Fri Dec 10 18:16:08 2004 +0000
@@ -62,6 +62,8 @@
 				}
 			}
 		}
+
+		RebuildVehicleLists();
 	}
 
 	return 0;
@@ -81,6 +83,8 @@
 		dst->schedule_ptr = _ptr_to_next_order++;
 
 		InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
+
+		RebuildVehicleLists();
 	}
 	return 0;
 }
@@ -126,6 +130,8 @@
 				}
 			}
 		}
+
+		RebuildVehicleLists();
 	}
 
 	return 0;
@@ -240,6 +246,8 @@
 
 			InvalidateWindow(WC_VEHICLE_ORDERS, src->index);
 			InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
+
+			RebuildVehicleLists();
 		}
 		break;
 	}
@@ -281,6 +289,8 @@
 			memcpy(dst->schedule_ptr, src->schedule_ptr, (src->num_orders + 1) * sizeof(uint16));
 
 			InvalidateWindow(WC_VEHICLE_ORDERS, dst->index);
+
+			RebuildVehicleLists();
 		}
 		break;
 	}
--- a/roadveh_cmd.c	Fri Dec 10 15:12:48 2004 +0000
+++ b/roadveh_cmd.c	Fri Dec 10 18:16:08 2004 +0000
@@ -184,8 +184,7 @@
 		VehiclePositionChanged(v);
 
 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-		_vehicle_sort_dirty[VEHROAD] = true; // build a new bus/truck
-		InvalidateWindow(WC_ROADVEH_LIST, v->owner);
+		RebuildVehicleLists();
 		InvalidateWindow(WC_COMPANY, v->owner);
 	}
 
@@ -228,8 +227,7 @@
 	if (flags & DC_EXEC) {
 		// Invalidate depot
 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-		_vehicle_sort_dirty[VEHROAD] = true; // sell a bus/truck
-		InvalidateWindow(WC_ROADVEH_LIST, v->owner);
+		RebuildVehicleLists();
 		InvalidateWindow(WC_COMPANY, v->owner);
 		DeleteWindowById(WC_VEHICLE_VIEW, v->index);
 		DeleteVehicle(v);
@@ -422,8 +420,7 @@
 	DeleteWindowById(WC_VEHICLE_VIEW, v->index);
 	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 
-	_vehicle_sort_dirty[VEHROAD] = true; // delete bus/truck (eg. crash for example)
-	InvalidateWindow(WC_ROADVEH_LIST, v->owner);
+	RebuildVehicleLists();
 	InvalidateWindow(WC_COMPANY, v->owner);
 
 	if(IS_TILETYPE(v->tile, MP_STATION))
--- a/roadveh_gui.c	Fri Dec 10 15:12:48 2004 +0000
+++ b/roadveh_gui.c	Fri Dec 10 18:16:08 2004 +0000
@@ -698,154 +698,122 @@
 	}
 }
 
-// used to get a sorted list of the vehicles
-static SortStruct _road_sort[NUM_NORMAL_VEHICLES];
-static uint16 _num_road_sort[MAX_PLAYERS];
-
-static void GlobalSortRoadVehList()
-{
-	const Vehicle *v;
-	uint16 *i;
-	uint32 n = 0;
-
-	// reset #-of roadvehicles to 0 because ++ is used for value-assignment
-	for (i = _num_road_sort; i != endof(_num_road_sort); i++) {*i = 0;}
-
-	FOR_ALL_VEHICLES(v) {
-		if(v->type == VEH_Road) {
-			_road_sort[n].index = v->index;
-			_road_sort[n++].owner = v->owner;
-			_num_road_sort[v->owner]++; // add number of roadvehicless of player
-		}
-	}
-
-	// create cumulative roadvehicle-ownership
-	// roads are stored as a cummulative index, eg 25, 41, 43. This means
-	// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2
-	for (i = &_num_road_sort[1]; i != endof(_num_road_sort); i++) {*i += *(i-1);}
-
-	qsort(_road_sort, n, sizeof(_road_sort[0]), GeneralOwnerSorter); // sort by owner
 
-	// since indexes are messed up after adding/removing a station, mark all lists dirty
-	memset(_road_sort_dirty, true, sizeof(_road_sort_dirty));
-	_vehicle_sort_dirty[VEHROAD] = false;
-
-	DEBUG(misc, 1) ("Resorting global roadvehicles list...");
-}
-
-static void MakeSortedRoadVehList(byte owner)
-{
-	SortStruct *firstelement;
-	uint32 n = 0;
+static Widget _player_roadveh_widgets[] = {
+{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,								STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_9001_ROAD_VEHICLES,	STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,							STR_SORT_TIP},
+{      WWT_PANEL,    14,    81,   237,    14,    25, 0x0,											STR_SORT_TIP},
+{   WWT_CLOSEBOX,    14,   238,   248,    14,    25, STR_0225,								STR_SORT_TIP},
+{      WWT_PANEL,    14,   249,   259,    14,    25, 0x0,											STR_NULL},
+{     WWT_MATRIX,    14,     0,   248,    26,   207, 0x701,										STR_901A_ROAD_VEHICLES_CLICK_ON},
+{  WWT_SCROLLBAR,    14,   249,   259,    26,   207, 0x0,											STR_0190_SCROLL_BAR_SCROLLS_LIST},
+/* only for our road list, a 'Build Vehicle' button that opens the depot of the last built depot */
+{ WWT_PUSHTXTBTN,    14,     0,   129,   208,   219, STR_8815_NEW_VEHICLES,		STR_901B_BUILD_NEW_ROAD_VEHICLES},
+{      WWT_PANEL,    14,   130,   259,   208,   219, 0x0,											STR_NULL},
+{   WIDGETS_END},
+};
 
-	if (owner == 0) { // first element starts at 0th element and has n elements as described above
-		firstelement =	&_road_sort[0];
-		n =							_num_road_sort[0];
-	}	else { // nth element starts at the end of the previous one, and has n elements as described above
-		firstelement =	&_road_sort[_num_road_sort[owner-1]];
-		n =							_num_road_sort[owner] - _num_road_sort[owner-1];
-	}
-
-	_internal_sort_order			= _road_sort_order[owner];
-	_internal_name_sorter_id	= STR_SV_ROADVEH_NAME;
-	_last_vehicle_idx = 0; // used for "cache" in namesorting
-	qsort(firstelement, n, sizeof(_road_sort[0]), _vehicle_sorter[_road_sort_type[owner]]);
-
-	_road_sort_dirty[owner] = false;
-
-	DEBUG(misc, 1) ("Resorting Roadvehicles list player %d...", owner+1);
-}
+static Widget _other_player_roadveh_widgets[] = {
+{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,								STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_9001_ROAD_VEHICLES,	STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,							STR_SORT_TIP},
+{      WWT_PANEL,    14,    81,   237,    14,    25, 0x0,											STR_SORT_TIP},
+{   WWT_CLOSEBOX,    14,   238,   248,    14,    25, STR_0225,								STR_SORT_TIP},
+{      WWT_PANEL,    14,   249,   259,    14,    25, 0x0,											STR_NULL},
+{     WWT_MATRIX,    14,     0,   248,    26,   207, 0x701,										STR_901A_ROAD_VEHICLES_CLICK_ON},
+{  WWT_SCROLLBAR,    14,   249,   259,    26,   207, 0x0,											STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{   WIDGETS_END},
+};
 
 static void PlayerRoadVehWndProc(Window *w, WindowEvent *e)
 {
+	int station = (int)w->window_number >> 16;
+	int owner = w->window_number & 0xff;
+	vehiclelist_d *vl = &WP(w, vehiclelist_d);
+
 	switch(e->event) {
 	case WE_PAINT: {
-		uint32 i;
-		const byte window_number = (byte)w->window_number;
-
-		if (_road_sort_type[window_number] == SORT_BY_UNSORTED) // disable 'Sort By' tooltip on Unsorted sorting criteria
-			w->disabled_state |= (1 << 2);
-
-		// resort roadvehicles window if roadvehicles have been added/removed
-		if (_vehicle_sort_dirty[VEHROAD])
-			GlobalSortRoadVehList();
+		int x = 2;
+		int y = PLY_WND_PRC__OFFSET_TOP_WIDGET;
+		int max;
+		int i;
 
-		if (_road_sort_dirty[window_number]) {
-			MakeSortedRoadVehList(window_number);
-			/* reset sorting timeout */
-			w->custom[0] = DAY_TICKS;
-			w->custom[1] = PERIODIC_RESORT_DAYS;
-		}
+		BuildVehicleList(vl, VEH_Road, owner, station);
+		SortVehicleList(vl);
 
-		// roads are stored as a cummulative index, eg 25, 41, 43. This means
-		// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2 roads
-		i = (window_number == 0) ? 0 : _num_road_sort[window_number-1];
-		SetVScrollCount(w, _num_road_sort[window_number] - i);
+		SetVScrollCount(w, vl->list_length);
+
+		// disable 'Sort By' tooltip on Unsorted sorting criteria
+		if (vl->sort_type == SORT_BY_UNSORTED)
+			w->disabled_state |= (1 << 2);
 
 		/* draw the widgets */
 		{
-			Player *p = DEREF_PLAYER(window_number);
-			/* Company Name -- (###) Roadvehicles */
-			SetDParam(0, p->name_1);
-			SetDParam(1, p->name_2);
-			SetDParam(2, w->vscroll.count);
+			const Player *p = DEREF_PLAYER(owner);
+			/* XXX hack */
+			if (station == -1) {
+				/* Company Name -- (###) Road vehicles */
+				SetDParam(0, p->name_1);
+				SetDParam(1, p->name_2);
+				SetDParam(2, w->vscroll.count);
+				_player_roadveh_widgets[1].unkA = STR_9001_ROAD_VEHICLES;
+				_other_player_roadveh_widgets[1].unkA = STR_9001_ROAD_VEHICLES;
+			} else {
+				/* Station Name -- (###) Road vehicles */
+				SetDParam(0, DEREF_STATION(station)->index);
+				SetDParam(1, w->vscroll.count);
+				_player_roadveh_widgets[1].unkA = STR_SCHEDULED_ROAD_VEHICLES;
+				_other_player_roadveh_widgets[1].unkA = STR_SCHEDULED_ROAD_VEHICLES;
+			}
 			DrawWindowWidgets(w);
 		}
 		/* draw sorting criteria string */
-		DrawString(85, 15, _vehicle_sort_listing[_road_sort_type[window_number]], 0x10);
-		/* draw arrow pointing up/down for ascending/descending soring */
-		DoDrawString(_road_sort_order[window_number] & 1 ? "\xAA" : "\xA0", 69, 15, 0x10);
-
-		/* draw the roadvehicles */
-		{
-			Vehicle *v;
-			int n = 0;
-			const int x = 2;			// offset from left side of widget
-			int y = PLY_WND_PRC__OFFSET_TOP_WIDGET;	// offset from top of widget
-			i += w->vscroll.pos;	// offset from sorted roads list of current player
-
-			while (i < _num_road_sort[window_number]) {
-				StringID str;
-				v = DEREF_VEHICLE(_road_sort[i].index);
-
-				assert(v->type == VEH_Road && v->owner == window_number);
-
-				DrawRoadVehImage(v, x + 22, y + 6, INVALID_VEHICLE);
-				DrawVehicleProfitButton(v, x, y+13);
+		DrawString(85, 15, _vehicle_sort_listing[vl->sort_type], 0x10);
+		/* draw arrow pointing up/down for ascending/descending sorting */
+		DoDrawString(
+			vl->flags & VL_DESC ? "\xAA" : "\xA0", 69, 15, 0x10);
 
-				SetDParam(0, v->unitnumber);
-				if (IsRoadDepotTile(v->tile)) {
-					str = STR_021F;
-				} else {
-					str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
-				}
-				DrawString(x, y+2, str, 0);
+		max = min(w->vscroll.pos + w->vscroll.cap, vl->list_length);
+		for (i = w->vscroll.pos; i < max; ++i) {
+			Vehicle *v = DEREF_VEHICLE(vl->sort_list[i].index);
+			StringID str;
 
-				SetDParam(0, v->profit_this_year);
-				SetDParam(1, v->profit_last_year);
-				DrawString(x + 24, y + 18, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
+			assert(v->type == VEH_Road && v->owner == owner);
 
-				if (v->string_id != STR_SV_ROADVEH_NAME) {
-					SetDParam(0, v->string_id);
-					DrawString(x+24, y, STR_01AB, 0);
-				}
+			DrawRoadVehImage(v, x + 22, y + 6, INVALID_VEHICLE);
+			DrawVehicleProfitButton(v, x, y + 13);
 
-				y += PLY_WND_PRC__SIZE_OF_ROW_SMALL;
-				i++; // next road
-				if (++n == w->vscroll.cap) { break;} // max number of roads in the window
+			SetDParam(0, v->unitnumber);
+			if (IsRoadDepotTile(v->tile))
+				str = STR_021F;
+			else
+				str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
+			DrawString(x, y + 2, str, 0);
+
+			SetDParam(0, v->profit_this_year);
+			SetDParam(1, v->profit_last_year);
+			DrawString(x + 24, y + 18, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
+
+			if (v->string_id != STR_SV_TRAIN_NAME) {
+				SetDParam(0, v->string_id);
+				DrawString(x + 24, y, STR_01AB, 0);
 			}
+
+			y += PLY_WND_PRC__SIZE_OF_ROW_SMALL;
 		}
 		}	break;
 
 	case WE_CLICK: {
 		switch(e->click.widget) {
 		case 2: /* Flip sorting method ascending/descending */
-			_road_sort_order[(byte)w->window_number] ^= 1;
-			_road_sort_dirty[(byte)w->window_number] = true;
+			vl->flags ^= VL_DESC;
+			vl->flags |= VL_RESORT;
 			SetWindowDirty(w);
 			break;
+
 		case 3: case 4:/* Select sorting criteria dropdown menu */
-			ShowDropDownMenu(w, _vehicle_sort_listing, _road_sort_type[(byte)w->window_number], 4, 0); // do it for widget 4
+			ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 4, 0);
 			return;
 		case 6: { /* Matrix to show vehicles */
 			uint32 id_v = (e->click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / PLY_WND_PRC__SIZE_OF_ROW_SMALL;
@@ -855,13 +823,11 @@
 			id_v += w->vscroll.pos;
 
 			{
-				const byte owner = (byte)w->window_number;
 				Vehicle *v;
-				id_v += (owner == 0) ? 0 : _num_road_sort[owner - 1]; // first element in list
 
-				if (id_v >= _num_road_sort[owner]) { return;} // click out of vehicle bound
+				if (id_v >= vl->list_length) return; // click out of list bound
 
-				v	= DEREF_VEHICLE(_road_sort[id_v].index); // add the offset id_x to that
+				v	= DEREF_VEHICLE(vl->sort_list[id_v].index);
 
 				assert(v->type == VEH_Road && v->owner == owner);
 
@@ -889,49 +855,37 @@
 	}	break;
 
 	case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
-		if (_road_sort_type[(byte)w->window_number] != e->dropdown.index) // if value hasn't changed, dont resort list
-			_road_sort_dirty[(byte)w->window_number] = true;
+		if (vl->sort_type != e->dropdown.index) {
+			// value has changed -> resort
+			vl->flags |= VL_RESORT;
+			vl->sort_type = e->dropdown.index;
 
-		_road_sort_type[(byte)w->window_number] = e->dropdown.index;
-
-		if (_road_sort_type[(byte)w->window_number] != SORT_BY_UNSORTED) // enable 'Sort By' if a sorter criteria is chosen
-			w->disabled_state &= ~(1 << 2);
-
+			// enable 'Sort By' if a sorter criteria is chosen
+			if (vl->sort_type != SORT_BY_UNSORTED)
+				w->disabled_state &= ~(1 << 2);
+		}
 		SetWindowDirty(w);
 		break;
+
 	case WE_CREATE: /* set up resort timer */
-		w->custom[0] = DAY_TICKS;
-		w->custom[1] = PERIODIC_RESORT_DAYS;
+		vl->sort_list = NULL;
+		vl->flags = VL_REBUILD;
+		vl->sort_type = SORT_BY_UNSORTED;
+		vl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
 		break;
+
 	case WE_TICK: /* resort the list every 20 seconds orso (10 days) */
-		if (--w->custom[0] == 0) {
-			w->custom[0] = DAY_TICKS;
-			if (--w->custom[1] == 0) {
-				w->custom[1] = PERIODIC_RESORT_DAYS;
-				_road_sort_dirty[(byte)w->window_number] = true;
-				DEBUG(misc, 1) ("Periodic resort Roadvehicles list player %d...", w->window_number+1);
-				SetWindowDirty(w);
-			}
+		if (--vl->resort_timer == 0) {
+			DEBUG(misc, 1) ("Periodic resort road vehicles list player %d station %d",
+				owner, station);
+			vl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
+			vl->flags |= VL_RESORT;
+			SetWindowDirty(w);
 		}
 		break;
 	}
 }
 
-static const Widget _player_roadveh_widgets[] = {
-{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,								STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_9001_ROAD_VEHICLES,	STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,							STR_SORT_TIP},
-{      WWT_PANEL,    14,    81,   237,    14,    25, 0x0,											STR_SORT_TIP},
-{   WWT_CLOSEBOX,    14,   238,   248,    14,    25, STR_0225,								STR_SORT_TIP},
-{      WWT_PANEL,    14,   249,   259,    14,    25, 0x0,											STR_NULL},
-{     WWT_MATRIX,    14,     0,   248,    26,   207, 0x701,										STR_901A_ROAD_VEHICLES_CLICK_ON},
-{  WWT_SCROLLBAR,    14,   249,   259,    26,   207, 0x0,											STR_0190_SCROLL_BAR_SCROLLS_LIST},
-/* only for our road list, a 'Build Vehicle' button that opens the depot of the last built depot */
-{ WWT_PUSHTXTBTN,    14,     0,   129,   208,   219, STR_8815_NEW_VEHICLES,		STR_901B_BUILD_NEW_ROAD_VEHICLES},
-{      WWT_PANEL,    14,   130,   259,   208,   219, 0x0,											STR_NULL},
-{   WIDGETS_END},
-};
-
 static const WindowDesc _player_roadveh_desc = {
 	-1, -1, 260, 220,
 	WC_ROADVEH_LIST,0,
@@ -940,18 +894,6 @@
 	PlayerRoadVehWndProc
 };
 
-static const Widget _other_player_roadveh_widgets[] = {
-{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,								STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_9001_ROAD_VEHICLES,	STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,							STR_SORT_TIP},
-{      WWT_PANEL,    14,    81,   237,    14,    25, 0x0,											STR_SORT_TIP},
-{   WWT_CLOSEBOX,    14,   238,   248,    14,    25, STR_0225,								STR_SORT_TIP},
-{      WWT_PANEL,    14,   249,   259,    14,    25, 0x0,											STR_NULL},
-{     WWT_MATRIX,    14,     0,   248,    26,   207, 0x701,										STR_901A_ROAD_VEHICLES_CLICK_ON},
-{  WWT_SCROLLBAR,    14,   249,   259,    26,   207, 0x0,											STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{   WIDGETS_END},
-};
-
 static const WindowDesc _other_player_roadveh_desc = {
 	-1, -1, 260, 208,
 	WC_ROADVEH_LIST,0,
@@ -961,14 +903,14 @@
 };
 
 
-void ShowPlayerRoadVehicles(int player)
+void ShowPlayerRoadVehicles(int player, int station)
 {
 	Window *w;
 
 	if ( player == _local_player) {
-		w = AllocateWindowDescFront(&_player_roadveh_desc, player);
+		w = AllocateWindowDescFront(&_player_roadveh_desc, (station << 16) | player);
 	} else  {
-		w = AllocateWindowDescFront(&_other_player_roadveh_desc, player);
+		w = AllocateWindowDescFront(&_other_player_roadveh_desc, (station << 16) | player);
 	}
 	if (w) {
 		w->caption_color = player;
--- a/ship_cmd.c	Fri Dec 10 15:12:48 2004 +0000
+++ b/ship_cmd.c	Fri Dec 10 18:16:08 2004 +0000
@@ -870,8 +870,7 @@
 		VehiclePositionChanged(v);
 
 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-		_vehicle_sort_dirty[VEHSHIP] = true; // build a ship
-		InvalidateWindow(WC_SHIPS_LIST, v->owner);
+		RebuildVehicleLists();
 		InvalidateWindow(WC_COMPANY, v->owner);
 	}
 
@@ -894,8 +893,7 @@
 
 	if (flags & DC_EXEC) {
 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-		_vehicle_sort_dirty[VEHSHIP] = true; // sell a ship
-		InvalidateWindow(WC_SHIPS_LIST, v->owner);
+		RebuildVehicleLists();
 		InvalidateWindow(WC_COMPANY, v->owner);
 		DeleteWindowById(WC_VEHICLE_VIEW, v->index);
 		DeleteVehicle(v);
--- a/ship_gui.c	Fri Dec 10 15:12:48 2004 +0000
+++ b/ship_gui.c	Fri Dec 10 18:16:08 2004 +0000
@@ -866,157 +866,122 @@
 	}
 }
 
-// used to get a sorted list of the vehicles
-static SortStruct _ship_sort[NUM_NORMAL_VEHICLES];
-static uint16 _num_ship_sort[MAX_PLAYERS];
-
-static void GlobalSortShipList()
-{
-	const Vehicle *v;
-	uint16 *i;
-	uint32 n = 0;
-
-	// reset #-of ships to 0 because ++ is used for value-assignment
-	for (i = _num_ship_sort; i != endof(_num_ship_sort); i++) {*i = 0;}
-
-	FOR_ALL_VEHICLES(v) {
-		if(v->type == VEH_Ship) {
-			_ship_sort[n].index = v->index;
-			_ship_sort[n++].owner = v->owner;
-			_num_ship_sort[v->owner]++; // add number of ships of player
-		}
-	}
-
-	// create cumulative ship-ownership
-	// ships are stored as a cummulative index, eg 25, 41, 43. This means
-	// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2
-	for (i = &_num_ship_sort[1]; i != endof(_num_ship_sort); i++) {*i += *(i-1);}
-
-	qsort(_ship_sort, n, sizeof(_ship_sort[0]), GeneralOwnerSorter); // sort by owner
 
-	// since indexes are messed up after adding/removing a station, mark all lists dirty
-	memset(_ship_sort_dirty, true, sizeof(_ship_sort_dirty));
-	_vehicle_sort_dirty[VEHSHIP] = false;
-
-	DEBUG(misc, 1) ("Resorting global ships list...");	
-}
-
-static void MakeSortedShipList(byte owner)
-{
-	SortStruct *firstelement;
-	uint32 n = 0;
+static Widget _player_ships_widgets[] = {
+{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_9805_SHIPS,				STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,						STR_SORT_TIP},
+{      WWT_PANEL,    14,    81,   237,    14,    25, 0x0,										STR_NULL},
+{   WWT_CLOSEBOX,    14,   238,   248,    14,    25, STR_0225,							STR_SORT_TIP},
+{      WWT_PANEL,    14,   249,   259,    14,    25, 0x0,										STR_NULL},
+{     WWT_MATRIX,    14,     0,   248,    26,   169, 0x401,									STR_9823_SHIPS_CLICK_ON_SHIP_FOR},
+{  WWT_SCROLLBAR,    14,   249,   259,    26,   169, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHTXTBTN,    14,     0,   129,   170,   181, STR_9804_NEW_SHIPS,		STR_9824_BUILD_NEW_SHIPS_REQUIRES},
+{      WWT_PANEL,    14,   130,   259,   170,   181, 0x0,										STR_NULL},
+{   WIDGETS_END},
+};
 
-	if (owner == 0) { // first element starts at 0th element and has n elements as described above
-		firstelement =	&_ship_sort[0];
-		n =							_num_ship_sort[0];
-	}	else { // nth element starts at the end of the previous one, and has n elements as described above
-		firstelement =	&_ship_sort[_num_ship_sort[owner-1]];
-		n =							_num_ship_sort[owner] - _num_ship_sort[owner-1];
-	}
-
-	_internal_sort_order			= _ship_sort_order[owner];
-	_internal_name_sorter_id	= STR_SV_SHIP_NAME;
-	_last_vehicle_idx = 0; // used for "cache" in namesorting
-	qsort(firstelement, n, sizeof(_ship_sort[0]), _vehicle_sorter[_ship_sort_type[owner]]);
-
-	_ship_sort_dirty[owner] = false;
-
-	DEBUG(misc, 1) ("Resorting Ships list player %d...", owner+1);
-}
+static Widget _other_player_ships_widgets[] = {
+{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_9805_SHIPS,				STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,						STR_SORT_TIP},
+{      WWT_PANEL,    14,    81,   237,    14,    25, 0x0,										STR_NULL},
+{   WWT_CLOSEBOX,    14,   238,   248,    14,    25, STR_0225,							STR_SORT_TIP},
+{      WWT_PANEL,    14,   249,   259,    14,    25, 0x0,										STR_NULL},
+{     WWT_MATRIX,    14,     0,   248,    26,   169, 0x401,									STR_9823_SHIPS_CLICK_ON_SHIP_FOR},
+{  WWT_SCROLLBAR,    14,   249,   259,    26,   169, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{   WIDGETS_END},
+};
 
 static void PlayerShipsWndProc(Window *w, WindowEvent *e)
 {
+	int station = (int)w->window_number >> 16;
+	int owner = w->window_number & 0xff;
+	vehiclelist_d *vl = &WP(w, vehiclelist_d);
+
 	switch(e->event) {
 	case WE_PAINT: {
-		uint32 i;
-		const byte window_number = (byte)w->window_number;
-
-		if (_ship_sort_type[window_number] == SORT_BY_UNSORTED) // disable 'Sort By' tooltip on Unsorted sorting criteria
-			w->disabled_state |= (1 << 2);
-
-		// resort shipps window if roadvehicles have been added/removed
-		if (_vehicle_sort_dirty[VEHSHIP])
-			GlobalSortShipList();
+		int x = 2;
+		int y = PLY_WND_PRC__OFFSET_TOP_WIDGET;
+		int max;
+		int i;
 
-		if (_ship_sort_dirty[window_number]) {
-			MakeSortedShipList(window_number);
-			/* reset sorting timeout */
-			w->custom[0] = DAY_TICKS;
-			w->custom[1] = PERIODIC_RESORT_DAYS;
-		}
+		BuildVehicleList(vl, VEH_Ship, owner, station);
+		SortVehicleList(vl);
 
-		// ships are stored as a cummulative index, eg 25, 41, 43. This means
-		// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2 ships
-		i = (window_number == 0) ? 0 : _num_ship_sort[window_number-1];
-		SetVScrollCount(w, _num_ship_sort[window_number] - i);
+		SetVScrollCount(w, vl->list_length);
+
+		// disable 'Sort By' tooltip on Unsorted sorting criteria
+		if (vl->sort_type == SORT_BY_UNSORTED)
+			w->disabled_state |= (1 << 2);
 
 		/* draw the widgets */
 		{
-			Player *p = DEREF_PLAYER(window_number);
-			/* Company Name -- (###) Ships */
-			SetDParam(0, p->name_1);
-			SetDParam(1, p->name_2);
-			SetDParam(2, w->vscroll.count);
+			const Player *p = DEREF_PLAYER(owner);
+			/* XXX hack */
+			if (station == -1) {
+				/* Company Name -- (###) Trains */
+				SetDParam(0, p->name_1);
+				SetDParam(1, p->name_2);
+				SetDParam(2, w->vscroll.count);
+				_player_ships_widgets[1].unkA = STR_9805_SHIPS;
+				_other_player_ships_widgets[1].unkA = STR_9805_SHIPS;
+			} else {
+				/* Station Name -- (###) Trains */
+				SetDParam(0, DEREF_STATION(station)->index);
+				SetDParam(1, w->vscroll.count);
+				_player_ships_widgets[1].unkA = STR_SCHEDULED_SHIPS;
+				_other_player_ships_widgets[1].unkA = STR_SCHEDULED_SHIPS;
+			}
 			DrawWindowWidgets(w);
 		}
 		/* draw sorting criteria string */
-		DrawString(85, 15, _vehicle_sort_listing[_ship_sort_type[window_number]], 0x10);
-		/* draw arrow pointing up/down for ascending/descending soring */
-		DoDrawString(_ship_sort_order[window_number] & 1 ? "\xAA" : "\xA0", 69, 15, 0x10);
-
-		/* draw the ship vehicles */
-		{
-			Vehicle *v;
-			int n = 0;
-			const int x = 2;			// offset from left side of widget
-			int y = PLY_WND_PRC__OFFSET_TOP_WIDGET;	// offset from top of widget
-			i += w->vscroll.pos;	// offset from sorted ship list of current player
-
-			while (i < _num_ship_sort[window_number]) {
-				StringID str;
-				v = DEREF_VEHICLE(_ship_sort[i].index);
-
-				assert(v->type == VEH_Ship && v->owner == window_number);
-
-				DrawShipImage(v, x + 19, y + 6, INVALID_VEHICLE);
-				DrawVehicleProfitButton(v, x, y+13);
+		DrawString(85, 15, _vehicle_sort_listing[vl->sort_type], 0x10);
+		/* draw arrow pointing up/down for ascending/descending sorting */
+		DoDrawString(
+			vl->flags & VL_DESC ? "\xAA" : "\xA0", 69, 15, 0x10);
 
-				SetDParam(0, v->unitnumber);
-				if (IsShipDepotTile(v->tile)) {
-					str = STR_021F;
-				} else {
-					str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
-				}
-				DrawString(x, y+2, str, 0);
-
-				SetDParam(0, v->profit_this_year);
-				SetDParam(1, v->profit_last_year);
-				DrawString(x + 12, y + 28, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
+		max = min(w->vscroll.pos + w->vscroll.cap, vl->list_length);
+		for (i = w->vscroll.pos; i < max; ++i) {
+			Vehicle *v = DEREF_VEHICLE(vl->sort_list[i].index);
+			StringID str;
 
-				if (v->string_id != STR_SV_SHIP_NAME) {
-					SetDParam(0, v->string_id);
-					DrawString(x+12, y, STR_01AB, 0);
-				}
+			assert(v->type == VEH_Ship);
 
-				DrawSmallShipSchedule(v, x+138, y);
-
+			DrawShipImage(v, x + 19, y + 6, INVALID_VEHICLE);
+			DrawVehicleProfitButton(v, x, y + 13);
 
-				y += PLY_WND_PRC__SIZE_OF_ROW_BIG;
-				i++; // next ship
-				if (++n == w->vscroll.cap) { break;} // max number of ships in the window
+			SetDParam(0, v->unitnumber);
+			if (IsShipDepotTile(v->tile))
+				str = STR_021F;
+			else
+				str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
+			DrawString(x, y + 2, str, 0);
+
+			SetDParam(0, v->profit_this_year);
+			SetDParam(1, v->profit_last_year);
+			DrawString(x + 12, y + 28, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
+
+			if (v->string_id != STR_SV_SHIP_NAME) {
+				SetDParam(0, v->string_id);
+				DrawString(x + 12, y, STR_01AB, 0);
 			}
+
+			DrawSmallShipSchedule(v, x + 138, y);
+
+			y += PLY_WND_PRC__SIZE_OF_ROW_BIG;
 		}
 		}	break;
 
 	case WE_CLICK: {
 		switch(e->click.widget) {
 		case 2: /* Flip sorting method ascending/descending */
-			_ship_sort_order[(byte)w->window_number] ^= 1;
-			_ship_sort_dirty[(byte)w->window_number] = true;
+			vl->flags ^= VL_DESC;
+			vl->flags |= VL_RESORT;
 			SetWindowDirty(w);
 			break;
 		case 3: case 4:/* Select sorting criteria dropdown menu */
-			ShowDropDownMenu(w, _vehicle_sort_listing, _ship_sort_type[(byte)w->window_number], 4, 0); // do it for widget 4
+			ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 4, 0);
 			return;
 		case 6: { /* Matrix to show vehicles */
 			uint32 id_v = (e->click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / PLY_WND_PRC__SIZE_OF_ROW_BIG;
@@ -1026,15 +991,13 @@
 			id_v += w->vscroll.pos;
 
 			{
-				const byte owner = (byte)w->window_number;
 				Vehicle *v;
-				id_v += (owner == 0) ? 0 : _num_ship_sort[owner - 1]; // first element in list
 
-				if (id_v >= _num_ship_sort[owner]) { return;} // click out of vehicle bound
+				if (id_v >= vl->list_length) return; // click out of list bound
 
-				v	= DEREF_VEHICLE(_ship_sort[id_v].index); // add the offset id_x to that
+				v	= DEREF_VEHICLE(vl->sort_list[id_v].index);
 
-				assert(v->type == VEH_Ship && v->owner == owner);
+				assert(v->type == VEH_Ship);
 
 				ShowShipViewWindow(v);
 			}
@@ -1060,48 +1023,37 @@
 	}	break;
 
 	case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
-		if (_ship_sort_type[(byte)w->window_number] != e->dropdown.index) // if value hasn't changed, dont resort list
-			_ship_sort_dirty[(byte)w->window_number] = true;
+		if (vl->sort_type != e->dropdown.index) {
+			// value has changed -> resort
+			vl->flags |= VL_RESORT;
+			vl->sort_type = e->dropdown.index;
 
-		_ship_sort_type[(byte)w->window_number] = e->dropdown.index;
-
-		if (_ship_sort_type[(byte)w->window_number] != SORT_BY_UNSORTED) // enable 'Sort By' if a sorter criteria is chosen
-			w->disabled_state &= ~(1 << 2);
-
+			// enable 'Sort By' if a sorter criteria is chosen
+			if (vl->sort_type != SORT_BY_UNSORTED)
+				w->disabled_state &= ~(1 << 2);
+		}
 		SetWindowDirty(w);
 		break;
+
 	case WE_CREATE: /* set up resort timer */
-		w->custom[0] = DAY_TICKS;
-		w->custom[1] = PERIODIC_RESORT_DAYS;
+		vl->sort_list = NULL;
+		vl->flags = VL_REBUILD;
+		vl->sort_type = SORT_BY_UNSORTED;
+		vl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
 		break;
+
 	case WE_TICK: /* resort the list every 20 seconds orso (10 days) */
-		if (--w->custom[0] == 0) {
-			w->custom[0] = DAY_TICKS;
-			if (--w->custom[1] == 0) {
-				w->custom[1] = PERIODIC_RESORT_DAYS;
-				_ship_sort_dirty[(byte)w->window_number] = true;
-				DEBUG(misc, 1) ("Periodic resort Ships list player %d...", w->window_number+1);
-				SetWindowDirty(w);
-			}
+		if (--vl->resort_timer == 0) {
+			DEBUG(misc, 1) ("Periodic resort ships list player %d station %d",
+				owner, station);
+			vl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
+			vl->flags |= VL_RESORT;
+			SetWindowDirty(w);
 		}
 		break;
 	}
 }
 
-static const Widget _player_ships_widgets[] = {
-{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_9805_SHIPS,				STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,						STR_SORT_TIP},
-{      WWT_PANEL,    14,    81,   237,    14,    25, 0x0,										STR_NULL},
-{   WWT_CLOSEBOX,    14,   238,   248,    14,    25, STR_0225,							STR_SORT_TIP},
-{      WWT_PANEL,    14,   249,   259,    14,    25, 0x0,										STR_NULL},
-{     WWT_MATRIX,    14,     0,   248,    26,   169, 0x401,									STR_9823_SHIPS_CLICK_ON_SHIP_FOR},
-{  WWT_SCROLLBAR,    14,   249,   259,    26,   169, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHTXTBTN,    14,     0,   129,   170,   181, STR_9804_NEW_SHIPS,		STR_9824_BUILD_NEW_SHIPS_REQUIRES},
-{      WWT_PANEL,    14,   130,   259,   170,   181, 0x0,										STR_NULL},
-{   WIDGETS_END},
-};
-
 static const WindowDesc _player_ships_desc = {
 	-1, -1, 260, 182,
 	WC_SHIPS_LIST,0,
@@ -1110,18 +1062,6 @@
 	PlayerShipsWndProc
 };
 
-static const Widget _other_player_ships_widgets[] = {
-{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_9805_SHIPS,				STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,						STR_SORT_TIP},
-{      WWT_PANEL,    14,    81,   237,    14,    25, 0x0,										STR_NULL},
-{   WWT_CLOSEBOX,    14,   238,   248,    14,    25, STR_0225,							STR_SORT_TIP},
-{      WWT_PANEL,    14,   249,   259,    14,    25, 0x0,										STR_NULL},
-{     WWT_MATRIX,    14,     0,   248,    26,   169, 0x401,									STR_9823_SHIPS_CLICK_ON_SHIP_FOR},
-{  WWT_SCROLLBAR,    14,   249,   259,    26,   169, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{   WIDGETS_END},
-};
-
 static const WindowDesc _other_player_ships_desc = {
 	-1, -1, 260, 170,
 	WC_SHIPS_LIST,0,
@@ -1131,14 +1071,14 @@
 };
 
 
-void ShowPlayerShips(int player)
+void ShowPlayerShips(int player, int station)
 {
 	Window *w;
 
 	if ( player == _local_player) {
-		w = AllocateWindowDescFront(&_player_ships_desc, player);
+		w = AllocateWindowDescFront(&_player_ships_desc, (station << 16) | player);
 	} else  {
-		w = AllocateWindowDescFront(&_other_player_ships_desc, player);
+		w = AllocateWindowDescFront(&_other_player_ships_desc, (station << 16) | player);
 	}
 	if (w) {
 		w->caption_color = w->window_number;
--- a/station_gui.c	Fri Dec 10 15:12:48 2004 +0000
+++ b/station_gui.c	Fri Dec 10 18:16:08 2004 +0000
@@ -264,9 +264,13 @@
 {  WWT_SCROLLBAR,    14,   238,   248,    14,    65, 0x0,					STR_0190_SCROLL_BAR_SCROLLS_LIST},
 {      WWT_EMPTY,     0,     0,     0,     0,     0, 0x0,					STR_NULL},
 {     WWT_IMGBTN,    14,     0,   248,    66,   197, 0x0,					STR_NULL},
-{ WWT_PUSHTXTBTN,    14,     0,    82,   198,   209, STR_00E4_LOCATION,	STR_3053_CENTER_MAIN_VIEW_ON_STATION},
-{ WWT_PUSHTXTBTN,    14,    83,   165,   198,   209, STR_3033_ACCEPTS,	STR_3056_SHOW_LIST_OF_ACCEPTED_CARGO},
-{ WWT_PUSHTXTBTN,    14,   166,   248,   198,   209, STR_0130_RENAME,		STR_3055_CHANGE_NAME_OF_STATION},
+{ WWT_PUSHTXTBTN,    14,     0,    63,   198,   209, STR_00E4_LOCATION,	STR_3053_CENTER_MAIN_VIEW_ON_STATION},
+{ WWT_PUSHTXTBTN,    14,    64,   128,   198,   209, STR_3033_ACCEPTS,	STR_3056_SHOW_LIST_OF_ACCEPTED_CARGO},
+{ WWT_PUSHTXTBTN,    14,   129,   192,   198,   209, STR_0130_RENAME,		STR_3055_CHANGE_NAME_OF_STATION},
+{ WWT_PUSHTXTBTN,    14,   193,   206,   198,   209, STR_TRAIN, STR_NULL },
+{ WWT_PUSHTXTBTN,    14,   207,   220,   198,   209, STR_LORRY, STR_NULL },
+{ WWT_PUSHTXTBTN,    14,   221,   234,   198,   209, STR_PLANE, STR_NULL },
+{ WWT_PUSHTXTBTN,    14,   235,   248,   198,   209, STR_SHIP, STR_NULL },
 {   WIDGETS_END},
 };
 
@@ -277,9 +281,13 @@
 {  WWT_SCROLLBAR,    14,   238,   248,    14,    65, 0x0,					STR_0190_SCROLL_BAR_SCROLLS_LIST},
 {     WWT_IMGBTN,    14,     0,   248,    66,    97, 0x0,					STR_NULL},
 {      WWT_EMPTY,     0,     0,     0,     0,     0, 0x0,					STR_NULL},
-{ WWT_PUSHTXTBTN,    14,     0,    82,    98,   109, STR_00E4_LOCATION,	STR_3053_CENTER_MAIN_VIEW_ON_STATION},
-{ WWT_PUSHTXTBTN,    14,    83,   165,    98,   109, STR_3032_RATINGS,	STR_3054_SHOW_STATION_RATINGS},
-{ WWT_PUSHTXTBTN,    14,   166,   248,    98,   109, STR_0130_RENAME,		STR_3055_CHANGE_NAME_OF_STATION},
+{ WWT_PUSHTXTBTN,    14,     0,    63,    98,   109, STR_00E4_LOCATION,	STR_3053_CENTER_MAIN_VIEW_ON_STATION},
+{ WWT_PUSHTXTBTN,    14,    64,   128,    98,   109, STR_3032_RATINGS,	STR_3054_SHOW_STATION_RATINGS},
+{ WWT_PUSHTXTBTN,    14,   129,   192,    98,   109, STR_0130_RENAME,		STR_3055_CHANGE_NAME_OF_STATION},
+{ WWT_PUSHTXTBTN,    14,   193,   206,    98,   109, STR_TRAIN, STR_NULL },
+{ WWT_PUSHTXTBTN,    14,   207,   220,    98,   109, STR_LORRY, STR_NULL },
+{ WWT_PUSHTXTBTN,    14,   221,   234,    98,   109, STR_PLANE, STR_NULL },
+{ WWT_PUSHTXTBTN,    14,   235,   248,    98,   109, STR_SHIP, STR_NULL },
 {   WIDGETS_END},
 };
 
@@ -310,6 +318,13 @@
 	SetVScrollCount(w, num);
 
 	w->disabled_state = st->owner == _local_player ? 0 : (1 << 8);
+
+	if (!(st->facilities & FACIL_TRAIN)) SETBIT(w->disabled_state,  9);
+	if (!(st->facilities & FACIL_TRUCK_STOP) &&
+			!(st->facilities & FACIL_BUS_STOP)) SETBIT(w->disabled_state, 10);
+	if (!(st->facilities & FACIL_AIRPORT)) SETBIT(w->disabled_state, 11);
+	if (!(st->facilities & FACIL_DOCK)) SETBIT(w->disabled_state, 12);
+
 	SetDParam(0, st->index);
 	SetDParam(1, st->facilities);
 	DrawWindowWidgets(w);
@@ -443,6 +458,30 @@
 			SetDParam(1, st->town->townnameparts);
 			ShowQueryString(st->string_id, STR_3030_RENAME_STATION_LOADING, 31, 180, w->window_class, w->window_number);
 		}	break;
+
+		case 9: {
+			const Station *st = DEREF_STATION(w->window_number);
+			ShowPlayerTrains(st->owner, w->window_number);
+			break;
+		}
+
+		case 10: {
+			const Station *st = DEREF_STATION(w->window_number);
+			ShowPlayerRoadVehicles(st->owner, w->window_number);
+			break;
+		}
+
+		case 11: {
+			const Station *st = DEREF_STATION(w->window_number);
+			ShowPlayerAircraft(st->owner, w->window_number);
+			break;
+		}
+
+		case 12: {
+			const Station *st = DEREF_STATION(w->window_number);
+			ShowPlayerShips(st->owner, w->window_number);
+			break;
+		}
 		}
 		break;
 
@@ -456,6 +495,17 @@
 		st = DEREF_STATION(w->window_number);
 		DoCommandP(st->xy, w->window_number, 0, NULL, CMD_RENAME_STATION | CMD_MSG(STR_3031_CAN_T_RENAME_STATION));
 	} break;
+
+	case WE_DESTROY: {
+		WindowNumber wno =
+			(w->window_number << 16) | DEREF_STATION(w->window_number)->owner;
+
+		DeleteWindowById(WC_TRAINS_LIST, wno);
+		DeleteWindowById(WC_ROADVEH_LIST, wno);
+		DeleteWindowById(WC_SHIPS_LIST, wno);
+		DeleteWindowById(WC_AIRCRAFT_LIST, wno);
+		break;
+	}
 	}
 }
 
--- a/train_cmd.c	Fri Dec 10 15:12:48 2004 +0000
+++ b/train_cmd.c	Fri Dec 10 18:16:08 2004 +0000
@@ -499,8 +499,7 @@
 			NormalizeTrainVehInDepot(v);
 
 			InvalidateWindow(WC_VEHICLE_DEPOT, tile);
-			_vehicle_sort_dirty[VEHTRAIN] = true; // build a trainengine
-			InvalidateWindow(WC_TRAINS_LIST, v->owner);
+			RebuildVehicleLists();
 			InvalidateWindow(WC_COMPANY, v->owner);
 		}
 	}
@@ -811,8 +810,7 @@
 		// always redraw the depot. maybe redraw train list
 		InvalidateWindow(WC_VEHICLE_DEPOT, first->tile);
 		if (first->subtype == 0) {
-			_vehicle_sort_dirty[VEHTRAIN] = true; // sell a wagon / locomotive
-			InvalidateWindow(WC_TRAINS_LIST, first->owner);
+			RebuildVehicleLists();
 		}
 		// when selling an attached locomotive. we need to delete its window.
 		if (v->subtype == 0) {
@@ -2254,8 +2252,7 @@
 
 	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 	DeleteWindowById(WC_VEHICLE_VIEW, v->index);
-	_vehicle_sort_dirty[VEHTRAIN] = true; // remove crashed train
-	InvalidateWindow(WC_TRAINS_LIST, v->owner);
+	RebuildVehicleLists();
 	InvalidateWindow(WC_COMPANY, v->owner);
 
 	BeginVehicleMove(v);
--- a/train_gui.c	Fri Dec 10 15:12:48 2004 +0000
+++ b/train_gui.c	Fri Dec 10 18:16:08 2004 +0000
@@ -10,6 +10,7 @@
 #include "command.h"
 #include "player.h"
 #include "engine.h"
+#include "vehicle_gui.h"
 
 
 int _traininfo_vehicle_pitch = 0;
@@ -39,7 +40,7 @@
 		found = GetLastVehicleInChain(found);
 		// put the new wagon at the end of the loco.
 		DoCommandP(0, _new_wagon_id | (found->index<<16), 0, NULL, CMD_MOVE_RAIL_VEHICLE);
-		_vehicle_sort_dirty[VEHTRAIN] = true;
+		RebuildVehicleLists();
 	}
 }
 
@@ -1166,155 +1167,125 @@
 	WP(w,traindetails_d).tab = 0;
 }
 
-// used to get a sorted list of the vehicles
-static SortStruct _train_sort[NUM_NORMAL_VEHICLES];
-static uint16 _num_train_sort[MAX_PLAYERS];
-
-static void GlobalSortTrainList()
-{
-	const Vehicle *v;
-	uint16 *i;
-	uint32 n = 0;
-
-	// reset #-of trains to 0 because ++ is used for value-assignment
-	for (i = _num_train_sort; i != endof(_num_train_sort); i++) {*i = 0;}
-
-	FOR_ALL_VEHICLES(v) {
-		if(v->type == VEH_Train && v->subtype == 0) {
-			_train_sort[n].index = v->index;
-			_train_sort[n++].owner = v->owner;
-			_num_train_sort[v->owner]++; // add number of trains of player
-		}
-	}
-
-	// create cumulative train-ownership
-	// trains are stored as a cummulative index, eg 25, 41, 43. This means
-	// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2
-	for (i = &_num_train_sort[1]; i != endof(_num_train_sort); i++) {*i += *(i-1);}
-
-	qsort(_train_sort, n, sizeof(_train_sort[0]), GeneralOwnerSorter); // sort by owner
 
-	// since indexes are messed up after adding/removing a station, mark all lists dirty
-	memset(_train_sort_dirty, true, sizeof(_train_sort_dirty));
-	_vehicle_sort_dirty[VEHTRAIN] = false;
-
-	DEBUG(misc, 1) ("Resorting global trains list...");
-}
-
-static void MakeSortedTrainList(byte owner)
-{
-	SortStruct *firstelement;
-	uint32 n = 0;
+static Widget _player_trains_widgets[] = {
+{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,    14,    11,   324,     0,    13, STR_881B_TRAINS,				STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,           STR_SORT_TIP},
+{      WWT_PANEL,    14,    81,   232,    14,    25, 0x0,			              STR_SORT_TIP},
+{   WWT_CLOSEBOX,    14,   233,   243,    14,    25, STR_0225,              STR_SORT_TIP},
+{      WWT_PANEL,    14,   244,   324,    14,    25, 0x0,										STR_NULL},
+{     WWT_MATRIX,    14,     0,   313,    26,   207, 0x701,									STR_883D_TRAINS_CLICK_ON_TRAIN_FOR},
+{  WWT_SCROLLBAR,    14,   314,   324,    26,   207, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHTXTBTN,    14,     0,   161,   208,   219, STR_8815_NEW_VEHICLES,	STR_883E_BUILD_NEW_TRAINS_REQUIRES},
+{      WWT_PANEL,    14,   162,   324,   208,   219, 0x0,										STR_NULL},
+{   WIDGETS_END},
+};
 
-	if (owner == 0) { // first element starts at 0th element and has n elements as described above
-		firstelement =	&_train_sort[0];
-		n =							_num_train_sort[0];
-	}	else { // nth element starts at the end of the previous one, and has n elements as described above
-		firstelement =	&_train_sort[_num_train_sort[owner-1]];
-		n =							_num_train_sort[owner] - _num_train_sort[owner-1];
-	}
-
-	_internal_sort_order			= _train_sort_order[owner];
-	_internal_name_sorter_id	= STR_SV_TRAIN_NAME;
-	_last_vehicle_idx = 0; // used for "cache" in namesorting
-	qsort(firstelement, n, sizeof(_train_sort[0]), _vehicle_sorter[_train_sort_type[owner]]);
-
-	_train_sort_dirty[owner] = false;
-
-	DEBUG(misc, 1) ("Resorting Trains list player %d...", owner+1);
-}
+static Widget _other_player_trains_widgets[] = {
+{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,    14,    11,   324,     0,    13, STR_881B_TRAINS,				STR_018C_WINDOW_TITLE_DRAG_THIS},
+{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,           STR_SORT_TIP},
+{      WWT_PANEL,    14,    81,   232,    14,    25, 0x0,										STR_SORT_TIP},
+{   WWT_CLOSEBOX,    14,   233,   243,    14,    25, STR_0225,              STR_SORT_TIP},
+{      WWT_PANEL,    14,   244,   324,    14,    25, 0x0,										STR_NULL},
+{     WWT_MATRIX,    14,     0,   313,    26,   207, 0x701,									STR_883D_TRAINS_CLICK_ON_TRAIN_FOR},
+{  WWT_SCROLLBAR,    14,   314,   324,    26,   207, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{   WIDGETS_END},
+};
 
 static void PlayerTrainsWndProc(Window *w, WindowEvent *e)
 {
+	int station = (int)w->window_number >> 16;
+	int owner = w->window_number & 0xff;
+	vehiclelist_d *vl = &WP(w, vehiclelist_d);
+
 	switch(e->event) {
 	case WE_PAINT: {
-		uint32 i;
-		const byte window_number = (byte)w->window_number;
-
-		if (_train_sort_type[window_number] == SORT_BY_UNSORTED) // disable 'Sort By' tooltip on Unsorted sorting criteria
-			w->disabled_state |= (1 << 2);
-
-		// resort trains window if roadvehicles have been added/removed
-		if (_vehicle_sort_dirty[VEHTRAIN])
-			GlobalSortTrainList();
+		int x = 2;
+		int y = PLY_WND_PRC__OFFSET_TOP_WIDGET;
+		int max;
+		int i;
 
-		if (_train_sort_dirty[window_number]) {
-			MakeSortedTrainList(window_number);
-			/* reset sorting timeout */
-			w->custom[0] = DAY_TICKS;
-			w->custom[1] = PERIODIC_RESORT_DAYS;
-		}
+		BuildVehicleList(vl, VEH_Train, owner, station);
+		SortVehicleList(vl);
 
-		// Trains are stored as a cummulative index, eg 25, 41, 43. This means
-		// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2 trains
-		i = (window_number == 0) ? 0 : _num_train_sort[window_number-1];
-		SetVScrollCount(w, _num_train_sort[window_number] - i);
+		SetVScrollCount(w, vl->list_length);
+
+		// disable 'Sort By' tooltip on Unsorted sorting criteria
+		if (vl->sort_type == SORT_BY_UNSORTED)
+			w->disabled_state |= (1 << 2);
 
 		/* draw the widgets */
 		{
-			Player *p = DEREF_PLAYER(window_number);
-			/* Company Name -- (###) Trains */
-			SetDParam(0, p->name_1);
-			SetDParam(1, p->name_2);
-			SetDParam(2, w->vscroll.count);
+			const Player *p = DEREF_PLAYER(owner);
+			/* XXX hack */
+			if (station == -1) {
+				/* Company Name -- (###) Trains */
+				SetDParam(0, p->name_1);
+				SetDParam(1, p->name_2);
+				SetDParam(2, w->vscroll.count);
+				_player_trains_widgets[1].unkA = STR_881B_TRAINS;
+				_other_player_trains_widgets[1].unkA = STR_881B_TRAINS;
+			} else {
+				/* Station Name -- (###) Trains */
+				SetDParam(0, DEREF_STATION(station)->index);
+				SetDParam(1, w->vscroll.count);
+				_player_trains_widgets[1].unkA = STR_SCHEDULED_TRAINS;
+				_other_player_trains_widgets[1].unkA = STR_SCHEDULED_TRAINS;
+			}
 			DrawWindowWidgets(w);
 		}
 		/* draw sorting criteria string */
-		DrawString(85, 15, _vehicle_sort_listing[_train_sort_type[window_number]], 0x10);
-		/* draw arrow pointing up/down for ascending/descending soring */
-		DoDrawString(_train_sort_order[window_number] & 1 ? "\xAA" : "\xA0", 69, 15, 0x10);
-
-		/* draw the trains */
-		{
-			Vehicle *v;
-			int n = 0;
-			const int x = 2;			// offset from left side of widget
-			int y = PLY_WND_PRC__OFFSET_TOP_WIDGET;	// offset from top of widget
-			i += w->vscroll.pos;	// offset from sorted trains list of current player
-
-			while (i < _num_train_sort[window_number]) {
-				StringID str;
-				v = DEREF_VEHICLE(_train_sort[i].index);
-
-				assert(v->type == VEH_Train && v->subtype == 0 && v->owner == window_number);
-
-				DrawTrainImage(v, x + 21, y + 6 + _traininfo_vehicle_pitch, 10, 0, INVALID_VEHICLE);
-				DrawVehicleProfitButton(v, x, y+13);
+		DrawString(85, 15, _vehicle_sort_listing[vl->sort_type], 0x10);
+		/* draw arrow pointing up/down for ascending/descending sorting */
+		DoDrawString(
+			vl->flags & VL_DESC ? "\xAA" : "\xA0", 69, 15, 0x10);
 
-				SetDParam(0, v->unitnumber);
-				if (IsTrainDepotTile(v->tile)) {
-					str = STR_021F;
-				} else {
-					str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
-				}
-				DrawString(x, y+2, str, 0);
+		max = min(w->vscroll.pos + w->vscroll.cap, vl->list_length);
+		for (i = w->vscroll.pos; i < max; ++i) {
+			Vehicle *v = DEREF_VEHICLE(vl->sort_list[i].index);
+			StringID str;
 
-				SetDParam(0, v->profit_this_year);
-				SetDParam(1, v->profit_last_year);
-				DrawString(x + 21, y + 18, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
+			assert(v->type == VEH_Train && v->owner == owner);
 
-				if (v->string_id != STR_SV_TRAIN_NAME) {
-					SetDParam(0, v->string_id);
-					DrawString(x+21, y, STR_01AB, 0);
-				}
+			DrawTrainImage(
+				v, x + 21, y + 6 + _traininfo_vehicle_pitch, 10, 0, INVALID_VEHICLE);
+			DrawVehicleProfitButton(v, x, y + 13);
 
-				y += PLY_WND_PRC__SIZE_OF_ROW_SMALL;
-				i++; // next train
-				if (++n == w->vscroll.cap) { break;} // max number of trains in the window
+			SetDParam(0, v->unitnumber);
+			if (IsTrainDepotTile(v->tile))
+				str = STR_021F;
+			else
+				str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
+			DrawString(x, y + 2, str, 0);
+
+			SetDParam(0, v->profit_this_year);
+			SetDParam(1, v->profit_last_year);
+			DrawString(x + 21, y + 18, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
+
+			if (v->string_id != STR_SV_TRAIN_NAME) {
+				SetDParam(0, v->string_id);
+				DrawString(x + 21, y, STR_01AB, 0);
 			}
+
+			y += PLY_WND_PRC__SIZE_OF_ROW_SMALL;
 		}
-		}	break;
+		break;
+	}
 
 	case WE_CLICK: {
 		switch(e->click.widget) {
 		case 2: /* Flip sorting method ascending/descending */
-			_train_sort_order[(byte)w->window_number] ^= 1;
-			_train_sort_dirty[(byte)w->window_number] = true;
+			vl->flags ^= VL_DESC;
+			vl->flags |= VL_RESORT;
 			SetWindowDirty(w);
 			break;
+
 		case 3: case 4:/* Select sorting criteria dropdown menu */
-			ShowDropDownMenu(w, _vehicle_sort_listing, _train_sort_type[(byte)w->window_number], 4, 0); // do it for widget 4
+			ShowDropDownMenu(w, _vehicle_sort_listing, vl->sort_type, 4, 0);
 			return;
+
 		case 6: { /* Matrix to show vehicles */
 			uint32 id_v = (e->click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / PLY_WND_PRC__SIZE_OF_ROW_SMALL;
 
@@ -1323,13 +1294,11 @@
 			id_v += w->vscroll.pos;
 
 			{
-				const byte owner = (byte)w->window_number;
 				Vehicle *v;
-				id_v += (owner == 0) ? 0 : _num_train_sort[owner - 1]; // first element in list
 
-				if (id_v >= _num_train_sort[owner]) { return;} // click out of vehicle bound
+				if (id_v >= vl->list_length) return; // click out of list bound
 
-				v	= DEREF_VEHICLE(_train_sort[id_v].index); // add the offset id_x to that
+				v	= DEREF_VEHICLE(vl->sort_list[id_v].index);
 
 				assert(v->type == VEH_Train && v->subtype == 0 && v->owner == owner);
 
@@ -1357,48 +1326,37 @@
 	}	break;
 
 	case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
-		if (_train_sort_type[(byte)w->window_number] != e->dropdown.index) // if value hasn't changed, dont resort list
-			_train_sort_dirty[(byte)w->window_number] = true;
+		if (vl->sort_type != e->dropdown.index) {
+			// value has changed -> resort
+			vl->flags |= VL_RESORT;
+			vl->sort_type = e->dropdown.index;
 
-		_train_sort_type[(byte)w->window_number] = e->dropdown.index;
-
-		if (_train_sort_type[(byte)w->window_number] != SORT_BY_UNSORTED) // enable 'Sort By' if a sorter criteria is chosen
-			w->disabled_state &= ~(1 << 2);
-
+			// enable 'Sort By' if a sorter criteria is chosen
+			if (vl->sort_type != SORT_BY_UNSORTED)
+				w->disabled_state &= ~(1 << 2);
+		}
 		SetWindowDirty(w);
 		break;
+
 	case WE_CREATE: /* set up resort timer */
-		w->custom[0] = DAY_TICKS;
-		w->custom[1] = PERIODIC_RESORT_DAYS;
+		vl->sort_list = NULL;
+		vl->flags = VL_REBUILD;
+		vl->sort_type = SORT_BY_UNSORTED;
+		vl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
 		break;
+
 	case WE_TICK: /* resort the list every 20 seconds orso (10 days) */
-		if (--w->custom[0] == 0) {
-			w->custom[0] = DAY_TICKS;
-			if (--w->custom[1] == 0) {
-				w->custom[1] = PERIODIC_RESORT_DAYS;
-				_train_sort_dirty[(byte)w->window_number] = true;
-				DEBUG(misc, 1) ("Periodic resort Trains list player %d...", w->window_number+1);
-				SetWindowDirty(w);
-			}
+		if (--vl->resort_timer == 0) {
+			DEBUG(misc, 1) ("Periodic resort trains list player %d station %d",
+				owner, station);
+			vl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
+			vl->flags |= VL_RESORT;
+			SetWindowDirty(w);
 		}
 		break;
 	}
 }
 
-static const Widget _player_trains_widgets[] = {
-{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,    14,    11,   324,     0,    13, STR_881B_TRAINS,				STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,           STR_SORT_TIP},
-{      WWT_PANEL,    14,    81,   232,    14,    25, 0x0,			              STR_SORT_TIP},
-{   WWT_CLOSEBOX,    14,   233,   243,    14,    25, STR_0225,              STR_SORT_TIP},
-{      WWT_PANEL,    14,   244,   324,    14,    25, 0x0,										STR_NULL},
-{     WWT_MATRIX,    14,     0,   313,    26,   207, 0x701,									STR_883D_TRAINS_CLICK_ON_TRAIN_FOR},
-{  WWT_SCROLLBAR,    14,   314,   324,    26,   207, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHTXTBTN,    14,     0,   161,   208,   219, STR_8815_NEW_VEHICLES,	STR_883E_BUILD_NEW_TRAINS_REQUIRES},
-{      WWT_PANEL,    14,   162,   324,   208,   219, 0x0,										STR_NULL},
-{   WIDGETS_END},
-};
-
 static const WindowDesc _player_trains_desc = {
 	-1, -1, 325, 220,
 	WC_TRAINS_LIST,0,
@@ -1407,18 +1365,6 @@
 	PlayerTrainsWndProc
 };
 
-static const Widget _other_player_trains_widgets[] = {
-{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,    14,    11,   324,     0,    13, STR_881B_TRAINS,				STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHTXTBTN,    14,     0,    80,    14,    25, SRT_SORT_BY,           STR_SORT_TIP},
-{      WWT_PANEL,    14,    81,   232,    14,    25, 0x0,										STR_SORT_TIP},
-{   WWT_CLOSEBOX,    14,   233,   243,    14,    25, STR_0225,              STR_SORT_TIP},
-{      WWT_PANEL,    14,   244,   324,    14,    25, 0x0,										STR_NULL},
-{     WWT_MATRIX,    14,     0,   313,    26,   207, 0x701,									STR_883D_TRAINS_CLICK_ON_TRAIN_FOR},
-{  WWT_SCROLLBAR,    14,   314,   324,    26,   207, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{   WIDGETS_END},
-};
-
 static const WindowDesc _other_player_trains_desc = {
 	-1, -1, 325, 208,
 	WC_TRAINS_LIST,0,
@@ -1427,14 +1373,14 @@
 	PlayerTrainsWndProc
 };
 
-void ShowPlayerTrains(int player)
+void ShowPlayerTrains(int player, int station)
 {
 	Window *w;
 
 	if (player == _local_player) {
-		w = AllocateWindowDescFront(&_player_trains_desc, player);
+		w = AllocateWindowDescFront(&_player_trains_desc, (station << 16) | player);
 	} else {
-		w = AllocateWindowDescFront(&_other_player_trains_desc, player);
+		w = AllocateWindowDescFront(&_other_player_trains_desc, (station << 16) | player);
 	}
 	if (w) {
 		w->caption_color = w->window_number;
--- a/vehicle.c	Fri Dec 10 15:12:48 2004 +0000
+++ b/vehicle.c	Fri Dec 10 18:16:08 2004 +0000
@@ -1449,10 +1449,7 @@
 		StringID old_str = v->string_id;
 		v->string_id = str;
 		DeleteName(old_str);
-		_train_sort_dirty[v->owner]			= true;
-		_aircraft_sort_dirty[v->owner]	= true;
-		_ship_sort_dirty[v->owner]			= true;
-		_road_sort_dirty[v->owner]			= true;
+		ResortVehicleLists();
 		MarkWholeScreenDirty();
 	} else {
 		DeleteName(str);
--- a/vehicle_gui.c	Fri Dec 10 15:12:48 2004 +0000
+++ b/vehicle_gui.c	Fri Dec 10 18:16:08 2004 +0000
@@ -2,6 +2,7 @@
 #include "ttd.h"
 #include "table/strings.h"
 #include "vehicle.h"
+#include "window.h"
 
 VehicleSortListingTypeFunctions * const _vehicle_sorter[] = {
 	&VehicleUnsortedSorter,
@@ -28,14 +29,109 @@
 	INVALID_STRING_ID
 };
 
+void RebuildVehicleLists(void)
+{
+	Window *w;
+
+	for (w = _windows; w != _last_window; ++w)
+		switch (w->window_class) {
+			case WC_TRAINS_LIST:
+			case WC_ROADVEH_LIST:
+			case WC_SHIPS_LIST:
+			case WC_AIRCRAFT_LIST:
+				WP(w, vehiclelist_d).flags |= VL_REBUILD;
+				SetWindowDirty(w);
+				break;
+
+			default:
+				break;
+		}
+}
+
+void ResortVehicleLists(void)
+{
+	Window *w;
+
+	for (w = _windows; w != _last_window; ++w)
+		switch (w->window_class) {
+			case WC_TRAINS_LIST:
+			case WC_ROADVEH_LIST:
+			case WC_SHIPS_LIST:
+			case WC_AIRCRAFT_LIST:
+				WP(w, vehiclelist_d).flags |= VL_RESORT;
+				SetWindowDirty(w);
+				break;
+
+			default:
+				break;
+		}
+}
+
+void BuildVehicleList(vehiclelist_d *vl, int type, int owner, int station)
+{
+	SortStruct sort_list[NUM_NORMAL_VEHICLES];
+	int subtype = (type != VEH_Aircraft) ? 0 : 2;
+	int n = 0;
+	int i;
+
+	if (!(vl->flags & VL_REBUILD)) return;
+
+	DEBUG(misc, 1) ("Building vehicle list for player %d station %d...",
+		owner, station);	
+
+	if (station != -1) {
+		const Vehicle *v;
+		FOR_ALL_VEHICLES(v) {
+			if (v->type == type && v->subtype <= subtype) {
+				const Order *ord;
+				for (ord = v->schedule_ptr; ord->type != OT_NOTHING; ++ord)
+					if (ord->type == OT_GOTO_STATION && ord->station == station) {
+						sort_list[n].index = v - _vehicles;
+						sort_list[n].owner = v->owner;
+						++n;
+						break;
+					}
+			}
+		}
+	} else {
+		const Vehicle *v;
+		FOR_ALL_VEHICLES(v) {
+			if (v->type == type && v->subtype <= subtype && v->owner == owner) {
+				sort_list[n].index = v - _vehicles;
+				sort_list[n].owner = v->owner;
+				++n;
+			}
+		}
+	}
+
+	vl->sort_list = realloc(vl->sort_list, n * sizeof(vl->sort_list[0])); /* XXX unchecked malloc */
+	vl->list_length = n;
+
+	for (i = 0; i < n; ++i)
+		vl->sort_list[i] = sort_list[i];
+
+	vl->flags &= ~VL_REBUILD;
+	vl->flags |= VL_RESORT;
+}
+
+void SortVehicleList(vehiclelist_d *vl)
+{
+	if (!(vl->flags & VL_RESORT)) return;
+
+	_internal_sort_order = vl->flags & VL_DESC;
+	_internal_name_sorter_id = STR_SV_TRAIN_NAME;
+	_last_vehicle_idx = 0; // used for "cache" in namesorting
+	qsort(vl->sort_list, vl->list_length, sizeof(vl->sort_list[0]),
+		_vehicle_sorter[vl->sort_type]);
+
+	vl->resort_timer = DAY_TICKS * PERIODIC_RESORT_DAYS;
+	vl->flags &= ~VL_RESORT;
+}
+
+
 /* General Vehicle GUI based procedures that are independent of vehicle types */
 void InitializeVehiclesGuiList()
 {
-	memset(_train_sort_dirty, true, sizeof(_train_sort_dirty));
-	memset(_aircraft_sort_dirty, true, sizeof(_aircraft_sort_dirty));
-	memset(_ship_sort_dirty, true, sizeof(_ship_sort_dirty));
-	memset(_road_sort_dirty, true, sizeof(_road_sort_dirty));
-	memset(_vehicle_sort_dirty, true, sizeof(_vehicle_sort_dirty));
 }
 
 // draw the vehicle profit button in the vehicle list window.
--- a/vehicle_gui.h	Fri Dec 10 15:12:48 2004 +0000
+++ b/vehicle_gui.h	Fri Dec 10 18:16:08 2004 +0000
@@ -1,10 +1,18 @@
 #ifndef VEHICLE_GUI_H
 #define VEHICLE_GUI_H
 
+struct vehiclelist_d;
+
 void DrawVehicleProfitButton(Vehicle *v, int x, int y);
 void InitializeVehiclesGuiList();
 
 /* sorter stuff */
+void RebuildVehicleLists(void);
+void ResortVehicleLists(void);
+
+void BuildVehicleList(struct vehiclelist_d *vl, int type, int owner, int station);
+void SortVehicleList(struct vehiclelist_d *vl);
+
 typedef struct SortStruct { // store owner through sorting process
 	uint32	index;
 	byte		owner;
@@ -42,24 +50,6 @@
 	VEHAIRCRAFT	= 3
 };
 
-VARDEF bool _vehicle_sort_dirty[4];	// global sort, vehicles added/removed (4 types of vehicles)
-
-VARDEF bool _train_sort_dirty[MAX_PLAYERS];			// vehicles for a given player needs to be resorted (new criteria)
-VARDEF byte _train_sort_type[MAX_PLAYERS];			// different criteria for sorting
-VARDEF bool _train_sort_order[MAX_PLAYERS];			// sort descending/ascending
-
-VARDEF bool _aircraft_sort_dirty[MAX_PLAYERS];	// vehicles for a given player needs to be resorted (new criteria)
-VARDEF byte _aircraft_sort_type[MAX_PLAYERS];		// different criteria for sorting
-VARDEF bool _aircraft_sort_order[MAX_PLAYERS];	// sort descending/ascending
-
-VARDEF bool _ship_sort_dirty[MAX_PLAYERS];			// vehicles for a given player needs to be resorted (new criteria)
-VARDEF byte _ship_sort_type[MAX_PLAYERS];				// different criteria for sorting
-VARDEF bool _ship_sort_order[MAX_PLAYERS];			// sort descending/ascending
-
-VARDEF bool _road_sort_dirty[MAX_PLAYERS];			// vehicles for a given player needs to be resorted (new criteria)
-VARDEF byte _road_sort_type[MAX_PLAYERS];				// different criteria for sorting
-VARDEF bool _road_sort_order[MAX_PLAYERS];			// sort descending/ascending
-
 enum {
   PLY_WND_PRC__OFFSET_TOP_WIDGET	= 26,
 	PLY_WND_PRC__SIZE_OF_ROW_SMALL	= 26,
--- a/water_cmd.c	Fri Dec 10 15:12:48 2004 +0000
+++ b/water_cmd.c	Fri Dec 10 18:16:08 2004 +0000
@@ -533,8 +533,7 @@
 
 			v->vehstatus |= VS_CRASHED;
 			v->u.road.crashed_ctr = 2000;	// max 2220, disappear pretty fast
-			_vehicle_sort_dirty[VEHROAD] = true;
-			InvalidateWindow(WC_ROADVEH_LIST, v->owner);
+			RebuildVehicleLists();
 		}
 
 		else if (v->type == VEH_Train) {
@@ -550,8 +549,7 @@
 
 			v = u;
 			v->u.rail.crash_anim_pos = 4000; // max 4440, disappear pretty fast
-			_vehicle_sort_dirty[VEHTRAIN] = true;
-			InvalidateWindow(WC_TRAINS_LIST, v->owner);
+			RebuildVehicleLists();
 		} else
 			return;
 
--- a/window.h	Fri Dec 10 15:12:48 2004 +0000
+++ b/window.h	Fri Dec 10 18:16:08 2004 +0000
@@ -1,6 +1,8 @@
 #ifndef WINDOW_H
 #define WINDOW_H
 
+#include "vehicle_gui.h"
+
 typedef union WindowEvent WindowEvent;
 
 //typedef void WindowProc(Window *w, int event, int wparam, long lparam);
@@ -288,6 +290,21 @@
 	NewsItem *ni;
 } news_d;
 
+typedef enum VehicleListFlags {
+	VL_DESC    = 0x01,
+	VL_RESORT  = 0x02,
+	VL_REBUILD = 0x04
+} VehicleListFlags;
+
+typedef struct vehiclelist_d {
+	SortStruct *sort_list;
+	uint16 list_length;
+	byte sort_type;
+	VehicleListFlags flags;
+	uint16 resort_timer;
+} vehiclelist_d;
+assert_compile(sizeof(vehiclelist_d) <= WINDOW_CUSTOM_SIZE);
+
 enum WindowEvents {
 	WE_CLICK = 0,
 	WE_PAINT = 1,