mirror of https://github.com/OpenTTD/OpenTTD.git
(svn r23087) -Feature: Auto-refitting of vehicles during loading at a station when the vehicle allows it.
This commit is contained in:
parent
b9841bba81
commit
f200ffa90c
|
@ -142,7 +142,7 @@ static bool VerifyAutoreplaceRefitForOrders(const Vehicle *v, EngineID engine_ty
|
|||
const Order *o;
|
||||
const Vehicle *u = (v->type == VEH_TRAIN) ? v->First() : v;
|
||||
FOR_VEHICLE_ORDERS(u, o) {
|
||||
if (!o->IsRefit()) continue;
|
||||
if (!o->IsRefit() || o->IsAutoRefit()) continue;
|
||||
CargoID cargo_type = o->GetRefitCargo();
|
||||
|
||||
if (!HasBit(union_refit_mask_a, cargo_type)) continue;
|
||||
|
|
|
@ -65,6 +65,7 @@ enum CargoTypes {
|
|||
|
||||
NUM_CARGO = 32, ///< Maximal number of cargo types in a game.
|
||||
|
||||
CT_AUTO_REFIT = 0xFD, ///< Automatically choose cargo type when doing auto refitting.
|
||||
CT_NO_REFIT = 0xFE, ///< Do not refit cargo of a vehicle (used in vehicle orders and auto-replace/auto-new).
|
||||
CT_INVALID = 0xFF, ///< Invalid cargo type.
|
||||
};
|
||||
|
|
|
@ -1275,6 +1275,49 @@ static void LoadUnloadVehicle(Vehicle *front, int *cargo_left)
|
|||
/* Do not pick up goods when we have no-load set or loading is stopped. */
|
||||
if (front->current_order.GetLoadType() & OLFB_NO_LOAD || HasBit(front->vehicle_flags, VF_STOP_LOADING)) continue;
|
||||
|
||||
/* This order has a refit, the vehicle is a normal vehicle and completely empty, do it now. */
|
||||
if (front->current_order.IsRefit() && !v->IsArticulatedPart() && v->cargo.Count() == 0 &&
|
||||
(v->type != VEH_AIRCRAFT || (Aircraft::From(v)->IsNormalAircraft() && v->Next()->cargo.Count() == 0))) {
|
||||
CargoID new_cid = front->current_order.GetRefitCargo();
|
||||
byte new_subtype = front->current_order.GetRefitSubtype();
|
||||
|
||||
Backup<CompanyByte> cur_company(_current_company, front->owner, FILE_LINE);
|
||||
|
||||
/* Check if all articulated parts are empty and collect refit mask. */
|
||||
uint32 refit_mask = e->info.refit_mask;
|
||||
Vehicle *w = v;
|
||||
while (w->HasArticulatedPart()) {
|
||||
w = w->GetNextArticulatedPart();
|
||||
if (w->cargo.Count() > 0) new_cid = CT_NO_REFIT;
|
||||
refit_mask |= EngInfo(w->engine_type)->refit_mask;
|
||||
}
|
||||
|
||||
if (new_cid == CT_AUTO_REFIT) {
|
||||
/* Get refittable cargo type with the most waiting cargo. */
|
||||
int amount = 0;
|
||||
CargoID cid;
|
||||
FOR_EACH_SET_CARGO_ID(cid, refit_mask) {
|
||||
if (cargo_left[cid] > amount) {
|
||||
/* Try to find out if auto-refitting would succeed. In case the refit is allowed,
|
||||
* the returned refit capacity will be greater than zero. */
|
||||
DoCommand(v->tile, v->index, cid | 1U << 6 | new_subtype << 8 | 1U << 16, DC_QUERY_COST, GetCmdRefitVeh(v)); // Auto-refit and only this vehicle including artic parts.
|
||||
if (_returned_refit_capacity > 0) {
|
||||
amount = cargo_left[cid];
|
||||
new_cid = cid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Refit if given a valid cargo. */
|
||||
if (new_cid < NUM_CARGO) {
|
||||
DoCommand(v->tile, v->index, new_cid | 1U << 6 | new_subtype << 8 | 1U << 16, DC_EXEC, GetCmdRefitVeh(v)); // Auto-refit and only this vehicle including artic parts.
|
||||
ge = &st->goods[v->cargo_type];
|
||||
}
|
||||
|
||||
cur_company.Restore();
|
||||
}
|
||||
|
||||
/* update stats */
|
||||
int t;
|
||||
switch (front->type) {
|
||||
|
|
|
@ -153,6 +153,7 @@ enum EngineMiscFlags {
|
|||
EF_USES_2CC = 1, ///< Vehicle uses two company colours
|
||||
EF_RAIL_IS_MU = 2, ///< Rail vehicle is a multiple-unit (DMU/EMU)
|
||||
EF_RAIL_FLIPS = 3, ///< Rail vehicle can be flipped in the depot
|
||||
EF_AUTO_REFIT = 4, ///< Automatic refitting is allowed
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -95,21 +95,28 @@ public:
|
|||
|
||||
/**
|
||||
* Is this order a refit order.
|
||||
* @pre IsType(OT_GOTO_DEPOT)
|
||||
* @pre IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION)
|
||||
* @return true if a refit should happen.
|
||||
*/
|
||||
inline bool IsRefit() const { return this->refit_cargo < NUM_CARGO; }
|
||||
inline bool IsRefit() const { return this->refit_cargo < NUM_CARGO || this->refit_cargo == CT_AUTO_REFIT; }
|
||||
|
||||
/**
|
||||
* Is this order a auto-refit order.
|
||||
* @pre IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION)
|
||||
* @return true if a auto-refit should happen.
|
||||
*/
|
||||
inline bool IsAutoRefit() const { return this->refit_cargo == CT_AUTO_REFIT; }
|
||||
|
||||
/**
|
||||
* Get the cargo to to refit to.
|
||||
* @pre IsType(OT_GOTO_DEPOT)
|
||||
* @pre IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION)
|
||||
* @return the cargo type.
|
||||
*/
|
||||
inline CargoID GetRefitCargo() const { return this->refit_cargo; }
|
||||
|
||||
/**
|
||||
* Get the cargo subtype to to refit to.
|
||||
* @pre IsType(OT_GOTO_DEPOT)
|
||||
* @pre IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION)
|
||||
* @return the cargo subtype.
|
||||
*/
|
||||
inline byte GetRefitSubtype() const { return this->refit_subtype; }
|
||||
|
|
|
@ -144,10 +144,10 @@ void Order::MakeImplicit(StationID destination)
|
|||
}
|
||||
|
||||
/**
|
||||
* Make this depot order also a refit order.
|
||||
* Make this depot/station order also a refit order.
|
||||
* @param cargo the cargo type to change to.
|
||||
* @param subtype the subtype to change to.
|
||||
* @pre IsType(OT_GOTO_DEPOT).
|
||||
* @pre IsType(OT_GOTO_DEPOT) || IsType(OT_GOTO_STATION).
|
||||
*/
|
||||
void Order::SetRefit(CargoID cargo, byte subtype)
|
||||
{
|
||||
|
@ -1256,6 +1256,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||
switch (mof) {
|
||||
case MOF_NON_STOP:
|
||||
order->SetNonStopType((OrderNonStopFlags)data);
|
||||
if (data & ONSF_NO_STOP_AT_DESTINATION_STATION) order->SetRefit(CT_NO_REFIT);
|
||||
break;
|
||||
|
||||
case MOF_STOP_LOCATION:
|
||||
|
@ -1268,6 +1269,7 @@ CommandCost CmdModifyOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||
|
||||
case MOF_LOAD:
|
||||
order->SetLoadType((OrderLoadFlags)data);
|
||||
if (data & OLFB_NO_LOAD) order->SetRefit(CT_NO_REFIT);
|
||||
break;
|
||||
|
||||
case MOF_DEPOT_ACTION: {
|
||||
|
@ -1517,7 +1519,7 @@ CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
|||
CargoID cargo = GB(p2, 0, 8);
|
||||
byte subtype = GB(p2, 8, 8);
|
||||
|
||||
if (cargo >= NUM_CARGO && cargo != CT_NO_REFIT) return CMD_ERROR;
|
||||
if (cargo >= NUM_CARGO && cargo != CT_NO_REFIT && cargo != CT_AUTO_REFIT) return CMD_ERROR;
|
||||
|
||||
const Vehicle *v = Vehicle::GetIfValid(veh);
|
||||
if (v == NULL || !v->IsPrimaryVehicle()) return CMD_ERROR;
|
||||
|
@ -1528,6 +1530,9 @@ CommandCost CmdOrderRefit(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
|
|||
Order *order = v->GetOrder(order_number);
|
||||
if (order == NULL) return CMD_ERROR;
|
||||
|
||||
/* Automatic refit cargo is only supported for goto station orders. */
|
||||
if (cargo == CT_AUTO_REFIT && !order->IsType(OT_GOTO_STATION)) return CMD_ERROR;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
order->SetRefit(cargo, subtype);
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ CommandCost CmdSellVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||
}
|
||||
|
||||
/** Helper to run the refit cost callback. */
|
||||
static uint GetRefitCostFactor(const Vehicle *v, EngineID engine_type, CargoID new_cid, byte new_subtype)
|
||||
static uint GetRefitCostFactor(const Vehicle *v, EngineID engine_type, CargoID new_cid, byte new_subtype, bool *auto_refit_allowed)
|
||||
{
|
||||
/* Prepare callback param with info about the new cargo type. */
|
||||
const Engine *e = Engine::Get(engine_type);
|
||||
|
@ -217,9 +217,11 @@ static uint GetRefitCostFactor(const Vehicle *v, EngineID engine_type, CargoID n
|
|||
|
||||
uint16 cb_res = GetVehicleCallback(CBID_VEHICLE_REFIT_COST, param1, 0, engine_type, v);
|
||||
if (cb_res != CALLBACK_FAILED) {
|
||||
*auto_refit_allowed = HasBit(cb_res, 14);
|
||||
return GB(cb_res, 0, 14);
|
||||
}
|
||||
|
||||
*auto_refit_allowed = e->info.refit_cost == 0;
|
||||
return e->info.refit_cost;
|
||||
}
|
||||
|
||||
|
@ -230,13 +232,14 @@ static uint GetRefitCostFactor(const Vehicle *v, EngineID engine_type, CargoID n
|
|||
* @param new_cid Cargo type we are refitting to.
|
||||
* @param new_subtype New cargo subtype.
|
||||
* @return Price for refitting
|
||||
* @return[out] auto_refit_allowed The refit is allowed as an auto-refit.
|
||||
*/
|
||||
static CommandCost GetRefitCost(const Vehicle *v, EngineID engine_type, CargoID new_cid, byte new_subtype)
|
||||
static CommandCost GetRefitCost(const Vehicle *v, EngineID engine_type, CargoID new_cid, byte new_subtype, bool *auto_refit_allowed)
|
||||
{
|
||||
ExpensesType expense_type;
|
||||
const Engine *e = Engine::Get(engine_type);
|
||||
Price base_price;
|
||||
uint cost_factor = GetRefitCostFactor(v, engine_type, new_cid, new_subtype);
|
||||
uint cost_factor = GetRefitCostFactor(v, engine_type, new_cid, new_subtype, auto_refit_allowed);
|
||||
switch (e->type) {
|
||||
case VEH_SHIP:
|
||||
base_price = PR_BUILD_VEHICLE_SHIP;
|
||||
|
@ -273,9 +276,10 @@ static CommandCost GetRefitCost(const Vehicle *v, EngineID engine_type, CargoID
|
|||
* @param new_cid Cargotype to refit to
|
||||
* @param new_subtype Cargo subtype to refit to
|
||||
* @param flags Command flags
|
||||
* @param auto_refit Refitting is done as automatic refitting outside a depot.
|
||||
* @return Refit cost.
|
||||
*/
|
||||
static CommandCost RefitVehicle(Vehicle *v, bool only_this, uint8 num_vehicles, CargoID new_cid, byte new_subtype, DoCommandFlag flags)
|
||||
static CommandCost RefitVehicle(Vehicle *v, bool only_this, uint8 num_vehicles, CargoID new_cid, byte new_subtype, DoCommandFlag flags, bool auto_refit)
|
||||
{
|
||||
CommandCost cost(v->GetExpenseType(false));
|
||||
uint total_capacity = 0;
|
||||
|
@ -296,8 +300,9 @@ static CommandCost RefitVehicle(Vehicle *v, bool only_this, uint8 num_vehicles,
|
|||
const Engine *e = v->GetEngine();
|
||||
if (!e->CanCarryCargo()) continue;
|
||||
|
||||
/* If the vehicle is not refittable, count its capacity nevertheless if the cargo matches */
|
||||
bool refittable = HasBit(e->info.refit_mask, new_cid);
|
||||
/* If the vehicle is not refittable, or does not allow automatic refitting,
|
||||
* count its capacity nevertheless if the cargo matches */
|
||||
bool refittable = HasBit(e->info.refit_mask, new_cid) && (!auto_refit || HasBit(e->info.misc_flags, EF_AUTO_REFIT));
|
||||
if (!refittable && v->cargo_type != new_cid) continue;
|
||||
|
||||
/* Back up the vehicle's cargo type */
|
||||
|
@ -321,7 +326,15 @@ static CommandCost RefitVehicle(Vehicle *v, bool only_this, uint8 num_vehicles,
|
|||
v->cargo_subtype = temp_subtype;
|
||||
|
||||
if (new_cid != v->cargo_type) {
|
||||
cost.AddCost(GetRefitCost(v, v->engine_type, new_cid, new_subtype));
|
||||
bool auto_refit_allowed;
|
||||
CommandCost refit_cost = GetRefitCost(v, v->engine_type, new_cid, new_subtype, &auto_refit_allowed);
|
||||
if (auto_refit && !auto_refit_allowed) {
|
||||
/* Sorry, auto-refitting not allowed, subtract the cargo amount again from the total. */
|
||||
total_capacity -= amount;
|
||||
total_mail_capacity -= mail_capacity;
|
||||
continue;
|
||||
}
|
||||
cost.AddCost(refit_cost);
|
||||
}
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
|
@ -349,6 +362,7 @@ static CommandCost RefitVehicle(Vehicle *v, bool only_this, uint8 num_vehicles,
|
|||
* @param p1 vehicle ID to refit
|
||||
* @param p2 various bitstuffed elements
|
||||
* - p2 = (bit 0-4) - New cargo type to refit to.
|
||||
* - p2 = (bit 6) - Automatic refitting.
|
||||
* - p2 = (bit 7) - Refit only this vehicle. Used only for cloning vehicles.
|
||||
* - p2 = (bit 8-15) - New cargo subtype to refit to.
|
||||
* - p2 = (bit 16-23) - Number of vehicles to refit (not counting articulated parts). Zero means all vehicles.
|
||||
|
@ -370,9 +384,12 @@ CommandCost CmdRefitVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
|
|||
CommandCost ret = CheckOwnership(front->owner);
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
bool auto_refit = HasBit(p2, 6);
|
||||
|
||||
/* Don't allow shadows and such to be refitted. */
|
||||
if (v != front && (v->type == VEH_SHIP || v->type == VEH_AIRCRAFT)) return CMD_ERROR;
|
||||
if (!front->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type);
|
||||
/* Allow auto-refitting only during loading and normal refitting only in a depot. */
|
||||
if ((!auto_refit || !front->current_order.IsType(OT_LOADING)) && !front->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type);
|
||||
if (front->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_VEHICLE_IS_DESTROYED);
|
||||
|
||||
/* Check cargo */
|
||||
|
@ -384,7 +401,7 @@ CommandCost CmdRefitVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
|
|||
bool only_this = HasBit(p2, 7) || front->type == VEH_SHIP || front->type == VEH_AIRCRAFT;
|
||||
uint8 num_vehicles = GB(p2, 16, 8);
|
||||
|
||||
CommandCost cost = RefitVehicle(v, only_this, num_vehicles, new_cid, new_subtype, flags);
|
||||
CommandCost cost = RefitVehicle(v, only_this, num_vehicles, new_cid, new_subtype, flags, auto_refit);
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
/* Update the cached variables */
|
||||
|
@ -813,7 +830,8 @@ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
|
|||
CargoID initial_cargo = (e->CanCarryCargo() ? e->GetDefaultCargoType() : (CargoID)CT_INVALID);
|
||||
|
||||
if (v->cargo_type != initial_cargo && initial_cargo != CT_INVALID) {
|
||||
total_cost.AddCost(GetRefitCost(NULL, v->engine_type, v->cargo_type, v->cargo_subtype));
|
||||
bool dummy;
|
||||
total_cost.AddCost(GetRefitCost(NULL, v->engine_type, v->cargo_type, v->cargo_subtype, &dummy));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue