Ticket #3993: notciv_v5-1.patch
File notciv_v5-1.patch, 37.2 KB (added by , 8 years ago) |
---|
-
binaries/data/mods/public/globalscripts/Technologies.js
diff --git a/binaries/data/mods/public/globalscripts/Technologies.js b/binaries/data/mods/public/globalscripts/Technologies.js index b6783e2..764bd45 100644
a b function DoesModificationApply(modification, classes) 50 50 { 51 51 return MatchesClassList(classes, modification.affects); 52 52 } 53 54 55 /** 56 * Fetch the civ-specific technology requirements of a technology 57 * 58 * @param {object} techReqs - The technology requirements, derived from 59 * InterpretTechRequirements 60 * @param {string} civ - The civ 61 * 62 * @return An object containing the requirements specific to this civ 63 * for this technology or false if the civ cannot research this 64 * technology 65 */ 66 function GetCivSpecificReqsOfTech(techReqs, civ) 67 { 68 if (civ in techReqs) 69 { 70 if (techReqs[civ] === false) 71 return false; 72 return techReqs[civ] || {}; 73 } 74 75 if (techReqs.generic) 76 return techReqs.generic || {}; 77 78 return !Object.keys(techReqs).length; 79 } 80 81 /** 82 * Derives the technology requirements from a given technology template. 83 * Takes into account the `supersedes` attribute. 84 * 85 * @param {object} template - The template object. Loading of the template must have already occured. 86 * 87 * @return Derived technology requirements. See `InterpretTechRequirements` for object's syntax. 88 */ 89 function DeriveTechnologyRequirements(template) 90 { 91 let requirements = {} 92 93 if (template.requirements) 94 { 95 let op = Object.keys(template.requirements)[0]; 96 let val = template.requirements[op]; 97 requirements = InterpretTechRequirements(op, val); 98 } 99 100 if (template.supersedes) 101 { 102 if (requirements.generic) 103 { 104 if (!requirements.generic.techs) 105 requirements.generic.techs = []; 106 requirements.generic.techs.push(template.supersedes); 107 } 108 else if (!Object.keys(requirements).length) 109 requirements.generic = { "techs": [template.supersedes] }; 110 else 111 for (let ck in requirements) 112 if (requirements[ck]) 113 { 114 if (!requirements[ck].techs) 115 requirements[ck].techs = []; 116 requirements[ck].techs.push(template.supersedes); 117 } 118 } 119 120 return requirements; 121 } 122 123 /** 124 * Interprets the prerequisite requirements of a technology. 125 * 126 * Takes the initial { key: value } from the short-form requirements object in entity templates, 127 * and parses it into an object that can be more easily checked by simulation and gui. 128 * 129 * Works recursively if needed. 130 * 131 * The returned object is in the form: 132 * ``` 133 * { 134 * "civA": { 135 * "techs": ["tech1"] 136 * }, 137 * "civB": { 138 * "entities": [{ 139 * "class": "human", 140 * "number": 2, 141 * "variant": "count" 142 * }] 143 * }, 144 * "civC": false, 145 * "generic": { 146 * "techs": ["tech2"] 147 * } 148 * } 149 * ``` 150 * (Or, to translate: 151 * - `civA` needs `tech1` 152 * - `civB` needs 2 entities with the `human` class 153 * - `civC` cannot research this tech at all 154 * - and everyone else needs `tech2`) 155 * 156 * @param {string} operator - The base operation. Can be "civ", "notciv", "tech", "entity", "all" or "any". 157 * @param {mixed} value - The value associated with the above operation. 158 * 159 * @return Object containing the requirements, sorted. 160 */ 161 function InterpretTechRequirements(operator, value) 162 { 163 let requirements = {}; 164 165 switch (operator) 166 { 167 case "civ": 168 requirements[value] = {}; 169 break; 170 171 case "notciv": 172 requirements[value] = false; 173 requirements.generic = {}; 174 break; 175 176 case "class": 177 case "number": 178 case "numberOfTypes": 179 // do nothing 180 break; 181 182 case "entity": 183 requirements.generic = { "entities": [{ 184 "class": value.class, 185 "number": value.number || value.numberOfTypes, 186 "check": value.number ? "count" : "variants" 187 }]}; 188 break; 189 190 case "tech": 191 requirements.generic = { "techs": [value] }; 192 break; 193 194 case "all": 195 { 196 let civs = []; 197 let techs = []; 198 let entities = []; 199 for (let subvalue of value) 200 for (let newOper in subvalue) 201 { 202 let newValue = subvalue[newOper]; 203 let result = InterpretTechRequirements(newOper, newValue) 204 205 switch (newOper) 206 { 207 case "civ": 208 civs.push(Object.keys(result)[0]); 209 break; 210 211 case "notciv": 212 for (let civ in result) 213 requirements[civ] = result[civ]; 214 break; 215 216 case "tech": 217 techs = techs.concat(result.generic.techs); 218 break; 219 220 case "entity": 221 entities = entities.concat(result.generic.entities); 222 break; 223 224 case "any": 225 case "all": 226 { 227 for (let civ in result) 228 if (result[civ] === false) 229 requirements[civ] = false; 230 else if (newOper === "any") 231 civs.push(civ); 232 } 233 break; 234 235 } 236 } 237 if (!civs.length && (techs.length || entities.length)) 238 { 239 requirements.generic = {}; 240 if (techs.length) 241 requirements.generic.techs = techs; 242 if (entities.length) 243 requirements.generic.entities = entities; 244 } 245 else 246 for (let civ of civs) 247 { 248 requirements[civ] = {}; 249 if (techs.length) 250 requirements[civ].techs = techs; 251 if (entities.length) 252 requirements[civ].entities = entities; 253 } 254 } 255 break; 256 257 case "any": 258 { 259 for (let subvalue of value) 260 for (let newOper in subvalue) 261 { 262 let newValue = subvalue[newOper]; 263 let result = InterpretTechRequirements(newOper, newValue) 264 265 switch (newOper) 266 { 267 case "civ": 268 case "notciv": 269 for (let civ in result) 270 requirements[civ] = result[civ]; 271 break; 272 273 case "tech": 274 if (!requirements.generic) 275 requirements.generic = { "techs": [] }; 276 requirements.generic.techs.push(result.generic.techs); 277 break; 278 279 case "entity": 280 if (!requirements.generic) 281 requirements.generic = { "entities": [] }; 282 requirements.generic.entities.push(result.generic.entities); 283 break; 284 285 case "all": 286 for (let civ in result) 287 { 288 requirements[civ] = {}; 289 if (result[civ].techs) 290 requirements[civ].techs = result[civ].techs; 291 if (result[civ].entities) 292 requirements[civ].entities = result[civ].entities; 293 } 294 break; 295 296 case "any": 297 for (let civ in result) 298 { 299 if (!requirements[civ]) 300 { 301 warn("Possible any/all req operator problem - "+operator +":"+uneval(value)); 302 requirements[civ] = {}; 303 } 304 if (result[civ].techs) 305 for (let val of result[civ].techs) 306 requirements.generic.techs.push(val); 307 if (result[civ].entities) 308 for (let val of result[civ].entities) 309 requirements.generic.entities.push(val); 310 } 311 break; 312 } 313 } 314 } 315 break; 316 317 default: 318 warn("Unknown requirement operator: "+operator); 319 } 320 321 return requirements; 322 } -
binaries/data/mods/public/globalscripts/Templates.js
diff --git a/binaries/data/mods/public/globalscripts/Templates.js b/binaries/data/mods/public/globalscripts/Templates.js index 9b622db..8f76311 100644
a b function GetTechnologyDataHelper(template, civ) 371 371 ret.tooltip = template.tooltip; 372 372 ret.requirementsTooltip = template.requirementsTooltip || ""; 373 373 374 if (template.requirements && template.requirements.class) 375 ret.classRequirements = { 376 "class": template.requirements.class, 377 "number": template.requirements.number 378 }; 374 ret.reqs = DeriveTechnologyRequirements(template); 379 375 380 376 ret.description = template.description; 381 377 -
binaries/data/mods/public/globalscripts/utility.js
diff --git a/binaries/data/mods/public/globalscripts/utility.js b/binaries/data/mods/public/globalscripts/utility.js index 6146b46..eaef316 100644
a b function shuffleArray(source) 34 34 } 35 35 return result; 36 36 } 37 38 /** 39 * Removes prefixing path from a path or filename, leaving just the file's name (with extension) 40 * 41 * ie. a/b/c/file.ext -> file.ext 42 */ 43 function depath(path) 44 { 45 return path.slice(path.lastIndexOf("/") + 1); 46 } -
binaries/data/mods/public/gui/session/selection_panels.js
diff --git a/binaries/data/mods/public/gui/session/selection_panels.js b/binaries/data/mods/public/gui/session/selection_panels.js index c21fc4f..46a77d3 100644
a b g_SelectionPanels.Research = { 731 731 setPanelObjectPosition(pair, data.i, data.rowLength); 732 732 733 733 // Handle one or two techs 734 let player = data.unitEntState.player; 734 735 for (let i in techs) 735 736 { 736 737 let tech = techs[i]; … … g_SelectionPanels.Research = { 743 744 744 745 let neededResources = Engine.GuiInterfaceCall("GetNeededResources", { 745 746 "cost": template.cost, 746 "player": data.unitEntState.player747 "player": player 747 748 }); 748 749 749 750 let requirementsPassed = Engine.GuiInterfaceCall("CheckTechnologyRequirements", { 750 751 "tech": tech, 751 "player": data.unitEntState.player752 "player": player 752 753 }); 753 754 754 755 let button = Engine.GetGUIObjectByName("unitResearchButton[" + position + "]"); … … g_SelectionPanels.Research = { 763 764 if (!requirementsPassed) 764 765 { 765 766 let tip = template.requirementsTooltip; 766 if (template.classRequirements) 767 let reqs = GetCivSpecificReqsOfTech(template.reqs, GetSimState().players[player].civ); 768 if (reqs.entities) 767 769 { 768 let player = data.unitEntState.player; 769 let current = GetSimState().players[player].classCounts[template.classRequirements.class] || 0; 770 let remaining = template.classRequirements.number - current; 771 tip += " " + sprintf(translatePlural("Remaining: %(number)s to build.", "Remaining: %(number)s to build.", remaining), { 772 "number": remaining 770 let entityCounts = []; 771 for (let entity of reqs.entities) 772 { 773 let current = 0; 774 switch (entity.check) 775 { 776 case "count": 777 current = GetSimState().players[player].classCounts[entity.class] || 0; 778 break; 779 780 case "variants": 781 current = GetSimState().players[player].typeCountsByClass[entity.class] ? Object.keys(GetSimState().players[player].typeCountsByClass[entity.class]).length : 0; 782 break; 783 } 784 785 let remaining = entity.number - current; 786 if (remaining < 1) 787 continue; 788 789 entityCounts.push(sprintf(translatePlural("%(number)s entity of class %(class)s", "%(number)s entities of class %(class)s", remaining), { 790 "number": remaining, 791 "class": entity.class 792 })); 793 } 794 tip += " " + sprintf(translate("Remaining: %(entityCounts)s"), { 795 "entityCounts": entityCounts.join(translate(", ")) 773 796 }); 774 797 } 775 798 tooltips.push(tip); -
binaries/data/mods/public/gui/structree/helper.js
diff --git a/binaries/data/mods/public/gui/structree/helper.js b/binaries/data/mods/public/gui/structree/helper.js index eef5c6c..8c7fe49 100644
a b function fetchTokens(templateName, keypath) 92 92 return val._string.split(" "); 93 93 } 94 94 95 function depath(path)96 {97 return path.slice(path.lastIndexOf("/") + 1);98 }99 100 95 /** 101 96 * This is needed because getEntityCostTooltip in tooltip.js needs to get 102 97 * the template data of the different wallSet pieces. In the session this … … function GetTemplateData(templateName) 107 102 var template = loadTemplate(templateName); 108 103 return GetTemplateDataHelper(template, null, g_AuraData); 109 104 } 105 106 /** 107 * Determines and returns the phase in which a given technology can be 108 * first researched. Works recursively through the given tech's 109 * pre-requisite and superseded techs if necessary. 110 * 111 * @param {string} techName - The Technology's name 112 * @return The name of the phase the technology belongs to, or false if 113 * the current civ can't research this tech 114 */ 115 function GetPhaseOfTechnology(techName) 116 { 117 let phaseIdx = -1; 118 119 if (depath(techName).slice(0, 5) === "phase") 120 { 121 phaseIdx = g_ParsedData.phaseList.indexOf(GetActualPhase(techName)); 122 if (phaseIdx > 0) 123 return g_ParsedData.phaseList[phaseIdx - 1]; 124 } 125 126 let techReqs = GetCivSpecificReqsOfTech(g_ParsedData.techs[techName].reqs, g_SelectedCiv); 127 if (!techReqs) 128 return false; 129 130 for (let req of techReqs.techs) 131 { 132 if (depath(req).slice(0, 5) === "phase") 133 return req; 134 phaseIdx = Math.max(phaseIdx, g_ParsedData.phaseList.indexOf(GetPhaseOfTechnology(req))); 135 } 136 return g_ParsedData.phaseList[phaseIdx] || false; 137 } 138 139 function GetActualPhase(phaseName) 140 { 141 if (g_ParsedData.phases[phaseName]) 142 return g_ParsedData.phases[phaseName].actualPhase; 143 144 warn("Unrecognised phase (" + techName + ")"); 145 return g_ParsedData.phaseList[0]; 146 } 147 148 function GetPhaseOfTemplate(template) 149 { 150 if (!template.requiredTechnology) 151 return g_ParsedData.phaseList[0]; 152 153 if (depath(template.requiredTechnology).slice(0, 5) == "phase") 154 return GetActualPhase(template.requiredTechnology); 155 156 return GetPhaseOfTechnology(template.requiredTechnology); 157 } -
binaries/data/mods/public/gui/structree/load.js
diff --git a/binaries/data/mods/public/gui/structree/load.js b/binaries/data/mods/public/gui/structree/load.js index 534747b..c93b56a 100644
a b function loadUnit(templateName) 39 39 { 40 40 if (!Engine.TemplateExists(templateName)) 41 41 return null; 42 var template = loadTemplate(templateName); 43 44 var unit = GetTemplateDataHelper(template, null, g_AuraData); 45 unit.phase = false; 46 47 if (unit.requiredTechnology) 48 { 49 if (depath(unit.requiredTechnology).slice(0, 5) == "phase") 50 unit.phase = unit.requiredTechnology; 51 else if (unit.requiredTechnology.length) 52 unit.required = unit.requiredTechnology; 53 } 42 let template = loadTemplate(templateName); 43 let unit = GetTemplateDataHelper(template, null, g_AuraData); 54 44 55 45 unit.gather = getGatherRates(templateName); 56 46 … … function loadUnit(templateName) 93 83 94 84 function loadStructure(templateName) 95 85 { 96 var template = loadTemplate(templateName); 97 var structure = GetTemplateDataHelper(template, null, g_AuraData); 98 structure.phase = false; 99 100 if (structure.requiredTechnology) 101 { 102 if (depath(structure.requiredTechnology).slice(0, 5) == "phase") 103 structure.phase = structure.requiredTechnology; 104 else if (structure.requiredTechnology.length) 105 structure.required = structure.requiredTechnology; 106 } 86 let template = loadTemplate(templateName); 87 let structure = GetTemplateDataHelper(template, null, g_AuraData); 107 88 108 89 structure.production = { 109 90 "technology": [], … … function loadStructure(templateName) 179 160 180 161 function loadTechnology(techName) 181 162 { 182 var template = loadTechData(techName); 183 var tech = GetTechnologyDataHelper(template, g_SelectedCiv); 184 tech.reqs = {}; 163 let template = loadTechData(techName); 164 let tech = GetTechnologyDataHelper(template, g_SelectedCiv); 185 165 186 166 if (template.pair !== undefined) 187 167 tech.pair = template.pair; 188 168 189 if (template.requirements !== undefined)190 {191 for (let op in template.requirements)192 {193 let val = template.requirements[op];194 let req = calcReqs(op, val);195 196 switch (op)197 {198 case "tech":199 tech.reqs.generic = req;200 break;201 202 case "civ":203 tech.reqs[req] = [];204 break;205 206 case "any":207 if (req[0].length > 0)208 for (let r of req[0])209 {210 let v = req[0][r];211 if (typeof r == "number")212 tech.reqs[v] = [];213 else214 tech.reqs[r] = v;215 }216 if (req[1].length > 0)217 tech.reqs.generic = req[1];218 break;219 220 case "all":221 if (!req[0].length)222 tech.reqs.generic = req[1];223 else224 for (let r of req[0])225 tech.reqs[r] = req[1];226 break;227 }228 }229 }230 231 if (template.supersedes !== undefined)232 {233 if (tech.reqs.generic !== undefined)234 tech.reqs.generic.push(template.supersedes);235 else236 for (let ck of Object.keys(tech.reqs))237 tech.reqs[ck].push(template.supersedes);238 }239 240 169 return tech; 241 170 } 242 171 … … function loadTechnologyPair(pairCode) 258 187 259 188 return { 260 189 "techs": [ pairInfo.top, pairInfo.bottom ], 261 "req ": pairInfo.supersedes || ""190 "reqs": DeriveTechnologyRequirements(pairInfo) 262 191 }; 263 192 } 264 193 265 194 /** 266 * Calculate the prerequisite requirements of a technology.267 * Works recursively if needed.268 *269 * @param op The base operation. Can be "civ", "tech", "all" or "any".270 * @param val The value associated with the above operation.271 *272 * @return Sorted requirments.273 */274 function calcReqs(op, val)275 {276 switch (op)277 {278 case "civ":279 case "class":280 case "notciv":281 case "number":282 // nothing needs doing283 break;284 285 case "tech":286 if (depath(val).slice(0,4) === "pair")287 return loadTechnologyPair(val).techs;288 return [ val ];289 290 case "all":291 case "any":292 let t = [];293 let c = [];294 for (let nv of val)295 {296 for (let o in nv)297 {298 let v = nv[o];299 let r = calcReqs(o, v);300 switch (o)301 {302 case "civ":303 case "notciv":304 c.push(r);305 break;306 307 case "tech":308 t = t.concat(r);309 break;310 311 case "any":312 c = c.concat(r[0]);313 t = t.concat(r[1]);314 break;315 316 case "all":317 for (let ci in r[0])318 c[ci] = r[1];319 t = t;320 }321 }322 }323 return [ c, t ];324 325 default:326 warn("Unknown reqs operator: "+op);327 }328 return val;329 }330 331 /**332 195 * Unravel phases 333 196 * 334 197 * @param techs The current available store of techs … … function unravelPhases(techs) 343 206 { 344 207 let techdata = techs[techcode]; 345 208 346 if (! ("generic" in techdata.reqs) || techdata.reqs.generic.length < 2)209 if (!techdata.reqs.generic || !techdata.reqs.generic.techs || techdata.reqs.generic.techs.length < 2) 347 210 continue; 348 211 349 let reqTech = techs[techcode].reqs.generic [1];212 let reqTech = techs[techcode].reqs.generic.techs[1]; 350 213 351 214 // Tech that can't be researched anywhere 352 215 if (!(reqTech in techs)) … … function unravelPhases(techs) 355 218 if (!("generic" in techs[reqTech].reqs)) 356 219 continue; 357 220 358 let reqPhase = techs[reqTech].reqs.generic [0];359 let myPhase = techs[techcode].reqs.generic [0];221 let reqPhase = techs[reqTech].reqs.generic.techs[0]; 222 let myPhase = techs[techcode].reqs.generic.techs[0]; 360 223 361 224 if (reqPhase == myPhase || depath(reqPhase).slice(0,5) !== "phase" || depath(myPhase).slice(0,5) !== "phase") 362 225 continue; … … function unravelPhases(techs) 364 227 let reqPhasePos = phaseList.indexOf(reqPhase); 365 228 let myPhasePos = phaseList.indexOf(myPhase); 366 229 367 if ( phaseList.length === 0)230 if (!phaseList.length) 368 231 phaseList = [reqPhase, myPhase]; 369 232 else if (reqPhasePos < 0 && myPhasePos > -1) 370 233 phaseList.splice(myPhasePos, 0, reqPhase); -
binaries/data/mods/public/gui/structree/structree.js
diff --git a/binaries/data/mods/public/gui/structree/structree.js b/binaries/data/mods/public/gui/structree/structree.js index 65bfd9e..04d6049 100644
a b function selectCiv(civCode) 62 62 }; 63 63 64 64 // get initial units 65 var startStructs = [];66 65 for (let entity of g_CivData[civCode].StartEntities) 67 66 { 68 67 if (entity.Template.slice(0, 5) == "units") 69 68 g_Lists.units.push(entity.Template); 70 69 else if (entity.Template.slice(0, 6) == "struct") 71 {72 70 g_Lists.structures.push(entity.Template); 73 startStructs.push(entity.Template);74 }75 71 } 76 72 77 73 // Load units and structures … … function selectCiv(civCode) 115 111 else 116 112 { 117 113 let newTech = loadTechnology(techcode); 118 if (pair.req !== "")114 for (let civ in pair.reqs) 119 115 { 120 if ("generic" in newTech.reqs) 121 newTech.reqs.generic.concat(techPairs[pair.req].techs); 122 else 116 if (!newTech.reqs[civ]) 117 newTech.reqs[civ] = {}; 118 else if (newTech.reqs[civ] === false) 119 continue; 120 121 if (pair.reqs[civ] === false) 123 122 { 124 for (let civkey of Object.keys(newTech.reqs))125 newTech.reqs[civkey].concat(techPairs[pair.req].techs);123 newTech.reqs[civ] = false; 124 continue; 126 125 } 126 127 for (let type in pair.reqs[civ]) 128 if (pair.reqs[civ][type]) 129 newTech.reqs[civ][type].concat(pair.reqs[civ][type]) 127 130 } 128 131 g_ParsedData.techs[techcode] = newTech; 129 132 } … … function selectCiv(civCode) 169 172 for (let structCode of g_Lists.structures) 170 173 { 171 174 let structInfo = g_ParsedData.structures[structCode]; 175 structInfo.phase = GetPhaseOfTemplate(structInfo); 172 176 let structPhaseIdx = g_ParsedData.phaseList.indexOf(structInfo.phase); 173 177 174 178 // If this building is shared with another civ, … … function selectCiv(civCode) 180 184 for (let prod of structInfo.production.technology) 181 185 if (prod in techPairs) 182 186 structInfo.production.technology.splice( 183 structInfo.production.technology.indexOf(prod), 1,184 techPairs[prod].techs[0], techPairs[prod].techs[1]187 structInfo.production.technology.indexOf(prod), 188 1, ...techPairs[prod].techs 185 189 ); 186 190 187 191 // Sort techs by phase 188 192 let newProdTech = {}; 189 193 for (let prod of structInfo.production.technology) 190 194 { 191 let phase = ""; 192 193 if (depath(prod).slice(0,5) === "phase") 194 { 195 phase = g_ParsedData.phaseList.indexOf(g_ParsedData.phases[prod].actualPhase); 196 if (phase > 0) 197 phase = g_ParsedData.phaseList[phase - 1]; 198 } 199 else if (g_SelectedCiv in g_ParsedData.techs[prod].reqs) 200 { 201 for (let req of g_ParsedData.techs[prod].reqs[g_SelectedCiv]) 202 if (depath(req).slice(0,5) === "phase") 203 phase = req; 204 } 205 else if ("generic" in g_ParsedData.techs[prod].reqs) 206 { 207 for (let req of g_ParsedData.techs[prod].reqs.generic) 208 if (depath(req).slice(0,5) === "phase") 209 phase = req; 210 } 195 let phase = GetPhaseOfTechnology(prod); 196 if (phase === false) 197 continue; 211 198 212 if (depath(phase).slice(0,5) !== "phase" || 213 g_ParsedData.phaseList.indexOf(phase) < structPhaseIdx) 214 { 215 if (structInfo.phase !== false) 216 phase = structInfo.phase; 217 else 218 phase = g_ParsedData.phaseList[0]; 219 } 199 if (g_ParsedData.phaseList.indexOf(phase) < structPhaseIdx) 200 phase = structInfo.phase; 220 201 221 202 if (!(phase in newProdTech)) 222 203 newProdTech[phase] = []; … … function selectCiv(civCode) 224 205 newProdTech[phase].push(prod); 225 206 } 226 207 227 // Determine phase for units208 // Sort units by phase 228 209 let newProdUnits = {}; 229 210 for (let prod of structInfo.production.units) 230 211 { 231 212 if (!g_ParsedData.units[prod]) 232 213 continue; 233 214 234 let unit = g_ParsedData.units[prod]; 235 let phase = ""; 236 237 if (unit.phase !== false) 238 { 239 if (g_ParsedData.phaseList.indexOf(unit.phase) < 0) 240 phase = g_ParsedData.phases[unit.phase].actualPhase; 241 else 242 phase = unit.phase; 243 } 244 else if (unit.required !== undefined) 245 { 246 if (g_ParsedData.phases[unit.required]) 247 phase = g_ParsedData.phases[unit.required].actualPhase; 248 else if (g_ParsedData.techs[unit.required]) 249 { 250 let reqs = g_ParsedData.techs[unit.required].reqs; 251 if (reqs[g_SelectedCiv]) 252 phase = reqs[g_SelectedCiv][0]; 253 else if (reqs.generic) 254 phase = reqs.generic[0]; 255 else 256 warn("Empty requirements found on technology " + unit.required); 257 } 258 else 259 warn("Technology " + unit.required + " for " + prod + " not found."); 260 } 215 let phase = GetPhaseOfTemplate(g_ParsedData.units[prod]); 216 if (phase === false) 217 continue; 261 218 262 if (depath(phase).slice(0,5) !== "phase" || g_ParsedData.phaseList.indexOf(phase) < structPhaseIdx) 263 if (structInfo.phase !== false) 264 phase = structInfo.phase; 265 else 266 phase = g_ParsedData.phaseList[0]; 219 if (g_ParsedData.phaseList.indexOf(phase) < structPhaseIdx) 220 phase = structInfo.phase; 267 221 268 222 if (!(phase in newProdUnits)) 269 223 newProdUnits[phase] = []; … … function selectCiv(civCode) 278 232 } 279 233 280 234 // Determine the buildList for the civ (grouped by phase) 281 varbuildList = {};282 vartrainerList = [];235 let buildList = {}; 236 let trainerList = []; 283 237 for (let pha of g_ParsedData.phaseList) 284 238 buildList[pha] = []; 285 239 for (let structCode of g_Lists.structures) 286 240 { 287 if (!g_ParsedData.structures[structCode].phase || startStructs.indexOf(structCode) > -1) 288 g_ParsedData.structures[structCode].phase = g_ParsedData.phaseList[0]; 289 290 let myPhase = g_ParsedData.structures[structCode].phase; 291 if (g_ParsedData.phaseList.indexOf(myPhase) === -1) 292 myPhase = g_ParsedData.phases[myPhase].actualPhase; 293 294 buildList[myPhase].push(structCode); 241 let phase = g_ParsedData.structures[structCode].phase; 242 buildList[phase].push(structCode); 295 243 } 296 244 for (let unitCode of g_Lists.units) 297 245 if (g_ParsedData.units[unitCode] && g_ParsedData.units[unitCode].production) -
binaries/data/mods/public/simulation/ai/common-api/gamestate.js
diff --git a/binaries/data/mods/public/simulation/ai/common-api/gamestate.js b/binaries/data/mods/public/simulation/ai/common-api/gamestate.js index 2aad561..bae3a05 100644
a b m.GameState.prototype.canResearch = function(techTemplateName, noRequirementChec 199 199 200 200 if (noRequirementCheck === true) 201 201 return true; 202 203 // not already researched, check if we can.204 // basically a copy of the function in technologyManager since we can't use it.205 // Checks the requirements for a technology to see if it can be researched at the current time206 207 // The technology which this technology supersedes is required208 if (template.supersedes() && !this.playerData.researchedTechs[template.supersedes()])209 return false;210 202 211 203 // if this is a pair, we must check that the pair tech is not being researched 212 204 if (template.pair()) … … m.GameState.prototype.canResearch = function(techTemplateName, noRequirementChec 222 214 }; 223 215 224 216 /** 225 * Private function for checking a set of requirements is met 226 * basically copies TechnologyManager 217 * Private function for checking a set of requirements is met. 218 * Basically copies TechnologyManager, but compares against 219 * variables only available within the AI 227 220 */ 228 221 m.GameState.prototype.checkTechRequirements = function(reqs) 229 222 { 230 // If there are no requirements then all requirements are met 223 reqs = GetCivSpecificReqsOfTech(reqs, this.playerData.civ); 224 231 225 if (!reqs) 232 return true; 233 234 if (reqs.all) 235 return reqs.all.every(r => this.checkTechRequirements(r)); 236 if (reqs.any) 237 return reqs.any.some(r => this.checkTechRequirements(r)); 238 if (reqs.civ) 239 return this.playerData.civ == reqs.civ; 240 if (reqs.notciv) 241 return this.playerData.civ != reqs.notciv; 242 if (reqs.tech) 243 return this.playerData.researchedTechs[reqs.tech] !== undefined && this.playerData.researchedTechs[reqs.tech]; 244 if (reqs.class && reqs.numberOfTypes) 245 return this.playerData.typeCountsByClass[reqs.class] && 246 Object.keys(this.playerData.typeCountsByClass[reqs.class]).length >= reqs.numberOfTypes; 247 if (reqs.class && reqs.number) 248 return this.playerData.classCounts[reqs.class] && 249 this.playerData.classCounts[reqs.class] >= reqs.number; 250 251 // The technologies requirements are not a recognised format 252 error("Bad requirements " + uneval(reqs)); 253 return false; 226 return false; 227 228 if (reqs.techs) 229 for (let prerequisite of reqs.techs) 230 if (!this.playerData.researchedTechs[prerequisite]) 231 return false; 232 233 if (reqs.entities) 234 for (let entity of reqs.entities) 235 { 236 switch (entity.check) 237 { 238 case "count": 239 if (!this.playerData.classCounts[entity.class] || this.playerData.classCounts[entity.class] < entity.number) 240 return false; 241 break; 242 243 case "variants": 244 if (!this.playerData.typeCountsByClass[entity.class] || Object.keys(this.playerData.typeCountsByClass[entity.class]).length < entity.number) 245 return false; 246 break; 247 } 248 } 249 250 return true; 254 251 }; 255 252 256 253 m.GameState.prototype.getMap = function() -
binaries/data/mods/public/simulation/ai/common-api/technology.js
diff --git a/binaries/data/mods/public/simulation/ai/common-api/technology.js b/binaries/data/mods/public/simulation/ai/common-api/technology.js index 09f6504..5ae1fc5 100644
a b m.Technology.prototype.researchTime = function() 99 99 100 100 m.Technology.prototype.requirements = function() 101 101 { 102 if (!this._template.requirements) 103 return undefined; 104 return this._template.requirements; 102 return DeriveTechnologyRequirements(this._template); 105 103 }; 106 104 107 105 m.Technology.prototype.autoResearch = function() -
binaries/data/mods/public/simulation/components/ProductionQueue.js
diff --git a/binaries/data/mods/public/simulation/components/ProductionQueue.js b/binaries/data/mods/public/simulation/components/ProductionQueue.js index 6c72202..6d8cb98 100644
a b ProductionQueue.prototype.GetTechnologiesList = function() 168 168 169 169 // Remove any technologies that can't be researched by this civ 170 170 techs = techs.filter(tech => { 171 let reqs = cmpTechnologyManager.GetTechnologyTemplate(tech).requirements || null;171 let reqs = DeriveTechnologyRequirements(cmpTechnologyManager.GetTechnologyTemplate(tech)); 172 172 return cmpTechnologyManager.CheckTechnologyRequirements(reqs, true); 173 173 }); 174 174 -
binaries/data/mods/public/simulation/components/TechnologyManager.js
diff --git a/binaries/data/mods/public/simulation/components/TechnologyManager.js b/binaries/data/mods/public/simulation/components/TechnologyManager.js index f1f9cc7..610e3bc 100644
a b TechnologyManager.prototype.IsTechnologyResearched = function(tech) 97 97 // Checks the requirements for a technology to see if it can be researched at the current time 98 98 TechnologyManager.prototype.CanResearch = function(tech) 99 99 { 100 var template = this.GetTechnologyTemplate(tech); 100 let template = this.GetTechnologyTemplate(tech); 101 101 102 if (!template) 102 103 { 103 104 warn("Technology \"" + tech + "\" does not exist"); 104 105 return false; 105 106 } 106 107 107 // The technology which this technology supersedes is required108 if (template.supersedes && !this.IsTechnologyResearched(template.supersedes))109 return false;110 111 108 if (template.top && this.IsInProgress(template.top) || 112 109 template.bottom && this.IsInProgress(template.bottom)) 113 110 return false; … … TechnologyManager.prototype.CanResearch = function(tech) 121 118 if (this.IsTechnologyResearched(tech)) 122 119 return false; 123 120 124 return this.CheckTechnologyRequirements( template.requirements || null);121 return this.CheckTechnologyRequirements(DeriveTechnologyRequirements(template)); 125 122 }; 126 123 127 124 /** 128 125 * Private function for checking a set of requirements is met 129 * @param reqs Object of technology requirements as given by the technology template130 * @param civonly A boolean set to true if only the civ requirement ischecked126 * @param {object} reqs - Technology requirements as derived from the technology template by globalscripts 127 * @param {boolean} civonly - True if only the civ requirement is to be checked 131 128 * 132 * @return true if the requirements are checked 133 * false otherwise 129 * @return true if the requirements pass, false otherwise 134 130 */ 135 TechnologyManager.prototype.CheckTechnologyRequirements = function(reqs, civonly )131 TechnologyManager.prototype.CheckTechnologyRequirements = function(reqs, civonly = false) 136 132 { 137 // If there are no requirements then all requirements are met 133 let cmpPlayer = Engine.QueryInterface(this.entity, IID_Player); 134 reqs = GetCivSpecificReqsOfTech(reqs, cmpPlayer.GetCiv()); 135 138 136 if (!reqs) 139 return true;137 return false; 140 138 141 if (reqs.all)142 return reqs.all.every(r => this.CheckTechnologyRequirements(r, civonly));143 if (reqs.any)144 return reqs.any.some(r => this.CheckTechnologyRequirements(r, civonly));145 if (reqs.civ)146 {147 let cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);148 return cmpPlayer && cmpPlayer.GetCiv() == reqs.civ;149 }150 if (reqs.notciv)151 {152 let cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);153 return cmpPlayer && cmpPlayer.GetCiv() != reqs.notciv;154 }155 139 if (civonly) 156 140 return true; 157 if (reqs.tech) 158 return this.IsTechnologyResearched(reqs.tech); 159 if (reqs.class && reqs.numberOfTypes) 160 return this.typeCountsByClass[reqs.class] && 161 Object.keys(this.typeCountsByClass[reqs.class]).length >= reqs.numberOfTypes; 162 if (reqs.class && reqs.number) 163 return this.classCounts[reqs.class] && 164 this.classCounts[reqs.class] >= reqs.number; 165 // The technologies requirements are not a recognised format 166 error("Bad requirements " + uneval(reqs)); 167 return false; 168 }; 141 142 if (reqs.techs) 143 for (let prerequisite of reqs.techs) 144 if (!this.IsTechnologyResearched(prerequisite)) 145 return false; 146 147 if (reqs.entities) 148 for (let entity of reqs.entities) 149 { 150 switch (entity.check) 151 { 152 case "count": 153 if (!this.classCounts[entity.class] || this.classCounts[entity.class] < entity.number) 154 return false; 155 break; 156 157 case "variants": 158 if (!this.typeCountsByClass[entity.class] || Object.keys(this.typeCountsByClass[entity.class]).length < entity.number) 159 return false; 160 break; 161 } 162 } 163 164 return true; 165 } 169 166 170 167 TechnologyManager.prototype.OnGlobalOwnershipChanged = function(msg) 171 168 { -
binaries/data/mods/public/simulation/data/technologies/phase_city.json
diff --git a/binaries/data/mods/public/simulation/data/technologies/phase_city.json b/binaries/data/mods/public/simulation/data/technologies/phase_city.json index 01c5345..73d37a4 100644
a b 6 6 }, 7 7 "description": "Advances from a bustling town to a veritable metropolis, full of the wonders of modern technology.", 8 8 "cost": { "food": 0, "wood": 0, "stone": 750, "metal": 750 }, 9 "requirements": { "all": [{ " class": "Town", "number": 4}, { "notciv": "athen" }] },9 "requirements": { "all": [{ "entity": { "class": "Town", "number": 4 } }, { "notciv": "athen" }] }, 10 10 "requirementsTooltip": "Requires 4 new Town Phase structures (except Walls and Civic Centers).", 11 11 "supersedes": "phase_town", 12 12 "icon": "city_phase.png", -
binaries/data/mods/public/simulation/data/technologies/phase_city_athen.json
diff --git a/binaries/data/mods/public/simulation/data/technologies/phase_city_athen.json b/binaries/data/mods/public/simulation/data/technologies/phase_city_athen.json index 97b63da..42dd624 100644
a b 5 5 }, 6 6 "description": "Advances from a bustling town to a veritable metropolis, full of the wonders of modern technology. This is the Athenian city phase, where metal gathering rates are boosted because of the 'Silver Owls' bonus.", 7 7 "cost": { "food": 0, "wood": 0, "stone": 750, "metal": 750 }, 8 "requirements": { "all": [{ " class": "Town", "number": 4}, { "civ": "athen" }] },8 "requirements": { "all": [{ "entity": { "class": "Town", "number": 4 } }, { "civ": "athen" }] }, 9 9 "requirementsTooltip": "Requires 4 new Town Phase structures (except Walls and Civic Centers).", 10 10 "supersedes": "phase_town_athen", 11 11 "replaces": ["phase_city"], -
binaries/data/mods/public/simulation/data/technologies/phase_town.json
diff --git a/binaries/data/mods/public/simulation/data/technologies/phase_town.json b/binaries/data/mods/public/simulation/data/technologies/phase_town.json index 087435d..2bb12d1 100644
a b 6 6 }, 7 7 "description": "Advances from a small village to a bustling town, ready to expand rapidly.", 8 8 "cost": { "food": 500, "wood": 500, "stone": 0, "metal": 0 }, 9 "requirements": { "all": [{ " class": "Village", "number": 5}, { "notciv": "athen" }] },9 "requirements": { "all": [{ "entity": { "class": "Village", "number": 5 } }, { "notciv": "athen" }] }, 10 10 "requirementsTooltip": "Requires 5 Village Phase structures (except Palisades and Farm Fields).", 11 11 "supersedes": "phase_village", 12 12 "icon": "town_phase.png", -
binaries/data/mods/public/simulation/data/technologies/phase_town_athen.json
diff --git a/binaries/data/mods/public/simulation/data/technologies/phase_town_athen.json b/binaries/data/mods/public/simulation/data/technologies/phase_town_athen.json index e5ae4bf..9cf810c 100644
a b 5 5 }, 6 6 "description": "Advances from a small village to a bustling town, ready to expand rapidly. This is the Athenian town phase, where metal gathering rates are boosted because of the 'Silver Owls' bonus.", 7 7 "cost": { "food": 500, "wood": 500, "stone": 0, "metal": 0 }, 8 "requirements": { "all": [{ " class": "Village", "number": 5}, { "civ": "athen" }] },8 "requirements": { "all": [{ "entity": { "class": "Village", "number": 5 } }, { "civ": "athen" }] }, 9 9 "requirementsTooltip": "Requires 5 Village Phase structures (except Palisades and Farm Fields).", 10 10 "supersedes": "phase_village", 11 11 "replaces": ["phase_town"], -
binaries/data/mods/public/simulation/data/technologies/unlock_shared_dropsites.json
diff --git a/binaries/data/mods/public/simulation/data/technologies/unlock_shared_dropsites.json b/binaries/data/mods/public/simulation/data/technologies/unlock_shared_dropsites.json index 57f8ad6..d6007e5 100644
a b 2 2 "genericName": "Diaspora", 3 3 "description": "The extension of trade leads to the permanent establishment of storekeepers and their families in foreign countries, allowing them to exploit the wealth of these countries.", 4 4 "cost": { "food": 200, "wood": 200, "stone": 100, "metal": 100 }, 5 "requirements": { " class": "Trader", "number": 3},5 "requirements": { "entity": { "class": "Trader", "number": 3 } }, 6 6 "requirementsTooltip": "Requires 3 Traders", 7 7 "supersedes": "unlock_shared_los", 8 8 "icon": "diaspora.png",