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 = ▭ |
|
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 |