summaryrefslogtreecommitdiff
path: root/src/cargomonitor.cpp
blob: 40a029ac5337f1c0128b5827be5f43ae1e1768e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/* $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 <http://www.gnu.org/licenses/>.
 */

/** @file cargomonitor.cpp Implementation of the cargo transport monitoring. */

#include "stdafx.h"
#include "cargomonitor.h"
#include "station_base.h"

#include "safeguards.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.

/**
 * Helper method for #ClearCargoPickupMonitoring and #ClearCargoDeliveryMonitoring.
 * Clears all monitors that belong to the specified company or all if #INVALID_OWNER
 * is specified as company.
 * @param cargo_monitor_map reference to the cargo monitor map to operate on.
 * @param company company to clear cargo monitors for or #INVALID_OWNER if all cargo monitors should be cleared.
 */
static void ClearCargoMonitoring(CargoMonitorMap &cargo_monitor_map, CompanyID company = INVALID_OWNER)
{
	if (company == INVALID_OWNER) {
		cargo_monitor_map.clear();
		return;
	}

	CargoMonitorMap::iterator next;
	for (CargoMonitorMap::iterator it = cargo_monitor_map.begin(); it != cargo_monitor_map.end(); it = next) {
		next = it;
		next++;
		if (DecodeMonitorCompany(it->first) == company) {
			cargo_monitor_map.erase(it);
		}
	}
}

/**
 * Clear all pick-up cargo monitors.
 * @param company clear all pick-up monitors for this company or if #INVALID_OWNER
 * is passed, all pick-up monitors are cleared regardless of company.
 */
void ClearCargoPickupMonitoring(CompanyID company)
{
	ClearCargoMonitoring(_cargo_pickups, company);
}

/**
 * Clear all delivery cargo monitors.
 * @param company clear all delivery monitors for this company or if #INVALID_OWNER
 * is passed, all delivery monitors are cleared regardless of company.
 */
void ClearCargoDeliveryMonitoring(CompanyID company)
{
	ClearCargoMonitoring(_cargo_deliveries, company);
}

/**
 * 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).
 * @param 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 int32 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<CargoMonitorID, uint32> p(monitor, 0);
			monitor_map.insert(p);
		}
		return 0;
	} else {
		int32 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.
 */
int32 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.
 */
int32 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.
 * @param dest industry index where the cargo is delivered to.
 */
void AddCargoDelivery(CargoID cargo_type, CompanyID company, uint32 amount, SourceType src_type, SourceID src, const Station *st, IndustryID dest)
{
	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++) {
		if ((*ip)->index != dest) continue;
		CargoMonitorID num = EncodeCargoIndustryMonitor(company, cargo_type, (*ip)->index);
		CargoMonitorMap::iterator iter = _cargo_deliveries.find(num);
		if (iter != _cargo_deliveries.end()) iter->second += amount;
	}
}