MCPcopy Create free account
hub / github.com/OpenTTD/OpenTTD / CheckTrainAttachment

Function CheckTrainAttachment

src/train_cmd.cpp:1016–1118  ·  view source on GitHub ↗

* Check whether the train parts can be attached. * @param t the train to check * @return possible error of this command. */

Source from the content-addressed store, hash-verified

1014 * @return possible error of this command.
1015 */
1016static 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 */

Callers 1

ValidateTrainsFunction · 0.85

Calls 13

CommandCostClass · 0.85
InvalidFunction · 0.85
GetVehicleCallbackParentFunction · 0.85
GetGRFStringIDFunction · 0.85
IsEngineMethod · 0.80
SetNextMethod · 0.80
InvalidateNewGRFCacheMethod · 0.80
IsArticulatedPartMethod · 0.80
IsRearDualheadedMethod · 0.80
NextMethod · 0.45
GetGRFMethod · 0.45

Tested by

no test coverage detected