Changeset - r12269:f94731e7dc53
[Not reviewed]
master
0 13 0
rubidium - 15 years ago 2009-06-29 19:55:36
rubidium@openttd.org
(svn r16694) -Fix [FS#2995] (rgradual loading, rnewindustries): only pay for whatever has been actually unloaded and perform the payment when unloading has finished. This fixes, amongst others:
* cheating by starting to unload and after getting paid rushing to the depot to get sold (or unloading, loading and getting paid again for the remainder)
* cargo being dropped onto a station at the moment a stockpiling industry doesn't accept it anymore
* industries getting cargo that has not been unloaded yet and subsequently dumping it back on the station in one go
Note: you will now get paid after the unloading has finished, so you'll have to wait a bit longer for 'your' money.
13 files changed with 164 insertions and 115 deletions:
0 comments (0 inline, 0 general)
src/autoreplace_cmd.cpp
Show inline comments
 
@@ -108,13 +108,13 @@ static void TransferCargo(Vehicle *old_v
 
			}
 
			if (dest->cargo_type != src->cargo_type) continue;
 

	
 
			uint amount = min(src->cargo.Count(), dest->cargo_cap - dest->cargo.Count());
 
			if (amount <= 0) continue;
 

	
 
			src->cargo.MoveTo(&dest->cargo, amount);
 
			src->cargo.MoveTo(&dest->cargo, amount, CargoList::MTA_UNLOAD, NULL);
 
		}
 
	}
 

	
 
	/* Update train weight etc., the old vehicle will be sold anyway */
 
	if (part_of_chain && new_head->type == VEH_TRAIN) TrainConsistChanged(Train::From(new_head), true);
 
}
src/cargopacket.cpp
Show inline comments
 
@@ -2,12 +2,13 @@
 

	
 
/** @file cargopacket.cpp Implementation of the cargo packets */
 

	
 
#include "stdafx.h"
 
#include "station_base.h"
 
#include "core/pool_func.hpp"
 
#include "economy_base.h"
 

	
 
/* Initialize the cargopacket-pool */
 
CargoPacketPool _cargopacket_pool("CargoPacket");
 
INSTANTIATE_POOL_METHODS(CargoPacket)
 

	
 
void InitializeCargoPackets()
 
@@ -23,13 +24,12 @@ CargoPacket::CargoPacket(StationID sourc
 
	this->source_xy       = (source != INVALID_STATION) ? Station::Get(source)->xy : 0;
 
	this->loaded_at_xy    = this->source_xy;
 

	
 
	this->count           = count;
 
	this->days_in_transit = 0;
 
	this->feeder_share    = 0;
 
	this->paid_for        = false;
 
}
 

	
 
/*
 
 *
 
 * Cargo list implementation
 
 *
 
@@ -96,41 +96,47 @@ void CargoList::Truncate(uint count)
 
		packets.pop_back();
 
	}
 

	
 
	InvalidateCache();
 
}
 

	
 
bool CargoList::MoveTo(CargoList *dest, uint count, CargoList::MoveToAction mta, uint data)
 
bool CargoList::MoveTo(CargoList *dest, uint count, CargoList::MoveToAction mta, CargoPayment *payment, uint data)
 
{
 
	assert(mta == MTA_FINAL_DELIVERY || dest != NULL);
 
	assert(mta == MTA_UNLOAD || mta == MTA_CARGO_LOAD || payment != NULL);
 
	CargoList tmp;
 

	
 
	while (!packets.empty() && count > 0) {
 
		CargoPacket *cp = *packets.begin();
 
		if (cp->count <= count) {
 
			/* Can move the complete packet */
 
			packets.remove(cp);
 
			switch (mta) {
 
				case MTA_FINAL_DELIVERY:
 
					if (cp->source == data) {
 
						tmp.Append(cp);
 
					} else {
 
						payment->PayFinalDelivery(cp, cp->count);
 
						count -= cp->count;
 
						delete cp;
 
					}
 
					break;
 
					continue; // of the loop
 

	
 
				case MTA_CARGO_LOAD:
 
					cp->loaded_at_xy = data;
 
					/* When cargo is moved into another vehicle you have *always* paid for it */
 
					cp->paid_for     = false;
 
					/* FALL THROUGH */
 
				case MTA_OTHER:
 
					count -= cp->count;
 
					dest->packets.push_back(cp);
 
					break;
 

	
 
				case MTA_TRANSFER:
 
					payment->PayTransfer(cp, cp->count);
 
					break;
 

	
 
				case MTA_UNLOAD:
 
					break;
 
			}
 
			count -= cp->count;
 
			dest->packets.push_back(cp);
 
		} else {
 
			/* Can move only part of the packet, so split it into two pieces */
 
			if (mta != MTA_FINAL_DELIVERY) {
 
				CargoPacket *cp_new = new CargoPacket();
 

	
 
				Money fs = cp->feeder_share * count / static_cast<uint>(cp->count);
 
@@ -139,29 +145,31 @@ bool CargoList::MoveTo(CargoList *dest, 
 
				cp_new->source          = cp->source;
 
				cp_new->source_xy       = cp->source_xy;
 
				cp_new->loaded_at_xy    = (mta == MTA_CARGO_LOAD) ? data : cp->loaded_at_xy;
 

	
 
				cp_new->days_in_transit = cp->days_in_transit;
 
				cp_new->feeder_share    = fs;
 
				/* When cargo is moved into another vehicle you have *always* paid for it */
 
				cp_new->paid_for        = (mta == MTA_CARGO_LOAD) ? false : cp->paid_for;
 

	
 
				cp_new->count = count;
 
				dest->packets.push_back(cp_new);
 

	
 
				if (mta == MTA_TRANSFER) payment->PayTransfer(cp_new, count);
 
			} else {
 
				payment->PayFinalDelivery(cp, count);
 
			}
 
			cp->count -= count;
 

	
 
			count = 0;
 
		}
 
	}
 

	
 
	bool remaining = !packets.empty();
 

	
 
	if (mta == MTA_FINAL_DELIVERY && !tmp.Empty()) {
 
		/* There are some packets that could not be delivered at the station, put them back */
 
		tmp.MoveTo(this, UINT_MAX);
 
		tmp.MoveTo(this, UINT_MAX, MTA_UNLOAD, NULL);
 
		tmp.packets.clear();
 
	}
 

	
 
	if (dest != NULL) dest->InvalidateCache();
 
	InvalidateCache();
 

	
 
