--- a/src/vehicle.cpp Mon Apr 14 20:32:36 2008 +0000
+++ b/src/vehicle.cpp Tue Apr 15 00:47:19 2008 +0000
@@ -13,15 +13,13 @@
#include "timetable.h"
#include "viewport_func.h"
#include "gfx_func.h"
-#include "news.h"
+#include "news_func.h"
#include "command_func.h"
#include "saveload.h"
#include "player_func.h"
-#include "engine.h"
#include "debug.h"
#include "vehicle_gui.h"
#include "depot.h"
-#include "station.h"
#include "rail_type.h"
#include "train.h"
#include "aircraft.h"
@@ -34,7 +32,7 @@
#include "newgrf_engine.h"
#include "newgrf_sound.h"
#include "group.h"
-#include "order.h"
+#include "order_func.h"
#include "strings_func.h"
#include "zoom_func.h"
#include "functions.h"
@@ -48,6 +46,7 @@
#include "autoreplace_gui.h"
#include "string_func.h"
#include "settings_type.h"
+#include "oldpool_func.h"
#include "table/sprites.h"
#include "table/strings.h"
@@ -119,22 +118,27 @@
InvalidateWindow(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
}
-bool VehicleNeedsService(const Vehicle *v)
+bool Vehicle::NeedsServicing() const
{
- if (v->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
- if (v->current_order.type != OT_GOTO_DEPOT || !(v->current_order.flags & OFB_PART_OF_ORDERS)) { // Don't interfere with a depot visit by the order list
- if (_patches.gotodepot && VehicleHasDepotOrders(v)) return false;
- if (v->current_order.type == OT_LOADING) return false;
- if (v->current_order.type == OT_GOTO_DEPOT && v->current_order.flags & OFB_HALT_IN_DEPOT) return false;
- }
+ if (this->vehstatus & (VS_STOPPED | VS_CRASHED)) return false;
if (_patches.no_servicing_if_no_breakdowns && _opt.diff.vehicle_breakdowns == 0) {
- return EngineHasReplacementForPlayer(GetPlayer(v->owner), v->engine_type, v->group_id); /* Vehicles set for autoreplacing needs to go to a depot even if breakdowns are turned off */
+ /* Vehicles set for autoreplacing needs to go to a depot even if breakdowns are turned off.
+ * Note: If servicing is enabled, we postpone replacement till next service. */
+ return EngineHasReplacementForPlayer(GetPlayer(this->owner), this->engine_type, this->group_id);
}
return _patches.servint_ispercent ?
- (v->reliability < GetEngine(v->engine_type)->reliability * (100 - v->service_interval) / 100) :
- (v->date_of_last_service + v->service_interval < _date);
+ (this->reliability < GetEngine(this->engine_type)->reliability * (100 - this->service_interval) / 100) :
+ (this->date_of_last_service + this->service_interval < _date);
+}
+
+bool Vehicle::NeedsAutomaticServicing() const
+{
+ if (_patches.gotodepot && VehicleHasDepotOrders(this)) return false;
+ if (this->current_order.IsType(OT_LOADING)) return false;
+ if (this->current_order.IsType(OT_GOTO_DEPOT) && this->current_order.GetDepotActionType() & ODATFB_HALT) return false;
+ return NeedsServicing();
}
StringID VehicleInTheWayErrMsg(const Vehicle* v)
@@ -633,7 +637,7 @@
{
/* We need to set v->leave_depot_instantly as we have no control of it's contents at this time.
* Vehicle should stop in the depot if it was in 'stopping' state - train intered depot while slowing down. */
- if ((HasBit(v->current_order.flags, OF_HALT_IN_DEPOT) && !HasBit(v->current_order.flags, OF_PART_OF_ORDERS) && v->current_order.type == OT_GOTO_DEPOT) ||
+ if (((v->current_order.GetDepotActionType() & ODATFB_HALT) && !(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) && v->current_order.IsType(OT_GOTO_DEPOT)) ||
(v->vehstatus & VS_STOPPED)) {
/* we keep the vehicle in the depot since the user ordered it to stay */
v->leave_depot_instantly = false;
@@ -769,7 +773,7 @@
}
AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs,
- v->sprite_width, v->sprite_height, v->z_height, v->z_pos, (v->vehstatus & VS_SHADOW) != 0);
+ v->x_extent, v->y_extent, v->z_extent, v->z_pos, (v->vehstatus & VS_SHADOW) != 0);
}
void ViewportAddVehicles(DrawPixelInfo *dpi)
@@ -1544,7 +1548,7 @@
SetDParam(0, _vehicle_type_names[v->type]);
SetDParam(1, v->unitnumber);
- AddNewsItem(msg, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
+ AddNewsItem(msg, NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0);
}
void AgeVehicle(Vehicle *v)
@@ -1687,24 +1691,28 @@
}
/** 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 +1723,6 @@
/* 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 +1731,25 @@
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);
@@ -2034,7 +2039,7 @@
const Order *order;
FOR_VEHICLE_ORDERS(v, order) {
- if (order->type == OT_GOTO_STATION && order->dest == index) {
+ if (order->IsType(OT_GOTO_STATION) && order->GetDestination() == index) {
if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 50);
(*sort_list)[n++] = v;
break;
@@ -2078,7 +2083,7 @@
const Order *order;
FOR_VEHICLE_ORDERS(v, order) {
- if (order->type == OT_GOTO_DEPOT && order->dest == index) {
+ if (order->IsType(OT_GOTO_DEPOT) && order->GetDestination() == index) {
if (n == *length_of_array) ExtendVehicleListSize(sort_list, length_of_array, 25);
(*sort_list)[n++] = v;
break;
@@ -2175,7 +2180,7 @@
max += v->cargo_cap;
if (v->cargo_cap != 0) {
unloading += HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) ? 1 : 0;
- loading |= (u->current_order.flags & OFB_UNLOAD) == 0 && st->goods[v->cargo_type].days_since_pickup != 255;
+ loading |= !(u->current_order.GetUnloadType() & OUFB_UNLOAD) && st->goods[v->cargo_type].days_since_pickup != 255;
cars++;
}
}
@@ -2236,20 +2241,19 @@
TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
- if (v->current_order.type == OT_GOTO_DEPOT) {
+ if (v->current_order.IsType(OT_GOTO_DEPOT)) {
Order t;
InvalidateWindow(WC_VEHICLE_VIEW, v->index);
t = v->current_order;
- v->current_order.type = OT_DUMMY;
- v->current_order.flags = 0;
-
- if (t.refit_cargo < NUM_CARGO) {
+ v->current_order.MakeDummy();
+
+ if (t.IsRefit()) {
CommandCost cost;
_current_player = v->owner;
- cost = DoCommand(v->tile, v->index, t.refit_cargo | t.refit_subtype << 8, DC_EXEC, GetCmdRefitVeh(v));
+ cost = DoCommand(v->tile, v->index, t.GetRefitCargo() | t.GetRefitSubtype() << 8, DC_EXEC, GetCmdRefitVeh(v));
if (CmdFailed(cost)) {
v->leave_depot_instantly = false; // We ensure that the vehicle stays in the depot
@@ -2257,18 +2261,18 @@
/* Notify the user that we stopped the vehicle */
SetDParam(0, _vehicle_type_names[v->type]);
SetDParam(1, v->unitnumber);
- AddNewsItem(STR_ORDER_REFIT_FAILED, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
+ AddNewsItem(STR_ORDER_REFIT_FAILED, NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0);
}
} else if (v->owner == _local_player && cost.GetCost() != 0) {
ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
}
}
- if (HasBit(t.flags, OF_PART_OF_ORDERS)) {
+ if (t.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) {
/* Part of orders */
UpdateVehicleTimetable(v, true);
v->cur_order_index++;
- } else if (HasBit(t.flags, OF_HALT_IN_DEPOT)) {
+ } else if (t.GetDepotActionType() & ODATFB_HALT) {
/* Force depot visit */
v->vehstatus |= VS_STOPPED;
if (v->owner == _local_player) {
@@ -2283,7 +2287,7 @@
}
SetDParam(0, v->unitnumber);
- AddNewsItem(string, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0), v->index, 0);
+ AddNewsItem(string, NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0);
}
}
}
@@ -3057,7 +3061,7 @@
}
/** Will be called when vehicles need to be loaded. */
-static void Load_VEHS()
+void Load_VEHS()
{
int index;
Vehicle *v;
@@ -3100,7 +3104,7 @@
if (CheckSavegameVersion(5)) {
/* Convert the current_order.type (which is a mix of type and flags, because
* in those versions, they both were 4 bits big) to type and flags */
- v->current_order.flags = (v->current_order.type & 0xF0) >> 4;
+ v->current_order.flags = GB(v->current_order.type, 4, 4);
v->current_order.type.m_val &= 0x0F;
}
@@ -3134,25 +3138,22 @@
{
assert(IsTileType(tile, MP_STATION) || type == VEH_SHIP);
- if (this->current_order.type == OT_GOTO_STATION &&
- this->current_order.dest == this->last_station_visited) {
- /* Arriving at the ordered station.
- * Keep the load/unload flags, as we (obviously) still need them. */
- this->current_order.flags &= OFB_FULL_LOAD | OFB_UNLOAD | OFB_TRANSFER;
-
+ if (this->current_order.IsType(OT_GOTO_STATION) &&
+ this->current_order.GetDestination() == this->last_station_visited) {
/* Furthermore add the Non Stop flag to mark that this station
* is the actual destination of the vehicle, which is (for example)
* necessary to be known for HandleTrainLoading to determine
* whether the train is lost or not; not marking a train lost
* that arrives at random stations is bad. */
- this->current_order.flags |= OFB_NON_STOP;
+ this->current_order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
+
+ current_order.MakeLoading(true);
UpdateVehicleTimetable(this, true);
} else {
- /* This is just an unordered intermediate stop */
- this->current_order.flags = 0;
+ this->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
+ current_order.MakeLoading(false);
}
- current_order.type = OT_LOADING;
GetStation(this->last_station_visited)->loading_vehicles.push_back(this);
VehiclePayment(this);
@@ -3168,13 +3169,12 @@
void Vehicle::LeaveStation()
{
- assert(current_order.type == OT_LOADING);
+ assert(current_order.IsType(OT_LOADING));
/* Only update the timetable if the vehicle was supposed to stop here. */
- if (current_order.flags & OFB_NON_STOP) UpdateVehicleTimetable(this, false);
-
- current_order.type = OT_LEAVESTATION;
- current_order.flags = 0;
+ if (current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
+
+ current_order.MakeLeaveStation();
GetStation(this->last_station_visited)->loading_vehicles.remove(this);
HideFillingPercent(this->fill_percent_te_id);
@@ -3184,7 +3184,7 @@
void Vehicle::HandleLoading(bool mode)
{
- switch (this->current_order.type) {
+ switch (this->current_order.GetType()) {
case OT_LOADING: {
uint wait_time = max(this->current_order.wait_time - this->lateness_counter, 0);
@@ -3194,11 +3194,11 @@
this->PlayLeaveStationSound();
- Order b = this->current_order;
+ bool at_destination_station = this->current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE;
this->LeaveStation();
/* If this was not the final order, don't remove it from the list. */
- if (!(b.flags & OFB_NON_STOP)) return;
+ if (!at_destination_station) return;
break;
}
@@ -3237,9 +3237,9 @@
{
this->x_offs = 0;
this->y_offs = 0;
- this->sprite_width = 1;
- this->sprite_height = 1;
- this->z_height = 1;
+ this->x_extent = 1;
+ this->y_extent = 1;
+ this->z_extent = 1;
}
void StopAllVehicles()