diff --git a/src/cargoaction.cpp b/src/cargoaction.cpp index ac88c76173..ca54692eb0 100644 --- a/src/cargoaction.cpp +++ b/src/cargoaction.cpp @@ -107,7 +107,7 @@ bool CargoDelivery::operator()(CargoPacket *cp) { uint remove = this->Preprocess(cp); this->source->RemoveFromMeta(cp, VehicleCargoList::MTA_DELIVER, remove); - this->payment->PayFinalDelivery(cp, remove); + this->payment->PayFinalDelivery(cp, remove, this->current_tile); return this->Postprocess(cp, remove); } @@ -120,6 +120,7 @@ bool CargoLoad::operator()(CargoPacket *cp) { CargoPacket *cp_new = this->Preprocess(cp); if (cp_new == nullptr) return false; + cp_new->SetSourceXY(this->current_tile); this->source->RemoveFromCache(cp_new, cp_new->Count()); this->destination->Append(cp_new, VehicleCargoList::MTA_KEEP); return cp_new == cp; @@ -134,6 +135,7 @@ bool CargoReservation::operator()(CargoPacket *cp) { CargoPacket *cp_new = this->Preprocess(cp); if (cp_new == nullptr) return false; + cp_new->SetSourceXY(this->current_tile); this->source->reserved_count += cp_new->Count(); this->source->RemoveFromCache(cp_new, cp_new->Count()); this->destination->Append(cp_new, VehicleCargoList::MTA_LOAD); diff --git a/src/cargoaction.h b/src/cargoaction.h index c37af8a833..c842def480 100644 --- a/src/cargoaction.h +++ b/src/cargoaction.h @@ -39,10 +39,11 @@ public: /** Action of final delivery of cargo. */ class CargoDelivery : public CargoRemoval { protected: + TileIndex current_tile; ///< Current tile cargo delivery is happening. CargoPayment *payment; ///< Payment object where payments will be registered. public: - CargoDelivery(VehicleCargoList *source, uint max_move, CargoPayment *payment) : - CargoRemoval(source, max_move), payment(payment) {} + CargoDelivery(VehicleCargoList *source, uint max_move, CargoPayment *payment, TileIndex current_tile) : + CargoRemoval(source, max_move), current_tile(current_tile), payment(payment) {} bool operator()(CargoPacket *cp); }; @@ -78,17 +79,19 @@ public: /** Action of loading cargo from a station onto a vehicle. */ class CargoLoad : public CargoMovement { +protected: + TileIndex current_tile; ///< Current tile cargo loading is happening. public: - CargoLoad(StationCargoList *source, VehicleCargoList *destination, uint max_move) : - CargoMovement(source, destination, max_move) {} + CargoLoad(StationCargoList *source, VehicleCargoList *destination, uint max_move, TileIndex current_tile) : + CargoMovement(source, destination, max_move), current_tile(current_tile) {} bool operator()(CargoPacket *cp); }; /** Action of reserving cargo from a station to be loaded onto a vehicle. */ class CargoReservation : public CargoLoad { public: - CargoReservation(StationCargoList *source, VehicleCargoList *destination, uint max_move) : - CargoLoad(source, destination, max_move) {} + CargoReservation(StationCargoList *source, VehicleCargoList *destination, uint max_move, TileIndex current_tile) : + CargoLoad(source, destination, max_move, current_tile) {} bool operator()(CargoPacket *cp); }; diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp index 6b6778de0d..8ec0b276a8 100644 --- a/src/cargopacket.cpp +++ b/src/cargopacket.cpp @@ -110,15 +110,13 @@ CargoPacket::CargoPacket() * Creates a new cargo packet. * * @param first_station Source station of the packet. - * @param source_xy Source location of the packet. * @param count Number of cargo entities to put in this packet. * @param source_type 'Type' of source the packet comes from (for subsidies). * @param source_id Actual source of the packet (for subsidies). * @pre count != 0 */ -CargoPacket::CargoPacket(StationID first_station, TileIndex source_xy, uint16_t count, SourceType source_type, SourceID source_id) : +CargoPacket::CargoPacket(StationID first_station,uint16_t count, SourceType source_type, SourceID source_id) : count(count), - source_xy(source_xy), source_id(source_id), source_type(source_type), first_station(first_station) @@ -618,9 +616,10 @@ void VehicleCargoList::AgeCargo() * @param order_flags OrderUnloadFlags that will apply to the unload operation. * @param ge GoodsEntry for getting the flows. * @param payment Payment object for registering transfers. + * @param current_tile Current tile the cargo handling is happening on. * return If any cargo will be unloaded. */ -bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8 order_flags, const GoodsEntry *ge, CargoPayment *payment) +bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8_t order_flags, const GoodsEntry *ge, CargoPayment *payment, TileIndex current_tile) { this->AssertCountConsistency(); dbg_assert(this->action_counts[MTA_LOAD] == 0); @@ -698,7 +697,7 @@ bool VehicleCargoList::Stage(bool accepted, StationID current_station, StationID case MTA_TRANSFER: transfer_deliver.push_front(cp); /* Add feeder share here to allow reusing field for next station. */ - share = payment->PayTransfer(cp, cp->count); + share = payment->PayTransfer(cp, cp->count, current_tile); cp->AddFeederShare(share); this->feeder_share += share; cp->next_hop = cargo_next; @@ -812,9 +811,10 @@ uint VehicleCargoList::Shift(uint max_move, VehicleCargoList *dest) * @param dest StationCargoList to add transferred cargo to. * @param max_move Maximum amount of cargo to move. * @param payment Payment object to register payments in. + * @param current_tile Current tile the cargo handling is happening on. * @return Amount of cargo actually unloaded. */ -uint VehicleCargoList::Unload(uint max_move, StationCargoList *dest, CargoPayment *payment) +uint VehicleCargoList::Unload(uint max_move, StationCargoList *dest, CargoPayment *payment, TileIndex current_tile) { uint moved = 0; if (this->action_counts[MTA_TRANSFER] > 0) { @@ -824,7 +824,7 @@ uint VehicleCargoList::Unload(uint max_move, StationCargoList *dest, CargoPaymen } if (this->action_counts[MTA_TRANSFER] == 0 && this->action_counts[MTA_DELIVER] > 0 && moved < max_move) { uint move = std::min(this->action_counts[MTA_DELIVER], max_move - moved); - this->ShiftCargo(CargoDelivery(this, move, payment)); + this->ShiftCargo(CargoDelivery(this, move, payment, current_tile)); moved += move; } return moved; @@ -1088,11 +1088,12 @@ uint StationCargoList::Truncate(uint max_move, StationCargoAmountMap *cargo_per_ * @param max_move Maximum amount of cargo to reserve. * @param dest VehicleCargoList to reserve for. * @param next_station Next station(s) the loading vehicle will visit. + * @param current_tile Current tile the cargo handling is happening on. * @return Amount of cargo actually reserved. */ -uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, StationIDStack next_station) +uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, StationIDStack next_station, TileIndex current_tile) { - return this->ShiftCargo(CargoReservation(this, dest, max_move), next_station, true); + return this->ShiftCargo(CargoReservation(this, dest, max_move, current_tile), next_station, true); } /** @@ -1101,12 +1102,13 @@ uint StationCargoList::Reserve(uint max_move, VehicleCargoList *dest, StationIDS * @param max_move Amount of cargo to load. * @param dest Vehicle cargo list where the cargo resides. * @param next_station Next station(s) the loading vehicle will visit. + * @param current_tile Current tile the cargo handling is happening on. * @return Amount of cargo actually loaded. * @note Vehicles may or may not reserve, depending on their orders. The two * modes of loading are exclusive, though. If cargo is reserved we don't * need to load unreserved cargo. */ -uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, StationIDStack next_station) +uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, StationIDStack next_station, TileIndex current_tile) { uint move = std::min(dest->ActionCount(VehicleCargoList::MTA_LOAD), max_move); if (move > 0) { @@ -1114,7 +1116,7 @@ uint StationCargoList::Load(uint max_move, VehicleCargoList *dest, StationIDStac dest->Reassign(move); return move; } else { - return this->ShiftCargo(CargoLoad(this, dest, max_move), next_station, true); + return this->ShiftCargo(CargoLoad(this, dest, max_move, current_tile), next_station, true); } } diff --git a/src/cargopacket.h b/src/cargopacket.h index 31d63076d7..872cdd2517 100644 --- a/src/cargopacket.h +++ b/src/cargopacket.h @@ -54,7 +54,7 @@ private: uint16 count = 0; ///< The amount of cargo in this packet. uint16 periods_in_transit = 0; ///< Amount of cargo aging periods this packet has been in transit. Money feeder_share = 0; ///< Value of feeder pickup to be paid for on delivery of cargo. - TileIndex source_xy = 0; ///< The origin of the cargo. + TileIndex source_xy = INVALID_TILE; ///< The origin of the cargo. SourceID source_id = INVALID_SOURCE; ///< Index of industry/town/HQ, INVALID_SOURCE if unknown/invalid. SourceType source_type = SourceType::Industry; ///< Type of \c source_id. uint8 flags = 0; ///< NOSAVE: temporary flags @@ -79,7 +79,7 @@ public: static const uint16 MAX_COUNT = UINT16_MAX; CargoPacket(); - CargoPacket(StationID first_station, TileIndex source_xy, uint16_t count, SourceType source_type, SourceID source_id); + CargoPacket(StationID first_station, uint16_t count, SourceType source_type, SourceID source_id); CargoPacket(uint16_t count, uint16_t periods_in_transit, StationID first_station, TileIndex source_xy, Money feeder_share); CargoPacket(uint16_t count, Money feeder_share, const CargoPacket &original); ~CargoPacket(); @@ -97,6 +97,25 @@ public: this->next_hop = next_hop; } + /** + * Set the origin of the packet. + * + * Can only be set once. + * + * When a packet is created, it is moved to a station. But at that moment + * in time it is not known yet at which tile the cargo will be picked up. + * As this tile is used for payment information, we delay setting the + * source_xy till first pickup. + * + * @param tile Tile the cargo is being picked up from. + */ + void SetSourceXY(TileIndex tile) + { + if (this->source_xy == INVALID_TILE) { + this->source_xy = tile; + } + } + /** * Adds some feeder share to the packet. * @param new_share Feeder share to be added. @@ -178,12 +197,15 @@ public: } /** - * Gets the coordinates of the cargo's source. - * @return Source coordinates of cargo. + * Get the current distance the cargo has traveled. + * + * @param current_tile Current tile of the cargo. + * @return uint The distance (in tiles) traveled. */ - inline TileIndex GetSourceXY() const + inline uint GetDistance(TileIndex current_tile) const { - return this->source_xy; + assert(this->source_xy != INVALID_TILE); + return DistanceManhattan(this->source_xy, current_tile); } /** @@ -434,7 +456,7 @@ public: void InvalidateCache(); - bool Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8 order_flags, const GoodsEntry *ge, CargoPayment *payment); + bool Stage(bool accepted, StationID current_station, StationIDStack next_station, uint8_t order_flags, const GoodsEntry *ge, CargoPayment *payment, TileIndex current_tile); /** * Marks all cargo in the vehicle as to be kept. This is mostly useful for @@ -454,7 +476,7 @@ public: template uint Reassign(uint max_move); uint Return(uint max_move, StationCargoList *dest, StationID next_station); - uint Unload(uint max_move, StationCargoList *dest, CargoPayment *payment); + uint Unload(uint max_move, StationCargoList *dest, CargoPayment *payment, TileIndex current_tile); uint Shift(uint max_move, VehicleCargoList *dest); uint Truncate(uint max_move = UINT_MAX); uint Reroute(uint max_move, VehicleCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge); @@ -471,6 +493,7 @@ public: { return cp1->source_xy == cp2->source_xy && cp1->periods_in_transit == cp2->periods_in_transit && + cp1->first_station == cp2->first_station && cp1->source_type == cp2->source_type && cp1->source_id == cp2->source_id; } @@ -578,8 +601,8 @@ public: * amount of cargo to be moved. Second parameter is destination (if * applicable), return value is amount of cargo actually moved. */ - uint Reserve(uint max_move, VehicleCargoList *dest, StationIDStack next); - uint Load(uint max_move, VehicleCargoList *dest, StationIDStack next); + uint Reserve(uint max_move, VehicleCargoList *dest, StationIDStack next, TileIndex current_tile); + uint Load(uint max_move, VehicleCargoList *dest, StationIDStack next, TileIndex current_tile); uint Truncate(uint max_move = UINT_MAX, StationCargoAmountMap *cargo_per_source = nullptr); uint Reroute(uint max_move, StationCargoList *dest, StationID avoid, StationID avoid2, const GoodsEntry *ge); uint RerouteFromSource(uint max_move, StationCargoList *dest, StationID source, StationID avoid, StationID avoid2, const GoodsEntry *ge); @@ -605,6 +628,7 @@ public: { return cp1->source_xy == cp2->source_xy && cp1->periods_in_transit == cp2->periods_in_transit && + cp1->first_station == cp2->first_station && cp1->source_type == cp2->source_type && cp1->source_id == cp2->source_id; } diff --git a/src/economy.cpp b/src/economy.cpp index 18d3ea4ce4..1db31190d2 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -1322,15 +1322,15 @@ static uint DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, uint n * @param num_pieces amount of cargo delivered * @param cargo_type the type of cargo that is delivered * @param dest Station the cargo has been unloaded - * @param source_tile The origin of the cargo for distance calculation - * @param periods_in_transit ravel time in cargo aging periods + * @param distance The distance the cargo has traveled. + * @param periods_in_transit Travel time in cargo aging periods * @param company The company delivering the cargo * @param src_type Type of source of cargo (industry, town, headquarters) * @param src Index of source of cargo * @return Revenue for delivering cargo * @note The cargo is just added to the stockpile of the industry. It is due to the caller to trigger the industry's production machinery */ -static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID dest, TileIndex source_tile, uint16 periods_in_transit, Company *company, SourceType src_type, SourceID src) +static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID dest, uint distance, uint16_t periods_in_transit, Company *company, SourceType src_type, SourceID src) { assert(num_pieces > 0); @@ -1357,7 +1357,7 @@ static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID dest, Ti st->town->received[cs->town_effect].new_act += accepted_total; /* Determine profit */ - Money profit = GetTransportedGoodsIncome(accepted_total, DistanceManhattan(source_tile, st->xy), periods_in_transit, cargo_type); + Money profit = GetTransportedGoodsIncome(accepted_total, distance, periods_in_transit, cargo_type); /* Update the cargo monitor. */ AddCargoDelivery(cargo_type, company->index, accepted_total - accepted_ind, src_type, src, st); @@ -1454,15 +1454,16 @@ CargoPayment::~CargoPayment() * Handle payment for final delivery of the given cargo packet. * @param cp The cargo packet to pay for. * @param count The number of packets to pay for. + * @param current_tile Current tile the payment is happening on. */ -void CargoPayment::PayFinalDelivery(CargoPacket *cp, uint count) +void CargoPayment::PayFinalDelivery(CargoPacket *cp, uint count, TileIndex current_tile) { if (this->owner == nullptr) { this->owner = Company::Get(this->front->owner); } /* Handle end of route payment */ - Money profit = DeliverGoods(count, this->ct, this->current_station, cp->GetSourceXY(), cp->GetPeriodsInTransit(), this->owner, cp->GetSourceType(), cp->GetSourceID()); + Money profit = DeliverGoods(count, this->ct, this->current_station, cp->GetDistance(current_tile), cp->GetPeriodsInTransit(), this->owner, cp->GetSourceType(), cp->GetSourceID()); profit -= cp->GetFeederShare(count); @@ -1478,15 +1479,16 @@ void CargoPayment::PayFinalDelivery(CargoPacket *cp, uint count) * Handle payment for transfer of the given cargo packet. * @param cp The cargo packet to pay for; actual payment won't be made!. * @param count The number of packets to pay for. + * @param current_tile Current tile the payment is happening on. * @return The amount of money paid for the transfer. */ -Money CargoPayment::PayTransfer(CargoPacket *cp, uint count) +Money CargoPayment::PayTransfer(CargoPacket *cp, uint count, TileIndex current_tile) { + /* Pay transfer vehicle the difference between the payment for the journey from + * the source to the current point, and the sum of the previous transfer payments */ Money profit = -cp->GetFeederShare(count) + GetTransportedGoodsIncome( count, - /* pay transfer vehicle the difference between the payment for the journey from - * the source to the current point, and the sum of the previous transfer payments */ - DistanceManhattan(cp->GetSourceXY(), Station::Get(this->current_station)->xy), + cp->GetDistance(current_tile), cp->GetPeriodsInTransit(), this->ct); @@ -1556,7 +1558,8 @@ void PrepareUnload(Vehicle *front_v) HasBit(ge->status, GoodsEntry::GES_ACCEPTANCE), front_v->last_station_visited, next_station.Get(v->cargo_type), GetUnloadType(v), ge, - front_v->cargo_payment); + front_v->cargo_payment, + v->tile); if (v->cargo.UnloadCount() > 0) SetBit(v->vehicle_flags, VF_CARGO_UNLOADING); } } @@ -1751,7 +1754,7 @@ struct FinalizeRefitAction { if (this->do_reserve || (cargo_type_loading == nullptr || (cargo_type_loading->current_order.GetCargoLoadTypeRaw(v->cargo_type) & OLFB_FULL_LOAD))) { this->st->goods[v->cargo_type].CreateData().cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(), - &v->cargo, this->next_station.Get(v->cargo_type)); + &v->cargo, this->next_station.Get(v->cargo_type), v->tile); } this->consist_capleft[v->cargo_type] += v->cargo_cap - v->cargo.RemainingCount(); return true; @@ -1856,7 +1859,7 @@ struct ReserveCargoAction { } if (v->cargo_cap > v->cargo.RemainingCount() && MayLoadUnderExclusiveRights(st, v)) { st->goods[v->cargo_type].CreateData().cargo.Reserve(v->cargo_cap - v->cargo.RemainingCount(), - &v->cargo, next_station.Get(v->cargo_type)); + &v->cargo, next_station.Get(v->cargo_type), v->tile); } return true; @@ -2121,7 +2124,7 @@ static void LoadUnloadVehicle(Vehicle *front) } } - amount_unloaded = v->cargo.Unload(amount_unloaded, &ged->cargo, payment); + amount_unloaded = v->cargo.Unload(amount_unloaded, &ged->cargo, payment, v->tile); remaining = v->cargo.UnloadCount() > 0; if (amount_unloaded > 0) { dirty_vehicle = true; @@ -2196,7 +2199,7 @@ static void LoadUnloadVehicle(Vehicle *front) if (v->cargo.StoredCount() == 0) TriggerVehicle(v, VEHICLE_TRIGGER_NEW_CARGO); if (_settings_game.order.gradual_loading) cap_left = std::min(cap_left, GetLoadAmount(v)); - uint loaded = ged->cargo.Load(cap_left, &v->cargo, next_station.Get(v->cargo_type)); + uint loaded = ged->cargo.Load(cap_left, &v->cargo, next_station.Get(v->cargo_type), v->tile); if (v->cargo.ActionCount(VehicleCargoList::MTA_LOAD) > 0) { /* Remember if there are reservations left so that we don't stop * loading before they're loaded. */ diff --git a/src/economy_base.h b/src/economy_base.h index a36e915be0..cee669cf9a 100644 --- a/src/economy_base.h +++ b/src/economy_base.h @@ -37,8 +37,8 @@ struct CargoPayment : CargoPaymentPool::PoolItem<&_cargo_payment_pool> { CargoPayment(Vehicle *front); ~CargoPayment(); - Money PayTransfer(CargoPacket *cp, uint count); - void PayFinalDelivery(CargoPacket *cp, uint count); + Money PayTransfer(CargoPacket *cp, uint count, TileIndex current_tile); + void PayFinalDelivery(CargoPacket *cp, uint count, TileIndex current_tile); /** * Sets the currently handled cargo type. diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 7d9633d858..eaa302cec6 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -4710,7 +4710,7 @@ static uint UpdateStationWaiting(Station *st, CargoID type, uint amount, SourceT if (amount == 0) return 0; StationID next = ge.GetVia(st->index); - ge.CreateData().cargo.Append(new CargoPacket(st->index, st->xy, amount, source_type, source_id), next); + ge.CreateData().cargo.Append(new CargoPacket(st->index, amount, source_type, source_id), next); LinkGraph *lg = nullptr; if (ge.link_graph == INVALID_LINK_GRAPH) { if (LinkGraph::CanAllocateItem()) {