diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index 60214402cf..31da6552e4 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -35,6 +35,7 @@ #include "goal_base.h" #include "story_base.h" #include "zoning.h" +#include "tbtr_template_vehicle_func.h" #include "table/strings.h" @@ -1039,6 +1040,7 @@ CommandCost CmdSetCompanyColour(TileIndex tile, DoCommandFlag flags, uint32 p1, } ResetVehicleColourMap(); + InvalidateTemplateReplacementImages(); MarkWholeScreenDirty(); /* All graph related to companies use the company colour. */ diff --git a/src/economy.cpp b/src/economy.cpp index 321c13035b..74cdf7134a 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -51,6 +51,7 @@ #include "linkgraph/refresh.h" #include "tracerestrict.h" #include "tbtr_template_vehicle.h" +#include "tbtr_template_vehicle_func.h" #include "scope_info.h" #include "pathfinder/yapf/yapf_cache.h" @@ -578,6 +579,8 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner) NotifyRoadLayoutChanged(); + InvalidateTemplateReplacementImages(); + cur_company.Restore(); RegisterGameEvents(new_owner != INVALID_OWNER ? GEF_COMPANY_MERGE : GEF_COMPANY_DELETE); diff --git a/src/misc.cpp b/src/misc.cpp index 332b6edc64..5bcf4add9d 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -37,6 +37,7 @@ #include "command_func.h" #include "zoning.h" #include "cargopacket.h" +#include "tbtr_template_vehicle_func.h" #include "safeguards.h" @@ -153,6 +154,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin InvalidateVehicleTickCaches(); ClearVehicleTickCaches(); + InvalidateTemplateReplacementImages(); ResetObjectToPlace(); ResetRailPlacementSnapping(); diff --git a/src/openttd.cpp b/src/openttd.cpp index 9bfb939660..5698e42c58 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -77,6 +77,7 @@ #include "industry.h" #include "cargopacket.h" #include "core/checksum_func.hpp" +#include "tbtr_template_vehicle_func.h" #include "linkgraph/linkgraphschedule.h" #include "tracerestrict.h" @@ -431,6 +432,7 @@ static void ShutdownGame() ViewportMapClearTunnelCache(); InvalidateVehicleTickCaches(); ClearVehicleTickCaches(); + InvalidateTemplateReplacementImages(); ClearCommandLog(); ClearDesyncMsgLog(); diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 2158fb0414..1374ba207d 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -3838,7 +3838,7 @@ bool AfterLoadGame() AfterLoadLinkGraphs(); AfterLoadTraceRestrict(); - AfterLoadTemplateVehiclesUpdateImage(); + AfterLoadTemplateVehiclesUpdate(); if (SlXvIsFeaturePresent(XSLFI_TEMPLATE_REPLACEMENT, 1, 5)) { AfterLoadTemplateVehiclesUpdateProperties(); } @@ -3937,7 +3937,7 @@ void ReloadNewGRFData() /* redraw the whole screen */ MarkWholeScreenDirty(); CheckTrainsLengths(); - AfterLoadTemplateVehiclesUpdateImage(); + AfterLoadTemplateVehiclesUpdateImages(); AfterLoadTemplateVehiclesUpdateProperties(); UpdateAllAnimatedTileSpeeds(); } diff --git a/src/saveload/saveload_internal.h b/src/saveload/saveload_internal.h index 88cd1017a1..e49e7d6d42 100644 --- a/src/saveload/saveload_internal.h +++ b/src/saveload/saveload_internal.h @@ -50,7 +50,8 @@ void ResetTempEngineData(); Engine *GetTempDataEngine(EngineID index); void CopyTempEngineData(); -void AfterLoadTemplateVehiclesUpdateImage(); +void AfterLoadTemplateVehiclesUpdate(); +void AfterLoadTemplateVehiclesUpdateImages(); void AfterLoadTemplateVehiclesUpdateProperties(); extern int32 _saved_scrollpos_x; diff --git a/src/saveload/tbtr_template_veh_sl.cpp b/src/saveload/tbtr_template_veh_sl.cpp index 3abf270107..ae5bec2a42 100644 --- a/src/saveload/tbtr_template_veh_sl.cpp +++ b/src/saveload/tbtr_template_veh_sl.cpp @@ -99,7 +99,7 @@ void AfterLoadTemplateVehicles() } } -void AfterLoadTemplateVehiclesUpdateImage() +void AfterLoadTemplateVehiclesUpdate() { SavedRandomSeeds saved_seeds; SaveRandomSeeds(&saved_seeds); @@ -113,36 +113,14 @@ void AfterLoadTemplateVehiclesUpdateImage() } } - for (TemplateVehicle *tv : TemplateVehicle::Iterate()) { - if (tv->Prev() == nullptr) { - Backup cur_company(_current_company, tv->owner, FILE_LINE); - StringID err; - Train* t = VirtualTrainFromTemplateVehicle(tv, err, 0); - if (t != nullptr) { - int tv_len = 0; - for (TemplateVehicle *u = tv; u != nullptr; u = u->Next()) { - tv_len++; - } - int t_len = 0; - for (Train *u = t; u != nullptr; u = u->Next()) { - t_len++; - } - if (t_len == tv_len) { - Train *v = t; - for (TemplateVehicle *u = tv; u != nullptr; u = u->Next(), v = v->Next()) { - v->GetImage(DIR_W, EIT_IN_DEPOT, &u->sprite_seq); - u->image_dimensions.SetFromTrain(v); - } - } else { - DEBUG(misc, 0, "AfterLoadTemplateVehiclesUpdateImage: vehicle count mismatch: %u, %u", t_len, tv_len); - } - delete t; - } - cur_company.Restore(); - } - } - RestoreRandomSeeds(saved_seeds); + + InvalidateTemplateReplacementImages(); +} + +void AfterLoadTemplateVehiclesUpdateImages() +{ + InvalidateTemplateReplacementImages(); } void AfterLoadTemplateVehiclesUpdateProperties() diff --git a/src/tbtr_template_gui_main.cpp b/src/tbtr_template_gui_main.cpp index 47318e87ed..6e25e93092 100644 --- a/src/tbtr_template_gui_main.cpp +++ b/src/tbtr_template_gui_main.cpp @@ -642,6 +642,8 @@ public: void DrawTemplateList(const Rect &r) const { + if (!_template_vehicle_images_valid) UpdateAllTemplateVehicleImages(); + const_cast(this)->BuildTemplateGuiList(); int left = r.left; diff --git a/src/tbtr_template_vehicle.h b/src/tbtr_template_vehicle.h index dfd2613e63..910a57ec91 100644 --- a/src/tbtr_template_vehicle.h +++ b/src/tbtr_template_vehicle.h @@ -42,6 +42,8 @@ static const uint16 CONSIST_TAIL = 0xffff; typedef Pool TemplatePool; extern TemplatePool _template_pool; +extern bool _template_vehicle_images_valid; + /// listing/sorting templates typedef GUIList GUITemplateList; @@ -107,6 +109,7 @@ public: VehicleSpriteSeq sprite_seq; ///< NOSAVE: Vehicle appearance. TemplateVehicleImageDimensions image_dimensions; ///< NOSAVE: image dimensions + SpriteID colourmap; ///< NOSAVE: cached colour mapping TemplateVehicle(VehicleType type = VEH_INVALID, EngineID e = INVALID_ENGINE, byte B = 0, Owner = _local_company); TemplateVehicle(EngineID, RailVehicleInfo*); diff --git a/src/tbtr_template_vehicle_func.cpp b/src/tbtr_template_vehicle_func.cpp index 4c308b6cc8..41caebe6fa 100644 --- a/src/tbtr_template_vehicle_func.cpp +++ b/src/tbtr_template_vehicle_func.cpp @@ -19,6 +19,8 @@ #include "core/geometry_type.hpp" #include "debug.h" #include "zoom_func.h" +#include "core/backup_type.hpp" +#include "core/random_func.hpp" #include "table/sprites.h" #include "table/strings.h" @@ -41,7 +43,7 @@ #include "safeguards.h" -Vehicle *vhead, *vtmp; +bool _template_vehicle_images_valid = false; #ifdef _DEBUG // debugging printing functions for convenience, usually called from gdb @@ -125,8 +127,7 @@ void DrawTemplate(const TemplateVehicle *tv, int left, int right, int y) int offset = 0; while (t) { - PaletteID pal = GetEnginePalette(t->engine_type, _current_company); - t->sprite_seq.Draw(offset + t->image_dimensions.GetOffsetX(), t->image_dimensions.GetOffsetY() + ScaleGUITrad(10), pal, false); + t->sprite_seq.Draw(offset + t->image_dimensions.GetOffsetX(), t->image_dimensions.GetOffsetY() + ScaleGUITrad(10), t->colourmap, false); offset += t->image_dimensions.GetDisplayImageWidth(); t = t->Next(); @@ -170,6 +171,7 @@ void SetupTemplateVehicleFromVirtual(TemplateVehicle *tmp, TemplateVehicle *prev virt->GetImage(DIR_W, EIT_IN_DEPOT, &tmp->sprite_seq); tmp->image_dimensions.SetFromTrain(virt); + tmp->colourmap = GetUncachedTrainPaletteIgnoringGroup(virt); } // create a full TemplateVehicle based train according to a virtual train @@ -428,3 +430,43 @@ void TransferCargoForTrain(Train *old_veh, Train *new_head) /* Update train weight etc., the old vehicle will be sold anyway */ new_head->ConsistChanged(CCF_LOADUNLOAD); } + +void UpdateAllTemplateVehicleImages() +{ + SavedRandomSeeds saved_seeds; + SaveRandomSeeds(&saved_seeds); + + for (TemplateVehicle *tv : TemplateVehicle::Iterate()) { + if (tv->Prev() == nullptr) { + Backup cur_company(_current_company, tv->owner, FILE_LINE); + StringID err; + Train* t = VirtualTrainFromTemplateVehicle(tv, err, 0); + if (t != nullptr) { + int tv_len = 0; + for (TemplateVehicle *u = tv; u != nullptr; u = u->Next()) { + tv_len++; + } + int t_len = 0; + for (Train *u = t; u != nullptr; u = u->Next()) { + t_len++; + } + if (t_len == tv_len) { + Train *v = t; + for (TemplateVehicle *u = tv; u != nullptr; u = u->Next(), v = v->Next()) { + v->GetImage(DIR_W, EIT_IN_DEPOT, &u->sprite_seq); + u->image_dimensions.SetFromTrain(v); + u->colourmap = GetVehiclePalette(v); + } + } else { + DEBUG(misc, 0, "UpdateAllTemplateVehicleImages: vehicle count mismatch: %u, %u", t_len, tv_len); + } + delete t; + } + cur_company.Restore(); + } + } + + RestoreRandomSeeds(saved_seeds); + + _template_vehicle_images_valid = true; +} diff --git a/src/tbtr_template_vehicle_func.h b/src/tbtr_template_vehicle_func.h index a9d7b856a3..9959613d6b 100644 --- a/src/tbtr_template_vehicle_func.h +++ b/src/tbtr_template_vehicle_func.h @@ -15,7 +15,7 @@ #include "tbtr_template_vehicle.h" -Train* VirtualTrainFromTemplateVehicle(TemplateVehicle* tv, StringID &err, uint32 user); +Train* VirtualTrainFromTemplateVehicle(const TemplateVehicle* tv, StringID &err, uint32 user); void BuildTemplateGuiList(GUITemplateList*, Scrollbar*, Owner, RailType); @@ -59,4 +59,11 @@ void NeutralizeStatus(Train *t); bool TrainMatchesTemplate(const Train *t, const TemplateVehicle *tv); bool TrainMatchesTemplateRefit(const Train *t, const TemplateVehicle *tv); +void UpdateAllTemplateVehicleImages(); + +inline void InvalidateTemplateReplacementImages() +{ + _template_vehicle_images_valid = false; +} + #endif diff --git a/src/vehicle.cpp b/src/vehicle.cpp index b88cdbddd1..0e3c8f76a6 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -2670,15 +2670,16 @@ LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_ * @param parent_engine_type EngineID of the front vehicle. INVALID_VEHICLE if vehicle is at front itself. * @param v the vehicle. nullptr if in purchase list etc. * @param livery_setting The livery settings to use for acquiring the livery information. + * @param ignore_group Ignore group overrides. * @return livery to use */ -const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting) +const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting, bool ignore_group) { const Company *c = Company::Get(company); LiveryScheme scheme = LS_DEFAULT; if (livery_setting == LIT_ALL || (livery_setting == LIT_COMPANY && company == _local_company)) { - if (v != nullptr) { + if (v != nullptr && !ignore_group) { const Group *g = Group::GetIfValid(v->First()->group_id); if (g != nullptr) { /* Traverse parents until we find a livery or reach the top */ @@ -2701,9 +2702,9 @@ const Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID } -static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v) +static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, bool ignore_group = false) { - PaletteID map = (v != nullptr) ? v->colourmap : PAL_NONE; + PaletteID map = (v != nullptr && !ignore_group) ? v->colourmap : PAL_NONE; /* Return cached value if any */ if (map != PAL_NONE) return map; @@ -2734,13 +2735,13 @@ static PaletteID GetEngineColourMap(EngineID engine_type, CompanyID company, Eng /* Spectator has news shown too, but has invalid company ID - as well as dedicated server */ if (!Company::IsValidID(company)) return map; - const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries); + const Livery *livery = GetEngineLivery(engine_type, company, parent_engine_type, v, _settings_client.gui.liveries, ignore_group); map += livery->colour1; if (twocc) map += livery->colour2 * 16; /* Update cache */ - if (v != nullptr) const_cast(v)->colourmap = map; + if (v != nullptr && !ignore_group) const_cast(v)->colourmap = map; return map; } @@ -2769,6 +2770,16 @@ PaletteID GetVehiclePalette(const Vehicle *v) return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v); } +/** + * Get the uncached colour map for a train, ignoring the vehicle's group. + * @param v Vehicle to get colour map for + * @return A ready-to-use palette modifier + */ +PaletteID GetUncachedTrainPaletteIgnoringGroup(const Train *v) +{ + return GetEngineColourMap(v->engine_type, v->owner, v->GetGroundVehicleCache()->first_engine, v, true); +} + /** * Delete all implicit orders which were not reached. */ diff --git a/src/vehicle_func.h b/src/vehicle_func.h index 581da57426..c2bccf09a0 100644 --- a/src/vehicle_func.h +++ b/src/vehicle_func.h @@ -183,10 +183,11 @@ static inline bool IsCompanyBuildableVehicleType(const BaseVehicle *v) } LiveryScheme GetEngineLiveryScheme(EngineID engine_type, EngineID parent_engine_type, const Vehicle *v); -const struct Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting); +const struct Livery *GetEngineLivery(EngineID engine_type, CompanyID company, EngineID parent_engine_type, const Vehicle *v, byte livery_setting, bool ignore_group = false); SpriteID GetEnginePalette(EngineID engine_type, CompanyID company); SpriteID GetVehiclePalette(const Vehicle *v); +SpriteID GetUncachedTrainPaletteIgnoringGroup(const Train *v); extern const uint32 _veh_build_proc_table[]; extern const uint32 _veh_sell_proc_table[];