mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-06 06:15:04 +00:00
(svn r10266) -Codechange: keep track of the origin, time of travel and accumulated feeder share (transfers) of individual pieces of cargo. This means that cargo isn't thrown on a big pile when it's put in a station or unloaded at a station, however the GUI does not reflect these changes yet so you will not actually see it.
This commit is contained in:
parent
6159f58948
commit
e5c352818d
@ -181,6 +181,9 @@
|
||||
<File
|
||||
RelativePath=".\..\src\cargotype.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\cargopacket.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\command.cpp">
|
||||
</File>
|
||||
@ -401,6 +404,9 @@
|
||||
<File
|
||||
RelativePath=".\..\src\cargotype.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\cargopacket.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\command.h">
|
||||
</File>
|
||||
|
@ -471,6 +471,10 @@
|
||||
RelativePath=".\..\src\cargotype.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\cargopacket.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\command.cpp"
|
||||
>
|
||||
@ -763,6 +767,10 @@
|
||||
RelativePath=".\..\src\cargotype.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\cargopacket.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\..\src\command.h"
|
||||
>
|
||||
|
@ -6,6 +6,7 @@ aystar.cpp
|
||||
bmp.cpp
|
||||
callback_table.cpp
|
||||
cargotype.cpp
|
||||
cargopacket.cpp
|
||||
command.cpp
|
||||
console.cpp
|
||||
console_cmds.cpp
|
||||
@ -101,6 +102,7 @@ articulated_vehicles.h
|
||||
aystar.h
|
||||
bmp.h
|
||||
cargotype.h
|
||||
cargopacket.h
|
||||
command.h
|
||||
console.h
|
||||
currency.h
|
||||
|
@ -617,7 +617,7 @@ static void AiNew_State_FindStation(Player *p)
|
||||
if (p->ainew.tbt == AI_BUS && (FACIL_BUS_STOP & st->facilities) == FACIL_BUS_STOP) {
|
||||
if (st->town == town) {
|
||||
// Check how much cargo there is left in the station
|
||||
if ((st->goods[p->ainew.cargo].waiting_acceptance & 0xFFF) > RoadVehInfo(i)->capacity * AI_STATION_REUSE_MULTIPLER) {
|
||||
if ((int)st->goods[p->ainew.cargo].cargo.Count() > RoadVehInfo(i)->capacity * AI_STATION_REUSE_MULTIPLER) {
|
||||
if (AiNew_CheckVehicleStation(p, st)) {
|
||||
// We did found a station that was good enough!
|
||||
new_tile = st->xy;
|
||||
@ -1258,7 +1258,7 @@ static void AiNew_CheckVehicle(Player *p, Vehicle *v)
|
||||
if (v->profit_last_year + v->profit_this_year < AI_MINIMUM_ROUTE_PROFIT ||
|
||||
(v->reliability * 100 >> 16) < 40) {
|
||||
// There is a possibility that the route is fucked up...
|
||||
if (v->cargo_days > AI_VEHICLE_LOST_DAYS) {
|
||||
if (v->cargo.DaysInTransit() > AI_VEHICLE_LOST_DAYS) {
|
||||
// The vehicle is lost.. check the route, or else, get the vehicle
|
||||
// back to a depot
|
||||
// TODO: make this piece of code
|
||||
|
@ -680,13 +680,8 @@ CommandCost CmdRefitAircraft(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
||||
Vehicle *u = v->next;
|
||||
uint mail = IsCargoInClass(new_cid, CC_PASSENGERS) ? avi->mail_capacity : 0;
|
||||
u->cargo_cap = mail;
|
||||
if (v->cargo_type == new_cid) {
|
||||
v->cargo_count = min(pass, v->cargo_count);
|
||||
u->cargo_count = min(mail, u->cargo_count);
|
||||
} else {
|
||||
v->cargo_count = 0;
|
||||
u->cargo_count = 0;
|
||||
}
|
||||
v->cargo.Truncate(v->cargo_type == new_cid ? pass : 0);
|
||||
u->cargo.Truncate(v->cargo_type == new_cid ? mail : 0);
|
||||
v->cargo_type = new_cid;
|
||||
v->cargo_subtype = new_subtype;
|
||||
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
|
||||
@ -774,7 +769,7 @@ static void AgeAircraftCargo(Vehicle *v)
|
||||
if (_age_cargo_skip_counter != 0) return;
|
||||
|
||||
do {
|
||||
if (v->cargo_days != 0xFF) v->cargo_days++;
|
||||
v->cargo.AgeCargo();
|
||||
v = v->next;
|
||||
} while (v != NULL);
|
||||
}
|
||||
@ -1429,11 +1424,11 @@ static void CrashAirplane(Vehicle *v)
|
||||
InvalidateWindow(WC_VEHICLE_VIEW, v->index);
|
||||
|
||||
uint amt = 2;
|
||||
if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) amt += v->cargo_count;
|
||||
if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) amt += v->cargo.Count();
|
||||
SetDParam(0, amt);
|
||||
|
||||
v->cargo_count = 0;
|
||||
v->next->cargo_count = 0;
|
||||
v->cargo.Truncate(0);
|
||||
v->next->cargo.Truncate(0);
|
||||
const Station *st = GetStation(v->u.air.targetairport);
|
||||
StringID newsitem;
|
||||
if (st->airport_tile == 0) {
|
||||
@ -1469,7 +1464,7 @@ static void MaybeCrashAirplane(Vehicle *v)
|
||||
/* Crash the airplane. Remove all goods stored at the station. */
|
||||
for (CargoID i = 0; i < NUM_CARGO; i++) {
|
||||
st->goods[i].rating = 1;
|
||||
SB(st->goods[i].waiting_acceptance, 0, 12, 0);
|
||||
st->goods[i].cargo.Truncate(0);
|
||||
}
|
||||
|
||||
CrashAirplane(v);
|
||||
|
@ -125,7 +125,7 @@ static void AircraftDetailsWndProc(Window *w, WindowEvent *e)
|
||||
|
||||
/* Draw Transfer credits text */
|
||||
{
|
||||
SetDParam(0, v->cargo_feeder_share);
|
||||
SetDParam(0, v->cargo.FeederShare());
|
||||
DrawString(60, 101, STR_FEEDER_CARGO_VALUE, 0);
|
||||
}
|
||||
|
||||
@ -152,12 +152,13 @@ static void AircraftDetailsWndProc(Window *w, WindowEvent *e)
|
||||
y += 14;
|
||||
}
|
||||
|
||||
if (v->cargo_count != 0) {
|
||||
uint cargo_count = v->cargo.Count();
|
||||
if (cargo_count != 0) {
|
||||
|
||||
/* Cargo names (fix pluralness) */
|
||||
SetDParam(0, v->cargo_type);
|
||||
SetDParam(1, v->cargo_count);
|
||||
SetDParam(2, v->cargo_source);
|
||||
SetDParam(1, cargo_count);
|
||||
SetDParam(2, v->cargo.Source());
|
||||
DrawString(60, y, STR_8813_FROM, 0);
|
||||
|
||||
y += 10;
|
||||
|
@ -25,27 +25,23 @@
|
||||
static void MoveVehicleCargo(Vehicle *dest, Vehicle *source)
|
||||
{
|
||||
Vehicle *v = dest;
|
||||
int units_moved;
|
||||
|
||||
do {
|
||||
do {
|
||||
if (source->cargo_type != dest->cargo_type)
|
||||
continue; // cargo not compatible
|
||||
|
||||
if (dest->cargo_count == dest->cargo_cap)
|
||||
if (dest->cargo.Count() == dest->cargo_cap)
|
||||
continue; // the destination vehicle is already full
|
||||
|
||||
units_moved = min(source->cargo_count, dest->cargo_cap - dest->cargo_count);
|
||||
source->cargo_count -= units_moved;
|
||||
dest->cargo_count += units_moved;
|
||||
dest->cargo_source = source->cargo_source;
|
||||
uint units_moved = min(source->cargo.Count(), dest->cargo_cap - dest->cargo.Count());
|
||||
source->cargo.MoveTo(&dest->cargo, units_moved);
|
||||
|
||||
// copy the age of the cargo
|
||||
dest->cargo_days = source->cargo_days;
|
||||
dest->day_counter = source->day_counter;
|
||||
dest->tick_counter = source->tick_counter;
|
||||
|
||||
} while (source->cargo_count > 0 && (dest = dest->next) != NULL);
|
||||
} while (source->cargo.Count() > 0 && (dest = dest->next) != NULL);
|
||||
dest = v;
|
||||
} while ((source = source->next) != NULL);
|
||||
|
||||
|
351
src/cargopacket.cpp
Normal file
351
src/cargopacket.cpp
Normal file
@ -0,0 +1,351 @@
|
||||
/* $Id$ */
|
||||
|
||||
/** @file cargopacket.cpp Implementation of the cargo packets */
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "openttd.h"
|
||||
#include "station.h"
|
||||
#include "cargopacket.h"
|
||||
#include "saveload.h"
|
||||
|
||||
/**
|
||||
* Called if a new block is added to the station-pool
|
||||
*/
|
||||
static void CargoPacketPoolNewBlock(uint cpart_item)
|
||||
{
|
||||
/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
|
||||
* TODO - This is just a temporary stage, this will be removed. */
|
||||
for (CargoPacket *cp = GetCargoPacket(cpart_item); cp != NULL; cp = (cp->index + 1U < GetCargoPacketPoolSize()) ? GetCargoPacket(cp->index + 1U) : NULL) cp->index = cpart_item++;
|
||||
}
|
||||
|
||||
static void CargoPacketPoolCleanBlock(uint cpart_item, uint end_item)
|
||||
{
|
||||
for (uint i = cpart_item; i <= end_item; i++) {
|
||||
CargoPacket *cp = GetCargoPacket(i);
|
||||
if (cp->IsValid()) cp->~CargoPacket();
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the cargopacket-pool */
|
||||
DEFINE_OLD_POOL(CargoPacket, CargoPacket, CargoPacketPoolNewBlock, CargoPacketPoolCleanBlock)
|
||||
|
||||
void InitializeCargoPackets()
|
||||
{
|
||||
/* Clean the cargo packet pool and create 1 block in it */
|
||||
CleanPool(&_CargoPacket_pool);
|
||||
AddBlockToPool(&_CargoPacket_pool);
|
||||
|
||||
/* Check whether our &cargolist == &cargolist.packets "hack" works */
|
||||
CargoList::AssertOnWrongPacketOffset();
|
||||
}
|
||||
|
||||
CargoPacket::CargoPacket(StationID source, uint16 count)
|
||||
{
|
||||
if (source != INVALID_STATION) assert(count != 0);
|
||||
|
||||
this->source = source;
|
||||
this->source_xy = (source != INVALID_STATION) ? GetStation(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;
|
||||
}
|
||||
|
||||
CargoPacket::~CargoPacket()
|
||||
{
|
||||
this->count = 0;
|
||||
}
|
||||
|
||||
bool CargoPacket::SameSource(CargoPacket *cp)
|
||||
{
|
||||
return this->source_xy == cp->source_xy && this->days_in_transit == cp->days_in_transit && this->paid_for == cp->paid_for;
|
||||
}
|
||||
|
||||
void *CargoPacket::operator new(size_t size)
|
||||
{
|
||||
CargoPacket *cp = AllocateRaw();
|
||||
return cp;
|
||||
}
|
||||
|
||||
void *CargoPacket::operator new(size_t size, CargoPacket::ID cp_idx)
|
||||
{
|
||||
if (!AddBlockIfNeeded(&_CargoPacket_pool, cp_idx))
|
||||
error("CargoPackets: failed loading savegame: too many cargo packets");
|
||||
|
||||
CargoPacket *cp = GetCargoPacket(cp_idx);
|
||||
return cp;
|
||||
}
|
||||
|
||||
void CargoPacket::operator delete(void *p)
|
||||
{
|
||||
}
|
||||
|
||||
void CargoPacket::operator delete(void *p, CargoPacket::ID cp_idx)
|
||||
{
|
||||
}
|
||||
|
||||
/*static*/ CargoPacket *CargoPacket::AllocateRaw()
|
||||
{
|
||||
CargoPacket *cp = NULL;
|
||||
|
||||
/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
|
||||
* TODO - This is just a temporary stage, this will be removed. */
|
||||
for (cp = GetCargoPacket(0); cp != NULL; cp = (cp->index + 1U < GetCargoPacketPoolSize()) ? GetCargoPacket(cp->index + 1U) : NULL) {
|
||||
if (!cp->IsValid()) {
|
||||
CargoPacket::ID index = cp->index;
|
||||
|
||||
memset(cp, 0, sizeof(CargoPacket));
|
||||
cp->index = index;
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we can add a block to the pool */
|
||||
if (AddBlockToPool(&_CargoPacket_pool)) return AllocateRaw();
|
||||
|
||||
error("CargoPackets: too many cargo packets");
|
||||
}
|
||||
|
||||
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_END()
|
||||
};
|
||||
|
||||
static void Save_CAPA()
|
||||
{
|
||||
CargoPacket *cp;
|
||||
|
||||
FOR_ALL_CARGOPACKETS(cp) {
|
||||
SlSetArrayIndex(cp->index);
|
||||
SlObject(cp, _cargopacket_desc);
|
||||
}
|
||||
}
|
||||
|
||||
static void Load_CAPA()
|
||||
{
|
||||
int index;
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
if (!AddBlockIfNeeded(&_CargoPacket_pool, index)) {
|
||||
error("CargoPackets: failed loading savegame: too many cargo packets");
|
||||
}
|
||||
|
||||
CargoPacket *cp = GetCargoPacket(index);
|
||||
SlObject(cp, _cargopacket_desc);
|
||||
}
|
||||
}
|
||||
|
||||
extern const ChunkHandler _cargopacket_chunk_handlers[] = {
|
||||
{ 'CAPA', Save_CAPA, Load_CAPA, CH_ARRAY | CH_LAST},
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
* Cargo list implementation
|
||||
*
|
||||
*/
|
||||
|
||||
/* static */ void CargoList::AssertOnWrongPacketOffset()
|
||||
{
|
||||
CargoList cl;
|
||||
if ((void*)&cl != (void*)cl.Packets()) NOT_REACHED();
|
||||
}
|
||||
|
||||
|
||||
CargoList::~CargoList()
|
||||
{
|
||||
while (!packets.empty()) {
|
||||
delete packets.front();
|
||||
packets.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
const CargoList::List *CargoList::Packets() const
|
||||
{
|
||||
return &packets;
|
||||
}
|
||||
|
||||
void CargoList::AgeCargo()
|
||||
{
|
||||
if (empty) return;
|
||||
|
||||
uint dit = 0;
|
||||
for (List::const_iterator it = packets.begin(); it != packets.end(); it++) {
|
||||
if ((*it)->days_in_transit != 0xFF) (*it)->days_in_transit++;
|
||||
dit += (*it)->days_in_transit * (*it)->count;
|
||||
}
|
||||
days_in_transit = dit / count;
|
||||
}
|
||||
|
||||
bool CargoList::Empty() const
|
||||
{
|
||||
return empty;
|
||||
}
|
||||
|
||||
uint CargoList::Count() const
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
bool CargoList::UnpaidCargo() const
|
||||
{
|
||||
return unpaid_cargo;
|
||||
}
|
||||
|
||||
Money CargoList::FeederShare() const
|
||||
{
|
||||
return feeder_share;
|
||||
}
|
||||
|
||||
StationID CargoList::Source() const
|
||||
{
|
||||
return source;
|
||||
}
|
||||
|
||||
uint CargoList::DaysInTransit() const
|
||||
{
|
||||
return days_in_transit;
|
||||
}
|
||||
|
||||
void CargoList::Append(CargoPacket *cp)
|
||||
{
|
||||
assert(cp != NULL);
|
||||
assert(cp->IsValid());
|
||||
|
||||
for (List::iterator it = packets.begin(); it != packets.end(); it++) {
|
||||
if ((*it)->SameSource(cp)) {
|
||||
(*it)->count += cp->count;
|
||||
(*it)->feeder_share += cp->feeder_share;
|
||||
delete cp;
|
||||
|
||||
InvalidateCache();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* The packet could not be merged with another one */
|
||||
packets.push_back(cp);
|
||||
InvalidateCache();
|
||||
}
|
||||
|
||||
|
||||
void CargoList::Truncate(uint count)
|
||||
{
|
||||
for (List::iterator it = packets.begin(); it != packets.end(); it++) {
|
||||
uint local_count = (*it)->count;
|
||||
if (local_count <= count) {
|
||||
count -= local_count;
|
||||
continue;
|
||||
}
|
||||
|
||||
(*it)->count = count;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
while (!packets.empty()) {
|
||||
CargoPacket *cp = packets.back();
|
||||
if (cp->count != 0) break;
|
||||
delete cp;
|
||||
packets.pop_back();
|
||||
}
|
||||
|
||||
InvalidateCache();
|
||||
}
|
||||
|
||||
bool CargoList::MoveTo(CargoList *dest, uint count, CargoList::MoveToAction mta, uint data)
|
||||
{
|
||||
assert(mta == MTA_FINAL_DELIVERY || dest != 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 {
|
||||
count -= cp->count;
|
||||
delete cp;
|
||||
}
|
||||
break;
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
/* Can move only part of the packet, so split it into two pieces */
|
||||
if (mta != MTA_FINAL_DELIVERY) {
|
||||
CargoPacket *cp_new = new CargoPacket();
|
||||
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 = cp->feeder_share / count;
|
||||
/* 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);
|
||||
|
||||
cp->feeder_share /= cp->count - 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, MAX_UVALUE(uint));
|
||||
tmp.packets.clear();
|
||||
}
|
||||
|
||||
if (dest != NULL) dest->InvalidateCache();
|
||||
InvalidateCache();
|
||||
|
||||
return remaining;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
221
src/cargopacket.h
Normal file
221
src/cargopacket.h
Normal file
@ -0,0 +1,221 @@
|
||||
/* $Id$ */
|
||||
|
||||
/** @file cargotype.h */
|
||||
|
||||
#ifndef CARGOPACKET_H
|
||||
#define CARGOPACKET_H
|
||||
|
||||
#include <list>
|
||||
|
||||
/**
|
||||
* Container for cargo from the same location and time
|
||||
*/
|
||||
struct CargoPacket {
|
||||
bool touched;
|
||||
|
||||
typedef uint32 ID; ///< Type for cargopacket identifiers
|
||||
|
||||
ID index; ///< The unique index of this packet
|
||||
|
||||
StationID source; ///< The station where the cargo came from first
|
||||
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
|
||||
|
||||
uint16 count; ///< The amount of cargo in this packet
|
||||
byte days_in_transit; ///< Amount of days this packet has been in transit
|
||||
Money feeder_share; ///< Value of feeder pickup to be paid for on delivery of cargo
|
||||
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
|
||||
*/
|
||||
CargoPacket(StationID source = INVALID_STATION, uint16 count = 0);
|
||||
|
||||
/** Destroy the packet */
|
||||
~CargoPacket();
|
||||
|
||||
|
||||
/**
|
||||
* Is this a valid cargo packet ?
|
||||
* @return true if and only it is valid
|
||||
*/
|
||||
bool IsValid() const { return this->count != 0; }
|
||||
|
||||
/**
|
||||
* Checks whether the cargo packet is from (exactly) the same source
|
||||
* 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
|
||||
*/
|
||||
bool SameSource(CargoPacket *cp);
|
||||
|
||||
|
||||
/* normal new/delete operators. Used when building/removing station */
|
||||
void* operator new (size_t size);
|
||||
void operator delete(void *p);
|
||||
|
||||
/* new/delete operators accepting station index. Used when loading station from savegame. */
|
||||
void* operator new (size_t size, CargoPacket::ID cp_idx);
|
||||
void operator delete(void *p, CargoPacket::ID cp_idx);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Allocate the raw memory for this cargo packet
|
||||
* @return the allocated memory
|
||||
*/
|
||||
static CargoPacket *AllocateRaw();
|
||||
};
|
||||
|
||||
/** We want to use a pool */
|
||||
DECLARE_OLD_POOL(CargoPacket, CargoPacket, 10, 1000)
|
||||
|
||||
/**
|
||||
* Iterate over all _valid_ cargo packets from the given start
|
||||
* @param cp the variable used as "iterator"
|
||||
* @param start the cargo packet ID of the first packet to iterate over
|
||||
*/
|
||||
#define FOR_ALL_CARGOPACKETS_FROM(cp, start) for (cp = GetCargoPacket(start); cp != NULL; cp = (cp->index + 1U < GetCargoPacketPoolSize()) ? GetCargoPacket(cp->index + 1U) : NULL) if (cp->IsValid())
|
||||
|
||||
/**
|
||||
* Iterate over all _valid_ cargo packets from the begin of the pool
|
||||
* @param cp the variable used as "iterator"
|
||||
*/
|
||||
#define FOR_ALL_CARGOPACKETS(cp) FOR_ALL_CARGOPACKETS_FROM(cp, 0)
|
||||
|
||||
/**
|
||||
* Simple collection class for a list of cargo packets
|
||||
*/
|
||||
class CargoList {
|
||||
public:
|
||||
/** List of cargo packets */
|
||||
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
|
||||
};
|
||||
|
||||
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:
|
||||
/**
|
||||
* Needed for an ugly hack:
|
||||
* - vehicles and stations need to store cargo lists, so they use CargoList as container
|
||||
* - this internals of the container should be protected, e.g. private (or protected) by C++
|
||||
* - for saving/loading we need to pass pointer to objects
|
||||
* -> so *if* the pointer to the cargo list is the same as the pointer to the packet list
|
||||
* encapsulated in the CargoList, we can just pass the CargoList as "offset".
|
||||
* Normally we would then just add the offset of the packets variable within the cargo list
|
||||
* but that is not possible because the variable is private. Furthermore we are not sure
|
||||
* that this works on all platforms, we need to check whether the offset is actually 0.
|
||||
* This cannot be done compile time, because the variable is private. So we need to write
|
||||
* a function that does actually check the offset runtime and call it somewhere where it
|
||||
* is always called but it should not be called often.
|
||||
*/
|
||||
static void AssertOnWrongPacketOffset();
|
||||
|
||||
/** Create the cargo list */
|
||||
CargoList() { this->InvalidateCache(); }
|
||||
/** And destroy it ("frees" all cargo packets) */
|
||||
~CargoList();
|
||||
|
||||
/**
|
||||
* Returns a pointer to the cargo packet list (so you can iterate over it etc).
|
||||
* @return pointer to the packet list
|
||||
*/
|
||||
const CargoList::List *Packets() const;
|
||||
|
||||
/**
|
||||
* Ages the all cargo in this list
|
||||
*/
|
||||
void AgeCargo();
|
||||
|
||||
/**
|
||||
* Checks whether this list is empty
|
||||
* @return true if and only if the list is empty
|
||||
*/
|
||||
bool Empty() const;
|
||||
|
||||
/**
|
||||
* Returns the number of cargo entities in this list
|
||||
* @return the before mentioned number
|
||||
*/
|
||||
uint Count() const;
|
||||
|
||||
/**
|
||||
* Is there some cargo that has not been paid for?
|
||||
* @return true if and only if there is such a cargo
|
||||
*/
|
||||
bool UnpaidCargo() const;
|
||||
|
||||
/**
|
||||
* Returns total sum of the feeder share for all packets
|
||||
* @return the before mentioned number
|
||||
*/
|
||||
Money FeederShare() const;
|
||||
|
||||
/**
|
||||
* Returns source of the first cargo packet in this list
|
||||
* @return the before mentioned source
|
||||
*/
|
||||
StationID Source() const;
|
||||
|
||||
/**
|
||||
* Returns average number of days in transit for a cargo entity
|
||||
* @return the before mentioned number
|
||||
*/
|
||||
uint DaysInTransit() const;
|
||||
|
||||
|
||||
/**
|
||||
* Appends the given cargo packet
|
||||
* @warning After appending this packet may not exist anymore!
|
||||
* @note Do not use the cargo packet anymore after it has been appended to this CargoList!
|
||||
* @param cp the cargo packet to add
|
||||
* @pre cp != NULL
|
||||
*/
|
||||
void Append(CargoPacket *cp);
|
||||
|
||||
/**
|
||||
* Truncates the cargo in this list to the given amount. It leaves the
|
||||
* first count cargo entities and removes the rest.
|
||||
* @param count the maximum amount of entities to be in the list after the command
|
||||
*/
|
||||
void Truncate(uint count);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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
|
||||
* @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);
|
||||
|
||||
/** Invalidates the cached data and rebuild it */
|
||||
void InvalidateCache();
|
||||
};
|
||||
|
||||
#endif /* CARGOPACKET_H */
|
155
src/economy.cpp
155
src/economy.cpp
@ -1371,14 +1371,9 @@ void VehiclePayment(Vehicle *front_v)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
Money profit = 0;
|
||||
Money total_veh_profit = 0; // accumulates the profit across the vehicle chain (used by trains)
|
||||
Money route_profit = 0; // the grand total amount for the route. A-D of transfer chain A-B-C-D
|
||||
Money virtual_profit = 0; // virtual profit of one vehicle element for feeder systems
|
||||
Money virtual_profit_total = 0; // virtual profit for entire vehicle chain
|
||||
Money total_cargo_feeder_share = 0; // the feeder cash amount for the goods being loaded/unloaded in this load step
|
||||
|
||||
Money all_vehicles_cargo_feeder_share = front_v->cargo_feeder_share; // used to hold transfer value of complete vehicle chain - used by trains
|
||||
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 = GetStation(last_visited);
|
||||
@ -1395,75 +1390,70 @@ void VehiclePayment(Vehicle *front_v)
|
||||
|
||||
for (Vehicle *v = front_v; v != NULL; v = v->next) {
|
||||
/* No cargo to unload */
|
||||
if (v->cargo_cap == 0 || v->cargo_count == 0) continue;
|
||||
if (v->cargo_cap == 0 || v->cargo.Empty()) continue;
|
||||
|
||||
/* All cargo has already been paid for, no need to pay again */
|
||||
if (v->cargo_count == v->cargo_paid_for) {
|
||||
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();
|
||||
|
||||
if (v->cargo_source != last_visited &&
|
||||
HASBIT(ge->waiting_acceptance, 15) &&
|
||||
for (CargoList::List::const_iterator it = cargos->begin(); it != cargos->end(); it++) {
|
||||
CargoPacket *cp = *it;
|
||||
if (!cp->paid_for &&
|
||||
cp->source != last_visited &&
|
||||
ge->acceptance &&
|
||||
(front_v->current_order.flags & OF_TRANSFER) == 0) {
|
||||
/* Deliver goods to the station */
|
||||
st->time_since_unload = 0;
|
||||
|
||||
/* handle end of route payment */
|
||||
profit += DeliverGoods(v->cargo_count - v->cargo_paid_for, v->cargo_type, v->cargo_source, last_visited, v->cargo_source_xy, v->cargo_days);
|
||||
v->cargo_paid_for = v->cargo_count;
|
||||
route_profit = profit; // display amount paid for final route delivery, A-D of a chain A-B-C-D
|
||||
total_veh_profit = profit - all_vehicles_cargo_feeder_share; // whole vehicle is not payed for transfers picked up earlier
|
||||
total_cargo_feeder_share = -all_vehicles_cargo_feeder_share; // total of transfer fees in vehicle chain needs to be zero at end of unload
|
||||
Money profit = DeliverGoods(cp->count, v->cargo_type, cp->source, last_visited, cp->source_xy, cp->days_in_transit);
|
||||
cp->paid_for = true;
|
||||
route_profit += profit - cp->feeder_share; // display amount paid for final route delivery, A-D of a chain A-B-C-D
|
||||
vehicle_profit += profit; // whole vehicle is not payed for transfers picked up earlier
|
||||
|
||||
v->cargo_feeder_share = 0; // clear transfer cost per vehicle
|
||||
result |= 1;
|
||||
|
||||
SETBIT(v->vehicle_flags, VF_CARGO_UNLOADING);
|
||||
} else if (front_v->current_order.flags & (OF_UNLOAD | OF_TRANSFER)) {
|
||||
if ((front_v->current_order.flags & OF_TRANSFER) != 0) {
|
||||
virtual_profit = GetTransportedGoodsIncome(
|
||||
v->cargo_count - v->cargo_paid_for,
|
||||
if (!cp->paid_for && (front_v->current_order.flags & OF_TRANSFER) != 0) {
|
||||
Money profit = GetTransportedGoodsIncome(
|
||||
cp->count,
|
||||
/* pay transfer vehicle for only the part of transfer it has done: ie. cargo_loaded_at_xy to here */
|
||||
DistanceManhattan(v->cargo_loaded_at_xy, GetStation(last_visited)->xy),
|
||||
v->cargo_days,
|
||||
DistanceManhattan(cp->loaded_at_xy, GetStation(last_visited)->xy),
|
||||
cp->days_in_transit,
|
||||
v->cargo_type);
|
||||
|
||||
front_v->profit_this_year += virtual_profit;
|
||||
ge->feeder_profit += v->cargo_feeder_share + virtual_profit; // transfer cargo transfer fees to station
|
||||
total_cargo_feeder_share -= v->cargo_feeder_share; // accumulate deduction of feeder shares
|
||||
v->cargo_feeder_share = 0; // clear transfer cost
|
||||
|
||||
/* keep total of cargo unloaded (pending) for accurate cargoshare calculation on load */
|
||||
SB(ge->unload_pending, 0, 12, GB(ge->unload_pending, 0, 12) + v->cargo_count);
|
||||
|
||||
virtual_profit_total += virtual_profit; // accumulate transfer profits for whole vehicle
|
||||
v->cargo_paid_for = v->cargo_count; // record how much of the cargo has been paid for to eliminate double counting
|
||||
front_v->profit_this_year += profit;
|
||||
virtual_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; // record that the cargo has been paid for to eliminate double counting
|
||||
}
|
||||
result |= 2;
|
||||
|
||||
SETBIT(v->vehicle_flags, VF_CARGO_UNLOADING);
|
||||
}
|
||||
}
|
||||
v->cargo.InvalidateCache();
|
||||
}
|
||||
|
||||
/* Ensure a negative total is only applied to the vehicle if there is value to reduce. */
|
||||
front_v->cargo_feeder_share = max(front_v->cargo_feeder_share + total_cargo_feeder_share, 0LL);
|
||||
|
||||
if (virtual_profit_total > 0) {
|
||||
ShowFeederIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, virtual_profit_total);
|
||||
if (virtual_profit > 0) {
|
||||
ShowFeederIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, virtual_profit);
|
||||
}
|
||||
|
||||
if (route_profit != 0) {
|
||||
front_v->profit_this_year += total_veh_profit;
|
||||
front_v->profit_this_year += vehicle_profit;
|
||||
SubtractMoneyFromPlayer(-route_profit);
|
||||
|
||||
if (IsLocalPlayer() && !PlayVehicleSound(front_v, VSE_LOAD_UNLOAD)) {
|
||||
SndPlayVehicleFx(SND_14_CASHTILL, front_v);
|
||||
}
|
||||
|
||||
ShowCostOrIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, -total_veh_profit);
|
||||
ShowCostOrIncomeAnimation(front_v->x_pos, front_v->y_pos, front_v->z_pos, -vehicle_profit);
|
||||
}
|
||||
|
||||
_current_player = old_player;
|
||||
@ -1486,7 +1476,7 @@ static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
|
||||
if (_patches.improved_load && HASBIT(v->current_order.flags, OFB_FULL_LOAD)) {
|
||||
/* 'Reserve' this cargo for this vehicle, because we were first. */
|
||||
for (; v != NULL; v = v->next) {
|
||||
if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo_count;
|
||||
if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo.Count();
|
||||
}
|
||||
}
|
||||
return;
|
||||
@ -1502,14 +1492,13 @@ static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
|
||||
int unloading_time = 0;
|
||||
Vehicle *u = v;
|
||||
int result = 0;
|
||||
int cap;
|
||||
uint cap;
|
||||
|
||||
bool completely_empty = true;
|
||||
bool anything_unloaded = false;
|
||||
bool anything_loaded = false;
|
||||
uint32 cargo_not_full = 0;
|
||||
uint32 cargo_full = 0;
|
||||
Money total_cargo_feeder_share = 0; // the feeder cash amount for the goods being loaded/unloaded in this load step
|
||||
|
||||
v->cur_speed = 0;
|
||||
|
||||
@ -1526,36 +1515,19 @@ static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
|
||||
}
|
||||
|
||||
GoodsEntry *ge = &st->goods[v->cargo_type];
|
||||
int count = GB(ge->waiting_acceptance, 0, 12);
|
||||
|
||||
if (HASBIT(v->vehicle_flags, VF_CARGO_UNLOADING)) {
|
||||
uint16 amount_unloaded = _patches.gradual_loading ? min(v->cargo_count, load_amount) : v->cargo_count;
|
||||
uint cargo_count = v->cargo.Count();
|
||||
uint amount_unloaded = _patches.gradual_loading ? min(cargo_count, load_amount) : cargo_count;
|
||||
bool remaining; // Are there cargo entities in this vehicle that can still be unloaded here?
|
||||
|
||||
if (ge->acceptance && !(u->current_order.flags & OF_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);
|
||||
|
||||
if (v->cargo_source != last_visited && ge->waiting_acceptance & 0x8000 && !(u->current_order.flags & OF_TRANSFER)) {
|
||||
result |= 1;
|
||||
} else if (u->current_order.flags & (OF_UNLOAD | OF_TRANSFER)) {
|
||||
if (count == 0) {
|
||||
/* No goods waiting at station */
|
||||
ge->enroute_time = v->cargo_days;
|
||||
ge->enroute_from = v->cargo_source;
|
||||
ge->enroute_from_xy = v->cargo_source_xy;
|
||||
} else {
|
||||
/* Goods already waiting at station. Set counters to the worst value. */
|
||||
if (v->cargo_days >= ge->enroute_time) ge->enroute_time = v->cargo_days;
|
||||
|
||||
if (last_visited != ge->enroute_from) {
|
||||
ge->enroute_from = v->cargo_source;
|
||||
ge->enroute_from_xy = v->cargo_source_xy;
|
||||
}
|
||||
}
|
||||
/* Update amount of waiting cargo. There is, however, no sense in
|
||||
* updating the count variable because this vehicle will not be
|
||||
* able to take the cargo. */
|
||||
SB(ge->waiting_acceptance, 0, 12, min(amount_unloaded + count, 0xFFF));
|
||||
|
||||
/* if there is not enough to unload from pending, ensure it does not go -ve
|
||||
* else deduct amount actually unloaded from unload_pending */
|
||||
SB(ge->unload_pending, 0, 12, max(GB(ge->unload_pending, 0, 12) - amount_unloaded, 0U));
|
||||
remaining = v->cargo.MoveTo(&ge->cargo, amount_unloaded);
|
||||
|
||||
result |= 2;
|
||||
} else {
|
||||
@ -1570,11 +1542,8 @@ static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
|
||||
|
||||
unloading_time += amount_unloaded;
|
||||
|
||||
v->cargo_count -= amount_unloaded;
|
||||
v->cargo_paid_for -= min(amount_unloaded, v->cargo_paid_for);
|
||||
|
||||
anything_unloaded = true;
|
||||
if (_patches.gradual_loading && v->cargo_count != 0) {
|
||||
if (_patches.gradual_loading && remaining) {
|
||||
completely_empty = false;
|
||||
} else {
|
||||
/* We have finished unloading (cargo count == 0) */
|
||||
@ -1584,9 +1553,6 @@ static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We cannot have paid for more cargo than there is on board. */
|
||||
assert(v->cargo_paid_for <= v->cargo_count);
|
||||
|
||||
/* Do not pick up goods that we unloaded */
|
||||
if (u->current_order.flags & OF_UNLOAD) continue;
|
||||
|
||||
@ -1605,8 +1571,9 @@ static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
|
||||
|
||||
/* If there's goods waiting at the station, and the vehicle
|
||||
* has capacity for it, load it on the vehicle. */
|
||||
if (count != 0 &&
|
||||
(cap = v->cargo_cap - v->cargo_count) != 0) {
|
||||
if (!ge->cargo.Empty() &&
|
||||
(cap = v->cargo_cap - v->cargo.Count()) != 0) {
|
||||
uint count = ge->cargo.Count();
|
||||
|
||||
/* Skip loading this vehicle if another train/vehicle is already handling
|
||||
* the same cargo type at this station */
|
||||
@ -1623,7 +1590,7 @@ static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
|
||||
cargo_left[v->cargo_type] -= cap;
|
||||
}
|
||||
|
||||
if (v->cargo_count == 0) TriggerVehicle(v, VEHICLE_TRIGGER_NEW_CARGO);
|
||||
if (v->cargo.Empty()) TriggerVehicle(v, VEHICLE_TRIGGER_NEW_CARGO);
|
||||
|
||||
/* TODO: Regarding this, when we do gradual loading, we
|
||||
* should first unload all vehicles and then start
|
||||
@ -1635,32 +1602,16 @@ static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
|
||||
completely_empty = false;
|
||||
anything_loaded = true;
|
||||
|
||||
/* cargoshare is proportioned by the amount due to unload
|
||||
* Otherwise, with gradual loading, 100% of credits would be taken immediately,
|
||||
* even if the cargo volume represents a tiny percent of the whole.
|
||||
* ge->unload_pending holds the amount that has been credited, but has not yet been unloaded.
|
||||
*/
|
||||
int cargoshare = cap * 10000 / (ge->waiting_acceptance + ge->unload_pending);
|
||||
Money feeder_profit_share = ge->feeder_profit * cargoshare / 10000;
|
||||
v->cargo_count += cap;
|
||||
ge->waiting_acceptance -= cap;
|
||||
ge->cargo.MoveTo(&v->cargo, cap, CargoList::MTA_CARGO_LOAD, st->xy);
|
||||
|
||||
total_cargo_feeder_share += feeder_profit_share; // store cost for later payment when cargo unloaded
|
||||
v->cargo_loaded_at_xy = st->xy; // retains location of where the cargo was picked up for intermediate payments
|
||||
|
||||
ge->feeder_profit -= feeder_profit_share;
|
||||
unloading_time += cap;
|
||||
st->time_since_load = 0;
|
||||
|
||||
/* And record the source of the cargo, and the days in travel. */
|
||||
v->cargo_source = ge->enroute_from;
|
||||
v->cargo_source_xy = ge->enroute_from_xy;
|
||||
v->cargo_days = ge->enroute_time;
|
||||
result |= 2;
|
||||
st->last_vehicle_type = v->type;
|
||||
|
||||
result |= 2;
|
||||
}
|
||||
|
||||
if (v->cargo_count == v->cargo_cap) {
|
||||
if (v->cargo.Count() == v->cargo_cap) {
|
||||
SETBIT(cargo_full, v->cargo_type);
|
||||
} else {
|
||||
SETBIT(cargo_not_full, v->cargo_type);
|
||||
@ -1674,14 +1625,12 @@ static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
|
||||
if (_patches.improved_load && HASBIT(u->current_order.flags, OFB_FULL_LOAD)) {
|
||||
/* Update left cargo */
|
||||
for (v = u; v != NULL; v = v->next) {
|
||||
if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo_count;
|
||||
if (v->cargo_cap != 0) cargo_left[v->cargo_type] -= v->cargo_cap - v->cargo.Count();
|
||||
}
|
||||
}
|
||||
|
||||
v = u;
|
||||
|
||||
v->cargo_feeder_share += total_cargo_feeder_share;
|
||||
|
||||
if (anything_loaded || anything_unloaded) {
|
||||
if (_patches.gradual_loading) {
|
||||
/* The time it takes to load one 'slice' of cargo or passengers depends
|
||||
@ -1696,7 +1645,7 @@ static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
|
||||
if (_patches.full_load_any) {
|
||||
/* if the aircraft carries passengers and is NOT full, then
|
||||
* continue loading, no matter how much mail is in */
|
||||
if ((v->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS) && v->cargo_cap != v->cargo_count) ||
|
||||
if ((v->type == VEH_AIRCRAFT && IsCargoInClass(v->cargo_type, CC_PASSENGERS) && v->cargo_cap != v->cargo.Count()) ||
|
||||
(cargo_not_full && (cargo_full & ~cargo_not_full) == 0)) { // There are stull non-full cargos
|
||||
finished_loading = false;
|
||||
}
|
||||
@ -1754,7 +1703,7 @@ void LoadUnloadStation(Station *st)
|
||||
{
|
||||
int cargo_left[NUM_CARGO];
|
||||
|
||||
for (uint i = 0; i < NUM_CARGO; i++) cargo_left[i] = GB(st->goods[i].waiting_acceptance, 0, 12);
|
||||
for (uint i = 0; i < NUM_CARGO; i++) cargo_left[i] = st->goods[i].cargo.Count();
|
||||
|
||||
std::list<Vehicle *>::iterator iter;
|
||||
for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end(); ++iter) {
|
||||
|
@ -93,6 +93,7 @@ void InitializeTowns();
|
||||
void InitializeTrees();
|
||||
void InitializeSigns();
|
||||
void InitializeStations();
|
||||
void InitializeCargoPackets();
|
||||
static void InitializeNameMgr();
|
||||
void InitializePlayers();
|
||||
static void InitializeCheats();
|
||||
@ -134,6 +135,7 @@ void InitializeGame(int mode, uint size_x, uint size_y)
|
||||
InitializeTrees();
|
||||
InitializeSigns();
|
||||
InitializeStations();
|
||||
InitializeCargoPackets();
|
||||
InitializeIndustries();
|
||||
InitializeBuildingCounts();
|
||||
InitializeMainGui();
|
||||
|
@ -705,10 +705,10 @@ static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, by
|
||||
case 0x39: return v->cargo_type;
|
||||
case 0x3A: return v->cargo_cap;
|
||||
case 0x3B: return GB(v->cargo_cap, 8, 8);
|
||||
case 0x3C: return v->cargo_count;
|
||||
case 0x3D: return GB(v->cargo_count, 8, 8);
|
||||
case 0x3E: return v->cargo_source;
|
||||
case 0x3F: return v->cargo_days;
|
||||
case 0x3C: return v->cargo.Count();
|
||||
case 0x3D: return GB(v->cargo.Count(), 8, 8);
|
||||
case 0x3E: return v->cargo.Source();
|
||||
case 0x3F: return v->cargo.DaysInTransit();
|
||||
case 0x40: return v->age;
|
||||
case 0x41: return GB(v->age, 8, 8);
|
||||
case 0x42: return v->max_age;
|
||||
@ -811,12 +811,12 @@ static const SpriteGroup *VehicleResolveReal(const ResolverObject *object, const
|
||||
|
||||
totalsets = in_motion ? group->g.real.num_loaded : group->g.real.num_loading;
|
||||
|
||||
if (v->cargo_count == v->cargo_cap || totalsets == 1) {
|
||||
if (v->cargo.Count() == v->cargo_cap || totalsets == 1) {
|
||||
set = totalsets - 1;
|
||||
} else if (v->cargo_count == 0 || totalsets == 2) {
|
||||
} else if (v->cargo.Empty() || totalsets == 2) {
|
||||
set = 0;
|
||||
} else {
|
||||
set = v->cargo_count * (totalsets - 2) / max((uint16)1, v->cargo_cap) + 1;
|
||||
set = v->cargo.Count() * (totalsets - 2) / max((uint16)1, v->cargo_cap) + 1;
|
||||
}
|
||||
|
||||
return in_motion ? group->g.real.loaded[set] : group->g.real.loading[set];
|
||||
|
@ -400,7 +400,7 @@ static uint32 StationGetVariable(const ResolverObject *object, byte variable, by
|
||||
uint32 value = 0;
|
||||
|
||||
for (cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
|
||||
if (HASBIT(st->goods[cargo_type].waiting_acceptance, 15)) SETBIT(value, cargo_type);
|
||||
if (st->goods[cargo_type].acceptance) SETBIT(value, cargo_type);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@ -431,12 +431,12 @@ static uint32 StationGetVariable(const ResolverObject *object, byte variable, by
|
||||
const GoodsEntry *ge = &st->goods[c];
|
||||
|
||||
switch (variable) {
|
||||
case 0x60: return GB(ge->waiting_acceptance, 0, 12);
|
||||
case 0x60: return min(ge->cargo.Count(), 4095);
|
||||
case 0x61: return ge->days_since_pickup;
|
||||
case 0x62: return ge->rating;
|
||||
case 0x63: return ge->enroute_time;
|
||||
case 0x63: return ge->cargo.DaysInTransit();
|
||||
case 0x64: return ge->last_speed | (ge->last_age << 8);
|
||||
case 0x65: return GB(ge->waiting_acceptance, 12, 4);
|
||||
case 0x65: return ge->acceptance << 3;
|
||||
}
|
||||
}
|
||||
|
||||
@ -444,12 +444,12 @@ static uint32 StationGetVariable(const ResolverObject *object, byte variable, by
|
||||
if (variable >= 0x8C && variable <= 0xEC) {
|
||||
const GoodsEntry *g = &st->goods[GB(variable - 0x8C, 3, 4)];
|
||||
switch (GB(variable - 0x8C, 0, 3)) {
|
||||
case 0: return g->waiting_acceptance;
|
||||
case 1: return GB(g->waiting_acceptance, 8, 8);
|
||||
case 0: return g->cargo.Count();
|
||||
case 1: return GB(min(g->cargo.Count(), 4095), 0, 4) | (g->acceptance << 7);
|
||||
case 2: return g->days_since_pickup;
|
||||
case 3: return g->rating;
|
||||
case 4: return g->enroute_from;
|
||||
case 5: return g->enroute_time;
|
||||
case 4: return g->cargo.Source();
|
||||
case 5: return g->cargo.DaysInTransit();
|
||||
case 6: return g->last_speed;
|
||||
case 7: return g->last_age;
|
||||
}
|
||||
@ -484,12 +484,12 @@ static const SpriteGroup *StationResolveReal(const ResolverObject *object, const
|
||||
|
||||
case CT_DEFAULT:
|
||||
for (cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
|
||||
cargo += GB(st->goods[cargo_type].waiting_acceptance, 0, 12);
|
||||
cargo += st->goods[cargo_type].cargo.Count();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
cargo = GB(st->goods[cargo_type].waiting_acceptance, 0, 12);
|
||||
cargo = st->goods[cargo_type].cargo.Count();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -545,7 +545,7 @@ static const SpriteGroup *ResolveStation(ResolverObject *object)
|
||||
for (CargoID cargo = 0; cargo < NUM_CARGO; cargo++) {
|
||||
const CargoSpec *cs = GetCargo(cargo);
|
||||
if (cs->IsValid() && object->u.station.statspec->spritegroup[cargo] != NULL &&
|
||||
GB(object->u.station.st->goods[cargo].waiting_acceptance, 0, 12) != 0) {
|
||||
!object->u.station.st->goods[cargo].cargo.Empty()) {
|
||||
ctype = cargo;
|
||||
break;
|
||||
}
|
||||
|
@ -567,13 +567,16 @@ static bool LoadOldCargoPaymentRate(LoadgameState *ls, int num)
|
||||
|
||||
static uint8 _old_platforms;
|
||||
static uint _current_station_id;
|
||||
static uint16 _waiting_acceptance;
|
||||
static uint8 _cargo_source;
|
||||
static uint8 _cargo_days;
|
||||
|
||||
static const OldChunks goods_chunk[] = {
|
||||
OCL_SVAR( OC_UINT16, GoodsEntry, waiting_acceptance ),
|
||||
OCL_VAR ( OC_UINT16, 1, &_waiting_acceptance ),
|
||||
OCL_SVAR( OC_UINT8, GoodsEntry, days_since_pickup ),
|
||||
OCL_SVAR( OC_UINT8, GoodsEntry, rating ),
|
||||
OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, GoodsEntry, enroute_from ),
|
||||
OCL_SVAR( OC_UINT8, GoodsEntry, enroute_time ),
|
||||
OCL_VAR ( OC_UINT8, 1, &_cargo_source ),
|
||||
OCL_VAR ( OC_UINT8, 1, &_cargo_days ),
|
||||
OCL_SVAR( OC_UINT8, GoodsEntry, last_speed ),
|
||||
OCL_SVAR( OC_UINT8, GoodsEntry, last_age ),
|
||||
|
||||
@ -583,7 +586,17 @@ static const OldChunks goods_chunk[] = {
|
||||
static bool LoadOldGood(LoadgameState *ls, int num)
|
||||
{
|
||||
Station *st = GetStation(_current_station_id);
|
||||
return LoadChunk(ls, &st->goods[num], goods_chunk);
|
||||
GoodsEntry *ge = &st->goods[num];
|
||||
bool ret = LoadChunk(ls, ge, goods_chunk);
|
||||
if (ret && GB(_waiting_acceptance, 0, 12) != 0) {
|
||||
CargoPacket *cp = new CargoPacket();
|
||||
cp->source = (_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source;
|
||||
cp->count = GB(_waiting_acceptance, 0, 12);
|
||||
cp->days_in_transit = _cargo_days;
|
||||
ge->acceptance = HASBIT(_waiting_acceptance, 15);
|
||||
ge->cargo.Append(cp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const OldChunks station_chunk[] = {
|
||||
@ -1091,6 +1104,8 @@ static bool LoadOldVehicleUnion(LoadgameState *ls, int num)
|
||||
return res;
|
||||
}
|
||||
|
||||
static uint16 _cargo_count;
|
||||
|
||||
static const OldChunks vehicle_chunk[] = {
|
||||
OCL_SVAR( OC_UINT8, Vehicle, type ),
|
||||
OCL_SVAR( OC_UINT8, Vehicle, subtype ),
|
||||
@ -1133,9 +1148,9 @@ static const OldChunks vehicle_chunk[] = {
|
||||
|
||||
OCL_SVAR( OC_UINT8, Vehicle, cargo_type ),
|
||||
OCL_SVAR( OC_UINT16, Vehicle, cargo_cap ),
|
||||
OCL_SVAR( OC_UINT16, Vehicle, cargo_count ),
|
||||
OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Vehicle, cargo_source ),
|
||||
OCL_SVAR( OC_UINT8, Vehicle, cargo_days ),
|
||||
OCL_VAR ( OC_UINT16, 1, &_cargo_count ),
|
||||
OCL_VAR ( OC_UINT8, 1, &_cargo_source ),
|
||||
OCL_VAR ( OC_UINT8, 1, &_cargo_days ),
|
||||
|
||||
OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, age ),
|
||||
OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, max_age ),
|
||||
@ -1213,6 +1228,12 @@ static bool LoadOldVehicle(LoadgameState *ls, int num)
|
||||
|
||||
/* Vehicle-subtype is different in TTD(Patch) */
|
||||
if (v->type == VEH_SPECIAL) v->subtype = v->subtype >> 1;
|
||||
|
||||
if (_cargo_count != 0) {
|
||||
CargoPacket *cp = new CargoPacket((_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source, _cargo_count);
|
||||
cp->days_in_transit = _cargo_days;
|
||||
v->cargo.Append(cp);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -303,6 +303,7 @@ static void UnInitializeGame()
|
||||
CleanPool(&_Sign_pool);
|
||||
CleanPool(&_Order_pool);
|
||||
CleanPool(&_Group_pool);
|
||||
CleanPool(&_CargoPacket_pool);
|
||||
|
||||
free((void*)_town_sort);
|
||||
free((void*)_industry_sort);
|
||||
@ -930,6 +931,31 @@ void SwitchMode(int new_mode)
|
||||
}
|
||||
}
|
||||
|
||||
#include "cargopacket.h"
|
||||
void CheckCargoPacketLeaks()
|
||||
{
|
||||
CargoPacket *cp;
|
||||
FOR_ALL_CARGOPACKETS(cp) cp->touched = false;
|
||||
|
||||
Vehicle *v;
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
const CargoList::List *packets = v->cargo.Packets();
|
||||
for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) (*it)->touched = true;
|
||||
}
|
||||
|
||||
Station *st;
|
||||
FOR_ALL_STATIONS(st) {
|
||||
for (CargoID c = 0; c < NUM_CARGO; c++) {
|
||||
GoodsEntry *ge = &st->goods[c];
|
||||
|
||||
const CargoList::List *packets = ge->cargo.Packets();
|
||||
for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) (*it)->touched = true;
|
||||
}
|
||||
}
|
||||
|
||||
FOR_ALL_CARGOPACKETS(cp) assert(cp->touched);
|
||||
}
|
||||
|
||||
|
||||
/* State controlling game loop.
|
||||
* The state must not be changed from anywhere
|
||||
@ -964,6 +990,7 @@ void StateGameLoop()
|
||||
CallWindowTickEvent();
|
||||
NewsLoop();
|
||||
_current_player = p;
|
||||
CheckCargoPacketLeaks();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1896,13 +1923,19 @@ bool AfterLoadGame()
|
||||
if (CheckSavegameVersion(44)) {
|
||||
Vehicle *v;
|
||||
/* If we remove a station while cargo from it is still enroute, payment calculation will assume
|
||||
* 0, 0 to be the origin of the cargo, resulting in very high payments usually. v->cargo_source_xy
|
||||
* 0, 0 to be the source of the cargo, resulting in very high payments usually. v->source_xy
|
||||
* stores the coordinates, preserving them even if the station is removed. However, if a game is loaded
|
||||
* where this situation exists, the cargo-source information is lost. in this case, we set the origin
|
||||
* where this situation exists, the cargo-source information is lost. in this case, we set the source
|
||||
* to the current tile of the vehicle to prevent excessive profits
|
||||
*/
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
v->cargo_source_xy = IsValidStationID(v->cargo_source) ? GetStation(v->cargo_source)->xy : v->tile;
|
||||
const CargoList::List *packets = v->cargo.Packets();
|
||||
for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) {
|
||||
CargoPacket *cp = *it;
|
||||
cp->source_xy = IsValidStationID(cp->source) ? GetStation(cp->source)->xy : v->tile;
|
||||
cp->loaded_at_xy = cp->source_xy;
|
||||
}
|
||||
v->cargo.InvalidateCache();
|
||||
}
|
||||
|
||||
/* Store position of the station where the goods come from, so there
|
||||
@ -1915,12 +1948,12 @@ bool AfterLoadGame()
|
||||
for (CargoID c = 0; c < NUM_CARGO; c++) {
|
||||
GoodsEntry *ge = &st->goods[c];
|
||||
|
||||
/* In old versions, enroute_from used 0xFF as INVALID_STATION */
|
||||
if (CheckSavegameVersion(7) && ge->enroute_from == 0xFF) {
|
||||
ge->enroute_from = INVALID_STATION;
|
||||
const CargoList::List *packets = ge->cargo.Packets();
|
||||
for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) {
|
||||
CargoPacket *cp = *it;
|
||||
cp->source_xy = IsValidStationID(cp->source) ? GetStation(cp->source)->xy : st->xy;
|
||||
cp->loaded_at_xy = cp->source_xy;
|
||||
}
|
||||
|
||||
ge->enroute_from_xy = IsValidStationID(ge->enroute_from) ? GetStation(ge->enroute_from)->xy : st->xy;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1933,12 +1966,13 @@ bool AfterLoadGame()
|
||||
* loading again, even if it didn't actually load anything, so now the
|
||||
* amount of cargo that has been paid for is stored. */
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
if (HASBIT(v->vehicle_flags, 2)) {
|
||||
v->cargo_paid_for = v->cargo_count;
|
||||
CLRBIT(v->vehicle_flags, 2);
|
||||
} else {
|
||||
v->cargo_paid_for = 0;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,7 @@ typedef EngineID *EngineList; ///< engine list type placeholder acceptable for C
|
||||
/* IDs used in Pools */
|
||||
typedef uint16 VehicleID;
|
||||
typedef uint16 StationID;
|
||||
static const StationID INVALID_STATION = 0xFFFF;
|
||||
typedef uint16 RoadStopID;
|
||||
typedef uint16 TownID;
|
||||
typedef uint16 IndustryID;
|
||||
|
@ -97,7 +97,7 @@ int GetRoadVehImage(const Vehicle* v, Direction direction)
|
||||
}
|
||||
|
||||
image = direction + _roadveh_images[img];
|
||||
if (v->cargo_count >= v->cargo_cap / 2) image += _roadveh_full_adder[img];
|
||||
if (v->cargo.Count() >= v->cargo_cap / 2) image += _roadveh_full_adder[img];
|
||||
return image;
|
||||
}
|
||||
|
||||
@ -677,7 +677,7 @@ static void RoadVehCrash(Vehicle *v)
|
||||
v->u.road.crashed_ctr++;
|
||||
|
||||
for (Vehicle *u = v; u != NULL; u = u->next) {
|
||||
if (IsCargoInClass(u->cargo_type, CC_PASSENGERS)) pass += u->cargo_count;
|
||||
if (IsCargoInClass(u->cargo_type, CC_PASSENGERS)) pass += u->cargo.Count();
|
||||
|
||||
u->vehstatus |= VS_CRASHED;
|
||||
|
||||
@ -1826,7 +1826,7 @@ static void RoadVehController(Vehicle *v)
|
||||
static void AgeRoadVehCargo(Vehicle *v)
|
||||
{
|
||||
if (_age_cargo_skip_counter != 0) return;
|
||||
if (v->cargo_days != 255) v->cargo_days++;
|
||||
v->cargo.AgeCargo();
|
||||
}
|
||||
|
||||
void RoadVeh_Tick(Vehicle *v)
|
||||
@ -2069,7 +2069,7 @@ CommandCost CmdRefitRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
v->cargo_cap = capacity;
|
||||
v->cargo_count = (v->cargo_type == new_cid) ? min(capacity, v->cargo_count) : 0;
|
||||
v->cargo.Truncate((v->cargo_type == new_cid) ? capacity : 0);
|
||||
v->cargo_type = new_cid;
|
||||
v->cargo_subtype = new_subtype;
|
||||
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
|
||||
|
@ -154,10 +154,10 @@ static void RoadVehDetailsWndProc(Window *w, WindowEvent *e)
|
||||
|
||||
for (const Vehicle *u = v; u != NULL; u = u->next) {
|
||||
str = STR_8812_EMPTY;
|
||||
if (u->cargo_count != 0) {
|
||||
if (!u->cargo.Empty()) {
|
||||
SetDParam(0, u->cargo_type);
|
||||
SetDParam(1, u->cargo_count);
|
||||
SetDParam(2, u->cargo_source);
|
||||
SetDParam(1, u->cargo.Count());
|
||||
SetDParam(2, u->cargo.Source());
|
||||
str = STR_8813_FROM;
|
||||
}
|
||||
DrawString(34, 78 + y_offset, str, 0);
|
||||
@ -172,17 +172,17 @@ static void RoadVehDetailsWndProc(Window *w, WindowEvent *e)
|
||||
DrawString(34, 67 + y_offset, STR_9012_CAPACITY, 0);
|
||||
|
||||
str = STR_8812_EMPTY;
|
||||
if (v->cargo_count != 0) {
|
||||
if (!v->cargo.Empty()) {
|
||||
SetDParam(0, v->cargo_type);
|
||||
SetDParam(1, v->cargo_count);
|
||||
SetDParam(2, v->cargo_source);
|
||||
SetDParam(1, v->cargo.Count());
|
||||
SetDParam(2, v->cargo.Source());
|
||||
str = STR_8813_FROM;
|
||||
}
|
||||
DrawString(34, 78 + y_offset, str, 0);
|
||||
}
|
||||
|
||||
/* Draw Transfer credits text */
|
||||
SetDParam(0, v->cargo_feeder_share);
|
||||
SetDParam(0, v->cargo.FeederShare());
|
||||
DrawString(34, 90 + y_offset, STR_FEEDER_CARGO_VALUE, 0);
|
||||
|
||||
/* Draw service interval text */
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include <setjmp.h>
|
||||
#include <list>
|
||||
|
||||
extern const uint16 SAVEGAME_VERSION = 67;
|
||||
extern const uint16 SAVEGAME_VERSION = 68;
|
||||
uint16 _sl_version; ///< the major savegame version identifier
|
||||
byte _sl_minor_version; ///< the minor savegame version, DO NOT USE!
|
||||
|
||||
@ -820,7 +820,7 @@ void SlObject(void *object, const SaveLoad *sld)
|
||||
}
|
||||
|
||||
for (; sld->cmd != SL_END; sld++) {
|
||||
void *ptr = GetVariableAddress(object, sld);
|
||||
void *ptr = sld->global ? sld->address : GetVariableAddress(object, sld);
|
||||
SlObjectMember(ptr, sld);
|
||||
}
|
||||
}
|
||||
@ -831,14 +831,7 @@ void SlObject(void *object, const SaveLoad *sld)
|
||||
*/
|
||||
void SlGlobList(const SaveLoadGlobVarList *sldg)
|
||||
{
|
||||
if (_sl.need_length != NL_NONE) {
|
||||
SlSetLength(SlCalcObjLength(NULL, (const SaveLoad*)sldg));
|
||||
if (_sl.need_length == NL_CALCLENGTH) return;
|
||||
}
|
||||
|
||||
for (; sldg->cmd != SL_END; sldg++) {
|
||||
SlObjectMember(sldg->address, (const SaveLoad*)sldg);
|
||||
}
|
||||
SlObject(NULL, (const SaveLoad*)sldg);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1258,6 +1251,7 @@ extern const ChunkHandler _economy_chunk_handlers[];
|
||||
extern const ChunkHandler _animated_tile_chunk_handlers[];
|
||||
extern const ChunkHandler _newgrf_chunk_handlers[];
|
||||
extern const ChunkHandler _group_chunk_handlers[];
|
||||
extern const ChunkHandler _cargopacket_chunk_handlers[];
|
||||
|
||||
static const ChunkHandler * const _chunk_handlers[] = {
|
||||
_misc_chunk_handlers,
|
||||
@ -1276,6 +1270,7 @@ static const ChunkHandler * const _chunk_handlers[] = {
|
||||
_animated_tile_chunk_handlers,
|
||||
_newgrf_chunk_handlers,
|
||||
_group_chunk_handlers,
|
||||
_cargopacket_chunk_handlers,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -1307,6 +1302,7 @@ static uint ReferenceToInt(const void *obj, SLRefType rt)
|
||||
case REF_ORDER: return ((const Order*)obj)->index + 1;
|
||||
case REF_ROADSTOPS: return ((const RoadStop*)obj)->index + 1;
|
||||
case REF_ENGINE_RENEWS: return ((const EngineRenew*)obj)->index + 1;
|
||||
case REF_CARGO_PACKET: return ((const CargoPacket*)obj)->index + 1;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
|
||||
@ -1367,6 +1363,11 @@ static void *IntToReference(uint index, SLRefType rt)
|
||||
error("EngineRenews: failed loading savegame: too many EngineRenews");
|
||||
return GetEngineRenew(index);
|
||||
}
|
||||
case REF_CARGO_PACKET: {
|
||||
if (!AddBlockIfNeeded(&_CargoPacket_pool, index))
|
||||
error("CargoPackets: failed loading savegame: too many Cargo packets");
|
||||
return GetCargoPacket(index);
|
||||
}
|
||||
|
||||
case REF_VEHICLE_OLD: {
|
||||
/* Old vehicles were saved differently:
|
||||
|
@ -55,6 +55,7 @@ enum SLRefType {
|
||||
REF_VEHICLE_OLD = 4,
|
||||
REF_ROADSTOPS = 5,
|
||||
REF_ENGINE_RENEWS = 6,
|
||||
REF_CARGO_PACKET = 7,
|
||||
};
|
||||
|
||||
#define SL_MAX_VERSION 255
|
||||
@ -172,6 +173,7 @@ typedef byte SaveLoadType;
|
||||
|
||||
/** SaveLoad type struct. Do NOT use this directly but use the SLE_ macros defined just below! */
|
||||
struct SaveLoad {
|
||||
bool global; ///< should we load a global variable or a non-global one
|
||||
SaveLoadType cmd; ///< the action to take with the saved/loaded type, All types need different action
|
||||
VarType conv; ///< type of the variable to be saved, int
|
||||
uint16 length; ///< (conditional) length of the variable (eg. arrays) (max array size is 65536 elements)
|
||||
@ -180,7 +182,7 @@ struct SaveLoad {
|
||||
/* NOTE: This element either denotes the address of the variable for a global
|
||||
* variable, or the offset within a struct which is then bound to a variable
|
||||
* during runtime. Decision on which one to use is controlled by the function
|
||||
* that is called to save it. address: SlGlobList, offset: SlObject */
|
||||
* that is called to save it. address: global=true, offset: global=false */
|
||||
void *address; ///< address of variable OR offset of variable in the struct (max offset is 65536)
|
||||
};
|
||||
|
||||
@ -188,7 +190,7 @@ struct SaveLoad {
|
||||
typedef SaveLoad SaveLoadGlobVarList;
|
||||
|
||||
/* Simple variables, references (pointers) and arrays */
|
||||
#define SLE_GENERAL(cmd, base, variable, type, length, from, to) {cmd, type, length, from, to, (void*)cpp_offsetof(base, variable)}
|
||||
#define SLE_GENERAL(cmd, base, variable, type, length, from, to) {false, cmd, type, length, from, to, (void*)cpp_offsetof(base, variable)}
|
||||
#define SLE_CONDVAR(base, variable, type, from, to) SLE_GENERAL(SL_VAR, base, variable, type, 0, from, to)
|
||||
#define SLE_CONDREF(base, variable, type, from, to) SLE_GENERAL(SL_REF, base, variable, type, 0, from, to)
|
||||
#define SLE_CONDARR(base, variable, type, length, from, to) SLE_GENERAL(SL_ARR, base, variable, type, length, from, to)
|
||||
@ -209,7 +211,7 @@ typedef SaveLoad SaveLoadGlobVarList;
|
||||
#define SLE_INCLUDE(base, variable, include_index) SLE_GENERAL(SL_INCLUDE, base, variable, 0, 0, include_index, 0)
|
||||
|
||||
/* The same as the ones at the top, only the offset is given directly; used for unions */
|
||||
#define SLE_GENERALX(cmd, offset, type, param1, param2) {cmd, type, 0, param1, param2, (void*)(offset)}
|
||||
#define SLE_GENERALX(cmd, offset, type, param1, param2) {false, cmd, type, 0, param1, param2, (void*)(offset)}
|
||||
#define SLE_CONDVARX(offset, type, from, to) SLE_GENERALX(SL_VAR, offset, type, from, to)
|
||||
#define SLE_CONDREFX(offset, type, from, to) SLE_GENERALX(SL_REF, offset, type, from, to)
|
||||
|
||||
@ -220,10 +222,10 @@ typedef SaveLoad SaveLoadGlobVarList;
|
||||
#define SLE_INCLUDEX(offset, type) SLE_GENERALX(SL_INCLUDE, offset, type, 0, SL_MAX_VERSION)
|
||||
|
||||
/* End marker */
|
||||
#define SLE_END() {SL_END, 0, 0, 0, 0, NULL}
|
||||
#define SLE_END() {false, SL_END, 0, 0, 0, 0, NULL}
|
||||
|
||||
/* Simple variables, references (pointers) and arrays, but for global variables */
|
||||
#define SLEG_GENERAL(cmd, variable, type, length, from, to) {cmd, type, length, from, to, (void*)&variable}
|
||||
#define SLEG_GENERAL(cmd, variable, type, length, from, to) {true, cmd, type, length, from, to, (void*)&variable}
|
||||
|
||||
#define SLEG_CONDVAR(variable, type, from, to) SLEG_GENERAL(SL_VAR, variable, type, 0, from, to)
|
||||
#define SLEG_CONDREF(variable, type, from, to) SLEG_GENERAL(SL_REF, variable, type, 0, from, to)
|
||||
@ -237,9 +239,9 @@ typedef SaveLoad SaveLoadGlobVarList;
|
||||
#define SLEG_STR(variable, type) SLEG_CONDSTR(variable, type, lengthof(variable), 0, SL_MAX_VERSION)
|
||||
#define SLEG_LST(variable, type) SLEG_CONDLST(variable, type, 0, SL_MAX_VERSION)
|
||||
|
||||
#define SLEG_CONDNULL(length, from, to) {SL_ARR, SLE_FILE_U8 | SLE_VAR_NULL | SLF_CONFIG_NO, length, from, to, (void*)NULL}
|
||||
#define SLEG_CONDNULL(length, from, to) {true, SL_ARR, SLE_FILE_U8 | SLE_VAR_NULL | SLF_CONFIG_NO, length, from, to, (void*)NULL}
|
||||
|
||||
#define SLEG_END() {SL_END, 0, 0, 0, 0, NULL}
|
||||
#define SLEG_END() {true, SL_END, 0, 0, 0, 0, NULL}
|
||||
|
||||
/** Checks if the savegame is below major.minor.
|
||||
*/
|
||||
|
@ -784,7 +784,7 @@ reverse_direction:
|
||||
static void AgeShipCargo(Vehicle *v)
|
||||
{
|
||||
if (_age_cargo_skip_counter != 0) return;
|
||||
if (v->cargo_days != 255) v->cargo_days++;
|
||||
v->cargo.AgeCargo();
|
||||
}
|
||||
|
||||
void Ship_Tick(Vehicle *v)
|
||||
@ -1110,7 +1110,7 @@ CommandCost CmdRefitShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
v->cargo_cap = capacity;
|
||||
v->cargo_count = (v->cargo_type == new_cid) ? min(v->cargo_cap, v->cargo_count) : 0;
|
||||
v->cargo.Truncate((v->cargo_type == new_cid) ? capacity : 0);
|
||||
v->cargo_type = new_cid;
|
||||
v->cargo_subtype = new_subtype;
|
||||
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
|
||||
|
@ -93,16 +93,16 @@ static void ShipDetailsWndProc(Window *w, WindowEvent *e)
|
||||
DrawString(74, 67, STR_9817_CAPACITY, 0);
|
||||
|
||||
str = STR_8812_EMPTY;
|
||||
if (v->cargo_count != 0) {
|
||||
if (!v->cargo.Empty()) {
|
||||
SetDParam(0, v->cargo_type);
|
||||
SetDParam(1, v->cargo_count);
|
||||
SetDParam(2, v->cargo_source);
|
||||
SetDParam(1, v->cargo.Count());
|
||||
SetDParam(2, v->cargo.Source());
|
||||
str = STR_8813_FROM;
|
||||
}
|
||||
DrawString(74, 78, str, 0);
|
||||
|
||||
/* Draw Transfer credits text */
|
||||
SetDParam(0, v->cargo_feeder_share);
|
||||
SetDParam(0, v->cargo.FeederShare());
|
||||
DrawString(74, 89, STR_FEEDER_CARGO_VALUE, 0);
|
||||
|
||||
} break;
|
||||
|
@ -79,6 +79,10 @@ Station::~Station()
|
||||
|
||||
free(speclist);
|
||||
xy = 0;
|
||||
|
||||
for (CargoID c = 0; c < NUM_CARGO; c++) {
|
||||
goods[c].cargo.Truncate(0);
|
||||
}
|
||||
}
|
||||
|
||||
void* Station::operator new(size_t size)
|
||||
|
@ -12,34 +12,26 @@
|
||||
#include "tile.h"
|
||||
#include "road.h"
|
||||
#include "newgrf_station.h"
|
||||
#include "cargopacket.h"
|
||||
#include <list>
|
||||
|
||||
static const StationID INVALID_STATION = 0xFFFF;
|
||||
static const byte INITIAL_STATION_RATING = 175;
|
||||
|
||||
struct GoodsEntry {
|
||||
GoodsEntry() :
|
||||
waiting_acceptance(0),
|
||||
unload_pending(0),
|
||||
acceptance(false),
|
||||
days_since_pickup(0),
|
||||
rating(INITIAL_STATION_RATING),
|
||||
enroute_from(INVALID_STATION),
|
||||
enroute_from_xy(INVALID_TILE),
|
||||
last_speed(0),
|
||||
last_age(255),
|
||||
feeder_profit(0)
|
||||
last_age(255)
|
||||
{}
|
||||
|
||||
uint16 waiting_acceptance;
|
||||
uint16 unload_pending; ///< records how much cargo is awaiting transfer during gradual loading to allow correct fee calc
|
||||
bool acceptance;
|
||||
byte days_since_pickup;
|
||||
byte rating;
|
||||
StationID enroute_from;
|
||||
TileIndex enroute_from_xy;
|
||||
byte enroute_time;
|
||||
byte last_speed;
|
||||
byte last_age;
|
||||
Money feeder_profit;
|
||||
CargoList cargo; ///< The cargo packets of cargo waiting in this station
|
||||
};
|
||||
|
||||
/** A Stop for a Road Vehicle */
|
||||
|
@ -355,7 +355,7 @@ static uint GetAcceptanceMask(const Station *st)
|
||||
uint mask = 0;
|
||||
|
||||
for (CargoID i = 0; i < NUM_CARGO; i++) {
|
||||
if (st->goods[i].waiting_acceptance & 0x8000) mask |= 1 << i;
|
||||
if (st->goods[i].acceptance) mask |= 1 << i;
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
@ -536,7 +536,7 @@ static void UpdateStationAcceptance(Station *st, bool show_msg)
|
||||
(is_passengers && !(st->facilities & (byte)~FACIL_TRUCK_STOP)))
|
||||
amt = 0;
|
||||
|
||||
SB(st->goods[i].waiting_acceptance, 12, 4, amt);
|
||||
st->goods[i].acceptance = (amt >= 8);
|
||||
}
|
||||
|
||||
// Only show a message in case the acceptance was actually changed.
|
||||
@ -2347,11 +2347,10 @@ static void UpdateStationRating(Station *st)
|
||||
/* Slowly increase the rating back to his original level in the case we
|
||||
* didn't deliver cargo yet to this station. This happens when a bribe
|
||||
* failed while you didn't moved that cargo yet to a station. */
|
||||
if (ge->enroute_from == INVALID_STATION && ge->rating < INITIAL_STATION_RATING)
|
||||
if (ge->days_since_pickup == 255 && ge->rating < INITIAL_STATION_RATING)
|
||||
ge->rating++;
|
||||
/* Only change the rating if we are moving this cargo */
|
||||
if (ge->enroute_from != INVALID_STATION) {
|
||||
byte_inc_sat(&ge->enroute_time);
|
||||
if (ge->last_speed != 0) {
|
||||
byte_inc_sat(&ge->days_since_pickup);
|
||||
|
||||
int rating = 0;
|
||||
@ -2383,7 +2382,7 @@ static void UpdateStationRating(Station *st)
|
||||
(rating += 35, true);
|
||||
}
|
||||
|
||||
int waiting = GB(ge->waiting_acceptance, 0, 12);
|
||||
uint waiting = ge->cargo.Count();
|
||||
(rating -= 90, waiting > 1500) ||
|
||||
(rating += 55, waiting > 1000) ||
|
||||
(rating += 35, waiting > 600) ||
|
||||
@ -2409,12 +2408,13 @@ static void UpdateStationRating(Station *st)
|
||||
if (rating <= 127 && waiting != 0) {
|
||||
uint32 r = Random();
|
||||
if (rating <= (int)GB(r, 0, 7)) {
|
||||
waiting = max(waiting - (int)GB(r, 8, 2) - 1, 0);
|
||||
/* Need to have int, otherwise it will just overflow etc. */
|
||||
waiting = max((int)waiting - (int)GB(r, 8, 2) - 1, 0);
|
||||
waiting_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (waiting_changed) SB(ge->waiting_acceptance, 0, 12, waiting);
|
||||
if (waiting_changed) ge->cargo.Truncate(waiting);
|
||||
}
|
||||
}
|
||||
} while (++ge != endof(st->goods));
|
||||
@ -2467,7 +2467,7 @@ void ModifyStationRatingAround(TileIndex tile, PlayerID owner, int amount, uint
|
||||
for (CargoID i = 0; i < NUM_CARGO; i++) {
|
||||
GoodsEntry* ge = &st->goods[i];
|
||||
|
||||
if (ge->enroute_from != INVALID_STATION) {
|
||||
if (ge->days_since_pickup != 255) {
|
||||
ge->rating = clamp(ge->rating + amount, 0, 255);
|
||||
}
|
||||
}
|
||||
@ -2477,13 +2477,8 @@ void ModifyStationRatingAround(TileIndex tile, PlayerID owner, int amount, uint
|
||||
|
||||
static void UpdateStationWaiting(Station *st, CargoID type, uint amount)
|
||||
{
|
||||
SB(st->goods[type].waiting_acceptance, 0, 12,
|
||||
min(0xFFF, GB(st->goods[type].waiting_acceptance, 0, 12) + amount)
|
||||
);
|
||||
st->goods[type].cargo.Append(new CargoPacket(st->index, amount));
|
||||
|
||||
st->goods[type].enroute_time = 0;
|
||||
st->goods[type].enroute_from = st->index;
|
||||
st->goods[type].enroute_from_xy = st->xy;
|
||||
InvalidateWindow(WC_STATION_VIEW, st->index);
|
||||
st->MarkTilesDirty(true);
|
||||
}
|
||||
@ -2553,7 +2548,7 @@ uint MoveGoodsToStation(TileIndex tile, int w, int h, CargoID type, uint amount)
|
||||
if (around[i] == NULL) {
|
||||
if (!st->IsBuoy() &&
|
||||
(st->town->exclusive_counter == 0 || st->town->exclusivity == st->owner) && // check exclusive transport rights
|
||||
st->goods[type].rating != 0 &&
|
||||
st->goods[type].rating != 0 && st->goods[type].days_since_pickup != 255 && // we actually service the station
|
||||
(!_patches.selectgoods || st->goods[type].last_speed > 0) && // if last_speed is 0, no vehicle has been there.
|
||||
((st->facilities & ~FACIL_BUS_STOP) != 0 || IsCargoInClass(type, CC_PASSENGERS)) && // if we have other fac. than a bus stop, or the cargo is passengers
|
||||
((st->facilities & ~FACIL_TRUCK_STOP) != 0 || !IsCargoInClass(type, CC_PASSENGERS))) { // if we have other fac. than a cargo bay or the cargo is not passengers
|
||||
@ -2683,10 +2678,8 @@ void BuildOilRig(TileIndex tile)
|
||||
st->build_date = _date;
|
||||
|
||||
for (CargoID j = 0; j < NUM_CARGO; j++) {
|
||||
st->goods[j].waiting_acceptance = 0;
|
||||
st->goods[j].days_since_pickup = 0;
|
||||
st->goods[j].enroute_from = INVALID_STATION;
|
||||
st->goods[j].enroute_from_xy = INVALID_TILE;
|
||||
st->goods[j].acceptance = false;
|
||||
st->goods[j].days_since_pickup = 255;
|
||||
st->goods[j].rating = INITIAL_STATION_RATING;
|
||||
st->goods[j].last_speed = 0;
|
||||
st->goods[j].last_age = 255;
|
||||
@ -2810,6 +2803,8 @@ void AfterLoadStations()
|
||||
|
||||
st->speclist[i].spec = GetCustomStationSpecByGrf(st->speclist[i].grfid, st->speclist[i].localidx);
|
||||
}
|
||||
|
||||
for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2906,19 +2901,27 @@ static const SaveLoad _station_desc[] = {
|
||||
SLE_END()
|
||||
};
|
||||
|
||||
static uint16 _waiting_acceptance;
|
||||
static uint16 _cargo_source;
|
||||
static uint32 _cargo_source_xy;
|
||||
static uint16 _cargo_days;
|
||||
static Money _cargo_feeder_share;
|
||||
|
||||
static const SaveLoad _goods_desc[] = {
|
||||
SLE_VAR(GoodsEntry, waiting_acceptance, SLE_UINT16),
|
||||
SLE_CONDVAR(GoodsEntry, unload_pending, SLE_UINT16, 51, SL_MAX_VERSION),
|
||||
SLEG_CONDVAR( _waiting_acceptance, SLE_UINT16, 0, 67),
|
||||
SLE_CONDVAR(GoodsEntry, acceptance, SLE_BOOL, 68, SL_MAX_VERSION),
|
||||
SLE_CONDNULL(2, 51, 67),
|
||||
SLE_VAR(GoodsEntry, days_since_pickup, SLE_UINT8),
|
||||
SLE_VAR(GoodsEntry, rating, SLE_UINT8),
|
||||
SLE_CONDVAR(GoodsEntry, enroute_from, SLE_FILE_U8 | SLE_VAR_U16, 0, 6),
|
||||
SLE_CONDVAR(GoodsEntry, enroute_from, SLE_UINT16, 7, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(GoodsEntry, enroute_from_xy, SLE_UINT32, 44, SL_MAX_VERSION),
|
||||
SLE_VAR(GoodsEntry, enroute_time, SLE_UINT8),
|
||||
SLEG_CONDVAR( _cargo_source, SLE_FILE_U8 | SLE_VAR_U16, 0, 6),
|
||||
SLEG_CONDVAR( _cargo_source, SLE_UINT16, 7, 67),
|
||||
SLEG_CONDVAR( _cargo_source_xy, SLE_UINT32, 44, 67),
|
||||
SLEG_CONDVAR( _cargo_days, SLE_UINT8, 0, 67),
|
||||
SLE_VAR(GoodsEntry, last_speed, SLE_UINT8),
|
||||
SLE_VAR(GoodsEntry, last_age, SLE_UINT8),
|
||||
SLE_CONDVAR(GoodsEntry, feeder_profit, SLE_FILE_I32 | SLE_VAR_I64,14, 64),
|
||||
SLE_CONDVAR(GoodsEntry, feeder_profit, SLE_INT64, 65, SL_MAX_VERSION),
|
||||
SLEG_CONDVAR( _cargo_feeder_share, SLE_FILE_U32 | SLE_VAR_I64, 14, 64),
|
||||
SLEG_CONDVAR( _cargo_feeder_share, SLE_INT64, 65, 67),
|
||||
SLE_CONDLST(GoodsEntry, cargo, REF_CARGO_PACKET, 68, SL_MAX_VERSION),
|
||||
|
||||
SLE_END()
|
||||
};
|
||||
@ -2935,9 +2938,28 @@ static void SaveLoad_STNS(Station *st)
|
||||
{
|
||||
SlObject(st, _station_desc);
|
||||
|
||||
_waiting_acceptance = 0;
|
||||
|
||||
uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO;
|
||||
for (CargoID i = 0; i < num_cargo; i++) {
|
||||
SlObject(&st->goods[i], _goods_desc);
|
||||
GoodsEntry *ge = &st->goods[i];
|
||||
SlObject(ge, _goods_desc);
|
||||
if (_waiting_acceptance != 0) {
|
||||
ge->acceptance = HASBIT(_waiting_acceptance, 15);
|
||||
if (GB(_waiting_acceptance, 0, 12) != 0) {
|
||||
/* Don't construct the packet with station here, because that'll fail with old savegames */
|
||||
CargoPacket *cp = new CargoPacket();
|
||||
/* In old versions, enroute_from used 0xFF as INVALID_STATION */
|
||||
cp->source = (CheckSavegameVersion(7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source;
|
||||
cp->count = GB(_waiting_acceptance, 0, 12);
|
||||
cp->days_in_transit = _cargo_days;
|
||||
cp->feeder_share = _cargo_feeder_share;
|
||||
cp->source_xy = _cargo_source_xy;
|
||||
cp->days_in_transit = _cargo_days;
|
||||
cp->feeder_share = _cargo_feeder_share;
|
||||
ge->cargo.Append(cp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (st->num_specs != 0) {
|
||||
|
@ -134,8 +134,8 @@ static int CDECL StationWaitingSorter(const void *a, const void *b)
|
||||
Money sum1 = 0, sum2 = 0;
|
||||
|
||||
for (CargoID j = 0; j < NUM_CARGO; j++) {
|
||||
if (st1->goods[j].waiting_acceptance & 0xfff) sum1 += GetTransportedGoodsIncome(st1->goods[j].waiting_acceptance & 0xfff, 20, 50, j);
|
||||
if (st2->goods[j].waiting_acceptance & 0xfff) sum2 += GetTransportedGoodsIncome(st2->goods[j].waiting_acceptance & 0xfff, 20, 50, j);
|
||||
if (!st1->goods[j].cargo.Empty()) sum1 += GetTransportedGoodsIncome(st1->goods[j].cargo.Count(), 20, 50, j);
|
||||
if (!st2->goods[j].cargo.Empty()) sum2 += GetTransportedGoodsIncome(st2->goods[j].cargo.Count(), 20, 50, j);
|
||||
}
|
||||
|
||||
return (_internal_sort_order & 1) ? ClampToI32(sum2 - sum1) : ClampToI32(sum1 - sum2);
|
||||
@ -157,8 +157,8 @@ static int CDECL StationRatingMaxSorter(const void *a, const void *b)
|
||||
byte maxr2 = 0;
|
||||
|
||||
for (CargoID j = 0; j < NUM_CARGO; j++) {
|
||||
if (st1->goods[j].enroute_from != INVALID_STATION) maxr1 = max(maxr1, st1->goods[j].rating);
|
||||
if (st2->goods[j].enroute_from != INVALID_STATION) maxr2 = max(maxr2, st2->goods[j].rating);
|
||||
if (st1->goods[j].days_since_pickup != 255) maxr1 = max(maxr1, st1->goods[j].rating);
|
||||
if (st2->goods[j].days_since_pickup != 255) maxr2 = max(maxr2, st2->goods[j].rating);
|
||||
}
|
||||
|
||||
return (_internal_sort_order & 1) ? maxr2 - maxr1 : maxr1 - maxr2;
|
||||
@ -225,7 +225,7 @@ static void BuildStationsList(plstations_d* sl, PlayerID owner, byte facilities,
|
||||
if (facilities & st->facilities) { //only stations with selected facilities
|
||||
int num_waiting_cargo = 0;
|
||||
for (CargoID j = 0; j < NUM_CARGO; j++) {
|
||||
if (st->goods[j].waiting_acceptance & 0xFFF) {
|
||||
if (!st->goods[j].cargo.Empty()) {
|
||||
num_waiting_cargo++; //count number of waiting cargo
|
||||
if (HASBIT(cargo_filter, j)) {
|
||||
station_sort[n++] = st;
|
||||
@ -368,9 +368,8 @@ static void PlayerStationsWndProc(Window *w, WindowEvent *e)
|
||||
|
||||
/* show cargo waiting and station ratings */
|
||||
for (CargoID j = 0; j < NUM_CARGO; j++) {
|
||||
uint amount = GB(st->goods[j].waiting_acceptance, 0, 12);
|
||||
if (amount != 0) {
|
||||
StationsWndShowStationRating(x, y, j, amount, st->goods[j].rating);
|
||||
if (!st->goods[j].cargo.Empty()) {
|
||||
StationsWndShowStationRating(x, y, j, st->goods[j].cargo.Count(), st->goods[j].rating);
|
||||
x += 20;
|
||||
}
|
||||
}
|
||||
@ -705,9 +704,9 @@ static void DrawStationViewWindow(Window *w)
|
||||
|
||||
num = 1;
|
||||
for (CargoID i = 0; i < NUM_CARGO; i++) {
|
||||
if (GB(st->goods[i].waiting_acceptance, 0, 12) != 0) {
|
||||
if (!st->goods[i].cargo.Empty()) {
|
||||
num++;
|
||||
if (st->goods[i].enroute_from != station_id) num++;
|
||||
if (st->goods[i].cargo.Source() != station_id) num++;
|
||||
}
|
||||
}
|
||||
SetVScrollCount(w, num);
|
||||
@ -729,7 +728,7 @@ static void DrawStationViewWindow(Window *w)
|
||||
if (--pos < 0) {
|
||||
str = STR_00D0_NOTHING;
|
||||
for (CargoID i = 0; i < NUM_CARGO; i++) {
|
||||
if (GB(st->goods[i].waiting_acceptance, 0, 12) != 0) str = STR_EMPTY;
|
||||
if (!st->goods[i].cargo.Empty()) str = STR_EMPTY;
|
||||
}
|
||||
SetDParam(0, str);
|
||||
DrawString(x, y, STR_0008_WAITING, 0);
|
||||
@ -737,10 +736,10 @@ static void DrawStationViewWindow(Window *w)
|
||||
}
|
||||
|
||||
for (CargoID i = 0; i < NUM_CARGO && pos > -5; i++) {
|
||||
uint waiting = GB(st->goods[i].waiting_acceptance, 0, 12);
|
||||
uint waiting = st->goods[i].cargo.Count();
|
||||
if (waiting == 0) continue;
|
||||
|
||||
if (st->goods[i].enroute_from == station_id) {
|
||||
if (st->goods[i].cargo.Source() == station_id) {
|
||||
if (--pos < 0) {
|
||||
DrawCargoIcons(i, waiting, x, y);
|
||||
SetDParam(1, waiting);
|
||||
@ -759,7 +758,7 @@ static void DrawStationViewWindow(Window *w)
|
||||
}
|
||||
|
||||
if (pos > -5 && --pos < 0) {
|
||||
SetDParam(0, st->goods[i].enroute_from);
|
||||
SetDParam(0, st->goods[i].cargo.Source());
|
||||
DrawStringRightAligned(x + 234, y, STR_000B, 0);
|
||||
y += 10;
|
||||
}
|
||||
@ -774,7 +773,7 @@ static void DrawStationViewWindow(Window *w)
|
||||
|
||||
for (CargoID i = 0; i < NUM_CARGO; i++) {
|
||||
if (b >= endof(_userstring) - 5 - 1) break;
|
||||
if (st->goods[i].waiting_acceptance & 0x8000) {
|
||||
if (st->goods[i].acceptance) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
@ -800,7 +799,7 @@ static void DrawStationViewWindow(Window *w)
|
||||
if (!cs->IsValid()) continue;
|
||||
|
||||
const GoodsEntry *ge = &st->goods[i];
|
||||
if (ge->enroute_from == INVALID_STATION) continue;
|
||||
if (ge->days_since_pickup == 255) continue;
|
||||
|
||||
SetDParam(0, cs->name);
|
||||
SetDParam(2, ge->rating * 101 >> 8);
|
||||
|
@ -112,7 +112,7 @@ static void TrainCargoChanged(Vehicle* v)
|
||||
uint32 weight = 0;
|
||||
|
||||
for (Vehicle *u = v; u != NULL; u = u->next) {
|
||||
uint32 vweight = GetCargo(u->cargo_type)->weight * u->cargo_count * FreightWagonMult(u->cargo_type) / 16;
|
||||
uint32 vweight = GetCargo(u->cargo_type)->weight * u->cargo.Count() * FreightWagonMult(u->cargo_type) / 16;
|
||||
|
||||
/* Vehicle weight is not added for articulated parts. */
|
||||
if (!IsArticulatedPart(u)) {
|
||||
@ -463,7 +463,7 @@ int GetTrainImage(const Vehicle* v, Direction direction)
|
||||
|
||||
base = _engine_sprite_base[img] + ((direction + _engine_sprite_add[img]) & _engine_sprite_and[img]);
|
||||
|
||||
if (v->cargo_count >= v->cargo_cap / 2) base += _wagon_full_adder[img];
|
||||
if (v->cargo.Count() >= v->cargo_cap / 2) base += _wagon_full_adder[img];
|
||||
return base;
|
||||
}
|
||||
|
||||
@ -1761,7 +1761,7 @@ CommandCost CmdRefitRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32
|
||||
|
||||
num += amount;
|
||||
if (flags & DC_EXEC) {
|
||||
v->cargo_count = (v->cargo_type == new_cid) ? min(amount, v->cargo_count) : 0;
|
||||
v->cargo.Truncate((v->cargo_type == new_cid) ? amount : 0);
|
||||
v->cargo_type = new_cid;
|
||||
v->cargo_cap = amount;
|
||||
v->cargo_subtype = new_subtype;
|
||||
@ -2681,7 +2681,7 @@ static uint CountPassengersInTrain(const Vehicle* v)
|
||||
{
|
||||
uint num = 0;
|
||||
BEGIN_ENUM_WAGONS(v)
|
||||
if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) num += v->cargo_count;
|
||||
if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) num += v->cargo.Count();
|
||||
END_ENUM_WAGONS(v)
|
||||
return num;
|
||||
}
|
||||
@ -3294,8 +3294,7 @@ static void TrainLocoHandler(Vehicle *v, bool mode)
|
||||
|
||||
void Train_Tick(Vehicle *v)
|
||||
{
|
||||
if (_age_cargo_skip_counter == 0 && v->cargo_days != 0xff)
|
||||
v->cargo_days++;
|
||||
if (_age_cargo_skip_counter == 0) v->cargo.AgeCargo();
|
||||
|
||||
v->tick_counter++;
|
||||
|
||||
|
@ -327,13 +327,12 @@ void ShowTrainViewWindow(const Vehicle *v)
|
||||
static void TrainDetailsCargoTab(const Vehicle *v, int x, int y)
|
||||
{
|
||||
if (v->cargo_cap != 0) {
|
||||
uint num = v->cargo_count;
|
||||
StringID str = STR_8812_EMPTY;
|
||||
|
||||
if (num != 0) {
|
||||
if (!v->cargo.Empty()) {
|
||||
SetDParam(0, v->cargo_type);
|
||||
SetDParam(1, num);
|
||||
SetDParam(2, v->cargo_source);
|
||||
SetDParam(1, v->cargo.Count());
|
||||
SetDParam(2, v->cargo.Source());
|
||||
SetDParam(3, _patches.freight_trains);
|
||||
str = FreightWagonMult(v->cargo_type) > 1 ? STR_FROM_MULT : STR_8813_FROM;
|
||||
}
|
||||
@ -387,7 +386,7 @@ static void DrawTrainDetailsWindow(Window *w)
|
||||
}
|
||||
|
||||
do {
|
||||
act_cargo[u->cargo_type] += u->cargo_count;
|
||||
act_cargo[u->cargo_type] += u->cargo.Count();
|
||||
max_cargo[u->cargo_type] += u->cargo_cap;
|
||||
} while ((u = u->next) != NULL);
|
||||
|
||||
@ -504,7 +503,7 @@ static void DrawTrainDetailsWindow(Window *w)
|
||||
DrawString(x, y + 2, FreightWagonMult(i) > 1 ? STR_TOTAL_CAPACITY_MULT : STR_013F_TOTAL_CAPACITY, 0);
|
||||
}
|
||||
}
|
||||
SetDParam(0, v->cargo_feeder_share);
|
||||
SetDParam(0, v->cargo.FeederShare());
|
||||
DrawString(x, y + 15, STR_FEEDER_CARGO_VALUE, 0);
|
||||
}
|
||||
}
|
||||
|
@ -233,6 +233,8 @@ void AfterLoadVehicles()
|
||||
v->first = NULL;
|
||||
if (v->type == VEH_TRAIN) v->u.rail.first_engine = INVALID_ENGINE;
|
||||
if (v->type == VEH_ROAD) v->u.road.first_engine = INVALID_ENGINE;
|
||||
|
||||
v->cargo.InvalidateCache();
|
||||
}
|
||||
|
||||
FOR_ALL_VEHICLES(v) {
|
||||
@ -690,6 +692,7 @@ void DestroyVehicle(Vehicle *v)
|
||||
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
|
||||
}
|
||||
|
||||
v->cargo.Truncate(0);
|
||||
UpdateVehiclePosHash(v, INVALID_COORD, 0);
|
||||
v->next_hash = NULL;
|
||||
v->next_new_hash = NULL;
|
||||
@ -2277,7 +2280,7 @@ uint8 CalcPercentVehicleFilled(Vehicle *v)
|
||||
|
||||
/* Count up max and used */
|
||||
for (; v != NULL; v = v->next) {
|
||||
count += v->cargo_count;
|
||||
count += v->cargo.Count();
|
||||
max += v->cargo_cap;
|
||||
}
|
||||
|
||||
@ -2748,6 +2751,14 @@ SpriteID GetVehiclePalette(const Vehicle *v)
|
||||
return GetEngineColourMap(v->engine_type, v->owner, INVALID_ENGINE, v);
|
||||
}
|
||||
|
||||
static uint8 _cargo_days;
|
||||
static uint16 _cargo_source;
|
||||
static uint32 _cargo_source_xy;
|
||||
static uint16 _cargo_count;
|
||||
static uint16 _cargo_paid_for;
|
||||
static Money _cargo_feeder_share;
|
||||
static uint32 _cargo_loaded_at_xy;
|
||||
|
||||
/** Save and load of vehicles */
|
||||
extern const SaveLoad _common_veh_desc[] = {
|
||||
SLE_VAR(Vehicle, subtype, SLE_UINT8),
|
||||
@ -2786,12 +2797,13 @@ extern const SaveLoad _common_veh_desc[] = {
|
||||
|
||||
SLE_VAR(Vehicle, cargo_type, SLE_UINT8),
|
||||
SLE_CONDVAR(Vehicle, cargo_subtype, SLE_UINT8, 35, SL_MAX_VERSION),
|
||||
SLE_VAR(Vehicle, cargo_days, SLE_UINT8),
|
||||
SLE_CONDVAR(Vehicle, cargo_source, SLE_FILE_U8 | SLE_VAR_U16, 0, 6),
|
||||
SLE_CONDVAR(Vehicle, cargo_source, SLE_UINT16, 7, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Vehicle, cargo_source_xy, SLE_UINT32, 44, SL_MAX_VERSION),
|
||||
SLEG_CONDVAR( _cargo_days, SLE_UINT8, 0, 67),
|
||||
SLEG_CONDVAR( _cargo_source, SLE_FILE_U8 | SLE_VAR_U16, 0, 6),
|
||||
SLEG_CONDVAR( _cargo_source, SLE_UINT16, 7, 67),
|
||||
SLEG_CONDVAR( _cargo_source_xy, SLE_UINT32, 44, 67),
|
||||
SLE_VAR(Vehicle, cargo_cap, SLE_UINT16),
|
||||
SLE_VAR(Vehicle, cargo_count, SLE_UINT16),
|
||||
SLEG_CONDVAR( _cargo_count, SLE_UINT16, 0, 67),
|
||||
SLE_CONDLST(Vehicle, cargo, REF_CARGO_PACKET, 68, SL_MAX_VERSION),
|
||||
|
||||
SLE_VAR(Vehicle, day_counter, SLE_UINT8),
|
||||
SLE_VAR(Vehicle, tick_counter, SLE_UINT8),
|
||||
@ -2838,16 +2850,16 @@ extern const SaveLoad _common_veh_desc[] = {
|
||||
SLE_CONDVAR(Vehicle, build_year, SLE_INT32, 31, SL_MAX_VERSION),
|
||||
|
||||
SLE_VAR(Vehicle, load_unload_time_rem, SLE_UINT16),
|
||||
SLE_CONDVAR(Vehicle, cargo_paid_for, SLE_UINT16, 45, SL_MAX_VERSION),
|
||||
SLEG_CONDVAR( _cargo_paid_for, SLE_UINT16, 45, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Vehicle, vehicle_flags, SLE_UINT8, 40, SL_MAX_VERSION),
|
||||
|
||||
SLE_CONDVAR(Vehicle, profit_this_year, SLE_FILE_I32 | SLE_VAR_I64, 0, 64),
|
||||
SLE_CONDVAR(Vehicle, profit_this_year, SLE_INT64, 65, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Vehicle, profit_last_year, SLE_FILE_I32 | SLE_VAR_I64, 0, 64),
|
||||
SLE_CONDVAR(Vehicle, profit_last_year, SLE_INT64, 65, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Vehicle, cargo_feeder_share, SLE_FILE_I32 | SLE_VAR_I64,51, 64),
|
||||
SLE_CONDVAR(Vehicle, cargo_feeder_share, SLE_INT64, 65, SL_MAX_VERSION),
|
||||
SLE_CONDVAR(Vehicle, cargo_loaded_at_xy, SLE_UINT32, 51, SL_MAX_VERSION),
|
||||
SLEG_CONDVAR( _cargo_feeder_share, SLE_FILE_I32 | SLE_VAR_I64,51, 64),
|
||||
SLEG_CONDVAR( _cargo_feeder_share, SLE_INT64, 65, 67),
|
||||
SLEG_CONDVAR( _cargo_loaded_at_xy, SLE_UINT32, 51, 67),
|
||||
SLE_CONDVAR(Vehicle, value, SLE_FILE_I32 | SLE_VAR_I64, 0, 64),
|
||||
SLE_CONDVAR(Vehicle, value, SLE_INT64, 65, SL_MAX_VERSION),
|
||||
|
||||
@ -3030,6 +3042,8 @@ static void Load_VEHS()
|
||||
int index;
|
||||
Vehicle *v;
|
||||
|
||||
_cargo_count = 0;
|
||||
|
||||
while ((index = SlIterateArray()) != -1) {
|
||||
Vehicle *v;
|
||||
|
||||
@ -3038,9 +3052,8 @@ static void Load_VEHS()
|
||||
|
||||
v = GetVehicle(index);
|
||||
VehicleType vtype = (VehicleType)SlReadByte();
|
||||
SlObject(v, (SaveLoad*)_veh_descs[vtype]);
|
||||
|
||||
switch (v->type) {
|
||||
switch (vtype) {
|
||||
case VEH_TRAIN: v = new (v) Train(); break;
|
||||
case VEH_ROAD: v = new (v) RoadVehicle(); break;
|
||||
case VEH_SHIP: v = new (v) Ship(); break;
|
||||
@ -3051,6 +3064,20 @@ static void Load_VEHS()
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
|
||||
SlObject(v, (SaveLoad*)_veh_descs[vtype]);
|
||||
|
||||
if (_cargo_count != 0 && IsPlayerBuildableVehicleType(v)) {
|
||||
/* Don't construct the packet with station here, because that'll fail with old savegames */
|
||||
CargoPacket *cp = new CargoPacket();
|
||||
cp->source = _cargo_source;
|
||||
cp->source_xy = _cargo_source_xy;
|
||||
cp->count = _cargo_count;
|
||||
cp->days_in_transit = _cargo_days;
|
||||
cp->feeder_share = _cargo_feeder_share;
|
||||
cp->loaded_at_xy = _cargo_loaded_at_xy;
|
||||
v->cargo.Append(cp);
|
||||
}
|
||||
|
||||
/* Old savegames used 'last_station_visited = 0xFF' */
|
||||
if (CheckSavegameVersion(5) && v->last_station_visited == 0xFF)
|
||||
v->last_station_visited = INVALID_STATION;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "order.h"
|
||||
#include "rail.h"
|
||||
#include "road.h"
|
||||
#include "cargopacket.h"
|
||||
#include "texteff.hpp"
|
||||
|
||||
/** The returned bits of VehicleEnterTile. */
|
||||
@ -265,12 +266,10 @@ struct Vehicle {
|
||||
StationID last_station_visited;
|
||||
|
||||
CargoID cargo_type; // type of cargo this vehicle is carrying
|
||||
byte cargo_days; // how many days have the pieces been in transit
|
||||
StationID cargo_source; // source of cargo
|
||||
TileIndex cargo_source_xy; //< stores the Tile where the source station is located, in case it is removed
|
||||
uint16 cargo_cap; // total capacity
|
||||
uint16 cargo_count; // how many pieces are used
|
||||
byte cargo_subtype; ///< Used for livery refits (NewGRF variations)
|
||||
CargoList cargo; ///< The cargo this vehicle is carrying
|
||||
|
||||
|
||||
byte day_counter; // increased by one for each day
|
||||
byte tick_counter; // increased by one for each tick
|
||||
@ -312,13 +311,10 @@ struct Vehicle {
|
||||
bool leave_depot_instantly; // NOSAVE: stores if the vehicle needs to leave the depot it just entered. Used by autoreplace
|
||||
|
||||
uint16 load_unload_time_rem;
|
||||
uint16 cargo_paid_for; // How much of the cargo currently on board has been paid for.
|
||||
byte vehicle_flags; // Used for gradual loading and other miscellaneous things (@see VehicleFlags enum)
|
||||
|
||||
Money profit_this_year;
|
||||
Money profit_last_year;
|
||||
Money cargo_feeder_share; ///< value of feeder pickup to be paid for on delivery of cargo
|
||||
TileIndex cargo_loaded_at_xy; ///< tile index where feeder cargo was loaded
|
||||
Money value;
|
||||
|
||||
GroupID group_id; ///< Index of group Pool array
|
||||
|
@ -670,7 +670,7 @@ static void FloodVehicle(Vehicle *v)
|
||||
|
||||
/* crash all wagons, and count passengers */
|
||||
BEGIN_ENUM_WAGONS(v)
|
||||
if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo_count;
|
||||
if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) pass += v->cargo.Count();
|
||||
v->vehstatus |= VS_CRASHED;
|
||||
MarkAllViewportsDirty(v->left_coord, v->top_coord, v->right_coord + 1, v->bottom_coord + 1);
|
||||
END_ENUM_WAGONS(v)
|
||||
|
Loading…
Reference in New Issue
Block a user