From f200ffa90c6f3835468d5cc2ae79499b9058bd7b Mon Sep 17 00:00:00 2001 From: michi_cc Date: Fri, 4 Nov 2011 00:38:51 +0000 Subject: (svn r23087) -Feature: Auto-refitting of vehicles during loading at a station when the vehicle allows it. --- src/autoreplace_cmd.cpp | 2 +- src/cargo_type.h | 1 + src/economy.cpp | 43 +++++++++++++++++++++++++++++++++++++++++++ src/engine_type.h | 1 + src/order_base.h | 15 +++++++++++---- src/order_cmd.cpp | 11 ++++++++--- src/vehicle_cmd.cpp | 38 ++++++++++++++++++++++++++++---------- 7 files changed, 93 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp index 67387130f..39e294f6c 100644 --- a/src/autoreplace_cmd.cpp +++ b/src/autoreplace_cmd.cpp @@ -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; diff --git a/src/cargo_type.h b/src/cargo_type.h index 2ca29d203..5f38ad847 100644 --- a/src/cargo_type.h +++ b/src/cargo_type.h @@ -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. }; diff --git a/src/economy.cpp b/src/economy.cpp index 8da463fa0..ef1c64e5c 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -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 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) { diff --git a/src/engine_type.h b/src/engine_type.h index 115cc1f98..635c01f27 100644 --- a/src/engine_type.h +++ b/src/engine_type.h @@ -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 }; /** diff --git a/src/order_base.h b/src/order_base.h index 241e8b1b3..87d79d8a0 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -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; } diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index 5f69fcd14..11a968a8f 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -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); diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 9f088b971..0b16eb9f9 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -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)); } } -- cgit v1.2.3-54-g00ecf