/** * Merges the refit_masks of all articulated parts. * @param engine the first part * @param include_initial_cargo_type if true the default cargo type of the vehicle is included; if false only the refit_mask * @param union_mask returns bit mask of CargoIDs which are a refit option for at least one articulated part * @param intersection_mask returns bit mask of CargoIDs which are a refit option for every articulated part (with default capacity > 0) */ void GetArticulatedRefitMasks(EngineID engine, bool include_initial_cargo_type, uint32 *union_mask, uint32 *intersection_mask) { const Engine *e = Engine::Get(engine); uint32 veh_cargoes = GetAvailableVehicleCargoTypes(engine, include_initial_cargo_type); *union_mask = veh_cargoes; *intersection_mask = (veh_cargoes != 0) ? veh_cargoes : UINT32_MAX; if (!e->IsGroundVehicle()) return; if (!HasBit(e->info.callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return; for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) { EngineID artic_engine = GetNextArticulatedPart(i, engine); if (artic_engine == INVALID_ENGINE) break; veh_cargoes = GetAvailableVehicleCargoTypes(artic_engine, include_initial_cargo_type); *union_mask |= veh_cargoes; if (veh_cargoes != 0) *intersection_mask &= veh_cargoes; } }
/** * Checks whether the specs of freshly build articulated vehicles are consistent with the information specified in the purchase list. * Only essential information is checked to leave room for magic tricks/workarounds to grfcoders. * It checks: * For autoreplace/-renew: * - Default cargo type (without capacity) * - intersection and union of refit masks. */ void CheckConsistencyOfArticulatedVehicle(const Vehicle *v) { const Engine *engine = Engine::Get(v->engine_type); uint32 purchase_refit_union, purchase_refit_intersection; GetArticulatedRefitMasks(v->engine_type, true, &purchase_refit_union, &purchase_refit_intersection); CargoArray purchase_default_capacity = GetCapacityOfArticulatedParts(v->engine_type); uint32 real_refit_union = 0; uint32 real_refit_intersection = UINT_MAX; CargoArray real_default_capacity; do { uint32 refit_mask = GetAvailableVehicleCargoTypes(v->engine_type, true); real_refit_union |= refit_mask; if (refit_mask != 0) real_refit_intersection &= refit_mask; assert(v->cargo_type < NUM_CARGO); real_default_capacity[v->cargo_type] += v->cargo_cap; switch (v->type) { case VEH_TRAIN: v = Train::From(v)->HasArticulatedPart() ? Train::From(v)->GetNextArticPart() : NULL; break; case VEH_ROAD: v = RoadVehicle::From(v)->HasArticulatedPart() ? v->Next() : NULL; break; default: v = NULL; break; } } while (v != NULL); /* Check whether the vehicle carries more cargos than expected */ bool carries_more = false; for (CargoID cid = 0; cid < NUM_CARGO; cid++) { if (real_default_capacity[cid] != 0 && purchase_default_capacity[cid] == 0) { carries_more = true; break; } } /* show a warning once for each GRF after each game load */ if (real_refit_union != purchase_refit_union || real_refit_intersection != purchase_refit_intersection || carries_more) { ShowNewGrfVehicleError(engine->index, STR_NEWGRF_BUGGY, STR_NEWGRF_BUGGY_ARTICULATED_CARGO, GBUG_VEH_REFIT, false); } }