summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/aircraft_cmd.cpp1
-rw-r--r--src/command.cpp8
-rw-r--r--src/roadveh_cmd.cpp2
-rw-r--r--src/ship_cmd.cpp2
-rw-r--r--src/train_cmd.cpp5
-rw-r--r--src/vehicle.cpp73
6 files changed, 63 insertions, 28 deletions
diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp
index 3950cae50..c68c06383 100644
--- a/src/aircraft_cmd.cpp
+++ b/src/aircraft_cmd.cpp
@@ -597,6 +597,7 @@ int32 CmdSendAircraftToHangar(TileIndex tile, uint32 flags, uint32 p1, uint32 p2
* @param p2 various bitstuffed elements
* - p2 = (bit 0-7) - the new cargo type to refit to
* - p2 = (bit 8-15) - the new cargo subtype to refit to
+ * - p2 = (bit 16) - refit only this vehicle (ignored)
* @return cost of refit or error
*/
int32 CmdRefitAircraft(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
diff --git a/src/command.cpp b/src/command.cpp
index 94717a38d..0b20d9820 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -456,13 +456,17 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
* restrictions which may cause the test run to fail (the previous
* road fragments still stay there and the town won't let you
* disconnect the road system), but the exec will succeed and this
- * fact will trigger an assertion failure. --pasky */
+ * fact will trigger an assertion failure. --pasky
+ * CMD_CLONE_VEHICLE: Both building new vehicles and refitting them can be
+ * influenced by newgrf callbacks, which makes it impossible to accurately
+ * estimate the cost of cloning a vehicle. */
notest =
(cmd & 0xFF) == CMD_CLEAR_AREA ||
(cmd & 0xFF) == CMD_CONVERT_RAIL ||
(cmd & 0xFF) == CMD_LEVEL_LAND ||
(cmd & 0xFF) == CMD_REMOVE_ROAD ||
- (cmd & 0xFF) == CMD_REMOVE_LONG_ROAD;
+ (cmd & 0xFF) == CMD_REMOVE_LONG_ROAD ||
+ (cmd & 0xFF) == CMD_CLONE_VEHICLE;
_docommand_recursive = 1;
diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp
index 3d7f220fa..d0e3813dc 100644
--- a/src/roadveh_cmd.cpp
+++ b/src/roadveh_cmd.cpp
@@ -1851,6 +1851,8 @@ void RoadVehiclesYearlyLoop()
* @param p2 Bitstuffed elements
* - p2 = (bit 0-7) - the new cargo type to refit to
* - p2 = (bit 8-15) - the new cargo subtype to refit to
+ * - p2 = (bit 16) - refit only this vehicle (ignored)
+ * @return cost of refit or error
*/
int32 CmdRefitRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp
index dd86a960d..58864273b 100644
--- a/src/ship_cmd.cpp
+++ b/src/ship_cmd.cpp
@@ -1087,6 +1087,8 @@ int32 CmdSendShipToDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
* @param p2 various bitstuffed elements
* - p2 = (bit 0-7) - the new cargo type to refit to (p2 & 0xFF)
* - p2 = (bit 8-15) - the new cargo subtype to refit to
+ * - p2 = (bit 16) - refit only this vehicle (ignored)
+ * @return cost of refit or error
*/
int32 CmdRefitShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp
index bbdb77547..c3eedc2c5 100644
--- a/src/train_cmd.cpp
+++ b/src/train_cmd.cpp
@@ -1751,11 +1751,14 @@ int32 CmdForceTrainProceed(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
* param p2 various bitstuffed elements
* - p2 = (bit 0-7) - the new cargo type to refit to
* - p2 = (bit 8-15) - the new cargo subtype to refit to
+ * - p2 = (bit 16) - refit only this vehicle
+ * @return cost of refit or error
*/
int32 CmdRefitRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
CargoID new_cid = GB(p2, 0, 8);
byte new_subtype = GB(p2, 8, 8);
+ bool only_this = HASBIT(p2, 16);
if (!IsValidVehicleID(p1)) return CMD_ERROR;
@@ -1833,7 +1836,7 @@ int32 CmdRefitRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
}
}
}
- } while ((v = v->next) != NULL);
+ } while ((v = v->next) != NULL && !only_this);
_returned_refit_capacity = num;
diff --git a/src/vehicle.cpp b/src/vehicle.cpp
index f030656b9..90ee45ad6 100644
--- a/src/vehicle.cpp
+++ b/src/vehicle.cpp
@@ -1804,7 +1804,7 @@ int32 CmdCloneVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
Vehicle *v_front, *v;
Vehicle *w_front, *w, *w_rear;
- int cost, total_cost = 0;
+ int32 cost, total_cost = 0;
uint32 build_argument = 2;
if (!IsValidVehicleID(p1)) return CMD_ERROR;
@@ -1842,18 +1842,6 @@ int32 CmdCloneVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
v = v_front;
do {
-
- if (!(flags & DC_EXEC)) {
- /* Get the refit cost.
- * This is only needed when estimating as when the command is executed, the cost from the refit command is used.
- * This needs to be done for every single unit, so it should be done before checking if it's a multiheaded engine. */
- CargoID new_cargo_type = GetEngineCargoType(v->engine_type);
-
- if (new_cargo_type != v->cargo_type && new_cargo_type != CT_INVALID) {
- total_cost += GetRefitCost(v->engine_type);
- }
- }
-
if (IsMultiheaded(v) && !IsTrainEngine(v)) {
/* we build the rear ends of multiheaded trains with the front ones */
continue;
@@ -1869,18 +1857,6 @@ int32 CmdCloneVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
if (flags & DC_EXEC) {
w = GetVehicle(_new_vehicle_id);
- Vehicle *w2 = w;
- Vehicle *v2 = v;
- do {
- if (v2->cargo_type != w2->cargo_type || v2->cargo_subtype != w2->cargo_subtype) {
- /* We can't pay for refitting because we can't estimate refitting costs for a vehicle before it's build.
- * If we pay for it anyway, the cost and the estimated cost will not be the same and we will have an assert.
- * We need to check the whole chain if it is a train because some newgrf articulated engines can refit some units only (and not the front) */
- total_cost += DoCommand(0, w->index, v2->cargo_type | (v2->cargo_subtype << 8), flags, GetCmdRefitVeh(v));
- break; // We learned that the engine in question needed a refit. No need to check anymore
- }
- } while (v->type == VEH_TRAIN && (w2 = w2->next) != NULL && (v2 = v2->next) != NULL);
-
if (v->type == VEH_TRAIN && HASBIT(v->u.rail.flags, VRF_REVERSE_DIRECTION)) {
SETBIT(w->u.rail.flags, VRF_REVERSE_DIRECTION);
}
@@ -1904,6 +1880,53 @@ int32 CmdCloneVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
_new_vehicle_id = w_front->index;
}
+ /* Take care of refitting. */
+ w = w_front;
+ v = v_front;
+
+ /* Both building and refitting are influenced by newgrf callbacks, which
+ * makes it impossible to accurately estimate the cloning costs. In
+ * particular, it is possible for engines of the same type to be built with
+ * different numbers of articulated parts, so when refitting we have to
+ * loop over real vehicles first, and then the articulated parts of those
+ * vehicles in a different loop. */
+ do {
+ do {
+ if (flags & DC_EXEC) {
+ assert(w != NULL);
+
+ if (w->cargo_type != v->cargo_type || w->cargo_subtype != v->cargo_type) {
+ cost = DoCommand(0, w->index, v->cargo_type | (v->cargo_subtype << 8) | 1U << 16 , flags, GetCmdRefitVeh(v));
+ if (!CmdFailed(cost)) total_cost += cost;
+ }
+
+ if (w->type == VEH_TRAIN && EngineHasArticPart(w)) {
+ w = GetNextArticPart(w);
+ } else {
+ break;
+ }
+ } else {
+ CargoID initial_cargo = GetEngineCargoType(v->engine_type);
+
+ if (v->cargo_type != initial_cargo && initial_cargo != CT_INVALID) {
+ total_cost += GetRefitCost(v->engine_type);
+ }
+ }
+ } while (v->type == VEH_TRAIN && EngineHasArticPart(v) && (v = GetNextArticPart(v)) != NULL);
+
+ if (flags & DC_EXEC) w = GetNextVehicle(w);
+ } while (v->type == VEH_TRAIN && (v = GetNextVehicle(v)) != NULL);
+
+ /* Since we can't estimate the cost of cloning a vehicle accurately we must
+ * check whether the player has enough money manually. */
+ if (!CheckPlayerHasMoney(total_cost)) {
+ if (flags & DC_EXEC) {
+ /* The vehicle has already been bought, so now it must be sold again. */
+ DoCommand(w_front->tile, w_front->index, 1, flags, GetCmdSellVeh(w_front));
+ }
+ return CMD_ERROR;
+ }
+
/* Set the expense type last as refitting will make the cost go towards
* running costs... */
SET_EXPENSES_TYPE(EXPENSES_NEW_VEHICLES);