diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj index 91c0a004f9..b1a2ad6068 100644 --- a/projects/openttd_vs100.vcxproj +++ b/projects/openttd_vs100.vcxproj @@ -296,6 +296,7 @@ + @@ -390,6 +391,7 @@ + diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters index 0c21dc5e01..c799129ecc 100644 --- a/projects/openttd_vs100.vcxproj.filters +++ b/projects/openttd_vs100.vcxproj.filters @@ -117,6 +117,9 @@ Source Files + + Source Files + Source Files @@ -399,6 +402,9 @@ Header Files + + Header Files + Header Files diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj index 4e90a232bb..59917d8a34 100644 --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -454,6 +454,10 @@ RelativePath=".\..\src\bmp.cpp" > + + @@ -834,6 +838,10 @@ RelativePath=".\..\src\cargo_type.h" > + + diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj index dce0ee4125..1dde4fa36e 100644 --- a/projects/openttd_vs90.vcproj +++ b/projects/openttd_vs90.vcproj @@ -451,6 +451,10 @@ RelativePath=".\..\src\bmp.cpp" > + + @@ -831,6 +835,10 @@ RelativePath=".\..\src\cargo_type.h" > + + diff --git a/source.list b/source.list index 2ef5a3067b..2ab418ed74 100644 --- a/source.list +++ b/source.list @@ -4,6 +4,7 @@ animated_tile.cpp articulated_vehicles.cpp autoreplace.cpp bmp.cpp +cargomonitor.cpp cargopacket.cpp cargotype.cpp cheat.cpp @@ -123,6 +124,7 @@ base_station_base.h bmp.h bridge.h cargo_type.h +cargomonitor.h cargopacket.h cargotype.h cheat_func.h diff --git a/src/cargomonitor.cpp b/src/cargomonitor.cpp new file mode 100644 index 0000000000..be808fd8ed --- /dev/null +++ b/src/cargomonitor.cpp @@ -0,0 +1,125 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file cargomonitor.cpp Implementation of the cargo transport monitoring. */ + +#include "stdafx.h" +#include "cargomonitor.h" +#include "station_base.h" + +CargoMonitorMap _cargo_pickups; ///< Map of monitored pick-ups to the amount since last query/activation. +CargoMonitorMap _cargo_deliveries; ///< Map of monitored deliveries to the amount since last query/activation. + +/** Clear all pick-up cargo monitors. */ +void ClearCargoPickupMonitoring() +{ + _cargo_pickups.clear(); +} + +/** Clear all delivery cargo monitors. */ +void ClearCargoDeliveryMonitoring() +{ + _cargo_deliveries.clear(); +} + +/** + * Get and reset the amount associated with a cargo monitor. + * @param[in,out] monitor_map Monitoring map to search (and reset for the queried entry). + * @oaram monitor Cargo monitor to query/reset. + * @param keep_monitoring After returning from this call, continue monitoring. + * @return Amount collected since last query/activation for the monitored combination. + */ +static uint32 GetAmount(CargoMonitorMap &monitor_map, CargoMonitorID monitor, bool keep_monitoring) +{ + CargoMonitorMap::iterator iter = monitor_map.find(monitor); + if (iter == monitor_map.end()) { + if (keep_monitoring) { + std::pair p(monitor, 0); + monitor_map.insert(p); + } + return 0; + } else { + uint32 result = iter->second; + iter->second = 0; + if (!keep_monitoring) monitor_map.erase(iter); + return result; + } +} + +/** + * Get the amount of cargo delivered for the given cargo monitor since activation or last query. + * @param monitor Cargo monitor to query. + * @param keep_monitoring After returning from this call, continue monitoring. + * @return Amount of delivered cargo for the monitored combination. + */ +uint32 GetDeliveryAmount(CargoMonitorID monitor, bool keep_monitoring) +{ + return GetAmount(_cargo_deliveries, monitor, keep_monitoring); +} + +/** + * Get the amount of cargo picked up for the given cargo monitor since activation or last query. + * @param monitor Monitoring number to query. + * @param keep_monitoring After returning from this call, continue monitoring. + * @return Amount of picked up cargo for the monitored combination. + * @note Cargo pick up is counted on final delivery, to prevent users getting credit for picking up cargo without delivering it. + */ +uint32 GetPickupAmount(CargoMonitorID monitor, bool keep_monitoring) +{ + return GetAmount(_cargo_pickups, monitor, keep_monitoring); +} + +/** + * Cargo was delivered to its final destination, update the pickup and delivery maps. + * @param cargo_type type of cargo. + * @param company company delivering the cargo. + * @param amount Amount of cargo delivered. + * @param src_type type of \a src. + * @param src index of source. + * @param st station where the cargo is delivered to. + */ +void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, SourceType src_type, SourceID src, const Station *st) +{ + if (amount == 0) return; + + if (src != INVALID_SOURCE) { + /* Handle pickup update. */ + switch (src_type) { + case ST_INDUSTRY: { + CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, src); + CargoMonitorMap::iterator iter = _cargo_pickups.find(num); + if (iter != _cargo_pickups.end()) iter->second += amount; + break; + } + case ST_TOWN: { + CargoMonitorID num = EncodeCargoTownMonitor(company, cargo_type, src); + CargoMonitorMap::iterator iter = _cargo_pickups.find(num); + if (iter != _cargo_pickups.end()) iter->second += amount; + break; + } + default: break; + } + } + + /* Handle delivery. + * Note that delivery in the right area is sufficient to prevent trouble with neighbouring industries or houses. */ + + /* Town delivery. */ + CargoMonitorID num = EncodeCargoTownMonitor(company, cargo_type, st->town->index); + CargoMonitorMap::iterator iter = _cargo_deliveries.find(num); + if (iter != _cargo_deliveries.end()) iter->second += amount; + + /* Industry delivery. */ + for (const Industry * const *ip = st->industries_near.Begin(); ip != st->industries_near.End(); ip++) { + CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, (*ip)->index); + CargoMonitorMap::iterator iter = _cargo_deliveries.find(num); + if (iter != _cargo_deliveries.end()) iter->second += amount; + } +} + diff --git a/src/cargomonitor.h b/src/cargomonitor.h new file mode 100644 index 0000000000..1c7123b77b --- /dev/null +++ b/src/cargomonitor.h @@ -0,0 +1,148 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file cargomonitor.h Cargo transport monitoring declarations. */ + +#ifndef CARGOMONITOR_H +#define CARGOMONITOR_H + +#include "cargo_type.h" +#include "company_func.h" +#include "industry.h" +#include "town.h" +#include + +struct Station; + +/** + * Unique number for a company / cargo type / (town or industry). + * Encoding is as follows: + * - bits 0-15 town or industry number + * - bit 16 is set if it is an industry number (else it is a town number). + * - bits 19-23 Cargo type. + * - bits 24-31 %Company number. + */ +typedef uint32 CargoMonitorID; ///< Type of the cargo monitor number. + +/** Map type for storing and updating active cargo monitor numbers and their amounts. */ +typedef std::map CargoMonitorMap; + +extern CargoMonitorMap _cargo_pickups; +extern CargoMonitorMap _cargo_deliveries; + + +/** Constants for encoding and extracting cargo monitors. */ +enum CargoCompanyBits { + CCB_TOWN_IND_NUMBER_START = 0, ///< Start bit of the town or industry number. + CCB_TOWN_IND_NUMBER_LENGTH = 16, ///< Number of bits of the town or industry number. + CCB_IS_INDUSTRY_BIT = 16, ///< Bit indicating the town/industry number is an industry. + CCB_IS_INDUSTRY_BIT_VALUE = 1ul << CCB_IS_INDUSTRY_BIT, ///< Value of the #CCB_IS_INDUSTRY_BIT bit. + CCB_CARGO_TYPE_START = 19, ///< Start bit of the cargo type field. + CCB_CARGO_TYPE_LENGTH = 5, ///< Number of bits of the cargo type field. + CCB_COMPANY_START = 24, ///< Start bit of the company field. + CCB_COMPANY_LENGTH = 8, ///< Number of bits of the company field. +}; + + +/** + * Encode a cargo monitor for pickup or delivery at an industry. + * @param company Company performing the transport. + * @param ctype Cargo type being transported. + * @param ind %Industry providing or accepting the cargo. + * @return The encoded cargo/company/industry number. + */ +static inline CargoMonitorID EncodeCargoIndustryMonitor(CompanyID company, CargoID ctype, IndustryID ind) +{ + assert(ctype < (1 << CCB_CARGO_TYPE_LENGTH)); + + uint32 ret = 0; + SB(ret, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH, ind); + SetBit(ret, CCB_IS_INDUSTRY_BIT); + SB(ret, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH, ctype); + SB(ret, CCB_COMPANY_START, CCB_COMPANY_LENGTH, company); + return ret; +} + +/** + * Encode a cargo monitoring number for pickup or delivery at a town. + * @param company %Company performing the transport. + * @param ctype Cargo type being transported. + * @param town %Town providing or accepting the cargo. + * @return The encoded cargo/company/town number. + */ +static inline CargoMonitorID EncodeCargoTownMonitor(CompanyID company, CargoID ctype, TownID town) +{ + assert(ctype < (1 << CCB_CARGO_TYPE_LENGTH)); + + uint32 ret = 0; + SB(ret, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH, town); + SB(ret, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH, ctype); + SB(ret, CCB_COMPANY_START, CCB_COMPANY_LENGTH, company); + return ret; +} + +/** + * Extract the company from the cargo monitor. + * @param num Cargo monitoring number to decode. + * @return The extracted company id. + */ +static inline CompanyID DecodeMonitorCompany(CargoMonitorID num) +{ + return static_cast(GB(num, CCB_COMPANY_START, CCB_COMPANY_LENGTH)); +} + +/** + * Extract the cargo type from the cargo monitor. + * @param num Cargo monitoring number to decode. + * @return The extracted cargo type. + */ +static inline CargoID DecodeMonitorCargoType(CargoMonitorID num) +{ + return GB(num, CCB_CARGO_TYPE_START, CCB_CARGO_TYPE_LENGTH); +} + +/** + * Does the cargo number monitor an industry or a town? + * @param num Cargo monitoring number to decode. + * @return true if monitoring an industry, false if monitoring a town. + */ +static inline bool MonitorMonitorsIndustry(CargoMonitorID num) +{ + return HasBit(num, CCB_IS_INDUSTRY_BIT); +} + +/** + * Extract the industry number from the cargo monitor. + * @param num Cargo monitoring number to decode. + * @return The extracted industry id, or #INVALID_INDUSTRY if the number does not monitor an industry. + */ +static inline IndustryID DecodeMonitorIndustry(CargoMonitorID num) +{ + if (!MonitorMonitorsIndustry(num)) return INVALID_INDUSTRY; + return GB(num, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH); +} + +/** + * Extract the town number from the cargo monitor. + * @param num Cargo monitoring number to decode. + * @return The extracted town id, or #INVALID_TOWN if the number does not monitor a town. + */ +static inline TownID DecodeMonitorTown(CargoMonitorID num) +{ + if (MonitorMonitorsIndustry(num)) return INVALID_TOWN; + return GB(num, CCB_TOWN_IND_NUMBER_START, CCB_TOWN_IND_NUMBER_LENGTH); +} + +void ClearCargoPickupMonitoring(); +void ClearCargoDeliveryMonitoring(); +uint32 GetDeliveryAmount(CargoMonitorID monitor, bool keep_monitoring); +uint32 GetPickupAmount(CargoMonitorID monitor, bool keep_monitoring); +void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, SourceType src_type, SourceID src, const Station *st); + +#endif /* CARGOMONITOR_H */ diff --git a/src/economy.cpp b/src/economy.cpp index 66972b862e..1e140008af 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -44,6 +44,7 @@ #include "core/backup_type.hpp" #include "water.h" #include "game/game.hpp" +#include "cargomonitor.h" #include "table/strings.h" #include "table/pricebase.h" @@ -1027,6 +1028,9 @@ static Money DeliverGoods(int num_pieces, CargoID cargo_type, StationID dest, Ti /* Determine profit */ Money profit = GetTransportedGoodsIncome(accepted, DistanceManhattan(source_tile, st->xy), days_in_transit, cargo_type); + /* Update the cargo monitor. */ + AddCargoDelivery(cargo_type, company->index, accepted, src_type, src, st); + /* Modify profit if a subsidy is in effect */ if (CheckSubsidised(cargo_type, company->index, src_type, src, st)) { switch (_settings_game.difficulty.subsidy_multiplier) {