* Check whether the train parts can be attached. * @param t the train to check * @return possible error of this command. */
| 1014 | * @return possible error of this command. |
| 1015 | */ |
| 1016 | static CommandCost CheckTrainAttachment(Train *t) |
| 1017 | { |
| 1018 | /* No multi-part train, no need to check. */ |
| 1019 | if (t == nullptr || t->Next() == nullptr) return CommandCost(); |
| 1020 | |
| 1021 | /* The maximum length for a train. For each part we decrease this by one |
| 1022 | * and if the result is negative the train is simply too long. */ |
| 1023 | int allowed_len = _settings_game.vehicle.max_train_length * TILE_SIZE - t->gcache.cached_veh_length; |
| 1024 | |
| 1025 | /* For free-wagon chains, check if they are within the max_train_length limit. */ |
| 1026 | if (!t->IsEngine()) { |
| 1027 | t = t->Next(); |
| 1028 | while (t != nullptr) { |
| 1029 | allowed_len -= t->gcache.cached_veh_length; |
| 1030 | |
| 1031 | t = t->Next(); |
| 1032 | } |
| 1033 | |
| 1034 | if (allowed_len < 0) return CommandCost(STR_ERROR_TRAIN_TOO_LONG); |
| 1035 | return CommandCost(); |
| 1036 | } |
| 1037 | |
| 1038 | Train *head = t; |
| 1039 | Train *prev = t; |
| 1040 | |
| 1041 | /* Break the prev -> t link so it always holds within the loop. */ |
| 1042 | t = t->Next(); |
| 1043 | prev->SetNext(nullptr); |
| 1044 | |
| 1045 | /* Make sure the cache is cleared. */ |
| 1046 | head->InvalidateNewGRFCache(); |
| 1047 | |
| 1048 | while (t != nullptr) { |
| 1049 | allowed_len -= t->gcache.cached_veh_length; |
| 1050 | |
| 1051 | Train *next = t->Next(); |
| 1052 | |
| 1053 | /* Unlink the to-be-added piece; it is already unlinked from the previous |
| 1054 | * part due to the fact that the prev -> t link is broken. */ |
| 1055 | t->SetNext(nullptr); |
| 1056 | |
| 1057 | /* Don't check callback for articulated or rear dual headed parts */ |
| 1058 | if (!t->IsArticulatedPart() && !t->IsRearDualheaded()) { |
| 1059 | /* Back up and clear the first_engine data to avoid using wagon override group */ |
| 1060 | EngineID first_engine = t->gcache.first_engine; |
| 1061 | t->gcache.first_engine = EngineID::Invalid(); |
| 1062 | |
| 1063 | /* We don't want the cache to interfere. head's cache is cleared before |
| 1064 | * the loop and after each callback does not need to be cleared here. */ |
| 1065 | t->InvalidateNewGRFCache(); |
| 1066 | |
| 1067 | std::array<int32_t, 1> regs100; |
| 1068 | uint16_t callback = GetVehicleCallbackParent(CBID_TRAIN_ALLOW_WAGON_ATTACH, 0, 0, head->engine_type, t, head, regs100); |
| 1069 | |
| 1070 | /* Restore original first_engine data */ |
| 1071 | t->gcache.first_engine = first_engine; |
| 1072 | |
| 1073 | /* We do not want to remember any cached variables from the test run */ |
no test coverage detected