diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 99900913f0a..2e9ffda7e69 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -7175,10 +7175,6 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3 return CMD_ERROR; } - if (!(flags & DC_EXEC)) { - return CommandCost(); - } - CommandCost buy(EXPENSES_NEW_VEHICLES); const bool was_stopped = (incoming->vehstatus & VS_STOPPED) != 0; @@ -7235,8 +7231,6 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3 } } - RegisterGameEvents(GEF_TBTR_REPLACEMENT); - TemplateDepotVehicles depot_vehicles; if (tv->IsSetReuseDepotVehicles()) depot_vehicles.Init(tile); @@ -7245,6 +7239,60 @@ CommandCost CmdTemplateReplaceVehicle(TileIndex tile, DoCommandFlag flags, uint3 if (refit_cost.Succeeded()) buy.AddCost(refit_cost); }; + if (!(flags & DC_EXEC)) { + /* Simplified operation for cost estimation, this doesn't have to exactly match the actual cost due to CMD_NO_TEST */ + if (need_replacement || need_refit) { + std::vector in; + for (const Train *u = incoming; u != nullptr; u = u->GetNextUnit()) { + in.push_back(u); + } + auto process_unit = [&](const TemplateVehicle *cur_tmpl) { + for (auto iter = in.begin(); iter != in.end(); ++iter) { + const Train *u = *iter; + if (u->engine_type == cur_tmpl->engine_type) { + /* use existing engine */ + in.erase(iter); + if (refit_to_template) { + buy.AddCost(DoCommand(u->tile, u->index, cur_tmpl->cargo_type | cur_tmpl->cargo_subtype << 8 | (1 << 16) | (1 << 31), flags, GetCmdRefitVeh(u))); + } else { + refit_unit(u, store_refit_ct, store_refit_csubt); + } + return; + } + } + + if (tv->IsSetReuseDepotVehicles()) { + const Train *depot_eng = depot_vehicles.ContainsEngine(cur_tmpl->engine_type, incoming); + if (depot_eng != nullptr) { + depot_vehicles.RemoveVehicle(depot_eng->index); + if (refit_to_template) { + buy.AddCost(DoCommand(depot_eng->tile, depot_eng->index, cur_tmpl->cargo_type | cur_tmpl->cargo_subtype << 8 | (1 << 16) | (1 << 31), flags, GetCmdRefitVeh(depot_eng))); + } else { + refit_unit(depot_eng, store_refit_ct, store_refit_csubt); + } + return; + } + } + + CargoID refit_cargo = refit_to_template ? cur_tmpl->cargo_type : store_refit_ct; + uint32 refit_cmd = (refit_cargo != CT_INVALID) ? (refit_cargo << 24) : 0; + buy.AddCost(DoCommand(tile, cur_tmpl->engine_type | (1 << 16) | refit_cmd, 0, flags, CMD_BUILD_VEHICLE)); + }; + for (const TemplateVehicle *cur_tmpl = tv; cur_tmpl != nullptr; cur_tmpl = cur_tmpl->GetNextUnit()) { + process_unit(cur_tmpl); + } + if (!tv->IsSetKeepRemainingVehicles()) { + /* Sell leftovers */ + for (const Train *u : in) { + buy.AddCost(DoCommand(u->tile, u->index, 0, flags, CMD_SELL_VEHICLE)); + } + } + } + return buy; + } + + RegisterGameEvents(GEF_TBTR_REPLACEMENT); + if (need_replacement) { // step 1: generate primary for newchain and generate remainder_chain // 1. primary of incoming might already fit the template