Line data Source code
1 : function RequirementsHelper() {} 2 : 3 3 : RequirementsHelper.prototype.DEFAULT_RECURSION_DEPTH = 1; 4 : 5 3 : RequirementsHelper.prototype.EntityRequirementsSchema = 6 : "<element name='Entities' a:help='Entities that need to be controlled.'>" + 7 : "<oneOrMore>" + 8 : "<element a:help='Class of entity that needs to be controlled.'>" + 9 : "<anyName/>" + 10 : "<oneOrMore>" + 11 : "<choice>" + 12 : "<element name='Count' a:help='Number of entities required.'>" + 13 : "<data type='nonNegativeInteger'/>" + 14 : "</element>" + 15 : "<element name='Variants' a:help='Number of different entities of this class required.'>" + 16 : "<data type='nonNegativeInteger'/>" + 17 : "</element>" + 18 : "</choice>" + 19 : "</oneOrMore>" + 20 : "</element>" + 21 : "</oneOrMore>" + 22 : "</element>"; 23 : 24 3 : RequirementsHelper.prototype.TechnologyRequirementsSchema = 25 : "<element name='Techs' a:help='White-space separated list of technologies that need to be researched. ! negates a tech.'>" + 26 : "<attribute name='datatype'>" + 27 : "<value>tokens</value>" + 28 : "</attribute>" + 29 : "<text/>" + 30 : "</element>"; 31 : 32 : /** 33 : * @param {number} recursionDepth - How deep we recurse. 34 : * @return {string} - A RelaxRNG schema for requirements. 35 : */ 36 3 : RequirementsHelper.prototype.RequirementsSchema = function(recursionDepth) 37 : { 38 4 : return "" + 39 : "<oneOrMore>" + 40 : this.ChoicesSchema(--recursionDepth) + 41 : "</oneOrMore>"; 42 : }; 43 : 44 : /** 45 : * @param {number} recursionDepth - How deep we recurse. 46 : * @return {string} - A RelaxRNG schema for chosing requirements. 47 : */ 48 3 : RequirementsHelper.prototype.ChoicesSchema = function(recursionDepth) 49 : { 50 6 : const allAnySchema = recursionDepth > 0 ? "" + 51 : "<element name='All' a:help='Requires all of the conditions to be met.'>" + 52 : this.RequirementsSchema(recursionDepth) + 53 : "</element>" + 54 : "<element name='Any' a:help='Requires at least one of the following conditions met.'>" + 55 : this.RequirementsSchema(recursionDepth) + 56 : "</element>" : ""; 57 : 58 6 : return "" + 59 : "<choice>" + 60 : allAnySchema + 61 : this.EntityRequirementsSchema + 62 : this.TechnologyRequirementsSchema + 63 : "</choice>"; 64 : }; 65 : 66 : /** 67 : * @param {number} recursionDepth - How deeply recursive we build the schema. 68 : * @return {string} - A RelaxRNG schema for requirements. 69 : */ 70 3 : RequirementsHelper.prototype.BuildSchema = function(recursionDepth = this.DEFAULT_RECURSION_DEPTH) 71 : { 72 2 : return "" + 73 : "<element name='Requirements' a:help='The requirements that ought to be met before this entity can be produced.'>" + 74 : "<optional>" + 75 : this.ChoicesSchema(recursionDepth) + 76 : "</optional>" + 77 : "<optional>" + 78 : "<element name='Tooltip' a:help='A tooltip explaining the requirements.'>" + 79 : "<text/>" + 80 : "</element>" + 81 : "</optional>" + 82 : "</element>"; 83 : }; 84 : 85 : /** 86 : * @param {Object} template - The requirements template as defined above. 87 : * @param {number} playerID - 88 : * @return {boolean} - 89 : */ 90 3 : RequirementsHelper.prototype.AreRequirementsMet = function(template, playerID) 91 : { 92 55 : if (!template || !Object.keys(template).length) 93 1 : return true; 94 : 95 54 : const cmpTechManager = QueryPlayerIDInterface(playerID, IID_TechnologyManager); 96 54 : return cmpTechManager && this.AllRequirementsMet(template, cmpTechManager); 97 : }; 98 : 99 : /** 100 : * @param {Object} template - The requirements template for "all". 101 : * @param {component} cmpTechManager - 102 : * @return {boolean} - 103 : */ 104 3 : RequirementsHelper.prototype.AllRequirementsMet = function(template, cmpTechManager) 105 : { 106 97 : for (const requirementType in template) 107 : { 108 104 : const requirement = template[requirementType]; 109 104 : if (requirementType === "All" && !this.AllRequirementsMet(requirement, cmpTechManager)) 110 20 : return false; 111 84 : if (requirementType === "Any" && !this.AnyRequirementsMet(requirement, cmpTechManager)) 112 7 : return false; 113 77 : if (requirementType === "Entities") 114 : { 115 15 : for (const className in requirement) 116 : { 117 15 : const entReq = requirement[className]; 118 15 : if ("Count" in entReq && (!(className in cmpTechManager.classCounts) || cmpTechManager.classCounts[className] < entReq.Count)) 119 4 : return false; 120 11 : if ("Variants" in entReq && (!(className in cmpTechManager.typeCountsByClass) || Object.keys(cmpTechManager.typeCountsByClass[className]).length < entReq.Variants)) 121 3 : return false; 122 : } 123 : } 124 70 : if (requirementType === "Techs" && requirement._string) 125 33 : for (const tech of requirement._string.split(" ")) 126 39 : if (tech[0] === "!" ? cmpTechManager.IsTechnologyResearched(tech.substring(1)) : 127 : !cmpTechManager.IsTechnologyResearched(tech)) 128 20 : return false; 129 : } 130 43 : return true; 131 : }; 132 : 133 : /** 134 : * @param {Object} template - The requirements template for "any". 135 : * @param {component} cmpTechManager - 136 : * @return {boolean} - 137 : */ 138 3 : RequirementsHelper.prototype.AnyRequirementsMet = function(template, cmpTechManager) 139 : { 140 23 : for (const requirementType in template) 141 : { 142 33 : const requirement = template[requirementType]; 143 33 : if (requirementType === "All" && this.AllRequirementsMet(requirement, cmpTechManager)) 144 3 : return true; 145 30 : if (requirementType === "Any" && this.AnyRequirementsMet(requirement, cmpTechManager)) 146 1 : return true; 147 29 : if (requirementType === "Entities") 148 : { 149 12 : for (const className in requirement) 150 : { 151 12 : const entReq = requirement[className]; 152 12 : if ("Count" in entReq && className in cmpTechManager.classCounts && cmpTechManager.classCounts[className] >= entReq.Count) 153 3 : return true; 154 9 : if ("Variants" in entReq && className in cmpTechManager.typeCountsByClass && Object.keys(cmpTechManager.typeCountsByClass[className]).length >= entReq.Variants) 155 2 : return true; 156 : } 157 : } 158 24 : if (requirementType === "Techs" && requirement._string) 159 11 : for (const tech of requirement._string.split(" ")) 160 13 : if (tech[0] === "!" ? !cmpTechManager.IsTechnologyResearched(tech.substring(1)) : 161 : cmpTechManager.IsTechnologyResearched(tech)) 162 6 : return true; 163 : } 164 8 : return false; 165 : }; 166 : 167 3 : Engine.RegisterGlobal("RequirementsHelper", new RequirementsHelper());