@@ -169,23 +177,21 @@ bool CargoList::MoveTo(CargoList *dest, 
 
}
 

	
 
void CargoList::InvalidateCache()
 
{
 
	empty = packets.empty();
 
	count = 0;
 
	unpaid_cargo = false;
 
	feeder_share = 0;
 
	source = INVALID_STATION;
 
	days_in_transit = 0;
 

	
 
	if (empty) return;
 

	
 
	uint dit = 0;
 
	for (List::const_iterator it = packets.begin(); it != packets.end(); it++) {
 
		count        += (*it)->count;
 
		unpaid_cargo |= !(*it)->paid_for;
 
		dit          += (*it)->days_in_transit * (*it)->count;
 
		feeder_share += (*it)->feeder_share;
 
	}
 
	days_in_transit = dit / count;
 
	source = (*packets.begin())->source;
 
}
src/cargopacket.h
Show inline comments
 
@@ -26,13 +26,12 @@ struct CargoPacket : CargoPacketPool::Po
 
	TileIndex source_xy;    ///< The origin of the cargo (first station in feeder chain)
 
	TileIndex loaded_at_xy; ///< Location where this cargo has been loaded into the vehicle
 
	StationID source;       ///< The station where the cargo came from first
 

	
 
	uint16 count;           ///< The amount of cargo in this packet
 
	byte days_in_transit;   ///< Amount of days this packet has been in transit
 
	bool paid_for;          ///< Have we been paid for this cargo packet?
 

	
 
	/**
 
	 * Creates a new cargo packet
 
	 * @param source the source of the packet
 
	 * @param count  the number of cargo entities to put in this packet
 
	 * @pre count != 0 || source == INVALID_STATION
 
@@ -47,13 +46,13 @@ struct CargoPacket : CargoPacketPool::Po
 
	 * in time and location.
 
	 * @param cp the cargo packet to compare to
 
	 * @return true if and only if days_in_transit and source_xy are equal
 
	 */
 
	FORCEINLINE bool SameSource(const CargoPacket *cp) const
 
	{
 
		return this->source_xy == cp->source_xy && this->days_in_transit == cp->days_in_transit && this->paid_for == cp->paid_for;
 
		return this->source_xy == cp->source_xy && this->days_in_transit == cp->days_in_transit;
 
	}
 
};
 

	
 
/**
 
 * Iterate over all _valid_ cargo packets from the given start
 
 * @param var   the variable used as "iterator"
 
@@ -78,21 +77,21 @@ public:
 
	typedef std::list<CargoPacket *> List;
 

	
 
	/** Kind of actions that could be done with packets on move */
 
	enum MoveToAction {
 
		MTA_FINAL_DELIVERY, ///< "Deliver" the packet to the final destination, i.e. destroy the packet
 
		MTA_CARGO_LOAD,     ///< Load the packet onto a vehicle, i.e. set the last loaded station ID
 
		MTA_OTHER           ///< "Just" move the packet to another cargo list
 
		MTA_TRANSFER,       ///< The cargo is moved as part of a transfer
 
		MTA_UNLOAD,         ///< The cargo is moved as part of a forced unload
 
	};
 

	
 
private:
 
	List packets;         ///< The cargo packets in this list
 

	
 
	bool empty;           ///< Cache for whether this list is empty or not
 
	uint count;           ///< Cache for the number of cargo entities
 
	bool unpaid_cargo;    ///< Cache for the unpaid cargo
 
	Money feeder_share;   ///< Cache for the feeder share
 
	StationID source;     ///< Cache for the source of the packet
 
	uint days_in_transit; ///< Cache for the number of days in transit
 

	
 
