(svn r12421) -Feature: [autoreplace] the autoreplace button in train depots will now also replace wagons even if they aren't connected to a locomotive

fixed estimated cost in CmdDepotMassAutoReplace() (will still not estimate wagon removal profits)
  Made it possible to command CmdDepotMassAutoReplace() to either replace everything or nothing (the button will still happily replace just some of the vehicles if cash premits)
This commit is contained in:
bjarni 2008-03-25 21:58:13 +00:00
parent 97fb7fb8d9
commit 06c0e5df5a
3 changed files with 43 additions and 29 deletions

View File

@ -199,12 +199,21 @@ static CommandCost ReplaceVehicle(Vehicle **w, byte flags, Money total_cost)
*/
/* Get the vehicle in front of the one we move out */
Vehicle *front = old_v->Previous();
/* If the vehicle in front is the rear end of a dualheaded engine, then we need to use the one in front of that one */
if (IsRearDualheaded(front)) front = front->Previous();
/* Now we move the old one out of the train */
DoCommand(0, (INVALID_VEHICLE << 16) | old_v->index, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
/* Add the new vehicle */
DoCommand(0, (front->index << 16) | new_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
if (front == NULL) {
/* It would appear that we have the front wagon of a row of wagons without engines */
Vehicle *next = old_v->Next();
if (next != NULL) {
/* Move the chain to the new front wagon */
DoCommand(0, (new_v->index << 16) | next->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
}
} else {
/* If the vehicle in front is the rear end of a dualheaded engine, then we need to use the one in front of that one */
if (IsRearDualheaded(front)) front = front->Previous();
/* Now we move the old one out of the train */
DoCommand(0, (INVALID_VEHICLE << 16) | old_v->index, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
/* Add the new vehicle */
DoCommand(0, (front->index << 16) | new_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
}
} else {
// copy/clone the orders
DoCommand(0, (old_v->index << 16) | new_v->index, old_v->IsOrderListShared() ? CO_SHARE : CO_COPY, DC_EXEC, CMD_CLONE_ORDER);

View File

@ -542,12 +542,16 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
* 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. */
* estimate the cost of cloning a vehicle.
* CMD_DEPOT_MASS_AUTOREPLACE: we can't predict wagon removal so
* the test will not include income from any sold wagons.
* This means that the costs can sometimes be lower than estimated. */
notest =
(cmd & 0xFF) == CMD_CLEAR_AREA ||
(cmd & 0xFF) == CMD_LEVEL_LAND ||
(cmd & 0xFF) == CMD_REMOVE_LONG_ROAD ||
(cmd & 0xFF) == CMD_CLONE_VEHICLE;
(cmd & 0xFF) == CMD_CLONE_VEHICLE ||
(cmd & 0xFF) == CMD_DEPOT_MASS_AUTOREPLACE;
_docommand_recursive = 1;

View File

@ -1687,24 +1687,28 @@ CommandCost CmdDepotSellAllVehicles(TileIndex tile, uint32 flags, uint32 p1, uin
}
/** Autoreplace all vehicles in the depot
* Note: this command can make incorrect cost estimations
* Luckily the final price can only drop, not increase. This is due to the fact that
* estimation can't predict wagon removal so it presumes worst case which is no income from selling wagons.
* @param tile Tile of the depot where the vehicles are
* @param flags type of operation
* @param p1 Type of vehicle
* @param p2 Unused
* @param p2 If bit 0 is set, then either replace all or nothing (instead of replacing until money runs out)
*/
CommandCost CmdDepotMassAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
Vehicle **vl = NULL;
uint16 engine_list_length = 0;
uint16 engine_count = 0;
uint i, x = 0, y = 0, z = 0;
CommandCost cost;
uint i;
CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES);
VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8);
bool all_or_nothing = HasBit(p2, 0);
if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_player)) return CMD_ERROR;
/* Get the list of vehicles in the depot */
BuildDepotVehicleList(vehicle_type, tile, &vl, &engine_list_length, &engine_count, NULL, NULL, NULL);
BuildDepotVehicleList(vehicle_type, tile, &vl, &engine_list_length, &engine_count, &vl, &engine_list_length, &engine_count);
for (i = 0; i < engine_count; i++) {
@ -1715,10 +1719,6 @@ CommandCost CmdDepotMassAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uin
/* Ensure that the vehicle completely in the depot */
if (!v->IsInDepot()) continue;
x = v->x_pos;
y = v->y_pos;
z = v->z_pos;
if (stopped) {
v->vehstatus |= VS_STOPPED; // Stop the vehicle
v->leave_depot_instantly = true;
@ -1727,24 +1727,25 @@ CommandCost CmdDepotMassAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uin
if (CmdSucceeded(ret)) {
cost.AddCost(ret);
if (!(flags & DC_EXEC)) break;
/* There is a problem with autoreplace and newgrf
* It's impossible to tell the length of a train after it's being replaced before it's actually done
* Because of this, we can't estimate costs due to wagon removal and we will have to always return 0 and pay manually
* Since we pay after each vehicle is replaced and MaybeReplaceVehicle() check if the player got enough money
* we should never reach a condition where the player will end up with negative money from doing this */
SubtractMoneyFromPlayer(ret);
} else {
if (all_or_nothing) {
/* We failed to replace a vehicle even though we set all or nothing.
* We should never reach this if DC_EXEC is set since then it should
* have failed the estimation guess. */
assert(!(flags & DC_EXEC));
/* Now we will have to return an error.
* This goto will leave the loop and it's ok to do so because
* there is no point in the rest of the loop. */
goto error;
}
}
}
if (cost.GetCost() == 0) {
error:
/* Either we didn't replace anything or something went wrong.
* Either way we want to return an error and not execute this command. */
cost = CMD_ERROR;
} else {
if (flags & DC_EXEC) {
/* Display the cost animation now that DoCommandP() can't do it for us (see previous comments) */
if (IsLocalPlayer()) ShowCostOrIncomeAnimation(x, y, z, cost.GetCost());
}
cost = CommandCost();
}
free(vl);