(svn r2306) - CodeChange: Check the last commands; refits. This needed an extensive rewrite and global/local-cargo ID juggling and bitmasking. However with this done it looks better as well and is compatible with newgrf handling. Big thanks to HackyKid for doing most of the work. This also closes patch "[ 1199277 ] Command checks"
authorDarkvater
Sat, 14 May 2005 12:36:16 +0000
changeset 1802 448f187042d3
parent 1801 0deeaf4cc09d
child 1803 24a94314cfa9
(svn r2306) - CodeChange: Check the last commands; refits. This needed an extensive rewrite and global/local-cargo ID juggling and bitmasking. However with this done it looks better as well and is compatible with newgrf handling. Big thanks to HackyKid for doing most of the work. This also closes patch "[ 1199277 ] Command checks"
aircraft_cmd.c
aircraft_gui.c
command.c
engine.c
engine.h
lang/english.txt
newgrf.c
ship_cmd.c
ship_gui.c
station.h
train_cmd.c
train_gui.c
ttd.h
vehicle.c
vehicle.h
vehicle_gui.c
vehicle_gui.h
--- a/aircraft_cmd.c	Sat May 14 06:48:14 2005 +0000
+++ b/aircraft_cmd.c	Sat May 14 12:36:16 2005 +0000
@@ -504,32 +504,38 @@
 	return 0;
 }
 
-// p1 = vehicle
-// p2 = new cargo type(0xFF)
-// p2 = skip check for stopped in hanger (0x0100)
+/** Refits an aircraft to the specified cargo type.
+ * @param x,y unused
+ * @param p1 vehicle ID of the aircraft to refit
+ * @param p2 various bitstuffed elements
+ * - p2 = (bit 0-7) - the new cargo type to refit to (p2 & 0xFF)
+ * - p2 = (bit 8)   - skip check for stopped in hangar, used by autoreplace (p2 & 0x100)
+ * @todo p2 bit8 check <b>NEEDS TO GO</b>
+ */
 int32 CmdRefitAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 {
-	Vehicle *v,*u;
+	Vehicle *v;
 	int pass, mail;
 	int32 cost;
-	byte SkipStoppedInHangerCheck = (p2 & 0x100) >> 8; //excludes the cargo value
-	byte new_cargo_type = p2 & 0xFF; //gets the cargo number
-	AircraftVehicleInfo *avi;
+	bool SkipStoppedInHangerCheck = !!HASBIT(p2, 8); // XXX - needs to go, yes?
+	CargoID new_cid = p2 & 0xFF; //gets the cargo number
+	const AircraftVehicleInfo *avi;
 
 	if (!IsVehicleIndex(p1)) return CMD_ERROR;
 
 	v = GetVehicle(p1);
 
-	if (v->type != VEH_Aircraft) return CMD_ERROR;
+	if (v->type != VEH_Aircraft || !CheckOwnership(v->owner)) return CMD_ERROR;
+	if (!SkipStoppedInHangerCheck && !CheckStoppedInHangar(v)) return_cmd_error(STR_A01B_AIRCRAFT_MUST_BE_STOPPED);
 
 	avi = AircraftVehInfo(v->engine_type);
 
-	if (!CheckOwnership(v->owner) || (!CheckStoppedInHangar(v) && !(SkipStoppedInHangerCheck)))
-		return CMD_ERROR;
+	/* Check cargo */
+	if (new_cid > NUM_CARGO || !CanRefitTo(v, new_cid)) return CMD_ERROR;
 
 	SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_RUN);
 
