@@ -941,24 +941,38 @@ CommandCost CmdCompanyCtrl(DoCommandFlag
CommandCost CmdSetCompanyManagerFace(DoCommandFlag flags, CompanyManagerFace cmf)
{
if (!IsValidCompanyManagerFace(cmf)) return CMD_ERROR;
if (flags & DC_EXEC) {
Company::Get(_current_company)->face = cmf;
MarkWholeScreenDirty();
}
return CommandCost();
/**
* Update liveries for a company. This is called when the LS_DEFAULT scheme is changed, to update schemes with colours
* set to default.
* @param c Company to update.
*/
void UpdateCompanyLiveries(Company *c)
for (int i = 1; i < LS_END; i++) {
if (!HasBit(c->livery[i].in_use, 0)) c->livery[i].colour1 = c->livery[LS_DEFAULT].colour1;
if (!HasBit(c->livery[i].in_use, 1)) c->livery[i].colour2 = c->livery[LS_DEFAULT].colour2;
UpdateCompanyGroupLiveries(c);
* Change the company's company-colour
* @param flags operation to perform
* @param scheme scheme to set
* @param primary set first/second colour
* @param colour new colour for vehicles, property, etc.
* @return the cost of this operation or an error
CommandCost CmdSetCompanyColour(DoCommandFlag flags, LiveryScheme scheme, bool primary, Colours colour)
if (scheme >= LS_END || (colour >= COLOUR_END && colour != INVALID_COLOUR)) return CMD_ERROR;
/* Default scheme can't be reset to invalid. */
@@ -973,40 +987,36 @@ CommandCost CmdSetCompanyColour(DoComman
if (primary) {
if (scheme != LS_DEFAULT) SB(c->livery[scheme].in_use, 0, 1, colour != INVALID_COLOUR);
if (colour == INVALID_COLOUR) colour = (Colours)c->livery[LS_DEFAULT].colour1;
c->livery[scheme].colour1 = colour;
/* If setting the first colour of the default scheme, adjust the
* original and cached company colours too. */
if (scheme == LS_DEFAULT) {
if (!HasBit(c->livery[i].in_use, 0)) c->livery[i].colour1 = colour;
UpdateCompanyLiveries(c);
_company_colours[_current_company] = colour;
c->colour = colour;
CompanyAdminUpdate(c);
} else {
if (scheme != LS_DEFAULT) SB(c->livery[scheme].in_use, 1, 1, colour != INVALID_COLOUR);
if (colour == INVALID_COLOUR) colour = (Colours)c->livery[LS_DEFAULT].colour2;
c->livery[scheme].colour2 = colour;
if (!HasBit(c->livery[i].in_use, 1)) c->livery[i].colour2 = colour;
if (c->livery[scheme].in_use != 0) {
/* If enabling a scheme, set the default scheme to be in use too */
c->livery[LS_DEFAULT].in_use = 1;
/* Else loop through all schemes to see if any are left enabled.
* If not, disable the default scheme too. */
c->livery[LS_DEFAULT].in_use = 0;
for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
@@ -15,24 +15,25 @@
#include "gfx_type.h"
#include "vehicle_type.h"
bool MayCompanyTakeOver(CompanyID cbig, CompanyID small);
void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner);
static const int OWNED_BY_OWNER_IN_PARAMETERS_OFFSET = 2; ///< The index in the parameters for the owner information.
void SetDParamsForOwnedBy(Owner owner, TileIndex tile);
void SetLocalCompany(CompanyID new_company);
void ShowBuyCompanyDialog(CompanyID company, bool hostile_takeover);
void CompanyAdminUpdate(const Company *company);
void CompanyAdminBankrupt(CompanyID company_id);
void UpdateLandscapingLimits();
void UpdateCompanyLiveries(Company *c);
bool CheckCompanyHasMoney(CommandCost &cost);
void SubtractMoneyFromCompany(const CommandCost& cost);
void SubtractMoneyFromCompanyFract(CompanyID company, const CommandCost& cost);
CommandCost CheckOwnership(Owner owner, TileIndex tile = 0U);
CommandCost CheckTileOwnership(TileIndex tile);
extern CompanyID _local_company;
extern CompanyID _current_company;
extern Colours _company_colours[MAX_COMPANIES];
extern CompanyManagerFace _company_manager_face;
@@ -898,58 +898,57 @@ public:
Rect sec_squ = sec.WithWidth(this->square.width, rtl);
pri = pri.Indent(this->square.width + WidgetDimensions::scaled.hsep_normal, rtl);
sec = sec.Indent(this->square.width + WidgetDimensions::scaled.hsep_normal, rtl);
Rect ir = r.WithHeight(this->resize.step_height).Shrink(WidgetDimensions::scaled.matrix);
int square_offs = (ir.Height() - this->square.height) / 2;
int text_offs = (ir.Height() - GetCharacterHeight(FS_NORMAL)) / 2;
int y = ir.top;
/* Helper function to draw livery info. */
auto draw_livery = [&](StringID str, const Livery &liv, bool sel, bool def, int indent) {
auto draw_livery = [&](StringID str, const Livery &livery, bool is_selected, bool is_default_scheme, int indent) {
/* Livery Label. */
DrawString(sch.left + (rtl ? 0 : indent), sch.right - (rtl ? indent : 0), y + text_offs, str, sel ? TC_WHITE : TC_BLACK);
DrawString(sch.left + (rtl ? 0 : indent), sch.right - (rtl ? indent : 0), y + text_offs, str, is_selected ? TC_WHITE : TC_BLACK);
/* Text below the first dropdown. */
DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(liv.colour1), pri_squ.left, y + square_offs);
DrawString(pri.left, pri.right, y + text_offs, (def || HasBit(liv.in_use, 0)) ? STR_COLOUR_DARK_BLUE + liv.colour1 : STR_COLOUR_DEFAULT, sel ? TC_WHITE : TC_GOLD);
DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(livery.colour1), pri_squ.left, y + square_offs);
DrawString(pri.left, pri.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 0)) ? STR_COLOUR_DARK_BLUE + livery.colour1 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
/* Text below the second dropdown. */
if (sec.right > sec.left) { // Second dropdown has non-zero size.
DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(liv.colour2), sec_squ.left, y + square_offs);
DrawString(sec.left, sec.right, y + text_offs, (def || HasBit(liv.in_use, 1)) ? STR_COLOUR_DARK_BLUE + liv.colour2 : STR_COLOUR_DEFAULT, sel ? TC_WHITE : TC_GOLD);
DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(livery.colour2), sec_squ.left, y + square_offs);
DrawString(sec.left, sec.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 1)) ? STR_COLOUR_DARK_BLUE + livery.colour2 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
y += this->line_height;
};
const Company *c = Company::Get((CompanyID)this->window_number);
if (livery_class < LC_GROUP_RAIL) {
int pos = this->vscroll->GetPosition();
for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
if (pos-- > 0) continue;
draw_livery(STR_LIVERY_DEFAULT + scheme, c->livery[scheme], HasBit(this->sel, scheme), scheme == LS_DEFAULT, 0);
uint max = static_cast<uint>(std::min<size_t>(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->groups.size()));
for (uint i = this->vscroll->GetPosition(); i < max; ++i) {
const Group *g = this->groups[i];
const bool livery_set = HasBit(g->livery.in_use, 0);
SetDParam(0, g->index);
draw_livery(STR_GROUP_NAME, livery_set ? g->livery : c->livery[LS_DEFAULT], this->sel == g->index, livery_set, this->indents[i] * WidgetDimensions::scaled.hsep_indent);
draw_livery(STR_GROUP_NAME, g->livery, this->sel == g->index, false, this->indents[i] * WidgetDimensions::scaled.hsep_indent);
if (this->vscroll->GetCount() == 0) {
const StringID empty_labels[] = { STR_LIVERY_TRAIN_GROUP_EMPTY, STR_LIVERY_ROAD_VEHICLE_GROUP_EMPTY, STR_LIVERY_SHIP_GROUP_EMPTY, STR_LIVERY_AIRCRAFT_GROUP_EMPTY };
VehicleType vtype = (VehicleType)(this->livery_class - LC_GROUP_RAIL);
DrawString(ir.left, ir.right, y + text_offs, empty_labels[vtype], TC_BLACK);
void OnClick([[maybe_unused]] Point pt, int widget, [[maybe_unused]] int click_count) override
@@ -103,14 +103,15 @@ static inline bool IsAllGroupID(GroupID
uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e);
uint GetGroupNumVehicle(CompanyID company, GroupID id_g, VehicleType type);
uint GetGroupNumVehicleMinAge(CompanyID company, GroupID id_g, VehicleType type);
Money GetGroupProfitLastYearMinAge(CompanyID company, GroupID id_g, VehicleType type);
void SetTrainGroupID(Train *v, GroupID grp);
void UpdateTrainGroupID(Train *v);
void RemoveAllGroupsForCompany(const CompanyID company);
bool GroupIsInGroup(GroupID search, GroupID group);
void UpdateCompanyGroupLiveries(const Company *c);
#endif /* GROUP_H */
@@ -266,48 +266,66 @@ const Livery *GetParentLivery(const Grou
if (g->parent == INVALID_GROUP) {
const Company *c = Company::Get(g->owner);
return &c->livery[LS_DEFAULT];
const Group *pg = Group::Get(g->parent);
return &pg->livery;
* Propagate a livery change to a group's children.
* @param g Group.
* Propagate a livery change to a group's children, and optionally update cached vehicle colourmaps.
* @param g Group to propagate colours to children.
* @param reset_cache Reset colourmap of vehicles in this group.
void PropagateChildLivery(const Group *g)
static void PropagateChildLivery(const Group *g, bool reset_cache)
/* Company colour data is indirectly cached. */
for (Vehicle *v : Vehicle::Iterate()) {
if (v->group_id == g->index && (!v->IsGroundVehicle() || v->IsFrontEngine())) {
for (Vehicle *u = v; u != nullptr; u = u->Next()) {
u->colourmap = PAL_NONE;
u->InvalidateNewGRFCache();
if (reset_cache) {
for (Group *cg : Group::Iterate()) {
if (cg->parent == g->index) {
if (!HasBit(cg->livery.in_use, 0)) cg->livery.colour1 = g->livery.colour1;
if (!HasBit(cg->livery.in_use, 1)) cg->livery.colour2 = g->livery.colour2;
PropagateChildLivery(cg);
PropagateChildLivery(cg, reset_cache);
* Update group liveries for a company. This is called when the LS_DEFAULT scheme is changed, to update groups with
* colours set to default.
void UpdateCompanyGroupLiveries(const Company *c)
for (Group *g : Group::Iterate()) {
if (g->owner == c->index && g->parent == INVALID_GROUP) {
if (!HasBit(g->livery.in_use, 0)) g->livery.colour1 = c->livery[LS_DEFAULT].colour1;
if (!HasBit(g->livery.in_use, 1)) g->livery.colour2 = c->livery[LS_DEFAULT].colour2;
PropagateChildLivery(g, false);
Group::Group(Owner owner)
this->owner = owner;
this->folded = false;
* Create a new vehicle group.
* @param flags type of operation
* @param vt vehicle type
@@ -444,25 +462,25 @@ CommandCost CmdAlterGroup(DoCommandFlag
if (GroupIsInGroup(pg->index, g->index)) return_cmd_error(STR_ERROR_GROUP_CAN_T_SET_PARENT_RECURSION);
g->parent = (pg == nullptr) ? INVALID_GROUP : pg->index;
GroupStatistics::UpdateAutoreplace(g->owner);
if (g->livery.in_use == 0) {
const Livery *livery = GetParentLivery(g);
g->livery.colour1 = livery->colour1;
g->livery.colour2 = livery->colour2;
PropagateChildLivery(g);
PropagateChildLivery(g, true);
return CMD_ERROR;
InvalidateWindowData(WC_REPLACE_VEHICLE, g->vehicle_type, 1);
InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
InvalidateWindowData(WC_COMPANY_COLOUR, g->owner, g->vehicle_type);
InvalidateWindowClassesData(WC_VEHICLE_VIEW);
@@ -652,25 +670,25 @@ CommandCost CmdSetGroupLivery(DoCommandF
SB(g->livery.in_use, 0, 1, colour != INVALID_COLOUR);
if (colour == INVALID_COLOUR) colour = (Colours)GetParentLivery(g)->colour1;
g->livery.colour1 = colour;
SB(g->livery.in_use, 1, 1, colour != INVALID_COLOUR);
if (colour == INVALID_COLOUR) colour = (Colours)GetParentLivery(g)->colour2;
g->livery.colour2 = colour;
* Set group flag for a group and its sub-groups.
* @param g initial group.
* @param set 1 to set or 0 to clear protection.
static void SetGroupFlag(Group *g, GroupFlags flag, bool set, bool children)
@@ -3253,24 +3253,28 @@ bool AfterLoadGame()
extern TimeoutTimer<TimerGameTick> _new_competitor_timeout;
_new_competitor_timeout.storage.elapsed = 0;
_new_competitor_timeout.fired = _new_competitor_timeout.period == 0;
if (IsSavegameVersionBefore(SLV_NEWGRF_LAST_SERVICE)) {
/* Set service date provided to NewGRF. */
v->date_of_last_service_newgrf = v->date_of_last_service;
for (Company *c : Company::Iterate()) {
AfterLoadLabelMaps();
AfterLoadCompanyStats();
AfterLoadStoryBook();
_gamelog.PrintDebug(1);
InitializeWindowsAndCaches();
/* Restore the signals */
ResetSignalHandlers();
AfterLoadLinkGraphs();
Status change: