Ticket #4003: t4003-part1.patch

File t4003-part1.patch, 9.4 KB (added by mimo, 8 years ago)

Takes the cost multiplier into account for AI researches.

  • binaries/data/mods/public/simulation/ai/common-api/entity.js

     
    103103        return this.get("Identity/Civ");
    104104    },
    105105
    106     cost: function() {
     106    "cost": function(productionQueue) {
    107107        if (!this.get("Cost"))
    108108            return undefined;
    109109
    110110        let ret = {};
     111        let typeCost;
    111112        for (let type in this.get("Cost/Resources"))
    112             ret[type] = +this.get("Cost/Resources/" + type);
     113        {
     114            typeCost = +this.get("Cost/Resources/" + type);
     115            if (productionQueue)
     116                typeCost *= productionQueue.techCostMultiplier(type);
     117            ret[type] = typeCost;
     118        }
    113119        return ret;
    114120    },
    115121
    116     costSum: function() {
    117         if (!this.get("Cost"))
     122    "costSum": function(productionQueue) {
     123        let cost = this.cost(productionQueue);
     124        if (!cost)
    118125            return undefined;
    119 
    120126        let ret = 0;
    121         for (let type in this.get("Cost/Resources"))
    122             ret += +this.get("Cost/Resources/" + type);
     127        for (let type in cost)
     128            ret += cost[type];
    123129        return ret;
    124130    },
    125131
     132    "techCostMultiplier": function(type) {
     133        return +(this.get("ProductionQueue/TechCostMultiplier/"+type) || 1);
     134    },
     135
    126136    /**
    127137     * Returns the radius of a circle surrounding this entity's
    128138     * obstruction shape, or undefined if no obstruction.
     
    462472        return this.get("BuildRestrictions/Category");
    463473    },
    464474
    465     buildTime: function() {
    466         return +this.get("Cost/BuildTime");
     475    "buildTime": function(productionQueue) {
     476        let time = +this.get("Cost/BuildTime");
     477        if (productionQueue)
     478            time *= productionQueue.techCostMultiplier("time");
     479        return time;
    467480    },
    468481
    469482    buildDistance: function() {
  • binaries/data/mods/public/simulation/ai/common-api/gamestate.js

     
    693693};
    694694
    695695/**
    696  * Find buildings that are capable of training that template.
     696 * Return true if we have a building able to train that template
    697697 */
     698m.GameState.prototype.hasTrainer = function(template)
     699{   
     700    let civ = this.playerData.civ;
     701    for (let ent of this.getOwnTrainingFacilities().values())
     702    {
     703        let trainable = ent.trainableEntities(civ);
     704        if (trainable && trainable.indexOf(template) !== -1)
     705            return true;
     706    }
     707    return false;
     708};
     709
     710/**
     711 * Find buildings able to train that template.
     712 */
    698713m.GameState.prototype.findTrainers = function(template)
    699714{   
    700715    let civ = this.playerData.civ;
    701716    return this.getOwnTrainingFacilities().filter(function(ent) {
    702717        let trainable = ent.trainableEntities(civ);
    703         return trainable && trainable.indexOf(template) != -1;
     718        return trainable && trainable.indexOf(template) !== -1;
    704719    });
    705720};
    706721
     
    718733    return undefined;
    719734};
    720735
    721 /** Return true if one of the buildings is capable of researching the given tech */
     736/** Return true if one of our buildings is capable of researching the given tech */
    722737m.GameState.prototype.hasResearchers = function(templateName, noRequirementCheck)
    723738{
    724739    // let's check we can research the tech.
     
    752767{
    753768    // let's check we can research the tech.
    754769    if (!this.canResearch(templateName, noRequirementCheck))
    755         return [];
     770        return undefined;
    756771
    757772    let self = this;
    758773    let civ = this.playerData.civ;
  • binaries/data/mods/public/simulation/ai/common-api/technology.js

     
    6565    return this._pairedWith;
    6666};
    6767
    68 m.Technology.prototype.cost = function()
     68m.Technology.prototype.cost = function(productionQueue)
    6969{
    7070    if (!this._template.cost)
    7171        return undefined;
    72     return this._template.cost;
     72    let cost = {};
     73    for (let type in this._template.cost)
     74    {
     75        cost[type] = +this._template.cost[type];
     76        if (productionQueue)
     77            cost[type] *= productionQueue.techCostMultiplier(type);
     78    }
     79    return cost;
    7380};
    7481
     82m.Technology.prototype.costSum = function(productionQueue)
     83{
     84    let cost = this.cost(productionQueue);
     85    if (!cost)
     86        return undefined;
     87    let ret = 0;
     88    for (let type in cost)
     89        ret += cost[type];
     90    return ret;
     91};
     92
    7593// seconds
    7694m.Technology.prototype.researchTime = function()
    7795{
  • binaries/data/mods/public/simulation/ai/petra/queueManager.js

     
    355355            let item = queue.getNext();
    356356            if (this.accounts[name].canAfford(item.getCost()) && item.canStart(gameState))
    357357            {
    358                 this.finishingTime = gameState.ai.elapsedTime;
    359                 this.accounts[name].subtract(item.getCost());
    360                 queue.startNext(gameState);
    361                 queue.switched = 0;
     358                // canStart may update the cost because of the costMultiplier so we must check it again
     359                if (this.accounts[name].canAfford(item.getCost()))
     360                {
     361                    this.finishingTime = gameState.ai.elapsedTime;
     362                    this.accounts[name].subtract(item.getCost());
     363                    queue.startNext(gameState);
     364                    queue.switched = 0;
     365                }
    362366            }
    363367        }
    364368        else if (!queue.hasQueuedUnits())
  • binaries/data/mods/public/simulation/ai/petra/queueplan.js

     
    1212    this.template = gameState.getTemplate(this.type);
    1313    if (!this.template)
    1414    {
    15         API3.warn("Tried to add the inexisting template " + this.type + " to Petra. Please report this on the forums");
     15        API3.warn("Tried to add the inexisting template " + this.type + " to Petra.");
    1616        return false;
    1717    }
    1818    this.ID = gameState.ai.uniqueIDs.plans++;
    1919    this.cost = new API3.Resources(this.template.cost());
    2020    this.number = 1;
    21 
    2221    this.category = "";
    2322
    2423    return true;
  • binaries/data/mods/public/simulation/ai/petra/queueplanResearch.js

     
    99    if (this.template.researchTime === undefined)
    1010        return false;
    1111
     12    // Refine the estimated cost
     13    let researchers = this.getBestResearchers(gameState, true);
     14    if (researchers)
     15        this.cost = new API3.Resources(this.template.cost(researchers[0]));
     16
    1217    this.category = "technology";
    1318
    1419    this.rush = rush;
     
    2025
    2126m.ResearchPlan.prototype.canStart = function(gameState)
    2227{
    23     // also checks canResearch
    24     return gameState.hasResearchers(this.type);
     28    this.researchers = this.getBestResearchers(gameState);
     29    if (!this.researchers)
     30        return false;
     31    this.cost = new API3.Resources(this.template.cost(this.researchers[0]));
     32    return true;
    2533};
    2634
     35m.ResearchPlan.prototype.getBestResearchers = function(gameState, noRequirementCheck = false)
     36{
     37    let allResearchers = gameState.findResearchers(this.type, noRequirementCheck);
     38    if (!allResearchers || !allResearchers.hasEntities())
     39        return undefined;
     40
     41    // Keep only researchers with smallest cost
     42    let costMin = Math.min();
     43    let researchers;
     44    for (let ent of allResearchers.values())
     45    {
     46        let cost = this.template.costSum(ent);
     47        if (cost === costMin)
     48            researchers.push(ent);
     49        else if (cost < costMin)
     50        {
     51            costMin = cost;
     52            researchers = [ent];
     53        }
     54    }
     55    return researchers;
     56};
     57
    2758m.ResearchPlan.prototype.isInvalid = function(gameState)
    2859{
    2960    return gameState.isResearched(this.type) || gameState.isResearching(this.type);
     
    3162
    3263m.ResearchPlan.prototype.start = function(gameState)
    3364{
    34     let trainers = gameState.findResearchers(this.type).toEntityArray();
    35 
    36     // Prefer training buildings with short queues
    37     // (TODO: this should also account for units added to the queue by
    38     // plans that have already been executed this turn)
    39     if (trainers.length)
    40     {
    41         trainers.sort((a, b) => a.trainingQueueTime() - b.trainingQueueTime());
    42         // drop anything in the queue if we rush it.
    43         if (this.rush)
    44             trainers[0].stopAllProduction(0.45);
    45         trainers[0].research(this.type);
    46     }
     65    // Prefer researcher with shortest queues (no need to serialize this.researchers
     66    // as the functions canStart and start are always called on the same turn)
     67    this.researchers.sort((a, b) => a.trainingQueueTime() - b.trainingQueueTime());
     68    // Drop anything in the queue if we rush it.
     69    if (this.rush)
     70        this.researchers[0].stopAllProduction(0.45);
     71    this.researchers[0].research(this.type);
    4772    this.onStart(gameState);
    4873};
    4974
  • binaries/data/mods/public/simulation/ai/petra/queueplanTraining.js

     
    110110    this.number += amount;
    111111};
    112112
    113 // Find the promoted types corresponding to this.type
     113/** Find the promoted types corresponding to this.type */
    114114m.TrainingPlan.prototype.promotedTypes = function(gameState)
    115115{
    116116    let types = [];