-	switch (new_cargo_type) {
+	switch (new_cid) {
 		case CT_PASSENGERS:
 			pass = avi->passenger_capacity;
 			break;
@@ -548,24 +554,22 @@
 	_aircraft_refit_capacity = pass;
 
 	cost = 0;
-	if (IS_HUMAN_PLAYER(v->owner) && new_cargo_type != v->cargo_type) {
+	if (IS_HUMAN_PLAYER(v->owner) && new_cid != v->cargo_type) {
 		cost = _price.aircraft_base >> 7;
 	}
 
 	if (flags & DC_EXEC) {
+		Vehicle *u;
 		v->cargo_cap = pass;
 
 		u = v->next;
-		mail = avi->mail_capacity;
-		if (new_cargo_type != CT_PASSENGERS) {
-			mail = 0;
-		}
+		mail = (new_cid != CT_PASSENGERS) ? 0 : avi->mail_capacity;
 		u->cargo_cap = mail;
 		//autorefitted planes wants to keep the cargo
 		//it will be checked if the cargo is valid in CmdReplaceVehicle
 		if (!(SkipStoppedInHangerCheck))
 			v->cargo_count = u->cargo_count = 0;
-		v->cargo_type = new_cargo_type;
+		v->cargo_type = new_cid;
 		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 	}
 
--- a/aircraft_gui.c	Sat May 14 06:48:14 2005 +0000
+++ b/aircraft_gui.c	Sat May 14 12:36:16 2005 +0000
@@ -205,64 +205,11 @@
 	}
 }
 
-#define MAX_REFIT 0xFF
-
-const byte _aircraft_refit_normal[] = {
-	CT_PASSENGERS,
-	CT_MAIL,
-	CT_GOODS,
-	CT_VALUABLES,
-	MAX_REFIT
-};
-
-const byte _aircraft_refit_arctic[] = {
-	CT_PASSENGERS,
-	CT_MAIL,
-	CT_GOODS,
-	CT_FOOD,
-	MAX_REFIT
-};
-
-const byte _aircraft_refit_desert[] = {
-	CT_PASSENGERS,
-	CT_MAIL,
-	CT_FRUIT,
-	CT_GOODS,
-	CT_DIAMONDS,
-	MAX_REFIT
-};
-
-const byte _aircraft_refit_candy[] = {
-	CT_PASSENGERS,
-	CT_SUGAR,
-	CT_TOYS,
-	CT_CANDY,
-	CT_COLA,
-	CT_COTTON_CANDY,
-	CT_BUBBLES,
-	CT_TOFFEE,
-	CT_BATTERIES,
-	CT_PLASTIC,
-	CT_FIZZY_DRINKS,
-	MAX_REFIT
-};
-
-const byte * const _aircraft_refit_types[4] = {
-	_aircraft_refit_normal, _aircraft_refit_arctic, _aircraft_refit_desert, _aircraft_refit_candy
-};
-
-#undef MAX_REFIT
-
 static void AircraftRefitWndProc(Window *w, WindowEvent *e)
 {
-	switch(e->event) {
+	switch (e->event) {
 	case WE_PAINT: {
-		Vehicle *v = GetVehicle(w->window_number);
-		const byte *b;
-		int sel;
-		int x,y;
-		byte color;
-		int cargo;
+		const Vehicle *v = GetVehicle(w->window_number);
 
 		SetDParam(0, v->string_id);
 		SetDParam(1, v->unitnumber);
@@ -271,72 +218,31 @@
 		DrawString(1, 15, STR_A040_SELECT_CARGO_TYPE_TO_CARRY, 0);
 
 		/* TODO: Support for custom GRFSpecial-specified refitting! --pasky */
-
-		cargo = -1;
-		x = 6;
-		y = 25;
-		sel = WP(w,refit_d).sel;
-
-#define show_cargo(ctype) { \
-		color = 16; \
-		if (sel == 0) { \
-			cargo = ctype; \
-			color = 12; \
-		} \
-		sel--; \
-		DrawString(x, y, _cargoc.names_s[ctype], color); \
-		y += 10; \
-		}
-
-		if (_engine_refit_masks[v->engine_type]) {
-			uint32 mask = _engine_refit_masks[v->engine_type];
-			int cid = 0;
+		WP(w,refit_d).cargo = DrawVehicleRefitWindow(v, WP(w, refit_d).sel);
 
-			for (; mask; mask >>= 1, cid++) {
-				if (!(mask & 1)) // not this cid
-					continue;
-				if (!(_local_cargo_id_landscape[cid] & (1 << _opt.landscape))) // not in this landscape
-					continue;
-
-				show_cargo(_local_cargo_id_ctype[cid]);
-			}
-
-		} else { // generic refit list
-			b = _aircraft_refit_types[_opt.landscape];
-			do {
-				show_cargo(*b);
-			} while (*++b != 0xFF);
-		}
-
-#undef show_cargo
-
-		WP(w,refit_d).cargo = cargo;
-
-		if (cargo != -1) {
-			int32 cost = DoCommandByTile(v->tile, v->index, cargo, DC_QUERY_COST, CMD_REFIT_AIRCRAFT);
-			if (cost != CMD_ERROR) {
+		if (WP(w,refit_d).cargo != CT_INVALID) {
+			int32 cost = DoCommandByTile(v->tile, v->index, WP(w,refit_d).cargo, DC_QUERY_COST, CMD_REFIT_AIRCRAFT);
+			if (!CmdFailed(cost)) {
 				SetDParam(2, cost);
-				SetDParam(0, _cargoc.names_long_p[cargo]);
+				SetDParam(0, _cargoc.names_long_p[WP(w,refit_d).cargo]);
 				SetDParam(1, _aircraft_refit_capacity);
 				DrawString(1, 137, STR_A041_NEW_CAPACITY_COST_OF_REFIT, 0);
 			}
 		}
-
-		break;
-	}
+	}	break;
 
 	case WE_CLICK:
 		switch(e->click.widget) {
 		case 2: { /* listbox */
-				int y = e->click.pt.y - 25;
-				if (y >= 0) {
-					WP(w,refit_d).sel = y / 10;
-					SetWindowDirty(w);
-				}
-			} break;
+			int y = e->click.pt.y - 25;
+			if (y >= 0) {
+				WP(w,refit_d).sel = y / 10;
+				SetWindowDirty(w);
+			}
+		} break;
 		case 4: /* refit button */
-			if (WP(w,refit_d).cargo != 0xFF) {
-				Vehicle *v = GetVehicle(w->window_number);
+			if (WP(w,refit_d).cargo != CT_INVALID) {
+				const Vehicle *v = GetVehicle(w->window_number);
 				if (DoCommandP(v->tile, v->index, WP(w,refit_d).cargo, NULL, CMD_REFIT_AIRCRAFT | CMD_MSG(STR_A042_CAN_T_REFIT_AIRCRAFT)))
 					DeleteWindow(w);
 			}
--- a/command.c	Sat May 14 06:48:14 2005 +0000
+++ b/command.c	Sat May 14 12:36:16 2005 +0000
@@ -229,7 +229,7 @@
 	CmdBuildAircraft,							/* 61 */
 	CmdSendAircraftToHangar,			/* 62 */
 	CmdChangeAircraftServiceInt,	/* 63 */
-	CmdRefitAircraft,							/* 64 <-- REFIT: Hackykid */
+	CmdRefitAircraft,							/* 64 */
 
 	CmdPlaceSign,									/* 65 */
 	CmdRenameSign,								/* 66 */
@@ -263,7 +263,7 @@
 	CmdBuildShip,									/* 88 */
 	CmdSendShipToDepot,						/* 89 */
 	CmdChangeShipServiceInt,			/* 90 */
-	CmdRefitShip,									/* 91 <-- REFIT: Hackykid */
+	CmdRefitShip,									/* 91 */
 
 	NULL,            							/* 92 */
 	NULL,                         /* 93 */
@@ -284,7 +284,7 @@
 
 	CmdLevelLand,									/* 105 */
 
-	CmdRefitRailVehicle,					/* 106 <-- REFIT: Hackykid */
+	CmdRefitRailVehicle,					/* 106 */
 	CmdRestoreOrderIndex,					/* 107 */
 	CmdBuildLock,									/* 108 */
 	NULL,           							/* 109 */
--- a/engine.c	Sat May 14 06:48:14 2005 +0000
+++ b/engine.c	Sat May 14 12:36:16 2005 +0000
@@ -20,34 +20,74 @@
 	ENGINE_PREVIEWING = 4,
 };
 
-/* This maps per-landscape cargo ids to globally unique cargo ids usable ie. in
- * the custom GRF files. It is basically just a transcribed table from
- * TTDPatch's newgrf.txt. */
-byte _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO] = {
-	/* LT_NORMAL */ {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 12 },
-	/* LT_HILLY */  {  0,  1,  2,  3,  4,  5,  6,  7, 28, 11, 10, 12 },
-	/* LT_DESERT */ {  0, 16,  2,  3, 13,  5,  6,  7, 14, 15, 10, 12 },
-	/* LT_CANDY */  {  0, 17,  2, 18, 19, 20, 21, 22, 23, 24, 25, 26 },
-	// 27 is paper in temperate climate in TTDPatch
-	// Following can be renumbered:
-	// 29 is the default cargo for the purpose of spritesets
-	// 30 is the purchase list image (the equivalent of 0xff) for the purpose of spritesets
+/** TRANSLATE FROM LOCAL CARGO TO GLOBAL CARGO ID'S.
+ * This maps the per-landscape cargo ID's to globally unique cargo ID's usable ie. in
+ * the custom GRF  files. It is basically just a transcribed table from TTDPatch's newgrf.txt.
+ */
+const CargoID _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO] = {
+	/* LT_NORMAL */ {GC_PASSENGERS, GC_COAL,  GC_MAIL, GC_OIL, GC_LIVESTOCK, GC_GOODS, GC_GRAIN, GC_WOOD, GC_IRON_ORE,    GC_STEEL,  GC_VALUABLES, GC_PAPER_TEMP},
+	/* LT_HILLY */  {GC_PASSENGERS, GC_COAL,  GC_MAIL, GC_OIL, GC_LIVESTOCK, GC_GOODS, GC_GRAIN, GC_WOOD, GC_INVALID,     GC_PAPER,  GC_VALUABLES, GC_FOOD },
+	/* LT_DESERT */ {GC_PASSENGERS, GC_RUBBER,GC_MAIL, GC_OIL, GC_FRUIT,     GC_GOODS, GC_GRAIN, GC_WOOD, GC_COPPER_ORE,  GC_WATER,  GC_VALUABLES, GC_FOOD },
+	/* LT_CANDY */  {GC_PASSENGERS, GC_SUGAR, GC_MAIL, GC_TOYS,GC_BATTERIES, GC_CANDY, GC_TOFFEE,GC_COLA, GC_COTTON_CANDY,GC_BUBBLES,GC_PLASTIC,   GC_FIZZY_DRINKS },
+	/**
+	 * - GC_INVALID (255) means that  cargo is not available for that climate
+	 * - GC_PAPER_TEMP (27) is paper in  temperate climate in TTDPatch
+	 * Following can  be renumbered:
+	 * - GC_DEFAULT (29) is the defa ult cargo for the purpose of spritesets
+	 * - GC_PURCHASE (30) is the purchase list image (the equivalent of 0xff) for the purpose of spritesets
+	 */
 };
 
-/* These two arrays provide a reverse mapping. */
-byte _local_cargo_id_ctype[NUM_CID] = {
-	CT_PASSENGERS, CT_COAL, CT_MAIL, CT_OIL, CT_LIVESTOCK, CT_GOODS, CT_GRAIN, CT_WOOD, // 0-7
-	CT_IRON_ORE, CT_STEEL, CT_VALUABLES, CT_PAPER, CT_FOOD, CT_FRUIT, CT_COPPER_ORE, CT_WATER, // 8-15
-	CT_RUBBER, CT_SUGAR, CT_TOYS, CT_BATTERIES, CT_CANDY, CT_TOFFEE, CT_COLA, CT_COTTON_CANDY, // 16-23
-	CT_BUBBLES, CT_PLASTIC, CT_FIZZY_DRINKS, CT_PAPER /* unsup. */, CT_HILLY_UNUSED // 24-28
+/** BEGIN --- TRANSLATE FROM GLOBAL CARGO TO LOCAL CARGO ID'S **/
+/** Map global cargo ID's to local-cargo ID's */
+const CargoID _local_cargo_id_ctype[NUM_GLOBAL_CID] = {
+	CT_PASSENGERS,CT_COAL,   CT_MAIL,        CT_OIL,      CT_LIVESTOCK,CT_GOODS,  CT_GRAIN,      CT_WOOD,         /*  0- 7 */
+	CT_IRON_ORE,  CT_STEEL,  CT_VALUABLES,   CT_PAPER,    CT_FOOD,     CT_FRUIT,  CT_COPPER_ORE, CT_WATER,        /*  8-15 */
+	CT_RUBBER,    CT_SUGAR,  CT_TOYS,        CT_BATTERIES,CT_CANDY,    CT_TOFFEE, CT_COLA,       CT_COTTON_CANDY, /* 16-23 */
+	CT_BUBBLES,   CT_PLASTIC,CT_FIZZY_DRINKS,CT_PAPER     /* unsup. */,CT_HILLY_UNUSED,                           /* 24-28 */
+	CT_INVALID,   CT_INVALID                                                                                      /* 29-30 */
 };
 
-/* LT'th bit is set of the particular landscape if cargo available there.
- * 1: LT_NORMAL, 2: LT_HILLY, 4: LT_DESERT, 8: LT_CANDY */
-byte _local_cargo_id_landscape[NUM_CID] = {
-	15, 3, 15, 7, 3, 7, 7, 7, 1, 1, 7, 2, 7, // 0-12
-	4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1, 2, // 13-28
+#define MC(cargo) (1 << cargo)
+/** Bitmasked value where the global cargo ID is available in landscape
+ * 0: LT_NORMAL, 1: LT_HILLY, 2: LT_DESERT, 3: LT_CANDY */
+const uint32 _landscape_global_cargo_mask[NUM_LANDSCAPE] =
+{ /* LT_NORMAL: temperate */
+	MC(GC_PASSENGERS)|MC(GC_COAL)|MC(GC_MAIL)|MC(GC_OIL)|MC(GC_LIVESTOCK)|MC(GC_GOODS)|MC(GC_GRAIN)|MC(GC_WOOD)|
+	MC(GC_IRON_ORE)|MC(GC_STEEL)|MC(GC_VALUABLES)|MC(GC_FOOD)|MC(GC_UNDEFINED),
+	/* LT_HILLY: arctic */
+	MC(GC_PASSENGERS)|MC(GC_COAL)|MC(GC_MAIL)|MC(GC_OIL)|MC(GC_LIVESTOCK)|MC(GC_GOODS)|
+	MC(GC_GRAIN)|MC(GC_WOOD)|MC(GC_VALUABLES)|MC(GC_PAPER)|MC(GC_FOOD)|MC(GC_UNDEFINED),
+	/* LT_DESERT: rainforest/desert */
+	MC(GC_PASSENGERS)|MC(GC_MAIL)|MC(GC_OIL)|MC(GC_GOODS)|MC(GC_GRAIN)|MC(GC_WOOD)|
+	MC(GC_VALUABLES)|MC(GC_FOOD)|MC(GC_FRUIT)|MC(GC_COPPER_ORE)|MC(GC_WATER)|MC(GC_RUBBER),
+	/* LT_CANDY: toyland */
+	MC(GC_PASSENGERS)|MC(GC_MAIL)|MC(GC_SUGAR)|MC(GC_TOYS)|MC(GC_BATTERIES)|MC(GC_CANDY)|
+	MC(GC_TOFFEE)|MC(GC_COLA)|MC(GC_COTTON_CANDY)|MC(GC_BUBBLES)|MC(GC_PLASTIC)|MC(GC_FIZZY_DRINKS)
 };
+/** END   --- TRANSLATE FROM GLOBAL CARGO TO LOCAL CARGO ID'S **/
+
+/** Bitmasked values of what type of cargo is refittable for the given vehicle-type.
+ * This coupled with the landscape information (_landscape_global_cargo_mask) gives
+ * us exactly what is refittable and what is not */
+const uint32 _default_refitmasks[NUM_VEHICLE_TYPES] = {
+	/* Trains */
+	MC(GC_PASSENGERS)|MC(GC_COAL)|MC(GC_MAIL)|MC(GC_LIVESTOCK)|MC(GC_GOODS)|MC(GC_GRAIN)|MC(GC_WOOD)|MC(GC_IRON_ORE)|
+	MC(GC_STEEL)|MC(GC_VALUABLES)|MC(GC_PAPER)|MC(GC_FOOD)|MC(GC_FRUIT)|MC(GC_COPPER_ORE)|MC(GC_WATER)|MC(GC_SUGAR)|
+	MC(GC_TOYS)|MC(GC_CANDY)|MC(GC_TOFFEE)|MC(GC_COLA)|MC(GC_COTTON_CANDY)|MC(GC_BUBBLES)|MC(GC_PLASTIC)|MC(GC_FIZZY_DRINKS),
+	/* Road vehicles (not refittable by default) */
+	0,
+	/* Ships */
+	MC(GC_COAL)|MC(GC_MAIL)|MC(GC_LIVESTOCK)|MC(GC_GOODS)|MC(GC_GRAIN)|MC(GC_WOOD)|MC(GC_IRON_ORE)|MC(GC_STEEL)|MC(GC_VALUABLES)|
+	MC(GC_PAPER)|MC(GC_FOOD)|MC(GC_FRUIT)|MC(GC_COPPER_ORE)|MC(GC_WATER)|MC(GC_RUBBER)|MC(GC_SUGAR)|MC(GC_TOYS)|MC(GC_BATTERIES)|
+	MC(GC_CANDY)|MC(GC_TOFFEE)|MC(GC_COLA)|MC(GC_COTTON_CANDY)|MC(GC_BUBBLES)|MC(GC_PLASTIC)|MC(GC_FIZZY_DRINKS),
+	/* Aircraft */
+	MC(GC_PASSENGERS)|MC(GC_MAIL)|MC(GC_GOODS)|MC(GC_VALUABLES)|MC(GC_FOOD)|MC(GC_FRUIT)|MC(GC_SUGAR)|MC(GC_TOYS)|
+	MC(GC_BATTERIES)|MC(GC_CANDY)|MC(GC_TOFFEE)|MC(GC_COLA)|MC(GC_COTTON_CANDY)|MC(GC_BUBBLES)|MC(GC_PLASTIC)|MC(GC_FIZZY_DRINKS),
+	/* Special/Disaster */
+	0,0
+};
+#undef MC
 
 void ShowEnginePreviewWindow(int engine);
 
@@ -267,7 +307,7 @@
 // (It isn't and shouldn't be like this in the GRF files since new cargo types
 // may appear in future - however it's more convenient to store it like this in
 // memory. --pasky)
-static SpriteGroup _engine_custom_sprites[TOTAL_NUM_ENGINES][NUM_CID];
+static SpriteGroup _engine_custom_sprites[TOTAL_NUM_ENGINES][NUM_GLOBAL_CID];
 
 void SetCustomEngineSprites(byte engine, byte cargo, SpriteGroup *group)
 {
@@ -462,10 +502,11 @@
 static SpriteGroup *GetVehicleSpriteGroup(byte engine, const Vehicle *v)
 {
 	SpriteGroup *group;
-	byte cargo = CID_PURCHASE;
+	byte cargo = GC_PURCHASE;
 
 	if (v != NULL) {
 		cargo = _global_cargo_id[_opt.landscape][v->cargo_type];
+		assert(cargo != GC_INVALID);
 	}
 
 	group = &_engine_custom_sprites[engine][cargo];
@@ -483,7 +524,7 @@
 {
 	SpriteGroup *group;
 	RealSpriteGroup *rsg;
-	byte cargo = CID_PURCHASE;
+	byte cargo = GC_PURCHASE;
 	byte loaded = 0;
 	bool in_motion = 0;
 	int totalsets, spriteset;
@@ -493,6 +534,8 @@
 		int capacity = v->cargo_cap;
 
 		cargo = _global_cargo_id[_opt.landscape][v->cargo_type];
+		assert(cargo != GC_INVALID);
+
 		if (capacity == 0) capacity = 1;
 		loaded = (v->cargo_count * 100) / capacity;
 		in_motion = (v->cur_speed != 0);
--- a/engine.h	Sat May 14 06:48:14 2005 +0000
+++ b/engine.h	Sat May 14 12:36:16 2005 +0000
@@ -79,23 +79,56 @@
 	RVI_WAGON = 2,
 };
 
+enum {
+	NUM_VEHICLE_TYPES = 6
+};
 
 void AddTypeToEngines(void);
 void StartupEngines(void);
 
+enum GlobalCargo {
+	GC_PASSENGERS   =   0,
+	GC_COAL         =   1,
+	GC_MAIL         =   2,
+	GC_OIL          =   3,
+	GC_LIVESTOCK    =   4,
+	GC_GOODS        =   5,
+	GC_GRAIN        =   6, // GC_WHEAT / GC_MAIZE
+	GC_WOOD         =   7,
+	GC_IRON_ORE     =   8,
+	GC_STEEL        =   9,
+	GC_VALUABLES    =  10, // GC_GOLD / GC_DIAMONDS
+	GC_PAPER        =  11,
+	GC_FOOD         =  12,
+	GC_FRUIT        =  13,
+	GC_COPPER_ORE   =  14,
+	GC_WATER        =  15,
+	GC_RUBBER       =  16,
+	GC_SUGAR        =  17,
+	GC_TOYS         =  18,
+	GC_BATTERIES    =  19,
+	GC_CANDY        =  20,
+	GC_TOFFEE       =  21,
+	GC_COLA         =  22,
+	GC_COTTON_CANDY =  23,
+	GC_BUBBLES      =  24,
+	GC_PLASTIC      =  25,
+	GC_FIZZY_DRINKS =  26,
+	GC_PAPER_TEMP   =  27,
+	GC_UNDEFINED    =  28, // undefined; unused slot in arctic climate
+	GC_DEFAULT      =  29,
+	GC_PURCHASE     =  30,
+	GC_INVALID      = 255,
+	NUM_GLOBAL_CID  =  31
+};
 
-extern byte _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO];
-enum {
-	CID_DEFAULT = 29,
-	CID_PURCHASE = 30,
-	NUM_CID = 31,
-};
-extern byte _local_cargo_id_ctype[NUM_CID];
-extern byte _local_cargo_id_landscape[NUM_CID];
+VARDEF const uint32 _default_refitmasks[NUM_VEHICLE_TYPES];
+VARDEF const CargoID _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO];
+VARDEF const uint32 _landscape_global_cargo_mask[NUM_LANDSCAPE];
+VARDEF const CargoID _local_cargo_id_ctype[NUM_GLOBAL_CID];
 
-extern uint32 _engine_refit_masks[256];
-
-extern byte _engine_original_sprites[256];
+VARDEF uint32 _engine_refit_masks[256];
+VARDEF byte _engine_original_sprites[256];
 void SetWagonOverrideSprites(byte engine, struct SpriteGroup *group, byte *train_id, int trains);
 void SetCustomEngineSprites(byte engine, byte cargo, struct SpriteGroup *group);
 // loaded is in percents, overriding_engine 0xffff is none
--- a/lang/english.txt	Sat May 14 06:48:14 2005 +0000
+++ b/lang/english.txt	Sat May 14 12:36:16 2005 +0000
@@ -2445,6 +2445,7 @@
 STR_882D_VALUE                                                  :{LTBLUE}{STRING}{BLACK}   Value: {LTBLUE}{CURRENCY}
 STR_882E                                                        :{WHITE}{STRING}
 STR_882F_LOADING_UNLOADING                                      :{LTBLUE}Loading / Unloading
+STR_TRAIN_MUST_BE_STOPPED                                       :{WHITE}Train must be stopped inside depot
 STR_8830_CAN_T_SEND_TRAIN_TO_DEPOT                              :{WHITE}Can't send train to depot...
 STR_8831_NO_MORE_SPACE_FOR_ORDERS                               :{WHITE}No more space for orders
 STR_8832_TOO_MANY_ORDERS                                        :{WHITE}Too many orders
--- a/newgrf.c	Sat May 14 06:48:14 2005 +0000
+++ b/newgrf.c	Sat May 14 12:36:16 2005 +0000
@@ -1450,8 +1450,7 @@
 				return;
 			}
 
-			if (ctype == 0xFF)
-				ctype = CID_PURCHASE;
+			if (ctype == GC_INVALID) ctype = GC_PURCHASE;
 
 			if (wagover) {
 				// TODO: No multiple cargo types per vehicle yet. --pasky
@@ -1482,7 +1481,7 @@
 				// TODO: No multiple cargo types per vehicle yet. --pasky
 				SetWagonOverrideSprites(engine, &_cur_grffile->spritegroups[groupid], last_engines, last_engines_count);
 			} else {
-				SetCustomEngineSprites(engine, CID_DEFAULT, &_cur_grffile->spritegroups[groupid]);
+				SetCustomEngineSprites(engine, GC_DEFAULT, &_cur_grffile->spritegroups[groupid]);
 				last_engines[i] = engine;
 			}
 		}
--- a/ship_cmd.c	Sat May 14 06:48:14 2005 +0000
+++ b/ship_cmd.c	Sat May 14 12:36:16 2005 +0000
@@ -1067,36 +1067,39 @@
 	return 0;
 }
 
-
-// p1 = vehicle
-// p2 = new cargo (0xFF)
-// p2 = skip check for stopped in hanger (0x0100)
+/** Refits a ship to the specified cargo type.
+ * @param x,y unused
+ * @param p1 vehicle ID of the ship to refit
+ * @param p2 various bitstuffed elements
+ * - p2 = (bit 0-7) - the new cargo type to refit to (p2 & 0xFF)
+ * - p2 = (bit 8)   - skip check for stopped in depot, used by autoreplace (p2 & 0x100)
+ * @todo p2 bit8 check <b>NEEDS TO GO</b>
+ */
 int32 CmdRefitShip(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 {
 	Vehicle *v;
 	int32 cost;
-	byte SkipStoppedInDepotCheck = (p2 & 0x100) >> 8; //excludes the cargo value
-
-	p2 = p2 & 0xFF;
+	CargoID new_cid = p2 & 0xFF; //gets the cargo number
+	bool SkipStoppedInDepotCheck = !!HASBIT(p2, 8); // XXX - needs to go, yes?
 
 	if (!IsVehicleIndex(p1)) return CMD_ERROR;
 
 	v = GetVehicle(p1);
 
-	if (v->type != VEH_Ship || !CheckOwnership(v->owner))
-		return CMD_ERROR;
+	if (v->type != VEH_Ship || !CheckOwnership(v->owner)) return CMD_ERROR;
+	if (!SkipStoppedInDepotCheck) {
+		if (!IsTileDepotType(v->tile, TRANSPORT_WATER) || !(v->vehstatus&VS_STOPPED) || v->u.ship.state != 0x80)
+			return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN);
+	}
 
-	if (!( SkipStoppedInDepotCheck )) {
-		if (!IsTileDepotType(v->tile, TRANSPORT_WATER) ||
-				!(v->vehstatus&VS_STOPPED) ||
-				v->u.ship.state != 0x80)
-			return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN);
-		}
+	/* Check cargo */
+	if (!ShipVehInfo(v->engine_type)->refittable) return CMD_ERROR;
+	if (new_cid > NUM_CARGO || !CanRefitTo(v, new_cid)) return CMD_ERROR;
 
 	SET_EXPENSES_TYPE(EXPENSES_SHIP_RUN);
 
 	cost = 0;
-	if (IS_HUMAN_PLAYER(v->owner) && (byte)p2 != v->cargo_type) {
+	if (IS_HUMAN_PLAYER(v->owner) && new_cid != v->cargo_type) {
 		cost = _price.ship_base >> 7;
 	}
 
@@ -1105,12 +1108,10 @@
 		//it will be checked if the cargo is valid in CmdRenewVehicle
 		if (!(SkipStoppedInDepotCheck))
 			v->cargo_count = 0;
-		v->cargo_type = (byte)p2;
+		v->cargo_type = new_cid;
 		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 	}
 
 	return cost;
 
 }
-
-
--- a/ship_gui.c	Sat May 14 06:48:14 2005 +0000
+++ b/ship_gui.c	Sat May 14 12:36:16 2005 +0000
@@ -45,23 +45,11 @@
 	}
 }
 
-const byte _ship_refit_types[4][16] = {
-	{CT_MAIL, CT_COAL, CT_LIVESTOCK, CT_GOODS, CT_GRAIN, CT_WOOD, CT_IRON_ORE, CT_STEEL, CT_VALUABLES, 255},
-	{CT_MAIL, CT_COAL, CT_LIVESTOCK, CT_GOODS, CT_GRAIN, CT_WOOD, CT_PAPER, CT_FOOD, CT_VALUABLES, 255},
-	{CT_MAIL, CT_FRUIT, CT_GOODS, CT_COPPER_ORE, CT_GRAIN, CT_WOOD, CT_WATER, CT_VALUABLES, 255},
-	{CT_MAIL, CT_SUGAR, CT_TOYS, CT_CANDY, CT_COLA, CT_COTTON_CANDY, CT_BUBBLES, CT_TOFFEE, CT_BATTERIES, CT_PLASTIC, CT_FIZZY_DRINKS, 255},
-};
-
 static void ShipRefitWndProc(Window *w, WindowEvent *e)
 {
-	switch(e->event) {
+	switch (e->event) {
 	case WE_PAINT: {
-		Vehicle *v = GetVehicle(w->window_number);
-		const byte *b;
-		int sel;
-		int x,y;
-		byte color;
-		int cargo;
+		const Vehicle *v = GetVehicle(w->window_number);
 
 		SetDParam(0, v->string_id);
 		SetDParam(1, v->unitnumber);
@@ -69,71 +57,32 @@
 
 		DrawString(1, 15, STR_983F_SELECT_CARGO_TYPE_TO_CARRY, 0);
 
-		cargo = -1;
-		x = 6;
-		y = 25;
-		sel = WP(w,refit_d).sel;
-
-#define show_cargo(ctype) { \
-		color = 16; \
-		if (sel == 0) { \
-			cargo = ctype; \
-			color = 12; \
-		} \
-		sel--; \
-		DrawString(x, y, _cargoc.names_s[ctype], color); \
-		y += 10; \
-		}
-
-		if (_engine_refit_masks[v->engine_type]) {
-			uint32 mask = _engine_refit_masks[v->engine_type];
-			int cid = 0;
+		/* TODO: Support for custom GRFSpecial-specified refitting! --pasky */
+		WP(w,refit_d).cargo = DrawVehicleRefitWindow(v, WP(w, refit_d).sel);;
 
-			for (; mask; mask >>= 1, cid++) {
-				if (!(mask & 1)) // not this cid
-					continue;
-				if (!(_local_cargo_id_landscape[cid] & (1 << _opt.landscape))) // not in this landscape
-					continue;
-
-				show_cargo(_local_cargo_id_ctype[cid]);
-			}
-
-		} else { // generic refit list
-			b = _ship_refit_types[_opt.landscape];
-			do {
-				show_cargo(*b);
-			} while (*++b != 255);
-		}
-
-#undef show_cargo
-
-		WP(w,refit_d).cargo = cargo;
-
-		if (cargo != -1) {
-			int32 cost = DoCommandByTile(v->tile, v->index, cargo, 0, CMD_REFIT_SHIP);
-			if (cost != CMD_ERROR) {
+		if (WP(w,refit_d).cargo != CT_INVALID) {
+			int32 cost = DoCommandByTile(v->tile, v->index, WP(w,refit_d).cargo, DC_QUERY_COST, CMD_REFIT_SHIP);
+			if (!CmdFailed(cost)) {
 				SetDParam(2, cost);
-				SetDParam(0, _cargoc.names_long_p[cargo]);
+				SetDParam(0, _cargoc.names_long_p[WP(w,refit_d).cargo]);
 				SetDParam(1, v->cargo_cap);
 				DrawString(1, 137, STR_9840_NEW_CAPACITY_COST_OF_REFIT, 0);
 			}
 		}
-
-		break;
-	}
+	}	break;
 
 	case WE_CLICK:
 		switch(e->click.widget) {
 		case 2: { /* listbox */
-				int y = e->click.pt.y - 25;
-				if (y >= 0) {
-					WP(w,refit_d).sel = y / 10;
-					SetWindowDirty(w);
-				}
-			} break;
+			int y = e->click.pt.y - 25;
+			if (y >= 0) {
+				WP(w,refit_d).sel = y / 10;
+				SetWindowDirty(w);
+			}
+		} break;
 		case 4: /* refit button */
-			if (WP(w,refit_d).cargo != 0xFF) {
-				Vehicle *v = GetVehicle(w->window_number);
+			if (WP(w,refit_d).cargo != CT_INVALID) {
+				const Vehicle *v = GetVehicle(w->window_number);
 				if (DoCommandP(v->tile, v->index, WP(w,refit_d).cargo, NULL, CMD_REFIT_SHIP | CMD_MSG(STR_9841_CAN_T_REFIT_SHIP)))
 					DeleteWindow(w);
 			}
--- a/station.h	Sat May 14 06:48:14 2005 +0000
+++ b/station.h	Sat May 14 12:36:16 2005 +0000
@@ -248,7 +248,7 @@
 	StationLayout **layouts;
 
 	/* Sprite offsets for renderdata->seq->image. spritegroup[0] is default
-	 * whilst spritegroup[1] is "CID_PURCHASE". */
+	 * whilst spritegroup[1] is "GC_PURCHASE". */
 	SpriteGroup spritegroup[2];
 } StationSpec;
 
--- a/train_cmd.c	Sat May 14 06:48:14 2005 +0000
+++ b/train_cmd.c	Sat May 14 12:36:16 2005 +0000
@@ -1282,25 +1282,31 @@
 	return 0;
 }
 
-// p1 = vehicle to refit
-// p2 = new cargo (0xFF)
-// p2 = skip check for stopped in hanger (0x0100)
+/** Refits a train to the specified cargo type.
+ * @param x,y unused
+ * @param p1 vehicle ID of the train to refit
+ * @param p2 various bitstuffed elements
+ * - p2 = (bit 0-7) - the new cargo type to refit to (p2 & 0xFF)
+ * - p2 = (bit 8)   - skip check for stopped in depot, used by autoreplace (p2 & 0x100)
+ * @todo p2 bit8 check <b>NEEDS TO GO</b>
+ */
 int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 {
 	Vehicle *v;
 	int32 cost;
 	uint num;
-
-	byte SkipStoppedInDepotCheck = (p2 & 0x100) >> 8;
-
-	p2 = p2 & 0xFF;
+	CargoID new_cid = p2 & 0xFF; //gets the cargo number
+	bool SkipStoppedInDepotCheck = !!HASBIT(p2, 8); // XXX - needs to go, yes?
 
 	if (!IsVehicleIndex(p1)) return CMD_ERROR;
 
 	v = GetVehicle(p1);
 
-	if (v->type != VEH_Train || !CheckOwnership(v->owner) || ((CheckTrainStoppedInDepot(v) < 0) && !(SkipStoppedInDepotCheck)))
-		return CMD_ERROR;
+	if (v->type != VEH_Train || !CheckOwnership(v->owner)) return CMD_ERROR;
+	if (!SkipStoppedInDepotCheck && CheckTrainStoppedInDepot(v) < 0) return_cmd_error(STR_TRAIN_MUST_BE_STOPPED);
+
+	/* Check cargo */
+	if (new_cid > NUM_CARGO) return CMD_ERROR;
 
 	SET_EXPENSES_TYPE(EXPENSES_TRAIN_RUN);
 
@@ -1311,17 +1317,17 @@
 		/* XXX: We also refit all the attached wagons en-masse if they
 		 * can be refitted. This is how TTDPatch does it.  TODO: Have
 		 * some nice [Refit] button near each wagon. --pasky */
-		if ((!(RailVehInfo(v->engine_type)->flags & RVI_WAGON)
-		     || (_engine_refit_masks[v->engine_type] & (1 << p2)))
-		    && (byte) p2 != v->cargo_type && v->cargo_cap != 0) {
+		if (!CanRefitTo(v, new_cid)) continue;
+
+		if (new_cid != v->cargo_type && v->cargo_cap != 0) {
 			cost += (_price.build_railvehicle >> 8);
 			num += v->cargo_cap;
 			if (flags & DC_EXEC) {
-		//autorefitted train cars wants to keep the cargo
-		//it will be checked if the cargo is valid in CmdReplaceVehicle
+				//autorefitted train cars wants to keep the cargo
+				//it will be checked if the cargo is valid in CmdReplaceVehicle
 				if (!(SkipStoppedInDepotCheck))
 					v->cargo_count = 0;
-				v->cargo_type = (byte)p2;
+				v->cargo_type = new_cid;
 				InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 			}
 		}
--- a/train_gui.c	Sat May 14 06:48:14 2005 +0000
+++ b/train_gui.c	Sat May 14 12:36:16 2005 +0000
@@ -662,23 +662,11 @@
 	}
 }
 
-const byte _rail_vehicle_refit_types[4][16] = {
-	{ 0,1,2,4,5,6,7,8,9,10,0xFF },	// normal
-	{ 0,1,4,5,6,7,9,11,10,0xFF },		// arctic
-	{ 0,4,5,8,6,7,9,10,0xFF },			// desert
-	{ 0,1,3,5,7,8,9,6,4,10,11,0xFF }// candy
-};
-
 static void RailVehicleRefitWndProc(Window *w, WindowEvent *e)
 {
-	switch(e->event) {
+	switch (e->event) {
 	case WE_PAINT: {
-		Vehicle *v = GetVehicle(w->window_number);
-		const byte *b;
-		int sel;
-		int x,y;
-		byte color;
-		int cargo;
+		const Vehicle *v = GetVehicle(w->window_number);
 
 		SetDParam(0, v->string_id);
 		SetDParam(1, v->unitnumber);
@@ -686,57 +674,19 @@
 
 		DrawString(1, 15, STR_983F_SELECT_CARGO_TYPE_TO_CARRY, 0);
 
-		cargo = -1;
-		x = 6;
-		y = 25;
-		sel = WP(w,refit_d).sel;
-
-#define show_cargo(ctype) { \
-		color = 16; \
-		if (sel == 0) { \
-			cargo = ctype; \
-			color = 12; \
-		} \
-		sel--; \
-		DrawString(x, y, _cargoc.names_s[ctype], color); \
-		y += 10; \
-		}
-
-		if (_engine_refit_masks[v->engine_type]) {
-			uint32 mask = _engine_refit_masks[v->engine_type];
-			int cid = 0;
+		/* TODO: Support for custom GRFSpecial-specified refitting! --pasky */
+		WP(w,refit_d).cargo = DrawVehicleRefitWindow(v, WP(w, refit_d).sel);
 
-			for (; mask; mask >>= 1, cid++) {
-				if (!(mask & 1)) // not this cid
-					continue;
-				if (!(_local_cargo_id_landscape[cid] & (1 << _opt.landscape))) // not in this landscape
-					continue;
-
-				show_cargo(_local_cargo_id_ctype[cid]);
-			}
-
-		} else { // generic refit list
-			b = _rail_vehicle_refit_types[_opt.landscape];
-			do {
-				show_cargo(*b);
-			} while (*++b != 255);
-		}
-
-#undef show_cargo
-
-		WP(w,refit_d).cargo = cargo;
-
-		if (cargo != -1) {
-			int32 cost = DoCommandByTile(v->tile, v->index, cargo, 0, CMD_REFIT_RAIL_VEHICLE);
-			if (cost != CMD_ERROR) {
+		if (WP(w,refit_d).cargo != CT_INVALID) {
+			int32 cost = DoCommandByTile(v->tile, v->index, WP(w,refit_d).cargo, DC_QUERY_COST, CMD_REFIT_RAIL_VEHICLE);
+			if (!CmdFailed(cost)) {
 				SetDParam(2, cost);
-				SetDParam(0, _cargoc.names_long_p[cargo]);
+				SetDParam(0, _cargoc.names_long_p[WP(w,refit_d).cargo]);
 				SetDParam(1, _returned_refit_amount);
 				DrawString(1, 137, STR_9840_NEW_CAPACITY_COST_OF_REFIT, 0);
 			}
 		}
-		break;
-	}
+	}	break;
 
 	case WE_CLICK:
 		switch(e->click.widget) {
@@ -748,8 +698,8 @@
 			}
 		} break;
 		case 4: /* refit button */
-			if (WP(w,refit_d).cargo != 0xFF) {
-				Vehicle *v = GetVehicle(w->window_number);
+			if (WP(w,refit_d).cargo != CT_INVALID) {
+				const Vehicle *v = GetVehicle(w->window_number);
 				if (DoCommandP(v->tile, v->index, WP(w,refit_d).cargo, NULL, CMD_REFIT_RAIL_VEHICLE | CMD_MSG(STR_RAIL_CAN_T_REFIT_VEHICLE)))
 					DeleteWindow(w);
 			}
@@ -809,9 +759,9 @@
 
 static void TrainViewWndProc(Window *w, WindowEvent *e)
 {
-	switch(e->event) {
+	switch (e->event) {
 	case WE_PAINT: {
-		Vehicle *v, *u;
+		const Vehicle *v, *u;
 		StringID str;
 
 		v = GetVehicle(w->window_number);
@@ -820,22 +770,16 @@
 
 		SETBIT(w->disabled_state, 12);
 
-		/* See if any carriage can be refitted */
+		/* See if any vehicle can be refitted */
 		for ( u = v; u != NULL; u = u->next) {
-			if (_engine_refit_masks[u->engine_type] != 0) {
+			if (_engine_refit_masks[u->engine_type] != 0 ||
+						 (!(RailVehInfo(v->engine_type)->flags & RVI_WAGON) && v->cargo_cap != 0)) {
 				CLRBIT(w->disabled_state, 12);
 				/* We have a refittable carriage, bail out */
 				break;
 			}
 		}
 
-		/* Above code doesn't seem to handle non-newgrf engines, do it separately
-		TODO: handle engines which are NOT the head of the train, but don't break wagons */
-		if (v->cargo_cap != 0) {
-			/* we can refit this engine */
-			CLRBIT(w->disabled_state, 12);
-		}
-
 		/* draw widgets & caption */
 		SetDParam(0, v->string_id);
 		SetDParam(1, v->unitnumber);
--- a/ttd.h	Sat May 14 06:48:14 2005 +0000
+++ b/ttd.h	Sat May 14 12:36:16 2005 +0000
@@ -67,6 +67,7 @@
 typedef uint16 VehicleID;
 typedef byte PlayerID;
 typedef byte OrderID;
+typedef byte CargoID;
 typedef uint16 StringID;
 typedef uint16 SpriteID;
 typedef uint32 PalSpriteID;
--- a/vehicle.c	Sat May 14 06:48:14 2005 +0000
+++ b/vehicle.c	Sat May 14 12:36:16 2005 +0000
@@ -501,6 +501,28 @@
 	return false;
 }
 
+/** Check if a given vehicle (type) can be refitted to a given cargo
+ * @param *v vehicle to check
+ * @param cid_to check refit to this cargo-type
+ * @return true if it is possible, false otherwise
+ */
+bool CanRefitTo(const Vehicle *v, CargoID cid_to)
+{
+	CargoID cid = _global_cargo_id[_opt_ptr->landscape][cid_to];
+
+	if (cid == GC_INVALID) return false;
+
+	if (_engine_refit_masks[v->engine_type]) {
+		if (!HASBIT(_engine_refit_masks[v->engine_type], cid)) return false;
+	} else {
+		/* If we are talking about normal vehicles (no newgrf), you can only refit engines */
+		if (v->type == VEH_Train && (RailVehInfo(v->engine_type)->flags & RVI_WAGON)) return false;
+		if (!HASBIT(_default_refitmasks[v->type - VEH_Train], cid)) return false;
+	}
+
+	return true;
+}
+
 static void DoDrawVehicle(Vehicle *v)
 {
 	uint32 image = v->cur_image;
--- a/vehicle.h	Sat May 14 06:48:14 2005 +0000
+++ b/vehicle.h	Sat May 14 12:36:16 2005 +0000
@@ -262,6 +262,7 @@
 void InitializeTrains(void);
 
 bool CanFillVehicle(Vehicle *v);
+bool CanRefitTo(const Vehicle *v, CargoID cid_to);
 
 void ViewportAddVehicles(DrawPixelInfo *dpi);
 
--- a/vehicle_gui.c	Sat May 14 06:48:14 2005 +0000
+++ b/vehicle_gui.c	Sat May 14 12:36:16 2005 +0000
@@ -165,6 +165,42 @@
 	DrawSprite(SPR_BLOT | ormod, x, y);
 }
 
+/** Draw the list of available refit options.
+ * Draw the list and highlight the selected refit option (if any)
+ * @param *v vehicle(type) to get the refit-options of
+ * @param sel selected refit cargo-type in the window
+ * @return the cargo type that is hightlighted, CT_INVALID if none
+ */
+CargoID DrawVehicleRefitWindow(const Vehicle *v, int sel)
+{
+	uint32 cmask;
+	CargoID cid, cargo = CT_INVALID;
+	int y = 25;
+#define show_cargo(ctype) { \
+		byte colour = 16; \
+		if (sel == 0) { \
+			cargo = ctype; \
+			colour = 12; \
+} \
+		sel--; \
+		DrawString(6, y, _cargoc.names_s[ctype], colour); \
+		y += 10; \
+}
+
+		/* Check if engine has custom refit or normal ones, and get its bitmasked value.
+		 * Now just and it with the bitmasked available cargo on the current landscape, and
+		* where the bits are set: those are available */
+		cmask = (_engine_refit_masks[v->engine_type] != 0) ? _engine_refit_masks[v->engine_type] : _default_refitmasks[v->type - VEH_Train];
+		cmask &= _landscape_global_cargo_mask[_opt_ptr->landscape];
+
+		/* Check which cargo has been selected from the refit window and draw list */
+		for (cid = 0; cmask != 0; cmask >>= 1, cid++) {
+			if (HASBIT(cmask, 0)) // vehicle is refittable to this cargo
+				show_cargo(_local_cargo_id_ctype[cid]);
+		}
+		return cargo;
+}
+
 /************ Sorter functions *****************/
 int CDECL GeneralOwnerSorter(const void *a, const void *b)
 {
--- a/vehicle_gui.h	Sat May 14 06:48:14 2005 +0000
+++ b/vehicle_gui.h	Sat May 14 12:36:16 2005 +0000
@@ -6,6 +6,7 @@
 struct vehiclelist_d;
 
 void DrawVehicleProfitButton(Vehicle *v, int x, int y);
+CargoID DrawVehicleRefitWindow(const Vehicle *v, int sel);
 void InitializeVehiclesGuiList(void);
 
 /* sorter stuff */