public:
 
	friend const struct SaveLoad *GetGoodsDesc();
 
@@ -123,18 +122,12 @@ public:
 
	 * Returns the number of cargo entities in this list
 
	 * @return the before mentioned number
 
	 */
 
	FORCEINLINE uint Count() const { return this->count; }
 

	
 
	/**
 
	 * Is there some cargo that has not been paid for?
 
	 * @return true if and only if there is such a cargo
 
	 */
 
	FORCEINLINE bool UnpaidCargo() const { return this->unpaid_cargo; }
 

	
 
	/**
 
	 * Returns total sum of the feeder share for all packets
 
	 * @return the before mentioned number
 
	 */
 
	FORCEINLINE Money FeederShare() const { return this->feeder_share; }
 

	
 
	/**
 
@@ -168,24 +161,29 @@ public:
 

	
 
	/**
 
	 * Moves the given amount of cargo to another list.
 
	 * Depending on the value of mta the side effects of this function differ:
 
	 *  - MTA_FINAL_DELIVERY: destroys the packets that do not originate from a specific station
 
	 *  - MTA_CARGO_LOAD:     sets the loaded_at_xy value of the moved packets
 
	 *  - MTA_OTHER:          just move without side effects
 
	 *  - MTA_TRANSFER:       just move without side effects
 
	 *  - MTA_UNLOAD:         just move without side effects
 
	 * @param dest  the destination to move the cargo to
 
	 * @param count the amount of cargo entities to move
 
	 * @param mta   how to handle the moving (side effects)
 
	 * @param data  Depending on mta the data of this variable differs:
 
	 *              - MTA_FINAL_DELIVERY - station ID of packet's origin not to remove
 
	 *              - MTA_CARGO_LOAD     - station's tile index of load
 
	 *              - MTA_OTHER          - unused
 
	 * @param mta == MTA_FINAL_DELIVERY || dest != NULL
 
	 *              - MTA_TRANSFER       - unused
 
	 *              - MTA_UNLOAD         - unused
 
	 * @param payment The payment helper
 
	 *
 
	 * @pre mta == MTA_FINAL_DELIVERY || dest != NULL
 
	 * @pre mta == MTA_UNLOAD || mta == MTA_CARGO_LOAD || payment != NULL
 
	 * @return true if there are still packets that might be moved from this cargo list
 
	 */
 
	bool MoveTo(CargoList *dest, uint count, CargoList::MoveToAction mta = MTA_OTHER, uint data = 0);
 
	bool MoveTo(CargoList *dest, uint count, CargoList::MoveToAction mta, CargoPayment *payment, uint data = 0);
 

	
 
	/** Invalidates the cached data and rebuild it */
 
	void InvalidateCache();
 
};
 

	
 
#endif /* CARGOPACKET_H */
src/economy.cpp
Show inline comments
 
@@ -33,16 +33,22 @@
 
#include "autoreplace_func.h"
 
#include "company_gui.h"
 
#include "signs_base.h"
 
#include "subsidy_func.h"
 
#include "station_base.h"
 
#include "economy_base.h"
 
#include "core/pool_func.hpp"
 

	
 
#include "table/strings.h"
 
#include "table/sprites.h"
 

	
 

	
 
/* Initialize the cargo payment-pool */
 
CargoPaymentPool _cargo_payment_pool("CargoPayment");
 
INSTANTIATE_POOL_METHODS(CargoPayment)
 

	
 
/**
 
 * Multiply two integer values and shift the results to right.
 
 *
 
 * This function multiplies two integer values. The result is
 
 * shifted by the amount of shift to right.
 
 *
 
@@ -1145,21 +1151,22 @@ static void TriggerIndustryProduction(In
 
 * Makes us a new cargo payment helper.
 
 * @param front The front of the train
 
 * @param destinations List to add the destinations of 'our' cargo to
 
 */
 
CargoPayment::CargoPayment(Vehicle *front) :
 
	front(front),
 
	route_profit(0),
 
	visual_profit(0),
 
	owner(NULL),
 
	current_station(front->last_station_visited)
 
{
 
}
 

	
 
CargoPayment::~CargoPayment()
 
{
 
	if (this->CleaningPool()) return;
 

	
 
	this->front->cargo_payment = NULL;
 

	
 
	if (this->visual_profit == 0) return;
 

	
 
	CompanyID old_company = _current_company;
 
	_current_company = this->front->owner;
 

	
 
	SubtractMoneyFromCompany(CommandCost(this->front->GetExpenseType(true), -this->route_profit));
 
@@ -1192,14 +1199,12 @@ void CargoPayment::PayFinalDelivery(Carg
 
	/* Handle end of route payment */
 
	Money profit = DeliverGoods(count, this->ct, cp->source, this->current_station, cp->source_xy, cp->days_in_transit, this->owner);
 
	this->route_profit += profit;
 

	
 
	/* The vehicle's profit is whatever route profit there is minus feeder shares. */
 
	this->visual_profit += profit - cp->feeder_share;
 

	
 
	cp->paid_for = true;
 
}
 

	
 
/**
 
 * Handle payment for transfer of the given cargo packet.
 
 * @param cp The cargo packet to pay for.
 
 * @param count The number of packets to pay for.
 
@@ -1212,86 +1217,36 @@ void CargoPayment::PayTransfer(CargoPack
 
		DistanceManhattan(cp->loaded_at_xy, Station::Get(this->current_station)->xy),
 
		cp->days_in_transit,
 
		this->ct);
 

	
 
	this->visual_profit += profit; // accumulate transfer profits for whole vehicle
 
	cp->feeder_share    += profit; // account for the (virtual) profit already made for the cargo packet
 

	
 
	cp->paid_for = true;
 
}
 

	
 
/**
 
 * Performs the vehicle payment _and_ marks the vehicle to be unloaded.
 
 * Prepare the vehicle to be unloaded.
 
 * @param front_v the vehicle to be unloaded
 
 */
 
void VehiclePayment(Vehicle *front_v)
 
void PrepareUnload(Vehicle *front_v)
 
{
 
	int result = 0;
 

	
 
	Money vehicle_profit = 0; // Money paid to the train
 
	Money route_profit   = 0; // The grand total amount for the route. A-D of transfer chain A-B-C-D
 
	Money virtual_profit = 0; // The virtual profit for entire vehicle chain
 

	
 
	StationID last_visited = front_v->last_station_visited;
 
	Station *st = Station::Get(last_visited);
 

	
 
	/* At this moment loading cannot be finished */
 
	ClrBit(front_v->vehicle_flags, VF_LOADING_FINISHED);
 

	
 
	/* Start unloading in at the first possible moment */
 
	front_v->load_unload_time_rem = 1;
 

	
 
	CargoPayment payment(front_v);
 

	
 
	for (Vehicle *v = front_v; v != NULL; v = v->Next()) {
 
		/* No cargo to unload */
 
		if (v->cargo_cap == 0 || v->cargo.Empty() || (front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD)) continue;
 

	
 
		/* All cargo has already been paid for, no need to pay again */
 
		if (!v->cargo.UnpaidCargo()) {
 
			SetBit(v->vehicle_flags, VF_CARGO_UNLOADING);
 
			continue;
 
		}
 

	
 
		GoodsEntry *ge = &st->goods[v->cargo_type];
 
		const CargoList::List *cargos = v->cargo.Packets();
 

	
 
		payment.SetCargo(v->cargo_type);
 

	
 
		for (CargoList::List::const_iterator it = cargos->begin(); it != cargos->end(); it++) {
 
			CargoPacket *cp = *it;
 
			if (!cp->paid_for &&
 
					cp->source != last_visited &&
 
					HasBit(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE) &&
 
					(front_v->current_order.GetUnloadType() & OUFB_TRANSFER) == 0) {
 
				/* Deliver goods to the station */
 
				st->time_since_unload = 0;
 

	
 
				payment.PayFinalDelivery(cp, cp->count);
 

	
 
				result |= 1;
 

	
 
				SetBit(v->vehicle_flags, VF_CARGO_UNLOADING);
 
			} else if (front_v->current_order.GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) {
 
				if (!cp->paid_for && (front_v->current_order.GetUnloadType() & OUFB_TRANSFER) != 0) {
 
					payment.PayTransfer(cp, cp->count);
 
				}
 
				result |= 2;
 

	
 
	if ((front_v->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
 
		for (Vehicle *v = front_v; v != NULL; v = v->Next()) {
 
			if (v->cargo_cap > 0 && !v->cargo.Empty()) {
 
				SetBit(v->vehicle_flags, VF_CARGO_UNLOADING);
 
			}
 
		}
 
		v->cargo.InvalidateCache();
 
	}
 

	
 
	/* Call the production machinery of industries */
 
	const Industry * const *isend = _cargo_delivery_destinations.End();
 
	for (Industry **iid = _cargo_delivery_destinations.Begin(); iid != isend; iid++) {
 
		TriggerIndustryProduction(*iid);
 
	}
 
	_cargo_delivery_destinations.Clear();
 
	assert(front_v->cargo_payment == NULL);
 
	front_v->cargo_payment = new CargoPayment(front_v);
 
}
 

	
 
/**
 
 * Loads/unload the vehicle if possible.
 
 * @param v the vehicle to be (un)loaded
 
 * @param cargo_left the amount of each cargo type that is
 
@@ -1334,12 +1289,14 @@ static void LoadUnloadVehicle(Vehicle *v
 
	bool anything_loaded   = false;
 
	uint32 cargo_not_full  = 0;
 
	uint32 cargo_full      = 0;
 

	
 
	v->cur_speed = 0;
 

	
 
	CargoPayment *payment = v->cargo_payment;
 

	
 
	for (; v != NULL; v = v->Next()) {
 
		if (v->cargo_cap == 0) continue;
 

	
 
		byte load_amount = EngInfo(v->engine_type)->load_amount;
 

	
 
		/* The default loadamount for mail is 1/4 of the load amount for passengers */
 
@@ -1355,27 +1312,29 @@ static void LoadUnloadVehicle(Vehicle *v
 
		if (HasBit(v->vehicle_flags, VF_CARGO_UNLOADING) && (u->current_order.GetUnloadType() & OUFB_NO_UNLOAD) == 0) {
 
			uint cargo_count = v->cargo.Count();
 
			uint amount_unloaded = _settings_game.order.gradual_loading ? min(cargo_count, load_amount) : cargo_count;
 
			bool remaining = false; // Are there cargo entities in this vehicle that can still be unloaded here?
 
			bool accepted  = false; // Is the cargo accepted by the station?
 

	
 
			payment->SetCargo(v->cargo_type);
 

	
 
			if (HasBit(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE) && !(u->current_order.GetUnloadType() & OUFB_TRANSFER)) {
 
				/* The cargo has reached it's final destination, the packets may now be destroyed */
 
				remaining = v->cargo.MoveTo(NULL, amount_unloaded, CargoList::MTA_FINAL_DELIVERY, last_visited);
 
				remaining = v->cargo.MoveTo(NULL, amount_unloaded, CargoList::MTA_FINAL_DELIVERY, payment, last_visited);
 

	
 
				result |= 1;
 
				accepted = true;
 
			}
 

	
 
			/* The !accepted || v->cargo.Count == cargo_count clause is there
 
			 * to make it possible to force unload vehicles at the station where
 
			 * they were loaded, but to not force unload the vehicle when the
 
			 * station is still accepting the cargo in the vehicle. It doesn't
 
			 * accept cargo that was loaded at the same station. */
 
			if ((u->current_order.GetUnloadType() & (OUFB_UNLOAD | OUFB_TRANSFER)) && (!accepted || v->cargo.Count() == cargo_count)) {
 
				remaining = v->cargo.MoveTo(&ge->cargo, amount_unloaded);
 
				remaining = v->cargo.MoveTo(&ge->cargo, amount_unloaded, u->current_order.GetUnloadType() & OUFB_TRANSFER ? CargoList::MTA_TRANSFER : CargoList::MTA_UNLOAD, payment);
 
				SetBit(ge->acceptance_pickup, GoodsEntry::PICKUP);
 

	
 
				result |= 2;
 
			} else if (!accepted) {
 
				/* The order changed while unloading (unset unload/transfer) or the
 
				 * station does not accept goods anymore. */
 
@@ -1446,13 +1405,13 @@ static void LoadUnloadVehicle(Vehicle *v
 
			 * the whole vehicle chain is really totally empty, the
 
			 * completely_emptied assignment can then be safely
 
			 * removed; that's how TTDPatch behaves too. --pasky */
 
			completely_emptied = false;
 
			anything_loaded = true;
 

	
 
			ge->cargo.MoveTo(&v->cargo, cap, CargoList::MTA_CARGO_LOAD, st->xy);
 
			ge->cargo.MoveTo(&v->cargo, cap, CargoList::MTA_CARGO_LOAD, NULL, st->xy);
 

	
 
			st->time_since_load = 0;
 
			st->last_vehicle_type = v->type;
 

	
 
			StationAnimationTrigger(st, st->xy, STAT_ANIM_CARGO_TAKEN, v->cargo_type);
 

	
 
@@ -1482,12 +1441,14 @@ static void LoadUnloadVehicle(Vehicle *v
 
			if (cap_left > 0) cargo_left[v->cargo_type] -= cap_left;
 
		}
 
	}
 

	
 
	v = u;
 

	
 
	if (!anything_unloaded) delete payment;
 

	
 
	if (anything_loaded || anything_unloaded) {
 
		if (_settings_game.order.gradual_loading) {
 
			/* The time it takes to load one 'slice' of cargo or passengers depends
 
			 * on the vehicle type - the values here are those found in TTDPatch */
 
			const uint gradual_loading_wait_time[] = { 40, 20, 10, 20 };
 

	
 
@@ -1570,12 +1531,19 @@ void LoadUnloadStation(Station *st)
 

	
 
	std::list<Vehicle *>::iterator iter;
 
	for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end(); ++iter) {
 
		Vehicle *v = *iter;
 
		if (!(v->vehstatus & (VS_STOPPED | VS_CRASHED))) LoadUnloadVehicle(v, cargo_left);
 
	}
 

	
 
	/* Call the production machinery of industries */
 
	const Industry * const *isend = _cargo_delivery_destinations.End();
 
	for (Industry **iid = _cargo_delivery_destinations.Begin(); iid != isend; iid++) {
 
		TriggerIndustryProduction(*iid);
 
	}
 
	_cargo_delivery_destinations.Clear();
 
}
 

	
 
void CompaniesMonthlyLoop()
 
{
 
	CompaniesGenStatistics();
 
	if (_settings_game.economy.inflation) AddInflation();
src/economy_base.h
Show inline comments
 
@@ -4,25 +4,32 @@
 

	
 
#ifndef ECONOMY_BASE_H
 
#define ECONOMY_BASE_H
 

	
 
#include "cargopacket.h"
 

	
 
/** Type of pool to store cargo payments in. */
 
typedef Pool<CargoPayment, CargoPaymentID, 512, 64000> CargoPaymentPool;
 
/** The actual pool to store cargo payments in. */
 
extern CargoPaymentPool _cargo_payment_pool;
 

	
 
/**
 
 * Helper class to perform the cargo payment.
 
 */
 
struct CargoPayment {
 
struct CargoPayment : CargoPaymentPool::PoolItem<&_cargo_payment_pool> {
 
	Vehicle *front;      ///< The front vehicle to do the payment of
 
	Money route_profit;  ///< The amount of money to add/remove from the bank account
 
	Money visual_profit; ///< The visual profit to show
 

	
 
	/* Unsaved variables */
 
	Company *owner;            ///< The owner of the vehicle
 
	StationID current_station; ///< The current station
 
	CargoID ct;                ///< The currently handled cargo type
 

	
 
	/** Constructor for pool saveload */
 
	CargoPayment() {}
 
	CargoPayment(Vehicle *front);
 
	~CargoPayment();
 

	
 
	void PayTransfer(CargoPacket *cp, uint count);
 
	void PayFinalDelivery(CargoPacket *cp, uint count);
 

	
 
@@ -30,7 +37,10 @@ struct CargoPayment {
 
	 * Sets the currently handled cargo type.
 
	 * @param ct the cargo type to handle from now on.
 
	 */
 
	void SetCargo(CargoID ct) { this->ct = ct; }
 
};
 

	
 
#define FOR_ALL_CARGO_PAYMENTS_FROM(var, start) FOR_ALL_ITEMS_FROM(CargoPayment, cargo_payment_index, var, start)
 
#define FOR_ALL_CARGO_PAYMENTS(var) FOR_ALL_CARGO_PAYMENTS_FROM(var, 0)
 

	
 
#endif /* ECONOMY_BASE_H */
src/economy_func.h
Show inline comments
 
@@ -31,12 +31,12 @@ extern uint16 _cargo_payment_rates_frac[
 
int UpdateCompanyRatingAndValue(Company *c, bool update);
 
void StartupIndustryDailyChanges(bool init_counter);
 

	
 
Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type);
 
uint MoveGoodsToStation(TileIndex tile, int w, int h, CargoID type, uint amount);
 

	
 
void VehiclePayment(Vehicle *front_v);
 
void PrepareUnload(Vehicle *front_v);
 
void LoadUnloadStation(Station *st);
 

	
 
Money GetPriceByIndex(uint8 index);
 

	
 
#endif /* ECONOMY_FUNC_H */
src/economy_type.h
Show inline comments
 
@@ -122,7 +122,10 @@ enum ExpensesType {
 
	INVALID_EXPENSES      = 0xFF,
 
};
 

	
 
/** The "steps" in loan size, in British Pounds! */
 
static const int LOAN_INTERVAL = 10000;
 

	
 
struct CargoPayment;
 
typedef uint32 CargoPaymentID;
 

	
 
#endif /* ECONOMY_TYPE_H */
src/saveload/afterload.cpp
Show inline comments
 
@@ -26,12 +26,13 @@
 
#include "../unmovable_map.h"
 
#include "../tree_map.h"
 
#include "../company_func.h"
 
#include "../road_cmd.h"
 
#include "../ai/ai.hpp"
 
#include "../town.h"
 
#include "../economy_base.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "saveload_internal.h"
 

	
 
#include <signal.h>
 
@@ -544,12 +545,19 @@ bool AfterLoadGame()
 
	 *  a company does not exist yet. So create one here.
 
	 * 1 exeption: network-games. Those can have 0 companies
 
	 *   But this exeption is not true for non dedicated network_servers! */
 
	if (!Company::IsValidID(COMPANY_FIRST) && (!_networking || (_networking && _network_server && !_network_dedicated)))
 
		DoStartupNewCompany(false);
 

	
 
	/* Fix the cache for cargo payments. */
 
	CargoPayment *cp;
 
	FOR_ALL_CARGO_PAYMENTS(cp) {
 
		cp->front->cargo_payment = cp;
 
		cp->current_station = cp->front->last_station_visited;
 
	}
 

	
 
	if (CheckSavegameVersion(72)) {
 
		/* Locks/shiplifts in very old savegames had OWNER_WATER as owner */
 
		for (TileIndex t = 0; t < MapSize(); t++) {
 
			switch (GetTileType(t)) {
 
				default: break;
 

	
 
@@ -1266,19 +1274,14 @@ bool AfterLoadGame()
 
	if (CheckSavegameVersion(45)) {
 
		Vehicle *v;
 
		/* Originally just the fact that some cargo had been paid for was
 
		 * stored to stop people cheating and cashing in several times. This
 
		 * wasn't enough though as it was cleared when the vehicle started
 
		 * loading again, even if it didn't actually load anything, so now the
 
		 * amount of cargo that has been paid for is stored. */
 
		 * amount that has been paid is stored. */
 
		FOR_ALL_VEHICLES(v) {
 
			const CargoList::List *packets = v->cargo.Packets();
 
			for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) {
 
				CargoPacket *cp = *it;
 
				cp->paid_for = HasBit(v->vehicle_flags, 2);
 
			}
 
			ClrBit(v->vehicle_flags, 2);
 
			v->cargo.InvalidateCache();
 
		}
 
	}
 

	
 
	if (CheckSavegameVersion(120)) {
 
@@ -1867,12 +1870,27 @@ bool AfterLoadGame()
 
				const Vehicle *u = Vehicle::GetIfValid(v->dest_tile);
 
				if (u == NULL || u->type != VEH_ROAD || !IsRoadVehFront(u)) {
 
					delete v;
 
				}
 
			}
 
		}
 

	
 
		/* We didn't store cargo payment yet, so make them for vehicles that are
 
		 * currently at a station and loading/unloading. If they don't get any
 
		 * payment anymore they just removed in the next load/unload cycle.
 
		 * However, some 0.7 versions might have cargo payment. For those we just
 
		 * add cargopayment for the vehicles that don't have it.
 
		 */
 
		Station *st;
 
		FOR_ALL_STATIONS(st) {
 
			std::list<Vehicle *>::iterator iter;
 
			for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end(); ++iter) {
 
				Vehicle *v = *iter;
 
				if (v->cargo_payment == NULL) v->cargo_payment = new CargoPayment(v);
 
			}
 
		}
 
	}
 

	
 
	AfterLoadLabelMaps();
 

	
 
	GamelogPrintDebug(1);
 

	
src/saveload/cargopacket_sl.cpp
Show inline comments
 
@@ -5,19 +5,21 @@
 
#include "../stdafx.h"
 
#include "../cargopacket.h"
 

	
 
#include "saveload.h"
 

	
 
static const SaveLoad _cargopacket_desc[] = {
 
	SLE_VAR(CargoPacket, source,          SLE_UINT16),
 
	SLE_VAR(CargoPacket, source_xy,       SLE_UINT32),
 
	SLE_VAR(CargoPacket, loaded_at_xy,    SLE_UINT32),
 
	SLE_VAR(CargoPacket, count,           SLE_UINT16),
 
	SLE_VAR(CargoPacket, days_in_transit, SLE_UINT8),
 
	SLE_VAR(CargoPacket, feeder_share,    SLE_INT64),
 
	SLE_VAR(CargoPacket, paid_for,        SLE_BOOL),
 
	     SLE_VAR(CargoPacket, source,          SLE_UINT16),
 
	     SLE_VAR(CargoPacket, source_xy,       SLE_UINT32),
 
	     SLE_VAR(CargoPacket, loaded_at_xy,    SLE_UINT32),
 
	     SLE_VAR(CargoPacket, count,           SLE_UINT16),
 
	     SLE_VAR(CargoPacket, days_in_transit, SLE_UINT8),
 
	     SLE_VAR(CargoPacket, feeder_share,    SLE_INT64),
 

	
 
	/* Used to be paid_for, but that got changed. */
 
	SLE_CONDNULL(1, 0, 120),
 

	
 
	SLE_END()
 
};
 

	
 
static void Save_CAPA()
 
{
src/saveload/economy_sl.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/** @file economy_sl.cpp Code handling saving and loading of economy data */
 

	
 
#include "../stdafx.h"
 
#include "../economy_func.h"
 
#include "../economy_base.h"
 

	
 
#include "saveload.h"
 

	
 
/** Prices */
 
static void SaveLoad_PRIC()
 
{
 
@@ -48,11 +49,48 @@ static void Save_ECMY()
 
static void Load_ECMY()
 
{
 
	SlObject(&_economy, _economy_desc);
 
	StartupIndustryDailyChanges(CheckSavegameVersion(102));  // old savegames will need to be initialized
 
}
 

	
 
static const SaveLoad _cargopayment_desc[] = {
 
	SLE_REF(CargoPayment, front,         REF_VEHICLE),
 
	SLE_VAR(CargoPayment, route_profit,  SLE_INT64),
 
	SLE_VAR(CargoPayment, visual_profit, SLE_INT64),
 

	
 
	SLE_END()
 
};
 

	
 
static void Save_CAPY()
 
{
 
	CargoPayment *cp;
 
	FOR_ALL_CARGO_PAYMENTS(cp) {
 
		SlSetArrayIndex(cp->index);
 
		SlObject(cp, _cargopayment_desc);
 
	}
 
}
 

	
 
static void Load_CAPY()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		CargoPayment *cp = new (index) CargoPayment();
 
		SlObject(cp, _cargopayment_desc);
 
	}
 
}
 

	
 
static void Ptrs_CAPY()
 
{
 
	CargoPayment *cp;
 
	FOR_ALL_CARGO_PAYMENTS(cp) {
 
		SlObject(cp, _cargopayment_desc);
 
	}
 
}
 

	
 

	
 
extern const ChunkHandler _economy_chunk_handlers[] = {
 
	{ 'PRIC', SaveLoad_PRIC, SaveLoad_PRIC, NULL, CH_RIFF | CH_AUTO_LENGTH},
 
	{ 'CAPR', SaveLoad_CAPR, SaveLoad_CAPR, NULL, CH_RIFF | CH_AUTO_LENGTH},
 
	{ 'ECMY', Save_ECMY,     Load_ECMY,     NULL, CH_RIFF | CH_LAST},
 
	{ 'CAPY', Save_CAPY,     Load_CAPY,     Ptrs_CAPY, CH_ARRAY},
 
	{ 'PRIC', SaveLoad_PRIC, SaveLoad_PRIC, NULL,      CH_RIFF | CH_AUTO_LENGTH},
 
	{ 'CAPR', SaveLoad_CAPR, SaveLoad_CAPR, NULL,      CH_RIFF | CH_AUTO_LENGTH},
 
	{ 'ECMY', Save_ECMY,     Load_ECMY,     NULL,      CH_RIFF | CH_LAST},
 
};
src/saveload/saveload.cpp
Show inline comments
 
@@ -38,13 +38,13 @@
 
#include "../engine_base.h"
 

	
 
#include "table/strings.h"
 

	
 
#include "saveload_internal.h"
 

	
 
extern const uint16 SAVEGAME_VERSION = 120;
 
extern const uint16 SAVEGAME_VERSION = 121;
 

	
 
SavegameType _savegame_type; ///< type of savegame we are loading
 

	
 
uint32 _ttdp_version;     ///< version of TTDP savegame (if applicable)
 
uint16 _sl_version;       ///< the major savegame version identifier
 
byte   _sl_minor_version; ///< the minor savegame version, DO NOT USE!
src/vehicle.cpp
Show inline comments
 
@@ -35,12 +35,13 @@
 
#include "ai/ai.hpp"
 
#include "core/smallmap_type.hpp"
 
#include "depot_func.h"
 
#include "settings_type.h"
 
#include "network/network.h"
 
#include "core/pool_func.hpp"
 
#include "economy_base.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
#define GEN_HASH(x, y) ((GB((y), 6, 6) << 6) + GB((x), 7, 6))
 

	
 
@@ -443,12 +444,13 @@ void ResetVehicleColourMap()
 
typedef SmallMap<Vehicle *, bool, 4> AutoreplaceMap;
 
static AutoreplaceMap _vehicles_to_autoreplace;
 

	
 
void InitializeVehicles()
 
{
 
	_vehicle_pool.CleanPool();
 
	_cargo_payment_pool.CleanPool();
 

	
 
	_vehicles_to_autoreplace.Reset();
 
	ResetVehiclePosHash();
 
}
 

	
 
Vehicle *GetLastVehicleInChain(Vehicle *v)
 
@@ -1439,13 +1441,13 @@ void Vehicle::BeginLoading()
 
	} else {
 
		current_order.MakeLoading(false);
 
	}
 

	
 
	Station::Get(this->last_station_visited)->loading_vehicles.push_back(this);
 

	
 
	VehiclePayment(this);
 
	PrepareUnload(this);
 

	
 
	InvalidateWindow(GetWindowClassForVehicleType(this->type), this->owner);
 
	InvalidateWindowWidget(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
 
	InvalidateWindow(WC_VEHICLE_DETAILS, this->index);
 
	InvalidateWindow(WC_STATION_VIEW, this->last_station_visited);
 

	
 
@@ -1455,12 +1457,14 @@ void Vehicle::BeginLoading()
 
}
 

	
 
void Vehicle::LeaveStation()
 
{
 
	assert(current_order.IsType(OT_LOADING));
 

	
 
	delete this->cargo_payment;
 

	
 
	/* Only update the timetable if the vehicle was supposed to stop here. */
 
	if (current_order.GetNonStopType() != ONSF_STOP_EVERYWHERE) UpdateVehicleTimetable(this, false);
 

	
 
	current_order.MakeLeaveStation();
 
	Station *st = Station::Get(this->last_station_visited);
 
	st->loading_vehicles.remove(this);
src/vehicle_base.h
Show inline comments
 
@@ -88,13 +88,15 @@ public:
 
	 * but it can be used for heuristical purposes to estimate the distance.
 
	 */
 
	TileIndex dest_tile;
 

	
 
	Money profit_this_year;        ///< Profit this year << 8, low 8 bits are fract
 
	Money profit_last_year;        ///< Profit last year << 8, low 8 bits are fract
 
	Money value;
 
	Money value;                   ///< Value of the vehicle
 

	
 
	CargoPayment *cargo_payment;   ///< The cargo payment we're currently in
 

	
 
	/* Used for timetabling. */
 
	uint32 current_order_time;     ///< How many ticks have passed since this order started.
 
	int32 lateness_counter;        ///< How many ticks late (or early if negative) this vehicle is.
 

	
 
	/* Boundaries for the current position in the world and a next hash link.
0 comments (0 inline, 0 general)