TBTR: Refactor template replacement code
Adjust conditions for re-using existing engines in depot Reduce cost of searching for existing engines in depot Reduce cost of vehicle chain membership tests Improve replacement command error handling Tidy up code in general
This commit is contained in:
@@ -492,7 +492,7 @@ static const Command _command_proc_table[] = {
|
|||||||
DEF_CMD(CmdStartStopVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_START_STOP_VEHICLE
|
DEF_CMD(CmdStartStopVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_START_STOP_VEHICLE
|
||||||
DEF_CMD(CmdMassStartStopVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_MASS_START_STOP
|
DEF_CMD(CmdMassStartStopVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_MASS_START_STOP
|
||||||
DEF_CMD(CmdAutoreplaceVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_AUTOREPLACE_VEHICLE
|
DEF_CMD(CmdAutoreplaceVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_AUTOREPLACE_VEHICLE
|
||||||
DEF_CMD(CmdTemplateReplaceVehicle, 0, CMDT_VEHICLE_MANAGEMENT ), // CMD_TEMPLATE_REPLACE_VEHICLE
|
DEF_CMD(CmdTemplateReplaceVehicle, CMD_NO_TEST, CMDT_VEHICLE_MANAGEMENT ), // CMD_TEMPLATE_REPLACE_VEHICLE
|
||||||
DEF_CMD(CmdDepotSellAllVehicles, 0, CMDT_VEHICLE_CONSTRUCTION ), // CMD_DEPOT_SELL_ALL_VEHICLES
|
DEF_CMD(CmdDepotSellAllVehicles, 0, CMDT_VEHICLE_CONSTRUCTION ), // CMD_DEPOT_SELL_ALL_VEHICLES
|
||||||
DEF_CMD(CmdDepotMassAutoReplace, 0, CMDT_VEHICLE_CONSTRUCTION ), // CMD_DEPOT_MASS_AUTOREPLACE
|
DEF_CMD(CmdDepotMassAutoReplace, 0, CMDT_VEHICLE_CONSTRUCTION ), // CMD_DEPOT_MASS_AUTOREPLACE
|
||||||
DEF_CMD(CmdCreateGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_CREATE_GROUP
|
DEF_CMD(CmdCreateGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_CREATE_GROUP
|
||||||
|
@@ -68,7 +68,7 @@ static void Load_TMPLS()
|
|||||||
int index;
|
int index;
|
||||||
|
|
||||||
while ((index = SlIterateArray()) != -1) {
|
while ((index = SlIterateArray()) != -1) {
|
||||||
TemplateVehicle *tv = new (index) TemplateVehicle(); //TODO:check with veh sl code
|
TemplateVehicle *tv = new (index) TemplateVehicle();
|
||||||
SlObject(tv, GTD());
|
SlObject(tv, GTD());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -658,7 +658,7 @@ public:
|
|||||||
/* Draw the number of trains that still need to be treated by the currently selected template replacement */
|
/* Draw the number of trains that still need to be treated by the currently selected template replacement */
|
||||||
if (tid != INVALID_TEMPLATE) {
|
if (tid != INVALID_TEMPLATE) {
|
||||||
const TemplateVehicle *tv = TemplateVehicle::Get(tid);
|
const TemplateVehicle *tv = TemplateVehicle::Get(tid);
|
||||||
const int num_trains = NumTrainsNeedTemplateReplacement(g_id, tv);
|
const uint num_trains = CountsTrainsNeedingTemplateReplacement(g_id, tv);
|
||||||
// Draw number
|
// Draw number
|
||||||
SetDParam(0, num_trains);
|
SetDParam(0, num_trains);
|
||||||
int inner_right = DrawString(col2 + ScaleGUITrad(4), right - ScaleGUITrad(4), text_y, STR_JUST_INT, num_trains ? TC_ORANGE : TC_GREY, SA_RIGHT);
|
int inner_right = DrawString(col2 + ScaleGUITrad(4), right - ScaleGUITrad(4), text_y, STR_JUST_INT, num_trains ? TC_ORANGE : TC_GREY, SA_RIGHT);
|
||||||
|
@@ -68,9 +68,9 @@ void TemplateVehicleImageDimensions::SetFromTrain(const Train *t)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateVehicle::TemplateVehicle(VehicleType ty, EngineID eid, byte subtypeflag, Owner current_owner)
|
TemplateVehicle::TemplateVehicle(VehicleType type, EngineID eid, Owner current_owner)
|
||||||
{
|
{
|
||||||
this->type = ty;
|
this->type = type;
|
||||||
this->engine_type = eid;
|
this->engine_type = eid;
|
||||||
|
|
||||||
this->reuse_depot_vehicles = false;
|
this->reuse_depot_vehicles = false;
|
||||||
|
@@ -47,7 +47,7 @@ extern TemplatePool _template_pool;
|
|||||||
extern bool _template_vehicle_images_valid;
|
extern bool _template_vehicle_images_valid;
|
||||||
|
|
||||||
/// listing/sorting templates
|
/// listing/sorting templates
|
||||||
typedef GUIList<const TemplateVehicle*> GUITemplateList;
|
typedef GUIList<const TemplateVehicle *> GUITemplateList;
|
||||||
|
|
||||||
struct TemplateVehicleImageDimensions {
|
struct TemplateVehicleImageDimensions {
|
||||||
int reference_width;
|
int reference_width;
|
||||||
@@ -126,7 +126,7 @@ public:
|
|||||||
TemplateVehicleImageDimensions image_dimensions; ///< NOSAVE: image dimensions
|
TemplateVehicleImageDimensions image_dimensions; ///< NOSAVE: image dimensions
|
||||||
SpriteID colourmap; ///< NOSAVE: cached colour mapping
|
SpriteID colourmap; ///< NOSAVE: cached colour mapping
|
||||||
|
|
||||||
TemplateVehicle(VehicleType type = VEH_INVALID, EngineID e = INVALID_ENGINE, byte B = 0, Owner = _local_company);
|
TemplateVehicle(VehicleType type = VEH_INVALID, EngineID e = INVALID_ENGINE, Owner = _local_company);
|
||||||
|
|
||||||
TemplateVehicle(EngineID eid)
|
TemplateVehicle(EngineID eid)
|
||||||
{
|
{
|
||||||
@@ -143,16 +143,16 @@ public:
|
|||||||
|
|
||||||
~TemplateVehicle();
|
~TemplateVehicle();
|
||||||
|
|
||||||
inline TemplateVehicle* Next() const { return this->next; }
|
inline TemplateVehicle *Next() const { return this->next; }
|
||||||
inline TemplateVehicle* Prev() const { return this->previous; }
|
inline TemplateVehicle *Prev() const { return this->previous; }
|
||||||
inline TemplateVehicle* First() const { return this->first; }
|
inline TemplateVehicle *First() const { return this->first; }
|
||||||
|
|
||||||
void SetNext(TemplateVehicle*);
|
void SetNext(TemplateVehicle *v);
|
||||||
void SetPrev(TemplateVehicle*);
|
void SetPrev(TemplateVehicle *v);
|
||||||
void SetFirst(TemplateVehicle*);
|
void SetFirst(TemplateVehicle *v);
|
||||||
|
|
||||||
TemplateVehicle* GetNextUnit() const;
|
TemplateVehicle *GetNextUnit() const;
|
||||||
TemplateVehicle* GetPrevUnit();
|
TemplateVehicle *GetPrevUnit();
|
||||||
|
|
||||||
bool IsSetReuseDepotVehicles() const { return this->reuse_depot_vehicles; }
|
bool IsSetReuseDepotVehicles() const { return this->reuse_depot_vehicles; }
|
||||||
bool IsSetKeepRemainingVehicles() const { return this->keep_remaining_vehicles; }
|
bool IsSetKeepRemainingVehicles() const { return this->keep_remaining_vehicles; }
|
||||||
@@ -176,7 +176,6 @@ public:
|
|||||||
|
|
||||||
inline bool IsFreeWagonChain() const { return HasBit(this->subtype, GVSF_FREE_WAGON); }
|
inline bool IsFreeWagonChain() const { return HasBit(this->subtype, GVSF_FREE_WAGON); }
|
||||||
|
|
||||||
// since CmdBuildTemplateVehicle(...)
|
|
||||||
inline void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); }
|
inline void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); }
|
||||||
inline void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); }
|
inline void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); }
|
||||||
inline void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); }
|
inline void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); }
|
||||||
@@ -206,7 +205,7 @@ struct TemplateReplacement : TemplateReplacementPool::PoolItem<&_template_replac
|
|||||||
GroupID group;
|
GroupID group;
|
||||||
TemplateID sel_template;
|
TemplateID sel_template;
|
||||||
|
|
||||||
TemplateReplacement(GroupID gid, TemplateID tid) { this->group=gid; this->sel_template=tid; }
|
TemplateReplacement(GroupID gid, TemplateID tid) { this->group = gid; this->sel_template = tid; }
|
||||||
TemplateReplacement() {}
|
TemplateReplacement() {}
|
||||||
~TemplateReplacement();
|
~TemplateReplacement();
|
||||||
|
|
||||||
@@ -221,12 +220,12 @@ struct TemplateReplacement : TemplateReplacementPool::PoolItem<&_template_replac
|
|||||||
static void PreCleanPool();
|
static void PreCleanPool();
|
||||||
};
|
};
|
||||||
|
|
||||||
TemplateReplacement* GetTemplateReplacementByGroupID(GroupID);
|
TemplateReplacement *GetTemplateReplacementByGroupID(GroupID gid);
|
||||||
TemplateID GetTemplateIDByGroupID(GroupID);
|
TemplateID GetTemplateIDByGroupID(GroupID gid);
|
||||||
TemplateID GetTemplateIDByGroupIDRecursive(GroupID);
|
TemplateID GetTemplateIDByGroupIDRecursive(GroupID gid);
|
||||||
bool IssueTemplateReplacement(GroupID, TemplateID);
|
bool IssueTemplateReplacement(GroupID gid, TemplateID tid);
|
||||||
|
|
||||||
uint DeleteTemplateReplacementsByGroupID(GroupID);
|
uint DeleteTemplateReplacementsByGroupID(GroupID g_id);
|
||||||
|
|
||||||
void ReindexTemplateReplacements();
|
void ReindexTemplateReplacements();
|
||||||
|
|
||||||
|
@@ -45,48 +45,6 @@
|
|||||||
|
|
||||||
bool _template_vehicle_images_valid = false;
|
bool _template_vehicle_images_valid = false;
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
// debugging printing functions for convenience, usually called from gdb
|
|
||||||
void tbtr_debug_pat()
|
|
||||||
{
|
|
||||||
for (TemplateVehicle *tv : TemplateVehicle::Iterate()) {
|
|
||||||
if (tv->Prev()) continue;
|
|
||||||
tbtr_debug_ptv(tv);
|
|
||||||
printf("__________\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void tbtr_debug_pav()
|
|
||||||
{
|
|
||||||
for (Train *t : Train::Iterate()) {
|
|
||||||
if (t->Previous()) continue;
|
|
||||||
tbtr_debug_pvt(t);
|
|
||||||
printf("__________\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void tbtr_debug_ptv(TemplateVehicle* tv)
|
|
||||||
{
|
|
||||||
if (!tv) return;
|
|
||||||
while (tv->Next() ) {
|
|
||||||
printf("eid:%3d st:%2d tv:%p next:%p cargo: %d cargo_sub: %d\n", tv->engine_type, tv->subtype, tv, tv->Next(), tv->cargo_type, tv->cargo_subtype);
|
|
||||||
tv = tv->Next();
|
|
||||||
}
|
|
||||||
printf("eid:%3d st:%2d tv:%p next:%p cargo: %d cargo_sub: %d\n", tv->engine_type, tv->subtype, tv, tv->Next(), tv->cargo_type, tv->cargo_subtype);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tbtr_debug_pvt (const Train *printme)
|
|
||||||
{
|
|
||||||
for (const Train *tmp = printme; tmp; tmp = tmp->Next()) {
|
|
||||||
if (tmp->index <= 0) {
|
|
||||||
printf("train has weird index: %d %d %p\n", tmp->index, tmp->engine_type, tmp);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
printf("eid:%3d index:%2d subtype:%2d vehstat: %d cargo_t: %d cargo_sub: %d ref:%p\n", tmp->engine_type, tmp->index, tmp->subtype, tmp->vehstatus, tmp->cargo_type, tmp->cargo_subtype, tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void BuildTemplateGuiList(GUITemplateList *list, Scrollbar *vscroll, Owner oid, RailType railtype)
|
void BuildTemplateGuiList(GUITemplateList *list, Scrollbar *vscroll, Owner oid, RailType railtype)
|
||||||
{
|
{
|
||||||
list->clear();
|
list->clear();
|
||||||
@@ -204,14 +162,14 @@ TemplateVehicle* TemplateVehicleFromVirtualTrain(Train *virt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// forward declaration, defined in train_cmd.cpp
|
// forward declaration, defined in train_cmd.cpp
|
||||||
CommandCost CmdSellRailWagon(DoCommandFlag, Vehicle*, uint16, uint32);
|
CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint32 user);
|
||||||
|
|
||||||
Train* DeleteVirtualTrain(Train *chain, Train *to_del) {
|
Train *DeleteVirtualTrain(Train *chain, Train *to_del)
|
||||||
|
{
|
||||||
if (chain != to_del) {
|
if (chain != to_del) {
|
||||||
CmdSellRailWagon(DC_EXEC, to_del, 0, 0);
|
CmdSellRailWagon(DC_EXEC, to_del, 0, 0);
|
||||||
return chain;
|
return chain;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
chain = chain->GetNextUnit();
|
chain = chain->GetNextUnit();
|
||||||
CmdSellRailWagon(DC_EXEC, to_del, 0, 0);
|
CmdSellRailWagon(DC_EXEC, to_del, 0, 0);
|
||||||
return chain;
|
return chain;
|
||||||
@@ -219,13 +177,15 @@ Train* DeleteVirtualTrain(Train *chain, Train *to_del) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// retrieve template vehicle from template replacement that belongs to the given group
|
// retrieve template vehicle from template replacement that belongs to the given group
|
||||||
TemplateVehicle* GetTemplateVehicleByGroupID(GroupID gid) {
|
TemplateVehicle *GetTemplateVehicleByGroupID(GroupID gid)
|
||||||
|
{
|
||||||
if (gid >= NEW_GROUP) return nullptr;
|
if (gid >= NEW_GROUP) return nullptr;
|
||||||
const TemplateID tid = GetTemplateIDByGroupID(gid);
|
const TemplateID tid = GetTemplateIDByGroupID(gid);
|
||||||
return tid != INVALID_TEMPLATE ? TemplateVehicle::GetIfValid(tid) : nullptr;
|
return tid != INVALID_TEMPLATE ? TemplateVehicle::GetIfValid(tid) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateVehicle* GetTemplateVehicleByGroupIDRecursive(GroupID gid) {
|
TemplateVehicle *GetTemplateVehicleByGroupIDRecursive(GroupID gid)
|
||||||
|
{
|
||||||
if (gid >= NEW_GROUP) return nullptr;
|
if (gid >= NEW_GROUP) return nullptr;
|
||||||
const TemplateID tid = GetTemplateIDByGroupIDRecursive(gid);
|
const TemplateID tid = GetTemplateIDByGroupIDRecursive(gid);
|
||||||
return tid != INVALID_TEMPLATE ? TemplateVehicle::GetIfValid(tid) : nullptr;
|
return tid != INVALID_TEMPLATE ? TemplateVehicle::GetIfValid(tid) : nullptr;
|
||||||
@@ -258,30 +218,19 @@ bool TemplateVehicleContainsEngineOfRailtype(const TemplateVehicle *tv, RailType
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//helper
|
Train *ChainContainsEngine(EngineID eid, Train *chain)
|
||||||
bool ChainContainsVehicle(Train *chain, Train *mem)
|
|
||||||
{
|
{
|
||||||
for (; chain; chain = chain->Next()) {
|
for (; chain != nullptr; chain = chain->GetNextUnit()) {
|
||||||
if (chain == mem) {
|
if (chain->engine_type == eid) return chain;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// has O(n)
|
|
||||||
Train* ChainContainsEngine(EngineID eid, Train *chain) {
|
|
||||||
for (; chain; chain=chain->GetNextUnit())
|
|
||||||
if (chain->engine_type == eid)
|
|
||||||
return chain;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsTrainUsableAsTemplateReplacementSource(const Train *t)
|
static bool IsTrainUsableAsTemplateReplacementSource(const Train *t)
|
||||||
{
|
{
|
||||||
if (t->IsFreeWagon()) return true;
|
if (t->First()->IsFreeWagon()) return true;
|
||||||
|
|
||||||
if (t->IsPrimaryVehicle() && t->IsStoppedInDepot()) {
|
if (t->IsPrimaryVehicle() && t->IsStoppedInDepot() && t->GetNextUnit() == nullptr) {
|
||||||
if (t->GetNumOrders() != 0) return false;
|
if (t->GetNumOrders() != 0) return false;
|
||||||
if (t->IsOrderListShared()) return false;
|
if (t->IsOrderListShared()) return false;
|
||||||
if (t->group_id != DEFAULT_GROUP) return false;
|
if (t->group_id != DEFAULT_GROUP) return false;
|
||||||
@@ -291,18 +240,33 @@ static bool IsTrainUsableAsTemplateReplacementSource(const Train *t)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// has O(n^2)
|
void TemplateDepotVehicles::Init(TileIndex tile)
|
||||||
Train* DepotContainsEngine(TileIndex tile, EngineID eid, Train *not_in = nullptr)
|
|
||||||
{
|
{
|
||||||
for (Train *t : Train::Iterate()) {
|
FindVehicleOnPos(tile, VEH_TRAIN, this, [](Vehicle *v, void *data) -> Vehicle * {
|
||||||
|
TemplateDepotVehicles *self = static_cast<TemplateDepotVehicles *>(data);
|
||||||
|
self->vehicles.insert(v->index);
|
||||||
|
return v;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemplateDepotVehicles::RemoveVehicle(VehicleID id)
|
||||||
|
{
|
||||||
|
this->vehicles.erase(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Train *TemplateDepotVehicles::ContainsEngine(EngineID eid, Train *not_in)
|
||||||
|
{
|
||||||
|
for (VehicleID id : this->vehicles) {
|
||||||
|
Train *t = Train::GetIfValid(id);
|
||||||
|
if (t == nullptr) continue;
|
||||||
// conditions: v is stopped in the given depot, has the right engine and if 'not_in' is given v must not be contained within 'not_in'
|
// conditions: v is stopped in the given depot, has the right engine and if 'not_in' is given v must not be contained within 'not_in'
|
||||||
// if 'not_in' is nullptr, no check is needed
|
// if 'not_in' is nullptr, no check is needed
|
||||||
if (t->tile == tile
|
if (t->owner == _current_company
|
||||||
// If the veh belongs to a chain, wagons will not return true on IsStoppedInDepot(), only primary vehicles will
|
// If the veh belongs to a chain, wagons will not return true on IsStoppedInDepot(), only primary vehicles will
|
||||||
// in case of t not a primary veh, we demand it to be a free wagon to consider it for replacement
|
// in case of t not a primary veh, we demand it to be a free wagon to consider it for replacement
|
||||||
&& IsTrainUsableAsTemplateReplacementSource(t)
|
&& IsTrainUsableAsTemplateReplacementSource(t)
|
||||||
&& t->engine_type == eid
|
&& t->engine_type == eid
|
||||||
&& (not_in == nullptr || ChainContainsVehicle(not_in, t) == false)) {
|
&& (not_in == nullptr || not_in->First() != t->First())) {
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -370,9 +334,9 @@ void CopyWagonStatus(TemplateVehicle *from, Train *to)
|
|||||||
to->cargo_subtype = from->cargo_subtype;
|
to->cargo_subtype = from->cargo_subtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
int NumTrainsNeedTemplateReplacement(GroupID g_id, const TemplateVehicle *tv)
|
uint CountsTrainsNeedingTemplateReplacement(GroupID g_id, const TemplateVehicle *tv)
|
||||||
{
|
{
|
||||||
int count = 0;
|
uint count = 0;
|
||||||
if (!tv) return count;
|
if (!tv) return count;
|
||||||
|
|
||||||
for (Train *t : Train::Iterate()) {
|
for (Train *t : Train::Iterate()) {
|
||||||
@@ -382,6 +346,7 @@ int NumTrainsNeedTemplateReplacement(GroupID g_id, const TemplateVehicle *tv)
|
|||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
// refit each vehicle in t as is in tv, assume t and tv contain the same types of vehicles
|
// refit each vehicle in t as is in tv, assume t and tv contain the same types of vehicles
|
||||||
CommandCost CmdRefitTrainFromTemplate(Train *t, TemplateVehicle *tv, DoCommandFlag flags)
|
CommandCost CmdRefitTrainFromTemplate(Train *t, TemplateVehicle *tv, DoCommandFlag flags)
|
||||||
{
|
{
|
||||||
@@ -431,14 +396,14 @@ void TransferCargoForTrain(Train *old_veh, Train *new_head)
|
|||||||
{
|
{
|
||||||
assert(new_head->IsPrimaryVehicle() || new_head->IsFreeWagon());
|
assert(new_head->IsPrimaryVehicle() || new_head->IsFreeWagon());
|
||||||
|
|
||||||
CargoID _cargo_type = old_veh->cargo_type;
|
const CargoID cargo_type = old_veh->cargo_type;
|
||||||
byte _cargo_subtype = old_veh->cargo_subtype;
|
const byte cargo_subtype = old_veh->cargo_subtype;
|
||||||
|
|
||||||
// how much cargo has to be moved (if possible)
|
// how much cargo has to be moved (if possible)
|
||||||
uint remainingAmount = old_veh->cargo.TotalCount();
|
uint remainingAmount = old_veh->cargo.TotalCount();
|
||||||
// each vehicle in the new chain shall be given as much of the old cargo as possible, until none is left
|
// each vehicle in the new chain shall be given as much of the old cargo as possible, until none is left
|
||||||
for (Train *tmp = new_head; tmp != nullptr && remainingAmount > 0; tmp = tmp->GetNextUnit()) {
|
for (Train *tmp = new_head; tmp != nullptr && remainingAmount > 0; tmp = tmp->GetNextUnit()) {
|
||||||
if (tmp->cargo_type == _cargo_type && tmp->cargo_subtype == _cargo_subtype) {
|
if (tmp->cargo_type == cargo_type && tmp->cargo_subtype == cargo_subtype) {
|
||||||
// calculate the free space for new cargo on the current vehicle
|
// calculate the free space for new cargo on the current vehicle
|
||||||
uint curCap = tmp->cargo_cap - tmp->cargo.TotalCount();
|
uint curCap = tmp->cargo_cap - tmp->cargo.TotalCount();
|
||||||
uint moveAmount = std::min(remainingAmount, curCap);
|
uint moveAmount = std::min(remainingAmount, curCap);
|
||||||
@@ -450,11 +415,6 @@ void TransferCargoForTrain(Train *old_veh, Train *new_head)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: needs to be implemented, too
|
|
||||||
// // from autoreplace_cmd.cpp : 121
|
|
||||||
/* Any left-overs will be thrown away, but not their feeder share. */
|
|
||||||
//if (src->cargo_cap < src->cargo.TotalCount()) src->cargo.Truncate(src->cargo.TotalCount() - src->cargo_cap);
|
|
||||||
|
|
||||||
/* Update train weight etc., the old vehicle will be sold anyway */
|
/* Update train weight etc., the old vehicle will be sold anyway */
|
||||||
new_head->ConsistChanged(CCF_LOADUNLOAD);
|
new_head->ConsistChanged(CCF_LOADUNLOAD);
|
||||||
}
|
}
|
||||||
@@ -506,8 +466,7 @@ int GetTemplateVehicleEstimatedMaxAchievableSpeed(const TemplateVehicle *tv, int
|
|||||||
|
|
||||||
if (mass < 1) mass = 1;
|
if (mass < 1) mass = 1;
|
||||||
|
|
||||||
do
|
do {
|
||||||
{
|
|
||||||
max_speed++;
|
max_speed++;
|
||||||
acceleration = GetTrainRealisticAccelerationAtSpeed(max_speed, mass, tv->power, tv->max_te, tv->air_drag, tv->railtype);
|
acceleration = GetTrainRealisticAccelerationAtSpeed(max_speed, mass, tv->power, tv->max_te, tv->air_drag, tv->railtype);
|
||||||
} while (acceleration > 0 && max_speed < speed_cap);
|
} while (acceleration > 0 && max_speed < speed_cap);
|
||||||
|
@@ -12,8 +12,8 @@
|
|||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "window_gui.h"
|
#include "window_gui.h"
|
||||||
|
|
||||||
#include "tbtr_template_vehicle.h"
|
#include "tbtr_template_vehicle.h"
|
||||||
|
#include "3rdparty/cpp-btree/btree_set.h"
|
||||||
|
|
||||||
Train* VirtualTrainFromTemplateVehicle(const TemplateVehicle* tv, StringID &err, uint32 user);
|
Train* VirtualTrainFromTemplateVehicle(const TemplateVehicle* tv, StringID &err, uint32 user);
|
||||||
|
|
||||||
@@ -30,30 +30,28 @@ void SetupTemplateVehicleFromVirtual(TemplateVehicle *tmp, TemplateVehicle *prev
|
|||||||
|
|
||||||
CommandCost CmdTemplateReplaceVehicle(Train*, bool, DoCommandFlag);
|
CommandCost CmdTemplateReplaceVehicle(Train*, bool, DoCommandFlag);
|
||||||
|
|
||||||
#ifdef _DEBUG
|
TemplateVehicle *GetTemplateVehicleByGroupID(GroupID gid);
|
||||||
// for testing
|
TemplateVehicle *GetTemplateVehicleByGroupIDRecursive(GroupID gid);
|
||||||
void tbtr_debug_pat();
|
Train *ChainContainsEngine(EngineID eid, Train *chain);
|
||||||
void tbtr_debug_pav();
|
|
||||||
void tbtr_debug_ptv(TemplateVehicle*);
|
|
||||||
void tbtr_debug_pvt(const Train*);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TemplateVehicle* GetTemplateVehicleByGroupID(GroupID);
|
struct TemplateDepotVehicles {
|
||||||
TemplateVehicle* GetTemplateVehicleByGroupIDRecursive(GroupID);
|
btree::btree_set<VehicleID> vehicles;
|
||||||
bool ChainContainsVehicle(Train*, Train*);
|
|
||||||
Train* ChainContainsEngine(EngineID, Train*);
|
|
||||||
Train* DepotContainsEngine(TileIndex, EngineID, Train*);
|
|
||||||
|
|
||||||
int NumTrainsNeedTemplateReplacement(GroupID, const TemplateVehicle*);
|
void Init(TileIndex tile);
|
||||||
|
void RemoveVehicle(VehicleID id);
|
||||||
|
Train* ContainsEngine(EngineID eid, Train *not_in);
|
||||||
|
};
|
||||||
|
|
||||||
|
uint CountsTrainsNeedingTemplateReplacement(GroupID g_id, const TemplateVehicle *tv);
|
||||||
|
|
||||||
CommandCost TestBuyAllTemplateVehiclesInChain(TemplateVehicle *tv, TileIndex tile);
|
CommandCost TestBuyAllTemplateVehiclesInChain(TemplateVehicle *tv, TileIndex tile);
|
||||||
|
|
||||||
CommandCost CmdRefitTrainFromTemplate(Train *t, TemplateVehicle *tv, DoCommandFlag);
|
CommandCost CmdRefitTrainFromTemplate(Train *t, TemplateVehicle *tv, DoCommandFlag flags);
|
||||||
void BreakUpRemainders(Train *t);
|
void BreakUpRemainders(Train *t);
|
||||||
|
|
||||||
bool TemplateVehicleContainsEngineOfRailtype(const TemplateVehicle*, RailType);
|
bool TemplateVehicleContainsEngineOfRailtype(const TemplateVehicle *tv, RailType type);
|
||||||
|
|
||||||
void TransferCargoForTrain(Train*, Train*);
|
void TransferCargoForTrain(Train *old_veh, Train *new_head);
|
||||||
|
|
||||||
void NeutralizeStatus(Train *t);
|
void NeutralizeStatus(Train *t);
|
||||||
|
|
||||||
|
@@ -7075,51 +7075,42 @@ void ClearVehicleWindows(const Train *v)
|
|||||||
*/
|
*/
|
||||||
CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
|
||||||
{
|
{
|
||||||
VehicleID vehicle_id = p1;
|
Train *incoming = Train::GetIfValid(p1);
|
||||||
|
|
||||||
Vehicle* vehicle = Vehicle::GetIfValid(vehicle_id);
|
if (incoming == nullptr) {
|
||||||
|
|
||||||
if (vehicle == nullptr || vehicle->type != VEH_TRAIN) {
|
|
||||||
return CMD_ERROR;
|
return CMD_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool should_execute = (flags & DC_EXEC) != 0;
|
if (!(flags & DC_EXEC)) {
|
||||||
|
|
||||||
if (!should_execute) {
|
|
||||||
return CommandCost();
|
return CommandCost();
|
||||||
}
|
}
|
||||||
|
|
||||||
Train* incoming = Train::From(vehicle);
|
const bool leave_depot = (p2 != 0);
|
||||||
bool leaveDepot = (p2 != 0);
|
auto guard = scope_guard([&]() {
|
||||||
|
_new_vehicle_id = incoming->index;
|
||||||
|
if (leave_depot) incoming->vehstatus &= ~VS_STOPPED;
|
||||||
|
});
|
||||||
|
|
||||||
Train *new_chain = nullptr;
|
Train *new_chain = nullptr;
|
||||||
Train *remainder_chain = nullptr;
|
Train *remainder_chain = nullptr;
|
||||||
Train *tmp_chain = nullptr;
|
|
||||||
TemplateVehicle *tv = GetTemplateVehicleByGroupIDRecursive(incoming->group_id);
|
TemplateVehicle *tv = GetTemplateVehicleByGroupIDRecursive(incoming->group_id);
|
||||||
if (tv == nullptr) {
|
if (tv == nullptr) {
|
||||||
if (leaveDepot) incoming->vehstatus &= ~VS_STOPPED;
|
|
||||||
return CMD_ERROR;
|
return CMD_ERROR;
|
||||||
}
|
}
|
||||||
EngineID eid = tv->engine_type;
|
EngineID eid = tv->engine_type;
|
||||||
|
|
||||||
_new_vehicle_id = p1;
|
|
||||||
|
|
||||||
CommandCost buy(EXPENSES_NEW_VEHICLES);
|
|
||||||
CommandCost move_cost(EXPENSES_NEW_VEHICLES);
|
|
||||||
CommandCost tmp_result(EXPENSES_NEW_VEHICLES);
|
CommandCost tmp_result(EXPENSES_NEW_VEHICLES);
|
||||||
|
|
||||||
|
|
||||||
/* first some tests on necessity and sanity */
|
/* first some tests on necessity and sanity */
|
||||||
if (tv == nullptr) return buy;
|
if (tv == nullptr) return CommandCost();
|
||||||
if (tv->IsReplaceOldOnly() && !vehicle->NeedsAutorenewing(Company::Get(vehicle->owner), false)) {
|
if (tv->IsReplaceOldOnly() && !incoming->NeedsAutorenewing(Company::Get(incoming->owner), false)) {
|
||||||
if (leaveDepot) incoming->vehstatus &= ~VS_STOPPED;
|
return CommandCost();
|
||||||
return buy;
|
|
||||||
}
|
}
|
||||||
bool need_replacement = !TrainMatchesTemplate(incoming, tv);
|
bool need_replacement = !TrainMatchesTemplate(incoming, tv);
|
||||||
bool need_refit = !TrainMatchesTemplateRefit(incoming, tv);
|
bool need_refit = !TrainMatchesTemplateRefit(incoming, tv);
|
||||||
bool use_refit = tv->refit_as_template;
|
bool use_refit = tv->refit_as_template;
|
||||||
CargoID store_refit_ct = CT_INVALID;
|
CargoID store_refit_ct = CT_INVALID;
|
||||||
short store_refit_csubt = 0;
|
uint16 store_refit_csubt = 0;
|
||||||
// if a train shall keep its old refit, store the refit setting of its first vehicle
|
// if a train shall keep its old refit, store the refit setting of its first vehicle
|
||||||
if (!use_refit) {
|
if (!use_refit) {
|
||||||
for (Train *getc = incoming; getc != nullptr; getc = getc->GetNextUnit()) {
|
for (Train *getc = incoming; getc != nullptr; getc = getc->GetNextUnit()) {
|
||||||
@@ -7130,30 +7121,26 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: set result status to success/no success before returning
|
|
||||||
if (!need_replacement) {
|
if (!need_replacement) {
|
||||||
if (!need_refit || !use_refit) {
|
if (!need_refit || !use_refit) {
|
||||||
/* before returning, release incoming train first if 2nd param says so */
|
return CommandCost();
|
||||||
if (leaveDepot) incoming->vehstatus &= ~VS_STOPPED;
|
|
||||||
return buy;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
CommandCost buyCost = TestBuyAllTemplateVehiclesInChain(tv, tile);
|
CommandCost buy_cost = TestBuyAllTemplateVehiclesInChain(tv, tile);
|
||||||
if (!buyCost.Succeeded()) {
|
if (buy_cost.Failed()) {
|
||||||
if (leaveDepot) incoming->vehstatus &= ~VS_STOPPED;
|
if (buy_cost.GetErrorMessage() == INVALID_STRING_ID) return CommandCost(STR_ERROR_CAN_T_BUY_TRAIN);
|
||||||
if (buyCost.GetErrorMessage() == INVALID_STRING_ID) return_cmd_error(STR_ERROR_CAN_T_BUY_TRAIN);
|
return buy_cost;
|
||||||
return buyCost;
|
} else if (!CheckCompanyHasMoney(buy_cost)) {
|
||||||
} else if (!CheckCompanyHasMoney(buyCost)) {
|
return CommandCost(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY);
|
||||||
if (leaveDepot) incoming->vehstatus &= ~VS_STOPPED;
|
|
||||||
return_cmd_error(STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_replacement || (need_refit && use_refit)) RegisterGameEvents(GEF_TBTR_REPLACEMENT);
|
if (need_replacement || (need_refit && use_refit)) RegisterGameEvents(GEF_TBTR_REPLACEMENT);
|
||||||
|
|
||||||
/* define replacement behavior */
|
TemplateDepotVehicles depot_vehicles;
|
||||||
bool reuseDepot = tv->IsSetReuseDepotVehicles();
|
if (tv->IsSetReuseDepotVehicles()) depot_vehicles.Init(tile);
|
||||||
bool keepRemainders = tv->IsSetKeepRemainingVehicles();
|
|
||||||
|
CommandCost buy(EXPENSES_NEW_VEHICLES);
|
||||||
|
|
||||||
if (need_replacement) {
|
if (need_replacement) {
|
||||||
// step 1: generate primary for newchain and generate remainder_chain
|
// step 1: generate primary for newchain and generate remainder_chain
|
||||||
@@ -7163,46 +7150,70 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3
|
|||||||
// 3. primary might be available as orphan vehicle in the depot
|
// 3. primary might be available as orphan vehicle in the depot
|
||||||
// 4. we need to buy a new engine for the primary
|
// 4. we need to buy a new engine for the primary
|
||||||
// all options other than 1. need to make sure to copy incoming's primary's status
|
// all options other than 1. need to make sure to copy incoming's primary's status
|
||||||
if (eid == incoming->engine_type) { // 1
|
auto setup_head = [&]() -> CommandCost {
|
||||||
new_chain = incoming;
|
/* Case 1 */
|
||||||
remainder_chain = incoming->GetNextUnit();
|
if (eid == incoming->engine_type) {
|
||||||
if (remainder_chain) {
|
new_chain = incoming;
|
||||||
move_cost.AddCost(CmdMoveRailVehicle(tile, flags, remainder_chain->index | (1 << 20), INVALID_VEHICLE, 0));
|
remainder_chain = incoming->GetNextUnit();
|
||||||
|
if (remainder_chain) {
|
||||||
|
CommandCost move_cost = CmdMoveRailVehicle(tile, flags, remainder_chain->index | (1 << 20), INVALID_VEHICLE, 0);
|
||||||
|
if (move_cost.Failed()) {
|
||||||
|
/* This should not fail, if it does give up immediately */
|
||||||
|
return move_cost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CommandCost();
|
||||||
}
|
}
|
||||||
} else if ((tmp_chain = ChainContainsEngine(eid, incoming)) && tmp_chain != nullptr) { // 2
|
|
||||||
// new_chain is the needed engine, move it to an empty spot in the depot
|
/* Case 2 */
|
||||||
new_chain = tmp_chain;
|
new_chain = ChainContainsEngine(eid, incoming);
|
||||||
if (flags & DC_EXEC) ClearVehicleWindows(tmp_chain);
|
if (new_chain != nullptr) {
|
||||||
move_cost.AddCost(DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags, CMD_MOVE_RAIL_VEHICLE));
|
/* new_chain is the needed engine, move it to an empty spot in the depot */
|
||||||
remainder_chain = incoming;
|
CommandCost move_cost = DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags, CMD_MOVE_RAIL_VEHICLE);
|
||||||
} else if (reuseDepot && (tmp_chain = DepotContainsEngine(tile, eid, incoming)) && tmp_chain != nullptr) { // 3
|
if (move_cost.Succeeded()) {
|
||||||
new_chain = tmp_chain;
|
remainder_chain = incoming;
|
||||||
if (flags & DC_EXEC) ClearVehicleWindows(tmp_chain);
|
return CommandCost();
|
||||||
move_cost.AddCost(DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags, CMD_MOVE_RAIL_VEHICLE));
|
}
|
||||||
remainder_chain = incoming;
|
}
|
||||||
} else { // 4
|
|
||||||
tmp_result = DoCommand(tile, eid, 0, flags, CMD_BUILD_VEHICLE);
|
/* Case 3 */
|
||||||
|
if (tv->IsSetReuseDepotVehicles()) {
|
||||||
|
new_chain = depot_vehicles.ContainsEngine(eid, incoming);
|
||||||
|
if (new_chain != nullptr) {
|
||||||
|
ClearVehicleWindows(new_chain);
|
||||||
|
CommandCost move_cost = DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags, CMD_MOVE_RAIL_VEHICLE);
|
||||||
|
if (move_cost.Succeeded()) {
|
||||||
|
depot_vehicles.RemoveVehicle(new_chain->index);
|
||||||
|
remainder_chain = incoming;
|
||||||
|
return CommandCost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Case 4 */
|
||||||
|
CommandCost buy_cost = DoCommand(tile, eid | (1 << 16), 0, flags, CMD_BUILD_VEHICLE);
|
||||||
/* break up in case buying the vehicle didn't succeed */
|
/* break up in case buying the vehicle didn't succeed */
|
||||||
if (!tmp_result.Succeeded()) {
|
if (buy_cost.Failed()) {
|
||||||
return tmp_result;
|
return buy_cost;
|
||||||
}
|
}
|
||||||
buy.AddCost(tmp_result);
|
buy.AddCost(buy_cost);
|
||||||
new_chain = Train::Get(_new_vehicle_id);
|
new_chain = Train::Get(_new_vehicle_id);
|
||||||
/* make sure the newly built engine is not attached to any free wagons inside the depot */
|
|
||||||
move_cost.AddCost(DoCommand(tile, new_chain->index, INVALID_VEHICLE, flags, CMD_MOVE_RAIL_VEHICLE));
|
|
||||||
/* prepare the remainder chain */
|
/* prepare the remainder chain */
|
||||||
remainder_chain = incoming;
|
remainder_chain = incoming;
|
||||||
}
|
return CommandCost();
|
||||||
|
};
|
||||||
|
CommandCost head_result = setup_head();
|
||||||
|
if (head_result.Failed()) return head_result;
|
||||||
|
|
||||||
// If we bought a new engine or reused one from the depot, copy some parameters from the incoming primary engine
|
// If we bought a new engine or reused one from the depot, copy some parameters from the incoming primary engine
|
||||||
if (incoming != new_chain && flags == DC_EXEC) {
|
if (incoming != new_chain) {
|
||||||
CopyHeadSpecificThings(incoming, new_chain, flags);
|
CopyHeadSpecificThings(incoming, new_chain, flags);
|
||||||
NeutralizeStatus(incoming);
|
NeutralizeStatus(incoming);
|
||||||
|
|
||||||
// additionally, if we don't want to use the template refit, refit as incoming
|
// additionally, if we don't want to use the template refit, refit as incoming
|
||||||
// the template refit will be set further down, if we use it at all
|
// the template refit will be set further down, if we use it at all
|
||||||
if (!use_refit) {
|
if (!use_refit) {
|
||||||
uint32 cb = GetCmdRefitVeh(new_chain);
|
buy.AddCost(DoCommand(new_chain->tile, new_chain->index, store_refit_ct | store_refit_csubt << 8 | (1 << 16) | (1 << 31), flags, GetCmdRefitVeh(new_chain)));
|
||||||
DoCommand(new_chain->tile, new_chain->index, store_refit_ct | store_refit_csubt << 8 | (1 << 16) | (1 << 31), flags, cb);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7211,55 +7222,76 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3
|
|||||||
// 1. needed engine might be within remainder_chain already
|
// 1. needed engine might be within remainder_chain already
|
||||||
// 2. needed engine might be orphaned within the depot (copy status)
|
// 2. needed engine might be orphaned within the depot (copy status)
|
||||||
// 3. we need to buy (again) (copy status)
|
// 3. we need to buy (again) (copy status)
|
||||||
TemplateVehicle *cur_tmpl = tv->GetNextUnit();
|
|
||||||
Train *last_veh = new_chain;
|
Train *last_veh = new_chain;
|
||||||
while (cur_tmpl) {
|
for (TemplateVehicle *cur_tmpl = tv->GetNextUnit(); cur_tmpl != nullptr; cur_tmpl = cur_tmpl->GetNextUnit()) {
|
||||||
// 1. engine contained in remainder chain
|
Train *new_part = nullptr;
|
||||||
if ((tmp_chain = ChainContainsEngine(cur_tmpl->engine_type, remainder_chain)) && tmp_chain != nullptr) {
|
auto setup_chain_part = [&]() {
|
||||||
// advance remainder_chain (if necessary) to not lose track of it
|
/* Case 1: engine contained in remainder chain */
|
||||||
if (tmp_chain == remainder_chain) {
|
new_part = ChainContainsEngine(cur_tmpl->engine_type, remainder_chain);
|
||||||
remainder_chain = remainder_chain->GetNextUnit();
|
if (new_part != nullptr) {
|
||||||
|
Train *remainder_chain_next = remainder_chain;
|
||||||
|
if (new_part == remainder_chain) {
|
||||||
|
remainder_chain_next = remainder_chain->GetNextUnit();
|
||||||
|
}
|
||||||
|
CommandCost move_cost = CmdMoveRailVehicle(tile, flags, new_part->index, last_veh->index, 0);
|
||||||
|
if (move_cost.Succeeded()) {
|
||||||
|
remainder_chain = remainder_chain_next;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
move_cost.AddCost(CmdMoveRailVehicle(tile, flags, tmp_chain->index, last_veh->index, 0));
|
|
||||||
}
|
/* Case 2: engine contained somewhere else in the depot */
|
||||||
// 2. engine contained somewhere else in the depot
|
if (tv->IsSetReuseDepotVehicles()) {
|
||||||
else if (reuseDepot && (tmp_chain = DepotContainsEngine(tile, cur_tmpl->engine_type, new_chain)) && tmp_chain != nullptr) {
|
new_part = depot_vehicles.ContainsEngine(cur_tmpl->engine_type, new_chain);
|
||||||
move_cost.AddCost(CmdMoveRailVehicle(tile, flags, tmp_chain->index, last_veh->index, 0));
|
if (new_part != nullptr) {
|
||||||
}
|
CommandCost move_cost = CmdMoveRailVehicle(tile, flags, new_part->index, last_veh->index, 0);
|
||||||
// 3. must buy new engine
|
if (move_cost.Succeeded()) {
|
||||||
else {
|
depot_vehicles.RemoveVehicle(new_part->index);
|
||||||
tmp_result = DoCommand(tile, cur_tmpl->engine_type, 0, flags, CMD_BUILD_VEHICLE);
|
return;
|
||||||
if (!tmp_result.Succeeded()) {
|
}
|
||||||
return tmp_result;
|
}
|
||||||
}
|
}
|
||||||
buy.AddCost(tmp_result);
|
|
||||||
tmp_chain = Train::Get(_new_vehicle_id);
|
/* Case 3: must buy new engine */
|
||||||
move_cost.AddCost(CmdMoveRailVehicle(tile, flags, tmp_chain->index, last_veh->index, 0));
|
CommandCost buy_cost = DoCommand(tile, cur_tmpl->engine_type | (1 << 16), 0, flags, CMD_BUILD_VEHICLE);
|
||||||
|
if (buy_cost.Failed()) {
|
||||||
|
new_part = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
new_part = Train::Get(_new_vehicle_id);
|
||||||
|
CommandCost move_cost = CmdMoveRailVehicle(tile, flags, new_part->index, last_veh->index, 0);
|
||||||
|
if (move_cost.Succeeded()) {
|
||||||
|
buy.AddCost(buy_cost);
|
||||||
|
} else {
|
||||||
|
DoCommand(tile, new_part->index, 0, flags, CMD_SELL_VEHICLE);
|
||||||
|
new_part = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
setup_chain_part();
|
||||||
|
if (new_part != nullptr) {
|
||||||
|
last_veh = new_part;
|
||||||
}
|
}
|
||||||
// TODO: is this enough ? might it be that we bought a new wagon here and it now has std refit ?
|
// TODO: is this enough ? might it be that we bought a new wagon here and it now has std refit ?
|
||||||
if (need_refit && flags == DC_EXEC) {
|
if (need_refit && new_part != nullptr) {
|
||||||
if (use_refit) {
|
if (use_refit) {
|
||||||
uint32 cb = GetCmdRefitVeh(tmp_chain);
|
DoCommand(tile, new_part->index, cur_tmpl->cargo_type | (cur_tmpl->cargo_subtype << 8) | (1 << 16) | (1 << 31), flags, GetCmdRefitVeh(new_part));
|
||||||
DoCommand(tmp_chain->tile, tmp_chain->index, cur_tmpl->cargo_type | (cur_tmpl->cargo_subtype << 8) | (1 << 16) | (1 << 31), flags, cb);
|
|
||||||
} else {
|
} else {
|
||||||
uint32 cb = GetCmdRefitVeh(tmp_chain);
|
DoCommand(tile, new_part->index, store_refit_ct | (store_refit_csubt << 8) | (1 << 16) | (1 << 31), flags, GetCmdRefitVeh(new_part));
|
||||||
DoCommand(tmp_chain->tile, tmp_chain->index, store_refit_ct | (store_refit_csubt << 8) | (1 << 16) | (1 << 31), flags, cb);
|
|
||||||
}
|
}
|
||||||
if (HasBit(tmp_chain->flags, VRF_REVERSE_DIRECTION) != HasBit(cur_tmpl->ctrl_flags, TVCF_REVERSED)) {
|
if (HasBit(new_part->flags, VRF_REVERSE_DIRECTION) != HasBit(cur_tmpl->ctrl_flags, TVCF_REVERSED)) {
|
||||||
DoCommand(tmp_chain->tile, tmp_chain->index, true, flags, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE));
|
DoCommand(tile, new_part->index, true, flags, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cur_tmpl = cur_tmpl->GetNextUnit();
|
|
||||||
last_veh = tmp_chain;
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
/* no replacement done */
|
/* no replacement done */
|
||||||
else {
|
|
||||||
new_chain = incoming;
|
new_chain = incoming;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// step 3: reorder and neutralize the remaining vehicles from incoming
|
/// step 3: reorder and neutralize the remaining vehicles from incoming
|
||||||
// wagons remaining from remainder_chain should be filled up in as few freewagonchains as possible
|
// wagons remaining from remainder_chain should be filled up in as few free wagon chains as possible
|
||||||
// each locos might be left as singular in the depot
|
// each loco might be left as singular in the depot
|
||||||
// neutralize each remaining engine's status
|
// neutralize each remaining engine's status
|
||||||
|
|
||||||
// refit, only if the template option is set so
|
// refit, only if the template option is set so
|
||||||
@@ -7268,18 +7300,15 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (new_chain && remainder_chain) {
|
if (new_chain && remainder_chain) {
|
||||||
for (Train *ct = remainder_chain; ct; ct = ct->GetNextUnit()) {
|
for (Train *ct = remainder_chain; ct != nullptr; ct = ct->Next()) {
|
||||||
TransferCargoForTrain(ct, new_chain);
|
TransferCargoForTrain(ct, new_chain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// point incoming to the newly created train so that starting/stopping from the calling function can be done
|
// point incoming to the newly created train so that starting/stopping affects the replacement train
|
||||||
incoming = new_chain;
|
incoming = new_chain;
|
||||||
if (leaveDepot && flags == DC_EXEC) {
|
|
||||||
new_chain->vehstatus &= ~VS_STOPPED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (remainder_chain && keepRemainders && flags == DC_EXEC) {
|
if (remainder_chain && tv->IsSetKeepRemainingVehicles()) {
|
||||||
BreakUpRemainders(remainder_chain);
|
BreakUpRemainders(remainder_chain);
|
||||||
} else if (remainder_chain) {
|
} else if (remainder_chain) {
|
||||||
buy.AddCost(DoCommand(tile, remainder_chain->index | (1 << 20), 0, flags, CMD_SELL_VEHICLE));
|
buy.AddCost(DoCommand(tile, remainder_chain->index | (1 << 20), 0, flags, CMD_SELL_VEHICLE));
|
||||||
@@ -7288,8 +7317,6 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3
|
|||||||
/* Redraw main gui for changed statistics */
|
/* Redraw main gui for changed statistics */
|
||||||
SetWindowClassesDirty(WC_TEMPLATEGUI_MAIN);
|
SetWindowClassesDirty(WC_TEMPLATEGUI_MAIN);
|
||||||
|
|
||||||
_new_vehicle_id = new_chain->index;
|
|
||||||
|
|
||||||
return buy;
|
return buy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1638,12 +1638,14 @@ void CallVehicleTicks()
|
|||||||
|
|
||||||
tmpl_cur_company.Change(t->owner);
|
tmpl_cur_company.Change(t->owner);
|
||||||
|
|
||||||
|
_new_vehicle_id = INVALID_VEHICLE;
|
||||||
|
|
||||||
t->vehstatus |= VS_STOPPED;
|
t->vehstatus |= VS_STOPPED;
|
||||||
CommandCost res = DoCommand(t->tile, t->index, leaveDepot ? 1 : 0, DC_EXEC, CMD_TEMPLATE_REPLACE_VEHICLE);
|
CommandCost res = DoCommand(t->tile, t->index, leaveDepot ? 1 : 0, DC_EXEC, CMD_TEMPLATE_REPLACE_VEHICLE);
|
||||||
|
|
||||||
if (res.Succeeded()) {
|
if (_new_vehicle_id != INVALID_VEHICLE) {
|
||||||
VehicleID t_new = _new_vehicle_id;
|
VehicleID t_new = _new_vehicle_id;
|
||||||
t = Train::From(Vehicle::Get(t_new));
|
t = Train::Get(t_new);
|
||||||
const Company *c = Company::Get(_current_company);
|
const Company *c = Company::Get(_current_company);
|
||||||
SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->settings.engine_renew_money));
|
SubtractMoneyFromCompany(CommandCost(EXPENSES_NEW_VEHICLES, (Money)c->settings.engine_renew_money));
|
||||||
CommandCost res2 = DoCommand(0, t_new, 1, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
|
CommandCost res2 = DoCommand(0, t_new, 1, DC_EXEC, CMD_AUTOREPLACE_VEHICLE);
|
||||||
@@ -1653,14 +1655,13 @@ void CallVehicleTicks()
|
|||||||
|
|
||||||
if (!IsLocalCompany()) continue;
|
if (!IsLocalCompany()) continue;
|
||||||
|
|
||||||
if (res.Succeeded()) {
|
if (res.GetCost() != 0) {
|
||||||
if (res.GetCost() != 0) {
|
ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
|
||||||
ShowCostOrIncomeAnimation(x, y, z, res.GetCost());
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ShowAutoReplaceAdviceMessage(res, t);
|
if (res.Failed()) {
|
||||||
|
ShowAutoReplaceAdviceMessage(res, t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tmpl_cur_company.Restore();
|
tmpl_cur_company.Restore();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user