glx@9629: /* $Id$ */ glx@9629: glx@9629: /** @file cargopacket.cpp Implementation of the cargo packets */ glx@9629: glx@9629: #include "stdafx.h" glx@9629: #include "openttd.h" rubidium@9837: #include "station_base.h" glx@9629: #include "cargopacket.h" glx@9629: #include "saveload.h" rubidium@10142: #include "oldpool_func.h" glx@9629: glx@9629: /* Initialize the cargopacket-pool */ rubidium@9694: DEFINE_OLD_POOL_GENERIC(CargoPacket, CargoPacket) glx@9629: glx@9629: void InitializeCargoPackets() glx@9629: { glx@9629: /* Clean the cargo packet pool and create 1 block in it */ rubidium@9694: _CargoPacket_pool.CleanPool(); rubidium@9694: _CargoPacket_pool.AddBlockToPool(); glx@9629: } glx@9629: glx@9629: CargoPacket::CargoPacket(StationID source, uint16 count) glx@9629: { glx@9629: if (source != INVALID_STATION) assert(count != 0); glx@9629: glx@9629: this->source = source; glx@9629: this->source_xy = (source != INVALID_STATION) ? GetStation(source)->xy : 0; glx@9629: this->loaded_at_xy = this->source_xy; glx@9629: glx@9629: this->count = count; glx@9629: this->days_in_transit = 0; glx@9629: this->feeder_share = 0; glx@9629: this->paid_for = false; glx@9629: } glx@9629: glx@9629: CargoPacket::~CargoPacket() glx@9629: { glx@9629: this->count = 0; glx@9629: } glx@9629: glx@9732: bool CargoPacket::SameSource(const CargoPacket *cp) const glx@9629: { glx@9629: return this->source_xy == cp->source_xy && this->days_in_transit == cp->days_in_transit && this->paid_for == cp->paid_for; glx@9629: } glx@9629: glx@9629: static const SaveLoad _cargopacket_desc[] = { glx@9629: SLE_VAR(CargoPacket, source, SLE_UINT16), glx@9629: SLE_VAR(CargoPacket, source_xy, SLE_UINT32), glx@9629: SLE_VAR(CargoPacket, loaded_at_xy, SLE_UINT32), glx@9629: SLE_VAR(CargoPacket, count, SLE_UINT16), glx@9629: SLE_VAR(CargoPacket, days_in_transit, SLE_UINT8), glx@9629: SLE_VAR(CargoPacket, feeder_share, SLE_INT64), glx@9629: SLE_VAR(CargoPacket, paid_for, SLE_BOOL), glx@9629: glx@9629: SLE_END() glx@9629: }; glx@9629: glx@9629: static void Save_CAPA() glx@9629: { glx@9629: CargoPacket *cp; glx@9629: glx@9629: FOR_ALL_CARGOPACKETS(cp) { glx@9629: SlSetArrayIndex(cp->index); glx@9629: SlObject(cp, _cargopacket_desc); glx@9629: } glx@9629: } glx@9629: glx@9629: static void Load_CAPA() glx@9629: { glx@9629: int index; glx@9629: glx@9629: while ((index = SlIterateArray()) != -1) { rubidium@9694: CargoPacket *cp = new (index) CargoPacket(); glx@9629: SlObject(cp, _cargopacket_desc); glx@9629: } glx@9629: } glx@9629: glx@9629: extern const ChunkHandler _cargopacket_chunk_handlers[] = { glx@9629: { 'CAPA', Save_CAPA, Load_CAPA, CH_ARRAY | CH_LAST}, glx@9629: }; glx@9629: glx@9629: /* glx@9629: * glx@9629: * Cargo list implementation glx@9629: * glx@9629: */ glx@9629: glx@9629: CargoList::~CargoList() glx@9629: { glx@9629: while (!packets.empty()) { glx@9629: delete packets.front(); glx@9629: packets.pop_front(); glx@9629: } glx@9629: } glx@9629: glx@9629: const CargoList::List *CargoList::Packets() const glx@9629: { glx@9629: return &packets; glx@9629: } glx@9629: glx@9629: void CargoList::AgeCargo() glx@9629: { glx@9629: if (empty) return; glx@9629: glx@9629: uint dit = 0; glx@9629: for (List::const_iterator it = packets.begin(); it != packets.end(); it++) { glx@9629: if ((*it)->days_in_transit != 0xFF) (*it)->days_in_transit++; glx@9629: dit += (*it)->days_in_transit * (*it)->count; glx@9629: } glx@9629: days_in_transit = dit / count; glx@9629: } glx@9629: glx@9629: bool CargoList::Empty() const glx@9629: { glx@9629: return empty; glx@9629: } glx@9629: glx@9629: uint CargoList::Count() const glx@9629: { glx@9629: return count; glx@9629: } glx@9629: glx@9629: bool CargoList::UnpaidCargo() const glx@9629: { glx@9629: return unpaid_cargo; glx@9629: } glx@9629: glx@9629: Money CargoList::FeederShare() const glx@9629: { glx@9629: return feeder_share; glx@9629: } glx@9629: glx@9629: StationID CargoList::Source() const glx@9629: { glx@9629: return source; glx@9629: } glx@9629: glx@9629: uint CargoList::DaysInTransit() const glx@9629: { glx@9629: return days_in_transit; glx@9629: } glx@9629: glx@9629: void CargoList::Append(CargoPacket *cp) glx@9629: { glx@9629: assert(cp != NULL); glx@9629: assert(cp->IsValid()); glx@9629: glx@9629: for (List::iterator it = packets.begin(); it != packets.end(); it++) { rubidium@9631: if ((*it)->SameSource(cp) && (*it)->count + cp->count <= 65535) { glx@9629: (*it)->count += cp->count; glx@9629: (*it)->feeder_share += cp->feeder_share; glx@9629: delete cp; glx@9629: glx@9629: InvalidateCache(); glx@9629: return; glx@9629: } glx@9629: } glx@9629: glx@9629: /* The packet could not be merged with another one */ glx@9629: packets.push_back(cp); glx@9629: InvalidateCache(); glx@9629: } glx@9629: glx@9629: glx@9629: void CargoList::Truncate(uint count) glx@9629: { glx@9629: for (List::iterator it = packets.begin(); it != packets.end(); it++) { glx@9629: uint local_count = (*it)->count; glx@9629: if (local_count <= count) { glx@9629: count -= local_count; glx@9629: continue; glx@9629: } glx@9629: glx@9629: (*it)->count = count; glx@9629: count = 0; glx@9629: } glx@9629: glx@9629: while (!packets.empty()) { glx@9629: CargoPacket *cp = packets.back(); glx@9629: if (cp->count != 0) break; glx@9629: delete cp; glx@9629: packets.pop_back(); glx@9629: } glx@9629: glx@9629: InvalidateCache(); glx@9629: } glx@9629: glx@9629: bool CargoList::MoveTo(CargoList *dest, uint count, CargoList::MoveToAction mta, uint data) glx@9629: { glx@9629: assert(mta == MTA_FINAL_DELIVERY || dest != NULL); glx@9629: CargoList tmp; glx@9629: glx@9629: while (!packets.empty() && count > 0) { glx@9629: CargoPacket *cp = *packets.begin(); glx@9629: if (cp->count <= count) { glx@9629: /* Can move the complete packet */ glx@9629: packets.remove(cp); glx@9629: switch (mta) { glx@9629: case MTA_FINAL_DELIVERY: glx@9629: if (cp->source == data) { glx@9629: tmp.Append(cp); glx@9629: } else { glx@9629: count -= cp->count; glx@9629: delete cp; glx@9629: } glx@9629: break; glx@9629: case MTA_CARGO_LOAD: glx@9629: cp->loaded_at_xy = data; glx@9629: /* When cargo is moved into another vehicle you have *always* paid for it */ glx@9629: cp->paid_for = false; glx@9629: /* FALL THROUGH */ glx@9629: case MTA_OTHER: glx@9629: count -= cp->count; glx@9629: dest->packets.push_back(cp); glx@9629: break; glx@9629: } glx@9629: } else { glx@9629: /* Can move only part of the packet, so split it into two pieces */ glx@9629: if (mta != MTA_FINAL_DELIVERY) { glx@9629: CargoPacket *cp_new = new CargoPacket(); glx@9629: cp_new->source = cp->source; glx@9629: cp_new->source_xy = cp->source_xy; glx@9629: cp_new->loaded_at_xy = (mta == MTA_CARGO_LOAD) ? data : cp->loaded_at_xy; glx@9629: glx@9629: cp_new->days_in_transit = cp->days_in_transit; glx@9629: cp_new->feeder_share = cp->feeder_share / count; glx@9629: /* When cargo is moved into another vehicle you have *always* paid for it */ glx@9629: cp_new->paid_for = (mta == MTA_CARGO_LOAD) ? false : cp->paid_for; glx@9629: glx@9629: cp_new->count = count; glx@9629: dest->packets.push_back(cp_new); glx@9629: glx@9629: cp->feeder_share /= cp->count - count; glx@9629: } glx@9629: cp->count -= count; glx@9629: glx@9629: count = 0; glx@9629: } glx@9629: } glx@9629: glx@9629: bool remaining = !packets.empty(); glx@9629: glx@9629: if (mta == MTA_FINAL_DELIVERY && !tmp.Empty()) { glx@9629: /* There are some packets that could not be delivered at the station, put them back */ glx@9629: tmp.MoveTo(this, MAX_UVALUE(uint)); glx@9629: tmp.packets.clear(); glx@9629: } glx@9629: glx@9629: if (dest != NULL) dest->InvalidateCache(); glx@9629: InvalidateCache(); glx@9629: glx@9629: return remaining; glx@9629: } glx@9629: glx@9629: void CargoList::InvalidateCache() glx@9629: { glx@9629: empty = packets.empty(); glx@9629: count = 0; glx@9629: unpaid_cargo = false; glx@9629: feeder_share = 0; glx@9629: source = INVALID_STATION; glx@9629: days_in_transit = 0; glx@9629: glx@9629: if (empty) return; glx@9629: glx@9629: uint dit = 0; glx@9629: for (List::const_iterator it = packets.begin(); it != packets.end(); it++) { glx@9629: count += (*it)->count; glx@9629: unpaid_cargo |= !(*it)->paid_for; glx@9629: dit += (*it)->days_in_transit * (*it)->count; glx@9629: feeder_share += (*it)->feeder_share; glx@9629: } glx@9629: days_in_transit = dit / count; glx@9629: source = (*packets.begin())->source; glx@9629: } rubidium@10455: rubidium@10455: /** Restore an array of cargo packets from a backup rubidium@10455: * The end of the row should be marked by an invalid packet rubidium@10455: */ rubidium@10455: void CargoPacket::RestoreBackup() const rubidium@10455: { rubidium@10455: for (const CargoPacket *cargo = this; cargo->IsValid(); cargo++) { rubidium@10455: CargoPacket *dest = GetCargoPacket(cargo->index); rubidium@10455: assert(!dest->IsValid()); rubidium@10455: memcpy(dest, cargo, sizeof(CargoPacket)); rubidium@10455: } rubidium@10455: }