/// <summary> /// Generates all the ContractParameter objects required for the array of ConfigNodes, and /// adds them to the host object. /// </summary> /// <param name="contract">Contract to generate for</param> /// <param name="contractParamHost">The object to use as a parent for ContractParameters</param> /// <param name="paramFactories">The ParameterFactory objects to use to generate parameters.</param> /// <returns>Whether the generation was successful.</returns> public static bool GenerateParameters(ConfiguredContract contract, IContractParameterHost contractParamHost, List <ParameterFactory> paramFactories) { foreach (ParameterFactory paramFactory in paramFactories) { if (paramFactory.enabled) { // Set up the iterator int count = 1; int current = 0; if (paramFactory.iteratorType != null) { count = (int)paramFactory.dataNode["iteratorCount"]; } // Loop through the iterator, or do a single parameter for non-iterated parameters while (current++ < count) { // Refresh the deterministic values int oldValue = DataNode.IteratorCurrentIndex; if (paramFactory.iteratorType != null) { DataNode.IteratorCurrentIndex = current - 1; ConfigNodeUtil.UpdateNonDeterministicValues(paramFactory.dataNode, paramFactory.dataNode); } ContractParameter parameter = paramFactory.Generate(contract, contractParamHost); // Get the child parameters if (parameter != null) { if (!GenerateParameters(contract, parameter, paramFactory.childNodes)) { return(false); } } ContractConfiguratorParameter ccParam = parameter as ContractConfiguratorParameter; if (ccParam != null && ccParam.hideChildren) { foreach (ContractParameter child in ccParam.GetChildren()) { ContractConfiguratorParameter ccChild = child as ContractConfiguratorParameter; if (ccChild != null) { ccChild.Hide(); } } } // Restore the old value for the iterator list (for recursive iterations) DataNode.IteratorCurrentIndex = oldValue; } } } return(true); }
private bool SelectContractType() { if (!lastSpecificGenerationFailure.ContainsKey(prestige)) { lastSpecificGenerationFailure[prestige] = 0; } LoggingUtil.LogVerbose(this, "Generating a contract for prestige = " + prestige); // Loop through all the contract groups IEnumerable <ContractGroup> groups = ContractGroup.AllGroups; foreach (ContractGroup group in groups.Skip(nextGroup).Concat(groups.Take(nextGroup))) { LoggingUtil.LogVerbose(this, "Looking at group " + group); nextGroup = (nextGroup + 1) % groups.Count(); // Build a weighted list of ContractTypes to choose from Dictionary <ContractType, double> validContractTypes = new Dictionary <ContractType, double>(); double totalWeight = 0.0; foreach (ContractType ct in ContractType.AllValidContractTypes.Where(ct => ct.group == group)) { LoggingUtil.LogVerbose(this, "Checking ContractType = " + ct.name); // KSP tries to generate new contracts *incessantly*, to the point where this becomes // a real performance problem. So if we run into a situation where we did not // generate a contract and we are asked AGAIN after a very short time, then do // some logic to prevent re-checking uselessly. // If there was any generation failure within the last 100 frames, only look at // contracts specific to that prestige level if (lastGenerationFailure + 100 > Time.frameCount) { // If there was a generation failure for this specific prestige level in // the last 100 frames, then just skip the checks entirely if (lastSpecificGenerationFailure[prestige] + 100 > Time.frameCount) { return(false); } } // Only select contracts with the correct prestige level if (ct.prestige.Count == 0 || ct.prestige.Contains(prestige)) { validContractTypes.Add(ct, ct.weight); totalWeight += ct.weight; } } // Loop until we either run out of contracts in our list or make a selection System.Random generator = new System.Random(this.MissionSeed); while (validContractTypes.Count > 0) { ContractType selectedContractType = null; // Pick one of the contract types based on their weight double value = generator.NextDouble() * totalWeight; foreach (KeyValuePair <ContractType, double> pair in validContractTypes) { value -= pair.Value; if (value <= 0.0) { selectedContractType = pair.Key; break; } } // Shouldn't happen, but floating point rounding could put us here if (selectedContractType == null) { selectedContractType = validContractTypes.First().Key; } // Try to refresh non-deterministic values before we check requirements currentContract = this; LoggingUtil.LogVerbose(this, "Refresh non-deterministic values for CONTRACT_TYPE = " + selectedContractType.name); if (!ConfigNodeUtil.UpdateNonDeterministicValues(selectedContractType.dataNode)) { LoggingUtil.LogVerbose(this, selectedContractType.name + " was not generated: non-deterministic expression failure."); validContractTypes.Remove(selectedContractType); totalWeight -= selectedContractType.weight; } currentContract = null; // Check the requirements for our selection if (selectedContractType.MeetRequirements(this)) { contractType = selectedContractType; subType = contractType.name; return(true); } // Remove the selection, and try again else { LoggingUtil.LogVerbose(this, selectedContractType.name + " was not generated: requirement not met."); validContractTypes.Remove(selectedContractType); totalWeight -= selectedContractType.weight; } } } // Set our failure markers lastGenerationFailure = Time.frameCount; lastSpecificGenerationFailure[prestige] = Time.frameCount; return(false); }