Changeset - r28345:d8c125d15395
[Not reviewed]
master
0 6 0
Peter Nelson - 11 months ago 2023-12-27 15:26:33
peter1138@openttd.org
Fix: Changing default livery did not propagate to group liveries.

#11614 attempted to address this but did not handle 2CC properly, and changes to the default livery were not handled.
6 files changed with 59 insertions and 26 deletions:
0 comments (0 inline, 0 general)
src/company_cmd.cpp
Show inline comments
 
@@ -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 (flags & DC_EXEC) {
 
		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) {
 
				for (int i = 1; i < LS_END; i++) {
 
					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 (scheme == LS_DEFAULT) {
 
				for (int i = 1; i < LS_END; i++) {
 
					if (!HasBit(c->livery[i].in_use, 1)) c->livery[i].colour2 = colour;
 
				}
 
				UpdateCompanyGroupLiveries(c);
 
			}
 
		}
 

	
 
		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 {
 
			/* 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++) {
 
				if (c->livery[scheme].in_use != 0) {
src/company_func.h
Show inline comments
 
@@ -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;
src/company_gui.cpp
Show inline comments
 
@@ -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);
 
				}
 
			}
 
		} else {
 
			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
 
	{
src/group.h
Show inline comments
 
@@ -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 */
src/group_cmd.cpp
Show inline comments
 
@@ -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) {
 
		/* 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();
 
				}
 
			}
 
		}
 
	}
 

	
 
	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.
 
 * @param c Company to update.
 
 */
 
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);
 
		}
 

	
 
		if (flags & DC_EXEC) {
 
			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);
 
				MarkWholeScreenDirty();
 
			}
 
		}
 
	} else {
 
		return CMD_ERROR;
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		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
 

	
 
	if (flags & DC_EXEC) {
 
		if (primary) {
 
			SB(g->livery.in_use, 0, 1, colour != INVALID_COLOUR);
 
			if (colour == INVALID_COLOUR) colour = (Colours)GetParentLivery(g)->colour1;
 
			g->livery.colour1 = colour;
 
		} else {
 
			SB(g->livery.in_use, 1, 1, colour != INVALID_COLOUR);
 
			if (colour == INVALID_COLOUR) colour = (Colours)GetParentLivery(g)->colour2;
 
			g->livery.colour2 = colour;
 
		}
 

	
 
		PropagateChildLivery(g);
 
		PropagateChildLivery(g, true);
 
		MarkWholeScreenDirty();
 
	}
 

	
 
	return CommandCost();
 
}
 

	
 
/**
 
 * 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)
src/saveload/afterload.cpp
Show inline comments
 
@@ -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. */
 
		for (Vehicle *v : Vehicle::Iterate()) {
 
			v->date_of_last_service_newgrf = v->date_of_last_service;
 
		}
 
	}
 

	
 
	for (Company *c : Company::Iterate()) {
 
		UpdateCompanyLiveries(c);
 
	}
 

	
 
	AfterLoadLabelMaps();
 
	AfterLoadCompanyStats();
 
	AfterLoadStoryBook();
 

	
 
	_gamelog.PrintDebug(1);
 

	
 
	InitializeWindowsAndCaches();
 
	/* Restore the signals */
 
	ResetSignalHandlers();
 

	
 
	AfterLoadLinkGraphs();
 

	
0 comments (0 inline, 0 general)