summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarkvater <darkvater@openttd.org>2005-05-14 12:36:16 +0000
committerDarkvater <darkvater@openttd.org>2005-05-14 12:36:16 +0000
commit5174d3adfe9e3b120fd2c50847c7f9cf772a702b (patch)
tree1e61fee7bb3cc51b1847fb0b48b1f3cec7699f5a
parent3a4bedaad61c990c511cd1c23380546a9eebd358 (diff)
downloadopenttd-5174d3adfe9e3b120fd2c50847c7f9cf772a702b.tar.xz
(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"
-rw-r--r--aircraft_cmd.c38
-rw-r--r--aircraft_gui.c126
-rw-r--r--command.c6
-rw-r--r--engine.c95
-rw-r--r--engine.h53
-rw-r--r--lang/english.txt1
-rw-r--r--newgrf.c5
-rw-r--r--ship_cmd.c39
-rw-r--r--ship_gui.c85
-rw-r--r--station.h2
-rw-r--r--train_cmd.c36
-rw-r--r--train_gui.c88
-rw-r--r--ttd.h1
-rw-r--r--vehicle.c22
-rw-r--r--vehicle.h1
-rw-r--r--vehicle_gui.c36
-rw-r--r--vehicle_gui.h1
17 files changed, 291 insertions, 344 deletions
diff --git a/aircraft_cmd.c b/aircraft_cmd.c
index b351fca6f..691005349 100644
--- a/aircraft_cmd.c
+++ b/aircraft_cmd.c
@@ -504,32 +504,38 @@ int32 CmdChangeAircraftServiceInt(int x, int y, uint32 flags, uint32 p1, uint32
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 @@ int32 CmdRefitAircraft(int x, int y, uint32 flags, uint32 p1, uint32 p2)
_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);
}
diff --git a/aircraft_gui.c b/aircraft_gui.c
index 60502ad33..a263813be 100644
--- a/aircraft_gui.c
+++ b/aircraft_gui.c
@@ -205,64 +205,11 @@ static void ShowBuildAircraftWindow(uint tile)
}
}
-#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 @@ static void AircraftRefitWndProc(Window *w, WindowEvent *e)
DrawString(1, 15, STR_A040_SELECT_CARGO_TYPE_TO_CARRY, 0);
/* TODO: Support for custom GRFSpecial-specified refitting! --pasky */
+ WP(w,refit_d).cargo = DrawVehicleRefitWindow(v, WP(w, refit_d).sel);
- 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;
-
- 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);
}
diff --git a/command.c b/command.c
index 67fbb05f0..7eae3c4fd 100644
--- a/command.c
+++ b/command.c
@@ -229,7 +229,7 @@ static CommandProc * const _command_proc_table[] = {
CmdBuildAircraft, /* 61 */
CmdSendAircraftToHangar, /* 62 */
CmdChangeAircraftServiceInt, /* 63 */
- CmdRefitAircraft, /* 64 <-- REFIT: Hackykid */
+ CmdRefitAircraft, /* 64 */
CmdPlaceSign, /* 65 */
CmdRenameSign, /* 66 */
@@ -263,7 +263,7 @@ static CommandProc * const _command_proc_table[] = {
CmdBuildShip, /* 88 */
CmdSendShipToDepot, /* 89 */
CmdChangeShipServiceInt, /* 90 */
- CmdRefitShip, /* 91 <-- REFIT: Hackykid */
+ CmdRefitShip, /* 91 */
NULL, /* 92 */
NULL, /* 93 */
@@ -284,7 +284,7 @@ static CommandProc * const _command_proc_table[] = {
CmdLevelLand, /* 105 */
- CmdRefitRailVehicle, /* 106 <-- REFIT: Hackykid */
+ CmdRefitRailVehicle, /* 106 */
CmdRestoreOrderIndex, /* 107 */
CmdBuildLock, /* 108 */
NULL, /* 109 */
diff --git a/engine.c b/engine.c
index 64d2c826a..bcbb87438 100644
--- a/engine.c
+++ b/engine.c
@@ -20,34 +20,74 @@ enum {
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 @@ byte _engine_original_sprites[TOTAL_NUM_ENGINES];
// (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 RealSpriteGroup* ResolveVehicleSpriteGroup(SpriteGroup *spritegroup,
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 @@ int GetCustomEngineSprite(byte engine, const Vehicle *v, byte direction)
{
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 GetCustomEngineSprite(byte engine, const Vehicle *v, byte direction)
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);
diff --git a/engine.h b/engine.h
index cbb860dc9..b588478fe 100644
--- a/engine.h
+++ b/engine.h
@@ -79,23 +79,56 @@ enum {
RVI_WAGON = 2,
};
+enum {
+ NUM_VEHICLE_TYPES = 6
+};
void AddTypeToEngines(void);
void StartupEngines(void);
-
-extern byte _global_cargo_id[NUM_LANDSCAPE][NUM_CARGO];
-enum {
- CID_DEFAULT = 29,
- CID_PURCHASE = 30,
- NUM_CID = 31,
+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 _local_cargo_id_ctype[NUM_CID];
-extern byte _local_cargo_id_landscape[NUM_CID];
-extern uint32 _engine_refit_masks[256];
+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 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
diff --git a/lang/english.txt b/lang/english.txt
index c15eb9b78..892c6fae1 100644
--- a/lang/english.txt
+++ b/lang/english.txt
@@ -2445,6 +2445,7 @@ STR_882C_BUILT_VALUE :{LTBLUE}{STRING
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
diff --git a/newgrf.c b/newgrf.c
index 30c5a8f06..3607326aa 100644
--- a/newgrf.c
+++ b/newgrf.c
@@ -1450,8 +1450,7 @@ static void NewVehicle_SpriteGroupMapping(byte *buf, int len)
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 @@ static void NewVehicle_SpriteGroupMapping(byte *buf, int len)
// 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;
}
}
diff --git a/ship_cmd.c b/ship_cmd.c
index 24d21fc47..b8190d6b7 100644
--- a/ship_cmd.c
+++ b/ship_cmd.c
@@ -1067,36 +1067,39 @@ int32 CmdChangeShipServiceInt(int x, int y, uint32 flags, uint32 p1, uint32 p2)
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 (!( SkipStoppedInDepotCheck )) {
- if (!IsTileDepotType(v->tile, TRANSPORT_WATER) ||
- !(v->vehstatus&VS_STOPPED) ||
- v->u.ship.state != 0x80)
+ 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);
- }
+ }
+
+ /* 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 @@ int32 CmdRefitShip(int x, int y, uint32 flags, uint32 p1, uint32 p2)
//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;
}
-
-
diff --git a/ship_gui.c b/ship_gui.c
index c0cf59e10..1e1428de2 100644
--- a/ship_gui.c
+++ b/ship_gui.c
@@ -45,23 +45,11 @@ static void DrawShipImage(const Vehicle *v, int x, int y, VehicleID selection)
}
}
-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 @@ static void ShipRefitWndProc(Window *w, WindowEvent *e)
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; \
- }
+ /* TODO: Support for custom GRFSpecial-specified refitting! --pasky */
+ WP(w,refit_d).cargo = DrawVehicleRefitWindow(v, WP(w, refit_d).sel);;
- if (_engine_refit_masks[v->engine_type]) {
- uint32 mask = _engine_refit_masks[v->engine_type];
- int cid = 0;
-
- 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);
}
diff --git a/station.h b/station.h
index 08c3e01c0..608688fc7 100644
--- a/station.h
+++ b/station.h
@@ -248,7 +248,7 @@ typedef struct StationSpec {
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;
diff --git a/train_cmd.c b/train_cmd.c
index 255ede174..95770e442 100644
--- a/train_cmd.c
+++ b/train_cmd.c
@@ -1282,25 +1282,31 @@ int32 CmdForceTrainProceed(int x, int y, uint32 flags, uint32 p1, uint32 p2)
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 @@ int32 CmdRefitRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
/* 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);
}
}
diff --git a/train_gui.c b/train_gui.c
index c6bcf66cd..3cc68811f 100644
--- a/train_gui.c
+++ b/train_gui.c
@@ -662,23 +662,11 @@ void ShowTrainDepotWindow(uint tile)
}
}
-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 @@ static void RailVehicleRefitWndProc(Window *w, WindowEvent *e)
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;
-
- 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]);
- }
+ /* TODO: Support for custom GRFSpecial-specified refitting! --pasky */
+ WP(w,refit_d).cargo = DrawVehicleRefitWindow(v, WP(w, refit_d).sel);
- } 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 @@ static void RailVehicleRefitWndProc(Window *w, WindowEvent *e)
}
} 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 Widget _train_view_widgets[] = {
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 @@ static void TrainViewWndProc(Window *w, WindowEvent *e)
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);
diff --git a/ttd.h b/ttd.h
index 3c9e4ae2b..018198779 100644
--- a/ttd.h
+++ b/ttd.h
@@ -67,6 +67,7 @@ typedef struct DrawPixelInfo DrawPixelInfo;
typedef uint16 VehicleID;
typedef byte PlayerID;
typedef byte OrderID;
+typedef byte CargoID;
typedef uint16 StringID;
typedef uint16 SpriteID;
typedef uint32 PalSpriteID;
diff --git a/vehicle.c b/vehicle.c
index 025bb0679..a705ed93b 100644
--- a/vehicle.c
+++ b/vehicle.c
@@ -501,6 +501,28 @@ bool CanFillVehicle(Vehicle *v)
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;
diff --git a/vehicle.h b/vehicle.h
index a86a1ce37..f0699b5a6 100644
--- a/vehicle.h
+++ b/vehicle.h
@@ -262,6 +262,7 @@ Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z);
void InitializeTrains(void);
bool CanFillVehicle(Vehicle *v);
+bool CanRefitTo(const Vehicle *v, CargoID cid_to);
void ViewportAddVehicles(DrawPixelInfo *dpi);
diff --git a/vehicle_gui.c b/vehicle_gui.c
index 5832498e8..c83f287ec 100644
--- a/vehicle_gui.c
+++ b/vehicle_gui.c
@@ -165,6 +165,42 @@ void DrawVehicleProfitButton(Vehicle *v, int x, int y)
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)
{
diff --git a/vehicle_gui.h b/vehicle_gui.h
index 1af4e0aba..a4e010c69 100644
--- a/vehicle_gui.h
+++ b/vehicle_gui.h
@@ -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 */