src/autoreplace_cmd.cpp
changeset 10372 93844492fdd9
parent 10265 67510a0e5d1a
child 10398 e4cd3dc13498
equal deleted inserted replaced
10371:f4ebcb863ad6 10372:93844492fdd9
   204 				/* 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 */
   204 				/* 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 */
   205 				if (IsRearDualheaded(front)) front = front->Previous();
   205 				if (IsRearDualheaded(front)) front = front->Previous();
   206 				/* Now we move the old one out of the train */
   206 				/* Now we move the old one out of the train */
   207 				DoCommand(0, (INVALID_VEHICLE << 16) | old_v->index, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
   207 				DoCommand(0, (INVALID_VEHICLE << 16) | old_v->index, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
   208 				/* Add the new vehicle */
   208 				/* Add the new vehicle */
   209 				DoCommand(0, (front->index << 16) | new_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
   209 				CommandCost tmp_move = DoCommand(0, (front->index << 16) | new_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
       
   210 				if (CmdFailed(tmp_move)) {
       
   211 					cost.AddCost(tmp_move);
       
   212 					DoCommand(0, new_v->index, 1, DC_EXEC, GetCmdSellVeh(VEH_TRAIN));
       
   213 				}
   210 			}
   214 			}
   211 		} else {
   215 		} else {
   212 			// copy/clone the orders
   216 			// copy/clone the orders
   213 			DoCommand(0, (old_v->index << 16) | new_v->index, old_v->IsOrderListShared() ? CO_SHARE : CO_COPY, DC_EXEC, CMD_CLONE_ORDER);
   217 			DoCommand(0, (old_v->index << 16) | new_v->index, old_v->IsOrderListShared() ? CO_SHARE : CO_COPY, DC_EXEC, CMD_CLONE_ORDER);
   214 			new_v->cur_order_index = old_v->cur_order_index;
   218 			new_v->cur_order_index = old_v->cur_order_index;
   230 					// we got front and rear of a multiheaded engine right after each other. We should work with the next in line instead
   234 					// we got front and rear of a multiheaded engine right after each other. We should work with the next in line instead
   231 					temp_v = GetNextVehicle(temp_v);
   235 					temp_v = GetNextVehicle(temp_v);
   232 				}
   236 				}
   233 
   237 
   234 				if (temp_v != NULL) {
   238 				if (temp_v != NULL) {
   235 					DoCommand(0, (new_v->index << 16) | temp_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
   239 					CommandCost tmp_move = DoCommand(0, (new_v->index << 16) | temp_v->index, 1, DC_EXEC, CMD_MOVE_RAIL_VEHICLE);
       
   240 					if (CmdFailed(tmp_move)) {
       
   241 						cost.AddCost(tmp_move);
       
   242 						DoCommand(0, temp_v->index, 1, DC_EXEC, GetCmdSellVeh(VEH_TRAIN));
       
   243 					}
   236 				}
   244 				}
   237 			}
   245 			}
   238 		}
   246 		}
   239 		/* We are done setting up the new vehicle. Now we move the cargo from the old one to the new one */
   247 		/* We are done setting up the new vehicle. Now we move the cargo from the old one to the new one */
   240 		MoveVehicleCargo(new_v->type == VEH_TRAIN ? new_v->First() : new_v, old_v);
   248 		MoveVehicleCargo(new_v->type == VEH_TRAIN ? new_v->First() : new_v, old_v);
   361  * @return the costs, the success bool and sometimes an error message
   369  * @return the costs, the success bool and sometimes an error message
   362  */
   370  */
   363 CommandCost MaybeReplaceVehicle(Vehicle *v, uint32 flags, bool display_costs)
   371 CommandCost MaybeReplaceVehicle(Vehicle *v, uint32 flags, bool display_costs)
   364 {
   372 {
   365 	Vehicle *w;
   373 	Vehicle *w;
   366 	const Player *p = GetPlayer(v->owner);
   374 	Player *p = GetPlayer(v->owner);
   367 	CommandCost cost;
   375 	CommandCost cost;
   368 	bool stopped = false;
   376 	bool stopped = false;
       
   377 	BackuppedVehicle backup(true);
   369 
   378 
   370 	/* We only want "real" vehicle types. */
   379 	/* We only want "real" vehicle types. */
   371 	assert(IsPlayerBuildableVehicleType(v));
   380 	assert(IsPlayerBuildableVehicleType(v));
   372 
   381 
   373 	/* Ensure that this bool is cleared. */
   382 	/* Ensure that this bool is cleared. */
   408 		w = v;
   417 		w = v;
   409 		do {
   418 		do {
   410 			EngineID new_engine = GetNewEngineType(w, p);
   419 			EngineID new_engine = GetNewEngineType(w, p);
   411 			if (new_engine == INVALID_ENGINE) continue;
   420 			if (new_engine == INVALID_ENGINE) continue;
   412 
   421 
       
   422 			if (!backup.ContainsBackup()) {
       
   423 				/* We are going to try to replace a vehicle but we don't have any backup so we will make one. */
       
   424 				backup.Backup(v, p);
       
   425 			}
   413 			/* Now replace the vehicle */
   426 			/* Now replace the vehicle */
   414 			cost.AddCost(ReplaceVehicle(&w, flags, cost.GetCost(), p, new_engine));
   427 			cost.AddCost(ReplaceVehicle(&w, DC_EXEC, cost.GetCost(), p, new_engine));
   415 
   428 
   416 			if (flags & DC_EXEC &&
   429 			if (w->type != VEH_TRAIN || w->u.rail.first_engine == INVALID_ENGINE) {
   417 					(w->type != VEH_TRAIN || w->u.rail.first_engine == INVALID_ENGINE)) {
       
   418 				/* now we bought a new engine and sold the old one. We need to fix the
   430 				/* now we bought a new engine and sold the old one. We need to fix the
   419 				 * pointers in order to avoid pointing to the old one for trains: these
   431 				 * pointers in order to avoid pointing to the old one for trains: these
   420 				 * pointers should point to the front engine and not the cars
   432 				 * pointers should point to the front engine and not the cars
   421 				 */
   433 				 */
   422 				v = w;
   434 				v = w;
   423 			}
   435 			}
   424 		} while (w->type == VEH_TRAIN && (w = GetNextVehicle(w)) != NULL);
   436 		} while (w->type == VEH_TRAIN && (w = GetNextVehicle(w)) != NULL);
   425 
   437 
       
   438 		if (v->type == VEH_TRAIN && p->renew_keep_length) {
       
   439 			/* Remove wagons until the wanted length is reached */
       
   440 			cost.AddCost(WagonRemoval(v, old_total_length));
       
   441 		}
       
   442 
   426 		if (flags & DC_QUERY_COST || cost.GetCost() == 0) {
   443 		if (flags & DC_QUERY_COST || cost.GetCost() == 0) {
   427 			/* We didn't do anything during the replace so we will just exit here */
   444 			/* We didn't do anything during the replace so we will just exit here */
       
   445 			v = backup.Restore(v);
   428 			if (stopped) v->vehstatus &= ~VS_STOPPED;
   446 			if (stopped) v->vehstatus &= ~VS_STOPPED;
   429 			return cost;
   447 			return cost;
   430 		}
   448 		}
   431 
   449 
   432 		if (display_costs && !(flags & DC_EXEC)) {
   450 		if (display_costs) {
   433 			/* We want to ensure that we will not get below p->engine_renew_money.
   451 			/* We want to ensure that we will not get below p->engine_renew_money.
   434 			 * We will not actually pay this amount. It's for display and checks only. */
   452 			 * We will not actually pay this amount. It's for display and checks only. */
   435 			cost.AddCost((Money)p->engine_renew_money);
   453 			CommandCost tmp = cost;
   436 			if (CmdSucceeded(cost) && GetAvailableMoneyForCommand() < cost.GetCost()) {
   454 			tmp.AddCost((Money)p->engine_renew_money);
       
   455 			if (CmdSucceeded(tmp) && GetAvailableMoneyForCommand() < tmp.GetCost()) {
   437 				/* We don't have enough money so we will set cost to failed */
   456 				/* We don't have enough money so we will set cost to failed */
       
   457 				cost.AddCost((Money)p->engine_renew_money);
   438 				cost.AddCost(CMD_ERROR);
   458 				cost.AddCost(CMD_ERROR);
   439 			}
   459 			}
   440 		}
   460 		}
   441 
   461 
   442 		if (display_costs && CmdFailed(cost)) {
   462 		if (display_costs && CmdFailed(cost)) {
   455 				AddNewsItem(message, NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0);
   475 				AddNewsItem(message, NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0);
   456 			}
   476 			}
   457 		}
   477 		}
   458 	}
   478 	}
   459 
   479 
   460 	if (flags & DC_EXEC && CmdSucceeded(cost)) {
   480 	if (display_costs && IsLocalPlayer() && (flags & DC_EXEC) && CmdSucceeded(cost)) {
   461 		if (v->type == VEH_TRAIN && p->renew_keep_length) {
   481 		ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
   462 			/* Remove wagons until the wanted length is reached */
   482 	}
   463 			cost.AddCost(WagonRemoval(v, old_total_length));
   483 
   464 		}
   484 	if (!(flags & DC_EXEC) || CmdFailed(cost)) {
   465 
   485 		v = backup.Restore(v);
   466 		if (display_costs && IsLocalPlayer()) {
       
   467 			ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
       
   468 		}
       
   469 	}
   486 	}
   470 
   487 
   471 	/* Start the vehicle if we stopped it earlier */
   488 	/* Start the vehicle if we stopped it earlier */
   472 	if (stopped) v->vehstatus &= ~VS_STOPPED;
   489 	if (stopped) v->vehstatus &= ~VS_STOPPED;
   473 
   490