diff --git a/lang/english.txt b/lang/english.txt index 0c2cc29a18..82ae2330ce 100644 --- a/lang/english.txt +++ b/lang/english.txt @@ -2166,6 +2166,24 @@ STR_707E_OWNED_BY_OWNED_BY :{WHITE}({COMMA} STR_707F_HAS_BEEN_TAKEN_OVER_BY :{BLACK}{BIGFONT}{COMPANY} has been taken over by {COMPANY}! STR_7080_PROTECTED :{WHITE}This company is not old enough to trade shares yet... +STR_LIVERY_DEFAULT :Standard Livery +STR_LIVERY_STEAM :Steam Engine +STR_LIVERY_DIESEL :Diesel Engine +STR_LIVERY_ELECTRIC :Electric Engine +STR_LIVERY_MONORAIL :Monorail Engine +STR_LIVERY_MAGLEV :Maglev Engine +STR_LIVERY_DMU :DMU +STR_LIVERY_EMU :EMU +STR_LIVERY_PASSENGER_WAGON :Passenger Coach +STR_LIVERY_FREIGHT_WAGON :Freight Wagon +STR_LIVERY_BUS :Bus +STR_LIVERY_TRUCK :Lorry +STR_LIVERY_PASSENGER_SHIP :Passenger Ferry +STR_LIVERY_FREIGHT_SHIP :Freight Ship +STR_LIVERY_HELICOPTER :Helicopter +STR_LIVERY_SMALL_PLANE :Small Aeroplane +STR_LIVERY_LARGE_PLANE :Large Aeroplane + ##id 0x8000 STR_8000_KIRBY_PAUL_TANK_STEAM :Kirby Paul Tank (Steam) STR_8001_MJS_250_DIESEL :MJS 250 (Diesel) diff --git a/livery.h b/livery.h new file mode 100644 index 0000000000..1834f9c758 --- /dev/null +++ b/livery.h @@ -0,0 +1,57 @@ +/* $Id$ */ + +#ifndef LIVERY_H +#define LIVERY_H + + +/* List of different livery schemes. */ +typedef enum LiverySchemes { + LS_DEFAULT, + + /* Rail vehicles */ + LS_STEAM, + LS_DIESEL, + LS_ELECTRIC, + LS_MONORAIL, + LS_MAGLEV, + LS_DMU, + LS_EMU, + LS_PASSENGER_WAGON, + LS_FREIGHT_WAGON, + + /* Road vehicles */ + LS_BUS, + LS_TRUCK, + + /* Ships */ + LS_PASSENGER_SHIP, + LS_FREIGHT_SHIP, + + /* Aircraft */ + LS_HELICOPTER, + LS_SMALL_PLANE, + LS_LARGE_PLANE, + + LS_END +} LiveryScheme; + + +/* List of different livery classes, used only by the livery GUI. */ +typedef enum LiveryClasses { + LC_OTHER, + LC_RAIL, + LC_ROAD, + LC_SHIP, + LC_AIRCRAFT, + LC_END +} LiveryClass; + + +typedef struct Livery { + bool in_use; ///< Set if this livery should be used instead of the default livery. + byte colour1; ///< First colour, for all vehicles. + byte colour2; ///< Second colour, for vehicles with 2CC support. +} Livery; + +#endif /* LIVERY_H */ + diff --git a/misc_cmd.c b/misc_cmd.c index 38e8801b82..d96572bb6e 100644 --- a/misc_cmd.c +++ b/misc_cmd.c @@ -13,6 +13,7 @@ #include "economy.h" #include "network.h" #include "variables.h" +#include "livery.h" /** Change the player's face. * @param tile unused @@ -30,28 +31,78 @@ int32 CmdSetPlayerFace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) /** Change the player's company-colour * @param tile unused - * @param p1 unused + * @param p1 bitstuffed: + * p1 bits 0-7 scheme to set + * p1 bits 8-9 set in use state or first/second colour * @param p2 new colour for vehicles, property, etc. */ int32 CmdSetPlayerColor(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) { Player *p, *pp; byte colour; + LiveryScheme scheme = GB(p1, 0, 8); + byte state = GB(p1, 8, 2); if (p2 >= 16) return CMD_ERROR; // max 16 colours colour = p2; + if (scheme >= LS_END || state >= 3) return CMD_ERROR; + p = GetPlayer(_current_player); - /* Ensure no two companies have the same colour */ - FOR_ALL_PLAYERS(pp) { - if (pp->is_active && pp != p && pp->player_color == colour) - return CMD_ERROR; + /* Ensure no two companies have the same primary colour */ + if (scheme == LS_DEFAULT && state == 0) { + FOR_ALL_PLAYERS(pp) { + if (pp->is_active && pp != p && pp->player_color == colour) return CMD_ERROR; + } } if (flags & DC_EXEC) { - _player_colors[_current_player] = colour; - p->player_color = colour; + switch (state) { + case 0: + p->livery[scheme].colour1 = colour; + + /* If setting the first colour of the default scheme, adjust the + * original and cached player colours too. */ + if (scheme == LS_DEFAULT) { + _player_colors[_current_player] = colour; + p->player_color = colour; + } + break; + + case 1: + p->livery[scheme].colour2 = colour; + break; + + case 2: + p->livery[scheme].in_use = colour != 0; + + /* Now handle setting the default scheme's in_use flag. + * This is different to the other schemes, as it signifies if any + * scheme is active at all. If this flag is not set, then no + * processing of vehicle types occurs at all, and only the default + * colours will be used. */ + + /* If enabling a scheme, set the default scheme to be in use too */ + if (colour != 0) { + p->livery[LS_DEFAULT].in_use = true; + break; + } + + /* Else loop through all schemes to see if any are left enabled. + * If not, disable the default scheme too. */ + p->livery[LS_DEFAULT].in_use = false; + for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) { + if (p->livery[scheme].in_use) { + p->livery[LS_DEFAULT].in_use = true; + break; + } + } + break; + + default: + break; + } MarkWholeScreenDirty(); } return 0; diff --git a/openttd.c b/openttd.c index c891105f89..e48da751f4 100644 --- a/openttd.c +++ b/openttd.c @@ -1452,6 +1452,8 @@ bool AfterLoadGame(void) YapfNotifyTrackLayoutChange(INVALID_TILE, INVALID_TRACK); + if (CheckSavegameVersion(34)) FOR_ALL_PLAYERS(p) ResetPlayerLivery(p); + FOR_ALL_PLAYERS(p) p->avail_railtypes = GetPlayerRailtypes(p->index); if (!CheckSavegameVersion(27)) AfterLoadStations(); diff --git a/player.h b/player.h index 55c13abce6..55aec0ce98 100644 --- a/player.h +++ b/player.h @@ -7,6 +7,7 @@ #include "aystar.h" #include "rail.h" #include "engine.h" +#include "livery.h" typedef struct PlayerEconomyEntry { int32 income; @@ -161,6 +162,7 @@ typedef struct Player { int64 money64; // internal 64-bit version of the money. the 32-bit field will be clamped to plus minus 2 billion byte player_color; + Livery livery[LS_END]; byte player_money_fraction; byte avail_railtypes; byte block_preview; @@ -312,4 +314,11 @@ static inline int32 AddEngineReplacementForPlayer(Player *p, EngineID old_engine */ static inline int32 RemoveEngineReplacementForPlayer(Player *p, EngineID engine, uint32 flags) {return RemoveEngineReplacement(&p->engine_renew_list, engine, flags); } +/** + * Reset the livery schemes to the player's primary colour. + * This is used on loading games without livery information and on new player start up. + * @param p Player to reset. + */ +void ResetPlayerLivery(Player *p); + #endif /* PLAYER_H */ diff --git a/player_gui.c b/player_gui.c index a0a4f0927c..3041dc016d 100644 --- a/player_gui.c +++ b/player_gui.c @@ -245,78 +245,223 @@ void ShowPlayerFinances(PlayerID player) DoShowPlayerFinances(player, false, false); } -static void SelectPlayerColorWndProc(Window *w, WindowEvent *e) +/* List of colours for the livery window */ +static const StringID _colour_dropdown[] = { + STR_00D1_DARK_BLUE, + STR_00D2_PALE_GREEN, + STR_00D3_PINK, + STR_00D4_YELLOW, + STR_00D5_RED, + STR_00D6_LIGHT_BLUE, + STR_00D7_GREEN, + STR_00D8_DARK_GREEN, + STR_00D9_BLUE, + STR_00DA_CREAM, + STR_00DB_MAUVE, + STR_00DC_PURPLE, + STR_00DD_ORANGE, + STR_00DE_BROWN, + STR_00DF_GREY, + STR_00E0_WHITE, + INVALID_STRING_ID +}; + +/* Association of liveries to livery classes */ +static const LiveryClass livery_class[LS_END] = { + LC_OTHER, + LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, + LC_ROAD, LC_ROAD, + LC_SHIP, LC_SHIP, + LC_AIRCRAFT, LC_AIRCRAFT, LC_AIRCRAFT, +}; + +/* Number of liveries in each class, used to determine the height of the livery window */ +static const byte livery_height[] = { + 1, + 9, + 2, + 2, + 3, +}; + +typedef struct livery_d { + uint32 sel; + LiveryClass livery_class; +} livery_d; +assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(livery_d)); + +static void ShowColourDropDownMenu(Window *w, uint32 widget) +{ + uint32 used_colours = 0; + const Livery *livery; + LiveryScheme scheme; + + /* Disallow other player colours for the primary colour */ + if (HASBIT(WP(w, livery_d).sel, LS_DEFAULT) && widget == 10) { + const Player *p; + FOR_ALL_PLAYERS(p) { + if (p->is_active && p->index != _local_player) SETBIT(used_colours, p->player_color); + } + } + + /* Get the first selected livery to use as the default dropdown item */ + for (scheme = 0; scheme < LS_END; scheme++) { + if (HASBIT(WP(w, livery_d).sel, scheme)) break; + } + if (scheme == LS_END) scheme = LS_DEFAULT; + livery = &GetPlayer(w->window_number)->livery[scheme]; + + ShowDropDownMenu(w, _colour_dropdown, widget == 10 ? livery->colour1 : livery->colour2, widget, used_colours, 0); +} + +static void SelectPlayerLiveryWndProc(Window *w, WindowEvent *e) { switch (e->event) { - case WE_PAINT: { - const Player *p; - uint used_colors = 0; - int num_free = 16; - int x,y,pos; - int i; + case WE_PAINT: { + const Player *p = GetPlayer(w->window_number); + LiveryScheme scheme = LS_DEFAULT; + int y = 51; - FOR_ALL_PLAYERS(p) { - if (p->is_active) { - SETBIT(used_colors, p->player_color); - num_free--; + if ((WP(w, livery_d).sel == 0)) { + /* Disable dropdown controls if no scheme is selected */ + w->disabled_state = 1 << 9 | 1 << 10 | 1 << 11 | 1 << 12; + } else { + w->disabled_state = 0; + for (scheme = 0; scheme < LS_END; scheme++) { + if (HASBIT(WP(w, livery_d).sel, scheme)) break; + } + if (scheme == LS_END) scheme = LS_DEFAULT; } - } - WP(w,def_d).data_1 = used_colors; - SetVScrollCount(w, num_free); - DrawWindowWidgets(w); - x = 2; - y = 17; - pos = w->vscroll.pos; + SetDParam(0, STR_00D1_DARK_BLUE + p->livery[scheme].colour1); + SetDParam(1, STR_00D1_DARK_BLUE + p->livery[scheme].colour2); - for (i = 0; i != 16; i++) { - if (!(used_colors & 1) && --pos < 0 && pos >= -8) { - DrawString(x + 30, y, STR_00D1_DARK_BLUE + i, 2); - DrawSprite(GENERAL_SPRITE_COLOR(i) | PALETTE_MODIFIER_COLOR | SPR_VEH_BUS_SIDE_VIEW, x + 14, y + 4); - y += 14; + DrawWindowWidgets(w); + + for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) { + if (livery_class[scheme] == WP(w, livery_d).livery_class) { + bool sel = HASBIT(WP(w, livery_d).sel, scheme) != 0; + + if (scheme != LS_DEFAULT) { + DrawSprite(p->livery[scheme].in_use ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, 2, y); + } + + DrawString(15, y, STR_LIVERY_DEFAULT + scheme, sel ? 0xC : 0x10); + + DrawSprite(SPR_SQUARE | GENERAL_SPRITE_COLOR(p->livery[scheme].colour1) | PALETTE_MODIFIER_COLOR, 152, y); + DrawSprite(SPR_SQUARE | GENERAL_SPRITE_COLOR(p->livery[scheme].colour2) | PALETTE_MODIFIER_COLOR, 277, y); + + DrawString(165, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour1, sel ? 0xC : 2); + DrawString(290, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour2, sel ? 0xC : 2); + + y += 14; + } } - used_colors >>= 1; + break; } - } break; - case WE_CLICK: - if (e->click.widget == 2) { - int item = (e->click.pt.y - 13) / 14; - uint used_colors; - int i; + case WE_CLICK: { + switch (e->click.widget) { + /* Livery Class buttons */ + case 2: + case 3: + case 4: + case 5: + case 6: { + LiveryScheme scheme; - if ((uint)item >= 8) - return; - item += w->vscroll.pos; - used_colors = WP(w,def_d).data_1; + WP(w, livery_d).livery_class = e->click.widget - 2; + WP(w, livery_d).sel = 0; - for (i = 0; i != 16; i++) { - if (!(used_colors & 1) && --item < 0) { - DoCommandP(0, 0, i, NULL, CMD_SET_PLAYER_COLOR); - DeleteWindow(w); + /* Select the first item in the list */ + for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) { + if (livery_class[scheme] == WP(w, livery_d).livery_class) { + WP(w, livery_d).sel = 1 << scheme; + break; + } + } + w->click_state = 1 << e->click.widget; + w->height = 49 + livery_height[WP(w, livery_d).livery_class] * 14; + w->widget[13].bottom = w->height - 1; + w->widget[13].data = livery_height[WP(w, livery_d).livery_class] << 8 | 1; + MarkWholeScreenDirty(); + break; + } + + case 9: + case 10: // First colour dropdown + ShowColourDropDownMenu(w, 10); + break; + + case 11: + case 12: // Second colour dropdown + ShowColourDropDownMenu(w, 12); + break; + + case 13: { + LiveryScheme scheme; + LiveryScheme j = (e->click.pt.y - 48) / 14; + + for (scheme = 0; scheme <= j; scheme++) { + if (livery_class[scheme] != WP(w, livery_d).livery_class) j++; + if (scheme >= LS_END) return; + } + if (j >= LS_END) return; + + /* If clicking on the left edge, toggle using the livery */ + if (e->click.pt.x < 10) { + DoCommandP(0, j | (2 << 8), !GetPlayer(w->window_number)->livery[j].in_use, NULL, CMD_SET_PLAYER_COLOR); + } + + if (_ctrl_pressed) { + TOGGLEBIT(WP(w, livery_d).sel, j); + } else { + WP(w, livery_d).sel = 1 << j; + } + SetWindowDirty(w); break; } - used_colors >>= 1; } + break; + } + + case WE_DROPDOWN_SELECT: { + LiveryScheme scheme; + + for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) { + if (HASBIT(WP(w, livery_d).sel, scheme)) { + DoCommandP(0, scheme | (e->dropdown.button == 10 ? 0 : 256), e->dropdown.index, NULL, CMD_SET_PLAYER_COLOR); + } + } + break; } - break; } } -static const Widget _select_player_color_widgets[] = { -{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, -{ WWT_CAPTION, RESIZE_NONE, 14, 11, 149, 0, 13, STR_7007_NEW_COLOR_SCHEME, STR_018C_WINDOW_TITLE_DRAG_THIS}, -{ WWT_IMGBTN, RESIZE_NONE, 14, 0, 137, 14, 127, 0x0, STR_7034_CLICK_ON_SELECTED_NEW_COLOR}, -{ WWT_SCROLLBAR, RESIZE_NONE, 14, 138, 149, 14, 127, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, -{ WIDGETS_END}, +static const Widget _select_player_livery_widgets[] = { +{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW }, +{ WWT_CAPTION, RESIZE_NONE, 14, 11, 399, 0, 13, STR_7007_NEW_COLOR_SCHEME, STR_018C_WINDOW_TITLE_DRAG_THIS }, +{ WWT_IMGBTN, RESIZE_NONE, 14, 0, 21, 14, 35, SPR_IMG_COMPANY_GENERAL, STR_NULL }, +{ WWT_IMGBTN, RESIZE_NONE, 14, 22, 43, 14, 35, SPR_IMG_TRAINLIST, STR_NULL }, +{ WWT_IMGBTN, RESIZE_NONE, 14, 44, 65, 14, 35, SPR_IMG_TRUCKLIST, STR_NULL }, +{ WWT_IMGBTN, RESIZE_NONE, 14, 66, 87, 14, 35, SPR_IMG_SHIPLIST, STR_NULL }, +{ WWT_IMGBTN, RESIZE_NONE, 14, 88, 109, 14, 35, SPR_IMG_AIRPLANESLIST, STR_NULL }, +{ WWT_PANEL, RESIZE_NONE, 14, 110, 399, 14, 35, 0x0, STR_NULL }, +{ WWT_PANEL, RESIZE_NONE, 14, 0, 149, 36, 47, 0x0, STR_NULL }, +{ WWT_TEXTBTN, RESIZE_NONE, 14, 150, 262, 36, 47, STR_02BD, STR_7007_NEW_COLOR_SCHEME }, +{ WWT_TEXTBTN, RESIZE_NONE, 14, 263, 274, 36, 47, STR_0225, STR_7007_NEW_COLOR_SCHEME }, +{ WWT_TEXTBTN, RESIZE_NONE, 14, 275, 387, 36, 47, STR_02E1, STR_7007_NEW_COLOR_SCHEME }, +{ WWT_TEXTBTN, RESIZE_NONE, 14, 388, 399, 36, 47, STR_0225, STR_7007_NEW_COLOR_SCHEME }, +{ WWT_MATRIX, RESIZE_NONE, 14, 0, 399, 48, 48 + 1 * 14, (1 << 8) | 1, STR_NULL }, +{ WIDGETS_END }, }; -static const WindowDesc _select_player_color_desc = { - -1,-1, 150, 128, - WC_PLAYER_COLOR,0, +static const WindowDesc _select_player_livery_desc = { + -1,-1, 400, 49 + 1 * 14, + WC_PLAYER_COLOR, 0, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET, - _select_player_color_widgets, - SelectPlayerColorWndProc + _select_player_livery_widgets, + SelectPlayerLiveryWndProc }; static void SelectPlayerFaceWndProc(Window *w, WindowEvent *e) @@ -570,10 +715,12 @@ static void PlayerCompanyWndProc(Window *w, WindowEvent *e) } break; case 4: {/* change color */ - Window *wf = AllocateWindowDescFront(&_select_player_color_desc,w->window_number); + Window *wf = AllocateWindowDescFront(&_select_player_livery_desc, w->window_number); if (wf != NULL) { wf->caption_color = wf->window_number; - wf->vscroll.cap = 8; + WP(wf,livery_d).livery_class = LC_OTHER; + WP(wf,livery_d).sel = 1; + wf->click_state = 1 << 2; } } break; diff --git a/players.c b/players.c index 9e7aa85159..308eb71bd3 100644 --- a/players.c +++ b/players.c @@ -481,6 +481,17 @@ static Player *AllocatePlayer(void) return NULL; } +void ResetPlayerLivery(Player *p) +{ + LiveryScheme scheme; + + for (scheme = 0; scheme < LS_END; scheme++) { + p->livery[scheme].in_use = false; + p->livery[scheme].colour1 = p->player_color; + p->livery[scheme].colour2 = p->player_color; + } +} + Player *DoStartupNewPlayer(bool is_ai) { Player *p; @@ -490,6 +501,7 @@ Player *DoStartupNewPlayer(bool is_ai) // Make a color p->player_color = GeneratePlayerColor(); + ResetPlayerLivery(p); _player_colors[p->index] = p->player_color; p->name_1 = STR_SV_UNNAMED; p->is_active = true; @@ -1253,6 +1265,13 @@ static const SaveLoad _player_ai_build_rec_desc[] = { SLE_END() }; +static const SaveLoad _player_livery_desc[] = { + SLE_CONDVAR(Livery, in_use, SLE_BOOL, 34, SL_MAX_VERSION), + SLE_CONDVAR(Livery, colour1, SLE_UINT8, 34, SL_MAX_VERSION), + SLE_CONDVAR(Livery, colour2, SLE_UINT8, 34, SL_MAX_VERSION), + SLE_END() +}; + static void SaveLoad_PLYR(Player* p) { int i; @@ -1274,6 +1293,11 @@ static void SaveLoad_PLYR(Player* p) for (i = 0; i < p->num_valid_stat_ent; i++) { SlObject(&p->old_economy[i], _player_economy_desc); } + + // Write each livery entry. + for (i = 0; i < LS_END; i++) { + SlObject(&p->livery[i], _player_livery_desc); + } } static void Save_PLYR(void) diff --git a/saveload.c b/saveload.c index 31d372695f..d3ab95018d 100644 --- a/saveload.c +++ b/saveload.c @@ -30,7 +30,7 @@ #include "variables.h" #include -const uint16 SAVEGAME_VERSION = 33; +const uint16 SAVEGAME_VERSION = 34; uint16 _sl_version; /// the major savegame version identifier byte _sl_minor_version; /// the minor savegame version, DO NOT USE! diff --git a/vehicle.c b/vehicle.c index c43e393d88..38875a76a0 100644 --- a/vehicle.c +++ b/vehicle.c @@ -32,6 +32,7 @@ #include "network.h" #include "yapf/yapf.h" #include "date.h" +#include "newgrf_engine.h" #define INVALID_COORD (-0x8000) #define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6)) @@ -2301,26 +2302,100 @@ UnitID GetFreeUnitNumber(byte type) return unit; } -static PalSpriteID GetEngineColourMap(EngineID engine_type, PlayerID player) +static PalSpriteID GetEngineColourMap(EngineID engine_type, PlayerID player, EngineID parent_engine_type, CargoID cargo_type) { SpriteID map; - byte colour = _player_colors[player]; + const Player *p = GetPlayer(player); + LiveryScheme scheme = LS_DEFAULT; + + /* The default livery is always available for use, but its in_use flag determines + * whether any _other_ liveries are in use. */ + if (p->livery[LS_DEFAULT].in_use) { + /* Determine the livery scheme to use */ + switch (GetEngine(engine_type)->type) { + case VEH_Train: { + switch (_engine_info[engine_type].railtype) { + case RAILTYPE_RAIL: + case RAILTYPE_ELECTRIC: + { + const RailVehicleInfo *rvi = RailVehInfo(engine_type); + + if (cargo_type == CT_INVALID) cargo_type = rvi->cargo_type; + if (rvi->flags & RVI_WAGON) { + scheme = (cargo_type == CT_PASSENGERS || cargo_type == CT_MAIL || cargo_type == CT_VALUABLES) ? + LS_PASSENGER_WAGON : LS_FREIGHT_WAGON; + } else { + bool is_mu = HASBIT(_engine_info[engine_type].misc_flags, EF_RAIL_IS_MU); + + switch (rvi->engclass) { + case 0: scheme = LS_STEAM; break; + case 1: scheme = is_mu ? LS_DMU : LS_DIESEL; break; + case 2: scheme = is_mu ? LS_EMU : LS_ELECTRIC; break; + } + } + break; + } + + case RAILTYPE_MONO: scheme = LS_MONORAIL; break; + case RAILTYPE_MAGLEV: scheme = LS_MAGLEV; break; + } + break; + } + + case VEH_Road: { + const RoadVehicleInfo *rvi = RoadVehInfo(engine_type); + if (cargo_type == CT_INVALID) cargo_type = rvi->cargo_type; + scheme = (cargo_type == CT_PASSENGERS) ? LS_BUS : LS_TRUCK; + break; + } + + case VEH_Ship: { + const ShipVehicleInfo *svi = ShipVehInfo(engine_type); + if (cargo_type == CT_INVALID) cargo_type = svi->cargo_type; + scheme = (cargo_type == CT_PASSENGERS) ? LS_PASSENGER_SHIP : LS_FREIGHT_SHIP; + break; + } + + case VEH_Aircraft: { + const AircraftVehicleInfo *avi = AircraftVehInfo(engine_type); + if (cargo_type == CT_INVALID) cargo_type = CT_PASSENGERS; + switch (avi->subtype) { + case 0: scheme = LS_HELICOPTER; break; + case 1: scheme = LS_SMALL_PLANE; break; + case 3: scheme = LS_LARGE_PLANE; break; + } + break; + } + } + + /* Switch back to the default scheme if the resolved scheme is not in use */ + if (!p->livery[scheme].in_use) scheme = LS_DEFAULT; + } - /* XXX Magic 0x307 is the first company colour remap sprite */ map = HASBIT(EngInfo(engine_type)->misc_flags, EF_USES_2CC) ? - (SPR_2CCMAP_BASE + colour + colour * 16) : (PALETTE_RECOLOR_START + colour); + (SPR_2CCMAP_BASE + p->livery[scheme].colour1 + p->livery[scheme].colour2 * 16) : + (PALETTE_RECOLOR_START + p->livery[scheme].colour1); return SPRITE_PALETTE(map << PALETTE_SPRITE_START); } PalSpriteID GetEnginePalette(EngineID engine_type, PlayerID player) { - return GetEngineColourMap(engine_type, player); + return GetEngineColourMap(engine_type, player, INVALID_ENGINE, CT_INVALID); } PalSpriteID GetVehiclePalette(const Vehicle *v) { - return GetEngineColourMap(v->engine_type, v->owner); + if (v->type == VEH_Train) { + return GetEngineColourMap( + (v->u.rail.first_engine != INVALID_ENGINE && (IsArticulatedPart(v) || UsesWagonOverride(v))) ? + v->u.rail.first_engine : v->engine_type, + v->owner, + v->u.rail.first_engine, + v->cargo_type); + } + + return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v->cargo_type); } // Save and load of vehicles