public static List <CargoType> GetCargoTypesForCarType(TrainCarType trainCarType) { if (!trainCarTypeToCargoTypes.ContainsKey(trainCarType)) { CargoContainerType containerType = CargoTypes.CarTypeToContainerType[trainCarType]; Dictionary <CargoType, List <CargoContainerType> > cargoTypeToSupportedContainerTypes = Traverse.Create(typeof(CargoTypes)) .Field("cargoTypeToSupportedCarContainer") .GetValue <Dictionary <CargoType, List <CargoContainerType> > >(); trainCarTypeToCargoTypes[trainCarType] = ( from ct in Enum.GetValues(typeof(CargoType)).Cast <CargoType>().ToList <CargoType>() where cargoTypeToSupportedContainerTypes.ContainsKey(ct) && cargoTypeToSupportedContainerTypes[ct].Contains(containerType) select ct ).ToList(); } return(trainCarTypeToCargoTypes[trainCarType]); }
public static JobChainControllerWithEmptyHaulGeneration GenerateShuntingUnloadJobWithCarSpawning( StationController destinationStation, bool forceLicenseReqs, System.Random rng) { Debug.Log("[PersistentJobs] unload: generating with car spawning"); YardTracksOrganizer yto = YardTracksOrganizer.Instance; List <CargoGroup> availableCargoGroups = destinationStation.proceduralJobsRuleset.inputCargoGroups; int countTrainCars = rng.Next( destinationStation.proceduralJobsRuleset.minCarsPerJob, destinationStation.proceduralJobsRuleset.maxCarsPerJob); if (forceLicenseReqs) { Debug.Log("[PersistentJobs] unload: forcing license requirements"); if (!LicenseManager.IsJobLicenseAcquired(JobLicenses.Shunting)) { Debug.LogError("[PersistentJobs] unload: Trying to generate a ShuntingUnload job with " + "forceLicenseReqs=true should never happen if player doesn't have Shunting license!"); return(null); } availableCargoGroups = (from cg in availableCargoGroups where LicenseManager.IsLicensedForJob(cg.CargoRequiredLicenses) select cg).ToList(); countTrainCars = Math.Min(countTrainCars, LicenseManager.GetMaxNumberOfCarsPerJobWithAcquiredJobLicenses()); } if (availableCargoGroups.Count == 0) { Debug.LogWarning("[PersistentJobs] unload: no available cargo groups"); return(null); } CargoGroup chosenCargoGroup = Utilities.GetRandomFromEnumerable(availableCargoGroups, rng); // choose cargo & trainCar types Debug.Log("[PersistentJobs] unload: choosing cargo & trainCar types"); List <CargoType> availableCargoTypes = chosenCargoGroup.cargoTypes; List <CargoType> orderedCargoTypes = new List <CargoType>(); List <TrainCarType> orderedTrainCarTypes = new List <TrainCarType>(); for (int i = 0; i < countTrainCars; i++) { CargoType chosenCargoType = Utilities.GetRandomFromEnumerable(availableCargoTypes, rng); List <CargoContainerType> availableContainers = CargoTypes.GetCarContainerTypesThatSupportCargoType(chosenCargoType); CargoContainerType chosenContainerType = Utilities.GetRandomFromEnumerable(availableContainers, rng); List <TrainCarType> availableTrainCarTypes = CargoTypes.GetTrainCarTypesThatAreSpecificContainerType(chosenContainerType); TrainCarType chosenTrainCarType = Utilities.GetRandomFromEnumerable(availableTrainCarTypes, rng); orderedCargoTypes.Add(chosenCargoType); orderedTrainCarTypes.Add(chosenTrainCarType); } float approxTrainLength = yto.GetTotalCarTypesLength(orderedTrainCarTypes) + yto.GetSeparationLengthBetweenCars(countTrainCars); // choose starting track Debug.Log("[PersistentJobs] unload: choosing starting track"); Track startingTrack = Utilities.GetTrackThatHasEnoughFreeSpace(yto, destinationStation.logicStation.yard.TransferInTracks, approxTrainLength); if (startingTrack == null) { Debug.LogWarning("[PersistentJobs] unload: Couldn't find startingTrack with enough free space for train!"); return(null); } // choose random starting station // no need to ensure it has has free space; this is just a back story Debug.Log("[PersistentJobs] unload: choosing origin (inconsequential)"); List <StationController> availableOrigins = new List <StationController>(chosenCargoGroup.stations); StationController startingStation = Utilities.GetRandomFromEnumerable(availableOrigins, rng); // spawn trainCars Debug.Log("[PersistentJobs] unload: spawning trainCars"); RailTrack railTrack = SingletonBehaviour <LogicController> .Instance.LogicToRailTrack[startingTrack]; List <TrainCar> orderedTrainCars = CarSpawner.SpawnCarTypesOnTrack( orderedTrainCarTypes, railTrack, true, 0.0, false, true); if (orderedTrainCars == null) { Debug.LogWarning("[PersistentJobs] unload: Failed to spawn trainCars!"); return(null); } JobChainControllerWithEmptyHaulGeneration jcc = GenerateShuntingUnloadJobWithExistingCars( startingStation, startingTrack, destinationStation, orderedTrainCars, orderedCargoTypes, rng, true); if (jcc == null) { Debug.LogWarning("[PersistentJobs] unload: Couldn't generate job chain. Deleting spawned trainCars!"); SingletonBehaviour <CarSpawner> .Instance.DeleteTrainCars(orderedTrainCars, true); return(null); } return(jcc); }
public static JobChainControllerWithEmptyHaulGeneration GenerateShuntingLoadJobWithCarSpawning( StationController startingStation, bool forceLicenseReqs, System.Random rng) { Debug.Log("[PersistentJobs] load: generating with car spawning"); YardTracksOrganizer yto = YardTracksOrganizer.Instance; List <CargoGroup> availableCargoGroups = startingStation.proceduralJobsRuleset.outputCargoGroups; int countTrainCars = rng.Next( startingStation.proceduralJobsRuleset.minCarsPerJob, startingStation.proceduralJobsRuleset.maxCarsPerJob); if (forceLicenseReqs) { Debug.Log("[PersistentJobs] load: forcing license requirements"); if (!LicenseManager.IsJobLicenseAcquired(JobLicenses.Shunting)) { Debug.LogError("Trying to generate a ShuntingLoad job with forceLicenseReqs=true should " + "never happen if player doesn't have Shunting license!"); return(null); } availableCargoGroups = (from cg in availableCargoGroups where LicenseManager.IsLicensedForJob(cg.CargoRequiredLicenses) select cg).ToList(); countTrainCars = Math.Min(countTrainCars, LicenseManager.GetMaxNumberOfCarsPerJobWithAcquiredJobLicenses()); } if (availableCargoGroups.Count == 0) { Debug.LogWarning("[PersistentJobs] load: no available cargo groups"); return(null); } CargoGroup chosenCargoGroup = Utilities.GetRandomFromEnumerable(availableCargoGroups, rng); // choose cargo & trainCar types Debug.Log("[PersistentJobs] load: choosing cargo & trainCar types"); List <CargoType> availableCargoTypes = chosenCargoGroup.cargoTypes; List <CargoType> orderedCargoTypes = new List <CargoType>(); List <TrainCarType> orderedTrainCarTypes = new List <TrainCarType>(); for (int i = 0; i < countTrainCars; i++) { CargoType chosenCargoType = Utilities.GetRandomFromEnumerable(availableCargoTypes, rng); List <CargoContainerType> availableContainers = CargoTypes.GetCarContainerTypesThatSupportCargoType(chosenCargoType); CargoContainerType chosenContainerType = Utilities.GetRandomFromEnumerable(availableContainers, rng); List <TrainCarType> availableTrainCarTypes = CargoTypes.GetTrainCarTypesThatAreSpecificContainerType(chosenContainerType); TrainCarType chosenTrainCarType = Utilities.GetRandomFromEnumerable(availableTrainCarTypes, rng); orderedCargoTypes.Add(chosenCargoType); orderedTrainCarTypes.Add(chosenTrainCarType); } // choose starting tracks int maxCountTracks = startingStation.proceduralJobsRuleset.maxShuntingStorageTracks; int countTracks = rng.Next(1, maxCountTracks + 1); // bias toward less than max number of tracks for shorter trains if (orderedTrainCarTypes.Count < 2 * maxCountTracks) { countTracks = rng.Next(0, Mathf.FloorToInt(1.5f * maxCountTracks)) % maxCountTracks + 1; } Debug.Log(string.Format("[PersistentJobs] load: choosing {0} starting tracks", countTracks)); int countCarsPerTrainset = countTrainCars / countTracks; int countTrainsetsWithExtraCar = countTrainCars % countTracks; List <Track> tracks = new List <Track>(); do { tracks.Clear(); for (int i = 0; i < countTracks; i++) { int rangeStart = i * countCarsPerTrainset + Math.Min(i, countTrainsetsWithExtraCar); int rangeCount = i < countTrainsetsWithExtraCar ? countCarsPerTrainset + 1 : countCarsPerTrainset; List <TrainCarType> trainCarTypesPerTrack = orderedTrainCarTypes.GetRange(rangeStart, rangeCount); float approxTrainLengthPerTrack = yto.GetTotalCarTypesLength(trainCarTypesPerTrack) + yto.GetSeparationLengthBetweenCars(trainCarTypesPerTrack.Count); Track track = Utilities.GetTrackThatHasEnoughFreeSpace( yto, startingStation.logicStation.yard.StorageTracks.Except(tracks).ToList(), approxTrainLengthPerTrack / (float)countTracks); if (track == null) { break; } tracks.Add(track); } } while (tracks.Count < countTracks--); if (tracks.Count == 0) { Debug.LogWarning("[PersistentJobs] load: Couldn't find startingTrack with enough free space for train!"); return(null); } // choose random destination station that has at least 1 available track Debug.Log("[PersistentJobs] load: choosing destination"); float approxTrainLength = yto.GetTotalCarTypesLength(orderedTrainCarTypes) + yto.GetSeparationLengthBetweenCars(countTrainCars); List <StationController> availableDestinations = new List <StationController>(chosenCargoGroup.stations); StationController destStation = null; Track destinationTrack = null; while (availableDestinations.Count > 0 && destinationTrack == null) { destStation = Utilities.GetRandomFromEnumerable(availableDestinations, rng); availableDestinations.Remove(destStation); destinationTrack = Utilities.GetTrackThatHasEnoughFreeSpace( yto, yto.FilterOutOccupiedTracks(destStation.logicStation.yard.TransferInTracks), approxTrainLength); } if (destinationTrack == null) { Debug.LogWarning("Couldn't find a station with enough free space for train!"); return(null); } // spawn trainCars & form carsPerStartingTrack Debug.Log("[PersistentJobs] load: spawning trainCars"); List <TrainCar> orderedTrainCars = new List <TrainCar>(); List <CarsPerTrack> carsPerStartingTrack = new List <CarsPerTrack>(); for (int i = 0; i < tracks.Count; i++) { int rangeStart = i * countCarsPerTrainset + Math.Min(i, countTrainsetsWithExtraCar); int rangeCount = i < countTrainsetsWithExtraCar ? countCarsPerTrainset + 1 : countCarsPerTrainset; Debug.Log(string.Format( "[PersistentJobs] load: spawning cars in range [{0}-{1}) from total range [0-{2})", rangeStart, rangeStart + rangeCount, orderedTrainCarTypes.Count)); Track startingTrack = tracks[i]; RailTrack railTrack = SingletonBehaviour <LogicController> .Instance.LogicToRailTrack[startingTrack]; List <TrainCar> spawnedCars = CarSpawner.SpawnCarTypesOnTrack( orderedTrainCarTypes.GetRange(rangeStart, rangeCount), railTrack, true, 0.0, false, true); if (spawnedCars == null) { Debug.LogWarning("[PersistentJobs] load: Failed to spawn some trainCars!"); SingletonBehaviour <CarSpawner> .Instance.DeleteTrainCars(orderedTrainCars, true); return(null); } orderedTrainCars.AddRange(spawnedCars); carsPerStartingTrack.Add( new CarsPerTrack(startingTrack, (from car in spawnedCars select car.logicCar).ToList())); } JobChainControllerWithEmptyHaulGeneration jcc = GenerateShuntingLoadJobWithExistingCars( startingStation, carsPerStartingTrack, destStation, orderedTrainCars, orderedCargoTypes, rng, true); if (jcc == null) { Debug.LogWarning("[PersistentJobs] load: Couldn't generate job chain. Deleting spawned trainCars!"); SingletonBehaviour <CarSpawner> .Instance.DeleteTrainCars(orderedTrainCars, true); return(null); } return(jcc); }