Ticket #3993: notciv_v4-1.patch
File notciv_v4-1.patch, 34.4 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..ce75e28 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 function DeriveTechnologyRequirements(template) 82 { 83 let requirements = {} 84 85 if (template.requirements) 86 { 87 let op = Object.keys(template.requirements)[0]; 88 let val = template.requirements[op]; 89 requirements = InterpretTechRequirements(op, val); 90 } 91 92 if (template.supersedes) 93 { 94 if (requirements.generic) 95 { 96 if (!requirements.generic.techs) 97 requirements.generic.techs = []; 98 requirements.generic.techs.push(template.supersedes); 99 } 100 else if (!Object.keys(requirements).length) 101 requirements.generic = { "techs": [template.supersedes] }; 102 else 103 for (let ck in requirements) 104 if (requirements[ck]) 105 { 106 if (!requirements[ck].techs) 107 requirements[ck].techs = []; 108 requirements[ck].techs.push(template.supersedes); 109 } 110 } 111 112 return requirements; 113 } 114 115 /** 116 * Interprets the prerequisite requirements of a technology. 117 * 118 * Takes the initial { key: value } from the short-form requirements object in entity templates, 119 * and parses it into an object that can be more easily checked by simulation and gui. 120 * 121 * Works recursively if needed. 122 * 123 * @param {string} operator - The base operation. Can be "civ", "notciv", "tech", "entity", "all" or "any". 124 * @param {mixed} value - The value associated with the above operation. 125 * 126 * @return Object containing the requirements, sorted. 127 */ 128 function InterpretTechRequirements(operator, value) 129 { 130 let requirements = {}; 131 132 switch (operator) 133 { 134 case "civ": 135 requirements[value] = {}; 136 break; 137 138 case "notciv": 139 requirements[value] = false; 140 break; 141 142 case "class": 143 case "number": 144 // do nothing 145 break; 146 147 case "entity": 148 requirements.generic = { "entities": [{ 149 "class": value.class, 150 "number": value.number || value.numberOfTypes, 151 "check": value.number ? "count" : "variants" 152 }]}; 153 break; 154 155 case "tech": 156 if (depath(value).slice(0,4) === "pair") 157 return { "generic": loadTechnologyPair(value).techs }; 158 return { "generic": { "techs": [value] } }; 159 160 case "all": 161 { 162 let civs = []; 163 let techs = []; 164 let entities = []; 165 for (let subvalue of value) 166 for (let newOper in subvalue) 167 { 168 let newValue = subvalue[newOper]; 169 let result = InterpretTechRequirements(newOper, newValue) 170 171 switch (newOper) 172 { 173 case "civ": 174 civs.push(Object.keys(result)[0]); 175 break; 176 177 case "notciv": 178 requirements[Object.keys(result)[0]] = false; 179 break; 180 181 case "tech": 182 techs = techs.concat(result.generic.techs); 183 break; 184 185 case "entity": 186 entities = entities.concat(result.generic.entities); 187 break; 188 189 case "any": 190 case "all": 191 { 192 if (result.generic) 193 techs = techs.concat(result.generic); 194 else 195 for (let civ in result) 196 if (result[civ] === false) 197 requirements[civ] = false; 198 else if (newOper === "any") 199 civs.push(civ); 200 else 201 warn("Incomprehensible technology requirements - "+operator +":"+uneval(value)); 202 } 203 break; 204 205 } 206 } 207 if (!civs.length && (techs.length || entities.length)) 208 { 209 requirements.generic = {}; 210 if (techs.length) 211 requirements.generic.techs = techs; 212 if (entities.length) 213 requirements.generic.entities = entities; 214 } 215 else 216 for (let civ of civs) 217 { 218 requirements[civ] = {}; 219 if (techs.length) 220 requirements[civ].techs = techs; 221 if (entities.length) 222 requirements[civ].entities = entities; 223 } 224 } 225 break; 226 227 case "any": 228 { 229 for (let subvalue of value) 230 for (let newOper in subvalue) 231 { 232 let newValue = subvalue[newOper]; 233 let result = InterpretTechRequirements(newOper, newValue) 234 235 switch (newOper) 236 { 237 case "civ": 238 requirements[Object.keys(result)[0]] = {}; 239 break; 240 241 case "notciv": 242 requirements[Object.keys(result)[0]] = false; 243 break; 244 245 case "tech": 246 if (!requirements.generic) 247 requirements.generic = { "techs": [] }; 248 requirements.generic.techs.push(result.generic.techs); 249 break; 250 251 case "entity": 252 if (!requirements.generic) 253 requirements.generic = { "entities": [] }; 254 requirements.generic.entities.push(result.generic.entities); 255 break; 256 257 case "all": 258 for (let civ in result) 259 { 260 requirements[civ].techs = result[civ].techs; 261 } 262 break; 263 264 case "any": 265 for (let civ in result) 266 { 267 if (!requirements[civ]) 268 { 269 warn("Possible any/all req operator problem - "+operator +":"+uneval(value)); 270 requirements[civ] = {}; 271 } 272 for (let val of result[civ]) 273 requirements.generic.techs.push(val); 274 } 275 break; 276 } 277 } 278 } 279 break; 280 281 default: 282 warn("Unknown requirement operator: "+operator); 283 } 284 285 return requirements; 286 } -
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..fa216c9 100644
a b function shuffleArray(source) 34 34 } 35 35 return result; 36 36 } 37 38 function depath(path) 39 { 40 return path.slice(path.lastIndexOf("/") + 1); 41 } -
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..66e4103 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 { 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 773 }); 774 } 767 let reqs = GetCivSpecificReqsOfTech(template.reqs, GetSimState().players[player].civ); 768 if (reqs.entities) 769 for (let entity of reqs.entities) 770 if (entity.check == "count") 771 { 772 let current = GetSimState().players[player].classCounts[entity.class] || 0; 773 let remaining = entity.number - current; 774 tip += " " + sprintf(translatePlural("Remaining: %(number)s to build.", "Remaining: %(number)s to build.", remaining), { 775 "number": remaining 776 }); 777 } 775 778 tooltips.push(tip); 776 779 } 777 780 tooltips.push(getNeededResourcesTooltip(neededResources)); -
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..79205ba 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) 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..a254e3b 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) 169 165 for (let structCode of g_Lists.structures) 170 166 { 171 167 let structInfo = g_ParsedData.structures[structCode]; 168 structInfo.phase = GetPhaseOfTemplate(structInfo); 172 169 let structPhaseIdx = g_ParsedData.phaseList.indexOf(structInfo.phase); 173 170 174 171 // If this building is shared with another civ, … … function selectCiv(civCode) 188 185 let newProdTech = {}; 189 186 for (let prod of structInfo.production.technology) 190 187 { 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 } 188 let phase = GetPhaseOfTechnology(prod); 189 if (phase === false) 190 continue; 211 191 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 } 192 if (g_ParsedData.phaseList.indexOf(phase) < structPhaseIdx) 193 phase = structInfo.phase; 220 194 221 195 if (!(phase in newProdTech)) 222 196 newProdTech[phase] = []; … … function selectCiv(civCode) 224 198 newProdTech[phase].push(prod); 225 199 } 226 200 227 // Determine phase for units201 // Sort units by phase 228 202 let newProdUnits = {}; 229 203 for (let prod of structInfo.production.units) 230 204 { 231 205 if (!g_ParsedData.units[prod]) 232 206 continue; 233 207 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 } 208 let phase = GetPhaseOfTemplate(g_ParsedData.units[prod]); 209 if (phase === false) 210 continue; 261 211 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]; 212 if (g_ParsedData.phaseList.indexOf(phase) < structPhaseIdx) 213 phase = structInfo.phase; 267 214 268 215 if (!(phase in newProdUnits)) 269 216 newProdUnits[phase] = []; … … function selectCiv(civCode) 278 225 } 279 226 280 227 // Determine the buildList for the civ (grouped by phase) 281 varbuildList = {};282 vartrainerList = [];228 let buildList = {}; 229 let trainerList = []; 283 230 for (let pha of g_ParsedData.phaseList) 284 231 buildList[pha] = []; 285 232 for (let structCode of g_Lists.structures) 286 233 { 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); 234 let phase = g_ParsedData.structures[structCode].phase; 235 buildList[phase].push(structCode); 295 236 } 296 237 for (let unitCode of g_Lists.units) 297 238 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",