src/economy.cpp
changeset 10291 2c8bf5a13a1b
parent 10236 50afe9dd466e
child 10297 e17a18bb827f
equal deleted inserted replaced
10290:56925f09d693 10291:2c8bf5a13a1b
     9 #include "company_base.h"
     9 #include "company_base.h"
    10 #include "company_func.h"
    10 #include "company_func.h"
    11 #include "command_func.h"
    11 #include "command_func.h"
    12 #include "saveload.h"
    12 #include "saveload.h"
    13 #include "industry.h"
    13 #include "industry.h"
       
    14 #include "industry_map.h"
    14 #include "town.h"
    15 #include "town.h"
    15 #include "news_func.h"
    16 #include "news_func.h"
    16 #include "network/network.h"
    17 #include "network/network.h"
    17 #include "network/network_func.h"
    18 #include "network/network_func.h"
    18 #include "variables.h"
    19 #include "variables.h"
  1236 	if (time_factor < MIN_TIME_FACTOR) time_factor = MIN_TIME_FACTOR;
  1237 	if (time_factor < MIN_TIME_FACTOR) time_factor = MIN_TIME_FACTOR;
  1237 
  1238 
  1238 	return BigMulS(dist * time_factor * num_pieces, _cargo_payment_rates[cargo_type], 21);
  1239 	return BigMulS(dist * time_factor * num_pieces, _cargo_payment_rates[cargo_type], 21);
  1239 }
  1240 }
  1240 
  1241 
  1241 static void DeliverGoodsToIndustry(TileIndex xy, CargoID cargo_type, int num_pieces)
  1242 
  1242 {
  1243 struct FindIndustryToDeliverData {
  1243 	Industry *best = NULL;
  1244 	const Rect *rect;            ///< Station acceptance rectangle
  1244 	Industry *ind;
  1245 	CargoID cargo_type;          ///< Cargo type that was delivered
  1245 	const IndustrySpec *indspec;
  1246 
  1246 	uint best_dist;
  1247 	Industry *ind;               ///< Returns found industry
  1247 	uint accepted_cargo_index = 0;  ///< unlikely value, just for warning removing
  1248 	const IndustrySpec *indspec; ///< Spec of ind
  1248 
  1249 	uint cargo_index;            ///< Index of cargo_type in acceptance list of ind
  1249 	/* Check if there's an industry close to the station that accepts the cargo
  1250 };
  1250 	 * XXX - Think of something better to
  1251 
  1251 	 *       1) Only deliver to industries which are withing the catchment radius
  1252 static bool FindIndustryToDeliver(TileIndex ind_tile, void *user_data)
  1252 	 *       2) Distribute between industries if more than one is present */
  1253 {
  1253 	best_dist = (_settings_game.station.station_spread + 8) * 2;
  1254 	FindIndustryToDeliverData *callback_data = (FindIndustryToDeliverData *)user_data;
  1254 	FOR_ALL_INDUSTRIES(ind) {
  1255 	const Rect *rect = callback_data->rect;
  1255 		indspec = GetIndustrySpec(ind->type);
  1256 	CargoID cargo_type = callback_data->cargo_type;
  1256 		uint i;
  1257 
  1257 
  1258 	/* Only process industry tiles */
  1258 		for (i = 0; i < lengthof(ind->accepts_cargo); i++) {
  1259 	if (!IsTileType(ind_tile, MP_INDUSTRY)) return false;
  1259 			if (cargo_type == ind->accepts_cargo[i]) break;
  1260 
  1260 		}
  1261 	/* Only process tiles in the station acceptance rectangle */
  1261 
  1262 	int x = TileX(ind_tile);
  1262 		/* Check if matching cargo has been found */
  1263 	int y = TileY(ind_tile);
  1263 		if (i == lengthof(ind->accepts_cargo)) continue;
  1264 	if (x < rect->left || x > rect->right || y < rect->top || y > rect->bottom) return false;
  1264 
  1265 
  1265 		if (HasBit(indspec->callback_flags, CBM_IND_REFUSE_CARGO)) {
  1266 	Industry *ind = GetIndustryByTile(ind_tile);
  1266 			uint16 res = GetIndustryCallback(CBID_INDUSTRY_REFUSE_CARGO, 0, GetReverseCargoTranslation(cargo_type, indspec->grf_prop.grffile), ind, ind->type, ind->xy);
  1267 	const IndustrySpec *indspec = GetIndustrySpec(ind->type);
  1267 			if (res == 0) continue;
  1268 
  1268 		}
  1269 	uint cargo_index;
  1269 
  1270 	for (cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) {
  1270 		uint dist = DistanceManhattan(ind->xy, xy);
  1271 		if (cargo_type == ind->accepts_cargo[cargo_index]) break;
  1271 
  1272 	}
  1272 		if (dist < best_dist) {
  1273 	/* Check if matching cargo has been found */
  1273 			best = ind;
  1274 	if (cargo_index >= lengthof(ind->accepts_cargo)) return false;
  1274 			best_dist = dist;
  1275 
  1275 			accepted_cargo_index = i;
  1276 	/* Check if industry temporarly refuses acceptance */
  1276 		}
  1277 	if (HasBit(indspec->callback_flags, CBM_IND_REFUSE_CARGO)) {
  1277 	}
  1278 		uint16 res = GetIndustryCallback(CBID_INDUSTRY_REFUSE_CARGO, 0, GetReverseCargoTranslation(cargo_type, indspec->grf_prop.grffile), ind, ind->type, ind->xy);
  1278 
  1279 		if (res == 0) return false;
  1279 	/* Found one? */
  1280 	}
  1280 	if (best != NULL) {
  1281 
  1281 		indspec = GetIndustrySpec(best->type);
  1282 	/* Found industry accepting the cargo */
       
  1283 	callback_data->ind = ind;
       
  1284 	callback_data->indspec = indspec;
       
  1285 	callback_data->cargo_index = cargo_index;
       
  1286 	return true;
       
  1287 }
       
  1288 
       
  1289 /**
       
  1290  * Transfer goods from station to industry.
       
  1291  * All cargo is delivered to the nearest (Manhattan) industry to the station sign, which is inside the acceptance rectangle and actually accepts the cargo.
       
  1292  * @param st The station that accepted the cargo
       
  1293  * @param cargo_type Type of cargo delivered
       
  1294  * @param nun_pieces Amount of cargo delivered
       
  1295  */
       
  1296 static void DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, int num_pieces)
       
  1297 {
       
  1298 	if (st->rect.IsEmpty()) return;
       
  1299 
       
  1300 	/* Compute acceptance rectangle */
       
  1301 	uint catchment_radius = st->GetCatchmentRadius();
       
  1302 	Rect rect = {
       
  1303 		max(st->rect.left   - catchment_radius, 0u),
       
  1304 		max(st->rect.top    - catchment_radius, 0u),
       
  1305 		min(st->rect.right  + catchment_radius, MapMaxX()),
       
  1306 		min(st->rect.bottom + catchment_radius, MapMaxY())
       
  1307 	};
       
  1308 
       
  1309 	/* Compute maximum extent of acceptance rectangle wrt. station sign */
       
  1310 	TileIndex start_tile = st->xy;
       
  1311 	uint max_radius = max(
       
  1312 		max(DistanceManhattan(start_tile, TileXY(rect.left , rect.top)), DistanceManhattan(start_tile, TileXY(rect.left , rect.bottom))),
       
  1313 		max(DistanceManhattan(start_tile, TileXY(rect.right, rect.top)), DistanceManhattan(start_tile, TileXY(rect.right, rect.bottom)))
       
  1314 	);
       
  1315 
       
  1316 	FindIndustryToDeliverData callback_data;
       
  1317 	callback_data.rect = &rect;
       
  1318 	callback_data.cargo_type = cargo_type;
       
  1319 	callback_data.ind = NULL;
       
  1320 	callback_data.indspec = NULL;
       
  1321 	callback_data.cargo_index = 0;
       
  1322 
       
  1323 	/* Find the nearest industrytile to the station sign inside the catchment area, whose industry accepts the cargo.
       
  1324 	 * This fails in three cases:
       
  1325 	 *  1) The station accepts the cargo because there are enough houses around it accepting the cargo.
       
  1326 	 *  2) The industries in the catchment area temporarily reject the cargo, and the daily station loop has not yet updated station acceptance.
       
  1327 	 *  3) The results of callbacks CBID_INDUSTRY_REFUSE_CARGO and CBID_INDTILE_CARGO_ACCEPTANCE are inconsistent. (documented behaviour)
       
  1328 	 */
       
  1329 	if (CircularTileSearch(&start_tile, 2 * max_radius + 1, FindIndustryToDeliver, &callback_data)) {
       
  1330 		Industry *best = callback_data.ind;
       
  1331 		const IndustrySpec *indspec = callback_data.indspec;
       
  1332 		uint accepted_cargo_index = callback_data.cargo_index;
       
  1333 		assert(best != NULL && indspec != NULL);
  1282 		uint16 callback = indspec->callback_flags;
  1334 		uint16 callback = indspec->callback_flags;
  1283 
  1335 
  1284 		best->was_cargo_delivered = true;
  1336 		best->was_cargo_delivered = true;
  1285 		best->last_cargo_accepted_at = _date;
  1337 		best->last_cargo_accepted_at = _date;
  1286 
  1338 
  1393 	const CargoSpec *cs = GetCargo(cargo_type);
  1445 	const CargoSpec *cs = GetCargo(cargo_type);
  1394 	if (cs->town_effect == TE_FOOD) s_to->town->new_act_food += num_pieces;
  1446 	if (cs->town_effect == TE_FOOD) s_to->town->new_act_food += num_pieces;
  1395 	if (cs->town_effect == TE_WATER) s_to->town->new_act_water += num_pieces;
  1447 	if (cs->town_effect == TE_WATER) s_to->town->new_act_water += num_pieces;
  1396 
  1448 
  1397 	/* Give the goods to the industry. */
  1449 	/* Give the goods to the industry. */
  1398 	DeliverGoodsToIndustry(s_to->xy, cargo_type, num_pieces);
  1450 	DeliverGoodsToIndustry(s_to, cargo_type, num_pieces);
  1399 
  1451 
  1400 	/* Determine profit */
  1452 	/* Determine profit */
  1401 	profit = GetTransportedGoodsIncome(num_pieces, DistanceManhattan(source_tile, s_to->xy), days_in_transit, cargo_type);
  1453 	profit = GetTransportedGoodsIncome(num_pieces, DistanceManhattan(source_tile, s_to->xy), days_in_transit, cargo_type);
  1402 
  1454 
  1403 	/* Modify profit if a subsidy is in effect */
  1455 	/* Modify profit if a subsidy is in effect */