summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lang/english.txt18
-rw-r--r--livery.h57
-rw-r--r--misc_cmd.c65
-rw-r--r--openttd.c2
-rw-r--r--player.h9
-rw-r--r--player_gui.c257
-rw-r--r--players.c24
-rw-r--r--saveload.c2
-rw-r--r--vehicle.c87
9 files changed, 452 insertions, 69 deletions
diff --git a/lang/english.txt b/lang/english.txt
index 0c2cc29a1..82ae2330c 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 000000000..1834f9c75
--- /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 38e8801b8..d96572bb6 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 c891105f8..e48da751f 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 55c13abce..55aec0ce9 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 a0a4f0927..3041dc016 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)
{
- switch (e->event) {
- case WE_PAINT: {
- const Player *p;
- uint used_colors = 0;
- int num_free = 16;
- int x,y,pos;
- int i;
+ 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) {
- SETBIT(used_colors, p->player_color);
- num_free--;
- }
+ if (p->is_active && p->index != _local_player) SETBIT(used_colours, p->player_color);
}
- WP(w,def_d).data_1 = used_colors;
- SetVScrollCount(w, num_free);
- DrawWindowWidgets(w);
+ }
+
+ /* 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 = GetPlayer(w->window_number);
+ LiveryScheme scheme = LS_DEFAULT;
+ int y = 51;
+
+ 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;
+ }
+
+ SetDParam(0, STR_00D1_DARK_BLUE + p->livery[scheme].colour1);
+ SetDParam(1, STR_00D1_DARK_BLUE + p->livery[scheme].colour2);
+
+ 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);
- x = 2;
- y = 17;
- pos = w->vscroll.pos;
+ 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);
- 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;
+ 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;
-
- if ((uint)item >= 8)
- return;
- item += w->vscroll.pos;
- used_colors = WP(w,def_d).data_1;
-
- for (i = 0; i != 16; i++) {
- if (!(used_colors & 1) && --item < 0) {
- DoCommandP(0, 0, i, NULL, CMD_SET_PLAYER_COLOR);
- DeleteWindow(w);
+ case WE_CLICK: {
+ switch (e->click.widget) {
+ /* Livery Class buttons */
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6: {
+ LiveryScheme scheme;
+
+ WP(w, livery_d).livery_class = e->click.widget - 2;
+ WP(w, livery_d).sel = 0;
+
+ /* 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 9e7aa8515..308eb71bd 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 31d372695..d3ab95018 100644
--- a/saveload.c
+++ b/saveload.c
@@ -30,7 +30,7 @@
#include "variables.h"
#include <setjmp.h>
-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 c43e393d8..38875a76a 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