* Get the best fitting subtype when 'cloning'/'replacing' \a v_from with \a v_for. * All articulated parts of both vehicles are tested to find a possibly shared subtype. * For \a v_for only vehicle refittable to \a dest_cargo_type are considered. * @param v_from the vehicle to match the subtype from * @param v_for the vehicle to get the subtype for * @param dest_cargo_type Destination cargo
| 598 | * @return the best sub type |
| 599 | */ |
| 600 | uint8_t GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoType dest_cargo_type) |
| 601 | { |
| 602 | v_from = v_from->GetFirstEnginePart(); |
| 603 | v_for = v_for->GetFirstEnginePart(); |
| 604 | |
| 605 | /* Create a list of subtypes used by the various parts of v_for */ |
| 606 | static std::vector<StringID> subtypes; |
| 607 | subtypes.clear(); |
| 608 | for (; v_from != nullptr; v_from = v_from->HasArticulatedPart() ? v_from->GetNextArticulatedPart() : nullptr) { |
| 609 | const Engine *e_from = v_from->GetEngine(); |
| 610 | if (!e_from->CanCarryCargo() || !e_from->info.callback_mask.Test(VehicleCallbackMask::CargoSuffix)) continue; |
| 611 | include(subtypes, GetCargoSubtypeText(v_from)); |
| 612 | } |
| 613 | |
| 614 | uint8_t ret_refit_cyc = 0; |
| 615 | bool success = false; |
| 616 | if (!subtypes.empty()) { |
| 617 | /* Check whether any articulated part is refittable to 'dest_cargo_type' with a subtype listed in 'subtypes' */ |
| 618 | for (Vehicle *v = v_for; v != nullptr; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : nullptr) { |
| 619 | const Engine *e = v->GetEngine(); |
| 620 | if (!e->CanCarryCargo() || !e->info.callback_mask.Test(VehicleCallbackMask::CargoSuffix)) continue; |
| 621 | if (!HasBit(e->info.refit_mask, dest_cargo_type) && v->cargo_type != dest_cargo_type) continue; |
| 622 | |
| 623 | CargoType old_cargo_type = v->cargo_type; |
| 624 | uint8_t old_cargo_subtype = v->cargo_subtype; |
| 625 | |
| 626 | /* Set the 'destination' cargo */ |
| 627 | v->cargo_type = dest_cargo_type; |
| 628 | |
| 629 | /* Cycle through the refits */ |
| 630 | for (uint refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) { |
| 631 | v->cargo_subtype = refit_cyc; |
| 632 | |
| 633 | /* Make sure we don't pick up anything cached. */ |
| 634 | v->First()->InvalidateNewGRFCache(); |
| 635 | v->InvalidateNewGRFCache(); |
| 636 | |
| 637 | StringID subtype = GetCargoSubtypeText(v); |
| 638 | if (subtype == STR_EMPTY) break; |
| 639 | |
| 640 | if (std::ranges::find(subtypes, subtype) == subtypes.end()) continue; |
| 641 | |
| 642 | /* We found something matching. */ |
| 643 | ret_refit_cyc = refit_cyc; |
| 644 | success = true; |
| 645 | break; |
| 646 | } |
| 647 | |
| 648 | /* Reset the vehicle's cargo type */ |
| 649 | v->cargo_type = old_cargo_type; |
| 650 | v->cargo_subtype = old_cargo_subtype; |
| 651 | |
| 652 | /* Make sure we don't taint the vehicle. */ |
| 653 | v->First()->InvalidateNewGRFCache(); |
| 654 | v->InvalidateNewGRFCache(); |
| 655 | |
| 656 | if (success) break; |
| 657 | } |
no test coverage detected