@@ -54,35 +54,38 @@ void RemoveAllEngineReplacement(EngineRe
/**
* Retrieve the engine replacement in a given renewlist for an original engine type.
* @param erl The renewlist to search in.
* @param engine Engine type to be replaced.
* @param group The group related to this replacement.
* @param[out] replace_when_old Set to true if the replacement should be done when old.
* @return The engine type to replace with, or INVALID_ENGINE if no
* replacement is in the list.
*/
EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group)
EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group, bool *replace_when_old)
{
const EngineRenew *er = GetEngineReplacement(erl, engine, group);
if (er == NULL && (group == DEFAULT_GROUP || (Group::IsValidID(group) && !Group::Get(group)->replace_protection))) {
/* We didn't find anything useful in the vehicle's own group so we will try ALL_GROUP */
er = GetEngineReplacement(erl, engine, ALL_GROUP);
}
if (replace_when_old != NULL) *replace_when_old = er == NULL ? false : er->replace_when_old;
return er == NULL ? INVALID_ENGINE : er->to;
* Add an engine replacement to the given renewlist.
* @param erl The renewlist to add to.
* @param old_engine The original engine type.
* @param new_engine The replacement engine type.
* @param replace_when_old Replace when old or always?
* @param flags The calling command flags.
* @return 0 on success, CMD_ERROR on failure.
CommandCost AddEngineReplacement(EngineRenewList *erl, EngineID old_engine, EngineID new_engine, GroupID group, DoCommandFlag flags)
CommandCost AddEngineReplacement(EngineRenewList *erl, EngineID old_engine, EngineID new_engine, GroupID group, bool replace_when_old, DoCommandFlag flags)
/* Check if the old vehicle is already in the list */
EngineRenew *er = GetEngineReplacement(*erl, old_engine, group);
if (er != NULL) {
if (flags & DC_EXEC) er->to = new_engine;
return CommandCost();
@@ -90,12 +93,13 @@ CommandCost AddEngineReplacement(EngineR
if (!EngineRenew::CanAllocateItem()) return CMD_ERROR;
if (flags & DC_EXEC) {
er = new EngineRenew(old_engine, new_engine);
er->group_id = group;
er->replace_when_old = replace_when_old;
/* Insert before the first element */
er->next = (EngineRenew *)(*erl);
*erl = (EngineRenewList)er;
@@ -34,12 +34,13 @@ extern EngineRenewPool _enginerenew_pool
struct EngineRenew : EngineRenewPool::PoolItem<&_enginerenew_pool> {
EngineID from;
EngineID to;
EngineRenew *next;
GroupID group_id;
bool replace_when_old; ///< Do replacement only when vehicle is old.
EngineRenew(EngineID from = INVALID_ENGINE, EngineID to = INVALID_ENGINE) : from(from), to(to) {}
~EngineRenew() {}
};
#define FOR_ALL_ENGINE_RENEWS_FROM(var, start) FOR_ALL_ITEMS_FROM(EngineRenew, enginerenew_index, var, start)
@@ -222,27 +222,30 @@ static CargoID GetNewCargoTypeForReplace
* Get the EngineID of the replacement for a vehicle
* @param v The vehicle to find a replacement for
* @param c The vehicle's owner (it's faster to forward the pointer than refinding it)
* @param always_replace Always replace, even if not old.
* @param [out] e the EngineID of the replacement. INVALID_ENGINE if no replacement is found
* @return Error if the engine to build is not available
static CommandCost GetNewEngineType(const Vehicle *v, const Company *c, EngineID &e)
static CommandCost GetNewEngineType(const Vehicle *v, const Company *c, bool always_replace, EngineID &e)
assert(v->type != VEH_TRAIN || !v->IsArticulatedPart());
e = INVALID_ENGINE;
if (v->type == VEH_TRAIN && Train::From(v)->IsRearDualheaded()) {
/* we build the rear ends of multiheaded trains with the front ones */
e = EngineReplacementForCompany(c, v->engine_type, v->group_id);
bool replace_when_old;
e = EngineReplacementForCompany(c, v->engine_type, v->group_id, &replace_when_old);
if (!always_replace && replace_when_old && !v->NeedsAutorenewing(c, false)) e = INVALID_ENGINE;
/* Autoreplace, if engine is available */
if (e != INVALID_ENGINE && IsEngineBuildable(e, v->type, _current_company)) {
@@ -268,13 +271,13 @@ static CommandCost BuildReplacementVehic
*new_vehicle = NULL;
/* Shall the vehicle be replaced? */
const Company *c = Company::Get(_current_company);
EngineID e;
CommandCost cost = GetNewEngineType(old_veh, c, e);
CommandCost cost = GetNewEngineType(old_veh, c, true, e);
if (cost.Failed()) return cost;
if (e == INVALID_ENGINE) return CommandCost(); // neither autoreplace is set, nor autorenew is triggered
/* Does it need to be refitted */
CargoID refit_cargo = GetNewCargoTypeForReplace(old_veh, e, part_of_chain);
if (refit_cargo == CT_INVALID) return CommandCost(); // incompatible cargoes
@@ -680,13 +683,13 @@ CommandCost CmdAutoreplaceVehicle(TileIn
/* Test whether any replacement is set, before issuing a whole lot of commands that would end in nothing changed */
Vehicle *w = v;
bool any_replacements = false;
while (w != NULL) {
CommandCost cost = GetNewEngineType(w, c, e);
CommandCost cost = GetNewEngineType(w, c, false, e);
any_replacements |= (e != INVALID_ENGINE);
w = (!free_wagon && w->type == VEH_TRAIN ? Train::From(w)->GetNextUnit() : NULL);
CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES, 0);
@@ -733,12 +736,13 @@ CommandCost CmdAutoreplaceVehicle(TileIn
* Change engine renewal parameters
* @param tile unused
* @param flags operation to perform
* @param p1 packed data
* - bit 0 = replace when engine gets old?
* - bits 16-31 = engine group
* @param p2 packed data
* - bits 0-15 = old engine type
* - bits 16-31 = new engine type
* @param text unused
* @return the cost of this operation or an error
@@ -757,13 +761,13 @@ CommandCost CmdSetAutoReplace(TileIndex
if (!Engine::IsValidID(old_engine_type)) return CMD_ERROR;
if (new_engine_type != INVALID_ENGINE) {
if (!Engine::IsValidID(new_engine_type)) return CMD_ERROR;
if (!CheckAutoreplaceValidity(old_engine_type, new_engine_type, _current_company)) return CMD_ERROR;
cost = AddEngineReplacementForCompany(c, old_engine_type, new_engine_type, id_g, flags);
cost = AddEngineReplacementForCompany(c, old_engine_type, new_engine_type, id_g, HasBit(p1, 0), flags);
} else {
cost = RemoveEngineReplacementForCompany(c, old_engine_type, id_g, flags);
if (flags & DC_EXEC) GroupStatistics::UpdateAutoreplace(_current_company);
if ((flags & DC_EXEC) && IsLocalCompany()) InvalidateAutoreplaceWindow(old_engine_type, id_g);
@@ -13,14 +13,14 @@
#define AUTOREPLACE_FUNC_H
#include "command_type.h"
#include "company_base.h"
void RemoveAllEngineReplacement(EngineRenewList *erl);
EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group);
CommandCost AddEngineReplacement(EngineRenewList *erl, EngineID old_engine, EngineID new_engine, GroupID group, DoCommandFlag flags);
EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group, bool *replace_when_old = NULL);
CommandCost AddEngineReplacement(EngineRenewList *erl, EngineID old_engine, EngineID new_engine, GroupID group, bool replace_when_old, DoCommandFlag flags);
CommandCost RemoveEngineReplacement(EngineRenewList *erl, EngineID engine, GroupID group, DoCommandFlag flags);
* Remove all engine replacement settings for the given company.
* @param c the company.
@@ -31,18 +31,19 @@ static inline void RemoveAllEngineReplac
* Retrieve the engine replacement for the given company and original engine type.
* @param c company.
* @param engine Engine type.
static inline EngineID EngineReplacementForCompany(const Company *c, EngineID engine, GroupID group)
static inline EngineID EngineReplacementForCompany(const Company *c, EngineID engine, GroupID group, bool *replace_when_old = NULL)
return EngineReplacement(c->engine_renew_list, engine, group);
return EngineReplacement(c->engine_renew_list, engine, group, replace_when_old);
* Check if a company has a replacement set up for the given engine.
* @param c Company.
@@ -52,23 +53,38 @@ static inline EngineID EngineReplacement
static inline bool EngineHasReplacementForCompany(const Company *c, EngineID engine, GroupID group)
return EngineReplacementForCompany(c, engine, group) != INVALID_ENGINE;
* Check if a company has a replacement set up for the given engine when it gets old.
* @return True if a replacement when old was set up, false otherwise.
static inline bool EngineHasReplacementWhenOldForCompany(const Company *c, EngineID engine, GroupID group)
EngineReplacement(c->engine_renew_list, engine, group, &replace_when_old);
return replace_when_old;
* Add an engine replacement for the company.
static inline CommandCost AddEngineReplacementForCompany(Company *c, EngineID old_engine, EngineID new_engine, GroupID group, DoCommandFlag flags)
static inline CommandCost AddEngineReplacementForCompany(Company *c, EngineID old_engine, EngineID new_engine, GroupID group, bool replace_when_old, DoCommandFlag flags)
return AddEngineReplacement(&c->engine_renew_list, old_engine, new_engine, group, flags);
return AddEngineReplacement(&c->engine_renew_list, old_engine, new_engine, group, replace_when_old, flags);
* Remove an engine replacement for the company.
* @param engine The original engine type.
@@ -21,12 +21,13 @@
#include "engine_base.h"
#include "window_gui.h"
#include "engine_gui.h"
#include "settings_func.h"
#include "core/geometry_func.hpp"
#include "rail_gui.h"
#include "widgets/dropdown_func.h"
#include "widgets/autoreplace_widget.h"
uint GetEngineListHeight(VehicleType type);
void DrawEngineList(VehicleType type, int x, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group);
@@ -64,12 +65,18 @@ void InvalidateAutoreplaceWindow(EngineI
void AddRemoveEngineFromAutoreplaceAndBuildWindows(VehicleType type)
InvalidateWindowData(WC_REPLACE_VEHICLE, type, 0); // Update the autoreplace window
InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well
static const StringID _start_replace_dropdown[] = {
STR_REPLACE_VEHICLES_NOW,
STR_REPLACE_VEHICLES_WHEN_OLD,
INVALID_STRING_ID
* Window for the autoreplacing of vehicles.
class ReplaceVehicleWindow : public Window {
EngineID sel_engine[2]; ///< Selected engine left and right.
GUIEngineList engines[2]; ///< Left and right list of engines.
@@ -167,12 +174,24 @@ class ReplaceVehicleWindow : public Wind
/* Reset the flags about needed updates */
this->engines[0].RebuildDone();
this->engines[1].RebuildDone();
this->reset_sel_engine = false;
* Handle click on the start replace button.
* @param replace_when_old Replace now or only when old?
void ReplaceClick_StartReplace(bool replace_when_old)
EngineID veh_from = this->sel_engine[0];
EngineID veh_to = this->sel_engine[1];
DoCommandP(0, (replace_when_old ? 1 : 0) | (this->sel_group << 16), veh_from + (veh_to << 16), CMD_SET_AUTOREPLACE);
this->SetDirty();
public:
ReplaceVehicleWindow(const WindowDesc *desc, VehicleType vehicletype, GroupID id_g) : Window()
if (vehicletype == VEH_TRAIN) {
/* For rail vehicles find the most used vehicle type, which is usually
* better than 'just' the first/previous vehicle type. */
@@ -267,12 +286,23 @@ public:
d.width += padding.width;
d.height += padding.height;
*size = maxdim(*size, d);
break;
case WID_RV_START_REPLACE: {
Dimension d = GetStringBoundingBox(STR_REPLACE_VEHICLES_START);
for (int i = 0; _start_replace_dropdown[i] != INVALID_STRING_ID; i++) {
d = maxdim(d, GetStringBoundingBox(_start_replace_dropdown[i]));
virtual void SetStringParameters(int widget) const
switch (widget) {
@@ -298,14 +328,16 @@ public:
case WID_RV_INFO_TAB: {
const Company *c = Company::Get(_local_company);
if (this->sel_engine[0] != INVALID_ENGINE) {
if (!EngineHasReplacementForCompany(c, this->sel_engine[0], this->sel_group)) {
SetDParam(0, STR_REPLACE_NOT_REPLACING);
SetDParam(0, STR_ENGINE_NAME);
SetDParam(1, EngineReplacementForCompany(c, this->sel_engine[0], this->sel_group));
bool when_old = false;
EngineID e = EngineReplacementForCompany(c, this->sel_engine[0], this->sel_group, &when_old);
SetDParam(0, when_old ? STR_REPLACE_REPLACING_WHEN_OLD : STR_ENGINE_NAME);
SetDParam(1, e);
SetDParam(0, STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED);
DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMERECT_TOP, STR_BLACK_STRING, TC_FROMSTRING, SA_HOR_CENTER);
@@ -331,30 +363,25 @@ public:
if (this->engines[0].NeedRebuild() || this->engines[1].NeedRebuild()) this->GenerateLists();
Company *c = Company::Get(_local_company);
/* Disable the "Start Replacing" button if:
* Either engines list is empty
* or The selected replacement engine has a replacement (to prevent loops)
* or The right engines list (new replacement) has the existing replacement vehicle selected */
* or The selected replacement engine has a replacement (to prevent loops). */
this->SetWidgetDisabledState(WID_RV_START_REPLACE,
this->sel_engine[0] == INVALID_ENGINE ||
this->sel_engine[1] == INVALID_ENGINE ||
EngineReplacementForCompany(c, this->sel_engine[1], this->sel_group) != INVALID_ENGINE ||
EngineReplacementForCompany(c, this->sel_engine[0], this->sel_group) == this->sel_engine[1]);
EngineReplacementForCompany(c, this->sel_engine[1], this->sel_group) != INVALID_ENGINE);
/* Disable the "Stop Replacing" button if:
* The left engines list (existing vehicle) is empty
* or The selected vehicle has no replacement set up */
this->SetWidgetDisabledState(WID_RV_STOP_REPLACE,
!EngineHasReplacementForCompany(c, this->sel_engine[0], this->sel_group));
/* now the actual drawing of the window itself takes place */
SetDParam(0, STR_REPLACE_VEHICLE_TRAIN + this->window_number);
if (this->window_number == VEH_TRAIN) {
/* sets the colour of that art thing */
this->GetWidget<NWidgetCore>(WID_RV_TRAIN_FLUFF_LEFT)->colour = _company_colours[_local_company];
this->GetWidget<NWidgetCore>(WID_RV_TRAIN_FLUFF_RIGHT)->colour = _company_colours[_local_company];
/* Show the selected railtype in the pulldown menu */
@@ -398,16 +425,19 @@ public:
case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: // toggle renew_keep_length
DoCommandP(0, GetCompanySettingIndex("company.renew_keep_length"), Company::Get(_local_company)->settings.renew_keep_length ? 0 : 1, CMD_CHANGE_COMPANY_SETTING);
case WID_RV_START_REPLACE: { // Start replacing
DoCommandP(0, this->sel_group << 16, veh_from + (veh_to << 16), CMD_SET_AUTOREPLACE);
if (this->GetWidget<NWidgetLeaf>(widget)->ButtonHit(pt)) {
this->HandleButtonClick(WID_RV_START_REPLACE);
ReplaceClick_StartReplace(false);
bool replacment_when_old = EngineHasReplacementWhenOldForCompany(Company::Get(_local_company), this->sel_engine[0], this->sel_group);
ShowDropDownMenu(this, _start_replace_dropdown, replacment_when_old ? 1 : 0, WID_RV_START_REPLACE, !this->replace_engines ? 1 << 1 : 0, 0);
case WID_RV_STOP_REPLACE: { // Stop replacing
DoCommandP(0, this->sel_group << 16, veh_from + (INVALID_ENGINE << 16), CMD_SET_AUTOREPLACE);
@@ -438,23 +468,32 @@ public:
virtual void OnDropdownSelect(int widget, int index)
RailType temp = (RailType)index;
if (temp == sel_railtype) return; // we didn't select a new one. No need to change anything
sel_railtype = temp;
/* Reset scrollbar positions */
this->vscroll[0]->SetPosition(0);
this->vscroll[1]->SetPosition(0);
/* Rebuild the lists */
this->engines[0].ForceRebuild();
this->engines[1].ForceRebuild();
this->reset_sel_engine = true;
case WID_RV_TRAIN_RAILTYPE_DROPDOWN: {
case WID_RV_START_REPLACE:
this->ReplaceClick_StartReplace(index != 0);
virtual void OnResize()
this->vscroll[0]->SetCapacityFromWidget(this, WID_RV_LEFT_MATRIX);
this->vscroll[1]->SetCapacityFromWidget(this, WID_RV_RIGHT_MATRIX);
@@ -494,13 +533,13 @@ static const NWidgetPart _nested_replace
EndContainer(),
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_LEFT_DETAILS), SetMinimalSize(228, 102), SetResize(1, 0), EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_RIGHT_DETAILS), SetMinimalSize(228, 102), SetResize(1, 0), EndContainer(),
NWidget(NWID_HORIZONTAL),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_START_REPLACE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_VEHICLES_START, STR_REPLACE_HELP_START_BUTTON),
NWidget(NWID_PUSHBUTTON_DROPDOWN, COLOUR_GREY, WID_RV_START_REPLACE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_VEHICLES_START, STR_REPLACE_HELP_START_BUTTON),
NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_INFO_TAB), SetMinimalSize(167, 12), SetDataTip(0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB), SetResize(1, 0),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_STOP_REPLACE), SetMinimalSize(150, 12), SetDataTip(STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_TRAIN_ENGINEWAGON_TOGGLE), SetMinimalSize(139, 12), SetDataTip(STR_REPLACE_ENGINE_WAGON_SELECT, STR_REPLACE_ENGINE_WAGON_SELECT_HELP),
@@ -534,13 +573,13 @@ static const NWidgetPart _nested_replace
NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_LEFT_DETAILS), SetMinimalSize(228, 92), SetResize(1, 0), EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_RIGHT_DETAILS), SetMinimalSize(228, 92), SetResize(1, 0), EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY, WID_RV_INFO_TAB), SetMinimalSize(167, 12), SetDataTip(0x0, STR_REPLACE_HELP_REPLACE_INFO_TAB), SetResize(1, 0), EndContainer(),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_RV_STOP_REPLACE), SetMinimalSize(138, 12), SetDataTip(STR_REPLACE_VEHICLES_STOP, STR_REPLACE_HELP_STOP_BUTTON),
NWidget(WWT_RESIZEBOX, COLOUR_GREY),
@@ -3109,15 +3109,18 @@ STR_REPLACE_VEHICLE_SHIP
STR_REPLACE_VEHICLE_AIRCRAFT :Aircraft
STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}Select the engine type to replace
STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}Select the new engine type you would like to use in place of the left selected engine type
STR_REPLACE_VEHICLES_START :{BLACK}Start Replacing Vehicles
STR_REPLACE_VEHICLES_NOW :Replace all vehicles now
STR_REPLACE_VEHICLES_WHEN_OLD :Replace only old vehicles
STR_REPLACE_HELP_START_BUTTON :{BLACK}Press to begin replacement of the left selected engine type with the right selected engine type
STR_REPLACE_NOT_REPLACING :{BLACK}Not replacing
STR_REPLACE_NOT_REPLACING_VEHICLE_SELECTED :{BLACK}No vehicle selected
STR_REPLACE_REPLACING_WHEN_OLD :{ENGINE} when old
STR_REPLACE_VEHICLES_STOP :{BLACK}Stop Replacing Vehicles
STR_REPLACE_HELP_STOP_BUTTON :{BLACK}Press to stop the replacement of the engine type selected on the left
STR_REPLACE_ENGINE_WAGON_SELECT :{BLACK}Replacing: {ORANGE}{STRING}
STR_REPLACE_ENGINE_WAGON_SELECT_HELP :{BLACK}Switch between engine and wagon replacement windows
STR_REPLACE_ENGINES :Engines
@@ -17,12 +17,13 @@
static const SaveLoad _engine_renew_desc[] = {
SLE_VAR(EngineRenew, from, SLE_UINT16),
SLE_VAR(EngineRenew, to, SLE_UINT16),
SLE_REF(EngineRenew, next, REF_ENGINE_RENEWS),
SLE_CONDVAR(EngineRenew, group_id, SLE_UINT16, 60, SL_MAX_VERSION),
SLE_CONDVAR(EngineRenew, replace_when_old, SLE_BOOL, 175, SL_MAX_VERSION),
SLE_END()
static void Save_ERNW()
EngineRenew *er;
@@ -235,14 +235,15 @@
* 169 23816
* 170 23826
* 171 23835
* 172 23947
* 173 23967 1.2.0-RC1
* 174 23973 1.2.x
* 175 24136
extern const uint16 SAVEGAME_VERSION = 174; ///< Current savegame version of OpenTTD.
extern const uint16 SAVEGAME_VERSION = 175; ///< Current savegame version of OpenTTD.
SavegameType _savegame_type; ///< type of savegame we are loading
uint32 _ttdp_version; ///< version of TTDP savegame (if applicable)
uint16 _sl_version; ///< the major savegame version identifier
byte _sl_minor_version; ///< the minor savegame version, DO NOT USE!
@@ -64,23 +64,24 @@ uint16 _returned_mail_refit_capacity; //
VehiclePool _vehicle_pool("Vehicle");
INSTANTIATE_POOL_METHODS(Vehicle)
* Function to tell if a vehicle needs to be autorenewed
* @param *c The vehicle owner
* @param use_renew_setting Should the company renew setting be considered?
* @return true if the vehicle is old enough for replacement
bool Vehicle::NeedsAutorenewing(const Company *c) const
bool Vehicle::NeedsAutorenewing(const Company *c, bool use_renew_setting) const
/* We can always generate the Company pointer when we have the vehicle.
* However this takes time and since the Company pointer is often present
* when this function is called then it's faster to pass the pointer as an
* argument rather than finding it again. */
assert(c == Company::Get(this->owner));
if (!c->settings.engine_renew) return false;
if (use_renew_setting && !c->settings.engine_renew) return false;
if (this->age - this->max_age < (c->settings.engine_renew_months * 30)) return false;
/* Only engines need renewing */
if (this->type == VEH_TRAIN && !Train::From(this)->IsEngine()) return false;
return true;
@@ -128,16 +129,19 @@ bool Vehicle::NeedsServicing() const
* There are a lot more reasons for autoreplace to fail than we can test here reasonably. */
bool pending_replace = false;
Money needed_money = c->settings.engine_renew_money;
if (needed_money > c->money) return false;
for (const Vehicle *v = this; v != NULL; v = (v->type == VEH_TRAIN) ? Train::From(v)->GetNextUnit() : NULL) {
EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id);
bool replace_when_old = false;
EngineID new_engine = EngineReplacementForCompany(c, v->engine_type, v->group_id, &replace_when_old);
/* Check engine availability */
if (new_engine == INVALID_ENGINE || !HasBit(Engine::Get(new_engine)->company_avail, v->owner)) continue;
/* Is the vehicle old if we are not always replacing? */
if (replace_when_old && !v->NeedsAutorenewing(c, false)) continue;
/* Check refittability */
uint32 available_cargo_types, union_mask;
GetArticulatedRefitMasks(new_engine, true, &union_mask, &available_cargo_types);
/* Is there anything to refit? */
if (union_mask != 0) {
@@ -600,13 +600,13 @@ public:
this->service_interval = src->service_interval;
bool HandleBreakdown();
bool NeedsAutorenewing(const Company *c) const;
bool NeedsAutorenewing(const Company *c, bool use_renew_setting = true) const;
bool NeedsServicing() const;
bool NeedsAutomaticServicing() const;
* Determine the location for the station where the vehicle goes to next.
@@ -2047,12 +2047,13 @@ NWidgetLeaf::NWidgetLeaf(WidgetType tp,
case WWT_PUSHTXTBTN:
case WWT_TEXTBTN_2:
case WWT_LABEL:
case WWT_TEXT:
case WWT_MATRIX:
case NWID_BUTTON_DROPDOWN:
case NWID_PUSHBUTTON_DROPDOWN:
case WWT_ARROWBTN:
case WWT_PUSHARROWBTN:
this->SetFill(0, 0);
case WWT_EDITBOX:
@@ -2251,13 +2252,14 @@ void NWidgetLeaf::SetupSmallestSize(Wind
d2.width += extra.width;
d2.height += extra.height;
size = maxdim(size, d2);
case WWT_DROPDOWN:
case NWID_BUTTON_DROPDOWN: {
case NWID_PUSHBUTTON_DROPDOWN: {
static const Dimension extra = {WD_DROPDOWNTEXT_LEFT + WD_DROPDOWNTEXT_RIGHT, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM};
padding = &extra;
if (this->index >= 0) w->SetStringParameters(this->index);
Dimension d2 = GetStringBoundingBox(this->widget_data);
@@ -2377,12 +2379,13 @@ void NWidgetLeaf::Draw(const Window *w)
DrawDropdown(r, this->colour, clicked, this->widget_data);
DrawButtonDropdown(r, this->colour, clicked, (this->disp_flags & ND_DROPDOWN_ACTIVE) != 0, this->widget_data);
default:
NOT_REACHED();
@@ -2579,13 +2582,13 @@ static int MakeNWidget(const NWidgetPart
*biggest_index = max(*biggest_index, (int)parts->u.widget.index);
if (*dest != NULL) return num_used;
assert((parts->type & WWT_MASK) < WWT_LAST || parts->type == NWID_BUTTON_DROPDOWN);
assert((parts->type & WWT_MASK) < WWT_LAST || (parts->type & WWT_MASK) == NWID_BUTTON_DROPDOWN);
*dest = new NWidgetLeaf(parts->type, parts->u.widget.colour, parts->u.widget.index, 0x0, STR_NULL);
num_used++;
parts++;
@@ -99,12 +99,13 @@ enum WidgetType {
WWB_PUSHBUTTON = 1 << 7,
WWT_PUSHBTN = WWT_PANEL | WWB_PUSHBUTTON,
WWT_PUSHTXTBTN = WWT_TEXTBTN | WWB_PUSHBUTTON,
WWT_PUSHIMGBTN = WWT_IMGBTN | WWB_PUSHBUTTON,
WWT_PUSHARROWBTN = WWT_ARROWBTN | WWB_PUSHBUTTON,
NWID_PUSHBUTTON_DROPDOWN = NWID_BUTTON_DROPDOWN | WWB_PUSHBUTTON,
/** Different forms of sizing nested widgets, using NWidgetBase::AssignSizePosition() */
enum SizingType {
ST_SMALLEST, ///< Initialize nested widget tree to smallest size. Also updates \e current_x and \e current_y.
ST_RESIZE, ///< Resize the nested widget tree.
@@ -169,13 +169,13 @@ struct DropdownWindow : Window {
~DropdownWindow()
Window *w2 = FindWindowById(this->parent_wnd_class, this->parent_wnd_num);
if (w2 != NULL) {
if (w2->nested_array != NULL) {
NWidgetCore *nwi2 = w2->GetWidget<NWidgetCore>(this->parent_button);
if (nwi2->type == NWID_BUTTON_DROPDOWN) {
if ((nwi2->type & WWT_MASK) == NWID_BUTTON_DROPDOWN) {
nwi2->disp_flags &= ~ND_DROPDOWN_ACTIVE;
w2->RaiseWidget(this->parent_button);
@@ -355,13 +355,13 @@ void ShowDropDownList(Window *w, DropDow
wi_rect.left = nwi->pos_x;
wi_rect.right = nwi->pos_x + nwi->current_x - 1;
wi_rect.top = nwi->pos_y;
wi_rect.bottom = nwi->pos_y + nwi->current_y - 1;
wi_colour = nwi->colour;
if (nwi->type == NWID_BUTTON_DROPDOWN) {
if ((nwi->type & WWT_MASK) == NWID_BUTTON_DROPDOWN) {
nwi->disp_flags |= ND_DROPDOWN_ACTIVE;
w->LowerWidget(button);
w->SetWidgetDirty(button);
@@ -302,13 +302,13 @@ void CDECL Window::SetWidgetsLoweredStat
* Raise the buttons of the window.
* @param autoraise Raise only the push buttons of the window.
void Window::RaiseButtons(bool autoraise)
for (uint i = 0; i < this->nested_array_size; i++) {
if (this->nested_array[i] != NULL && (this->nested_array[i]->type & ~WWB_PUSHBUTTON) < WWT_LAST &&
if (this->nested_array[i] != NULL && ((this->nested_array[i]->type & ~WWB_PUSHBUTTON) < WWT_LAST || this->nested_array[i]->type == NWID_PUSHBUTTON_DROPDOWN) &&
(!autoraise || (this->nested_array[i]->type & WWB_PUSHBUTTON)) && this->IsWidgetLowered(i)) {
this->RaiseWidget(i);
this->SetWidgetDirty(i);
Status change: