Ticket #2377: AIAuraTech.patch

File AIAuraTech.patch, 51.8 KB (added by wraitii, 10 years ago)
  • Users/Lancelot/Desktop/0ad-svn/trunk/binaries/data/mods/public/simulation/ai/aegis/base-manager.js

     
    8686    this.anchor.setMetadata(PlayerID, "base", this.ID);
    8787    this.anchor.setMetadata(PlayerID, "baseAnchor", true);
    8888    this.buildings.updateEnt(this.anchor);
    89 
    9089    if (this.territoryBuildings.indexOf(this.anchor.id()) === -1)
    9190        this.territoryBuildings.push(this.anchor.id());
    9291    return true;
     
    908907        }
    909908    }
    910909
    911     // auras/techs are buggy and the AI tries to repair healthy buildings.
    912     // TODO: reimplement once that's fixed.
    913     return;
    914 
    915910    // don't repair if we're still under attack, unless it's like a vital (civcentre or wall) building that's getting destroyed.
    916911    for (var i in damagedBuildings) {
    917912        var target = damagedBuildings[i];
     
    947942};
    948943
    949944m.BaseManager.prototype.update = function(gameState, queues, events) {
     945
     946        warn (this.anchor.hitpoints());
     947
     948
    950949    Engine.ProfileStart("Base update - base " + this.ID);
    951950    var self = this;
    952951   
  • Users/Lancelot/Desktop/0ad-svn/trunk/binaries/data/mods/public/simulation/ai/common-api/entity.js

     
    11var API3 = function(m)
    22{
    33
    4 m.EntityTemplate = m.Class({
     4// defines a template.
     5// It's completely raw data, except it's slightly cleverer now and then.
     6m.Template = m.Class({
    57
    6     // techModifications should be the tech modifications of only one player.
    7     // gamestates handle "GetTemplate" and should push the player's
    8     // while entities should push the owner's
    9     _init: function(template, techModifications)
     8    _init: function(template)
    109    {
    11         this._techModifications = techModifications;
    1210        this._template = template;
    1311    },
    1412   
     13    // helper function to return a template value, optionally adjusting for tech.
     14    // TODO: there's no support for "_string" values here.
     15    get: function(string)
     16    {
     17        var value = this._template;
     18        if (this._auraTemplateModif && this._auraTemplateModif[string])     {
     19            return this._auraTemplateModif[string];
     20        } else if (this._techModif && this._techModif[string]) {
     21            return this._techModif[string];
     22        } else {
     23            var args = string.split("/");
     24            for (var i = 0; i < args.length; ++i)
     25                if (value[args[i]])
     26                    value = value[args[i]];
     27                else
     28                    return undefined;
     29            return value;
     30        }
     31    },
     32
    1533    genericName: function() {
    16         if (!this._template.Identity || !this._template.Identity.GenericName)
     34        if (!this.get("Identity") || !this.get("Identity/GenericName"))
    1735            return undefined;
    18         return this._template.Identity.GenericName;
     36        return this.get("Identity/GenericName");
    1937    },
    20                            
     38                         
    2139    rank: function() {
    22         if (!this._template.Identity)
     40        if (!this.get("Identity"))
    2341            return undefined;
    24         return this._template.Identity.Rank;
     42        return this.get("Identity/Rank");
    2543    },
    2644
    2745    classes: function() {
    28         if (!this._template.Identity || !this._template.Identity.Classes || !this._template.Identity.Classes._string)
     46        if (!this.get("Identity") || !this.get("Identity/Classes") || !this.get("Identity/Classes/_string"))
    2947            return undefined;
    30         return this._template.Identity.Classes._string.split(/\s+/);
     48        return this.get("Identity/Classes/_string").split(/\s+/);
    3149    },
    3250   
    3351    requiredTech: function() {
    34         if (!this._template.Identity || !this._template.Identity.RequiredTechnology)
    35             return undefined;
    36         return this._template.Identity.RequiredTechnology;
     52        return this.get("Identity/RequiredTechnology");
    3753    },
    38                            
     54                         
    3955    available: function(gameState) {
    40         if (!this._template.Identity || !this._template.Identity.RequiredTechnology)
    41             return true;
    42         return gameState.isResearched(this._template.Identity.RequiredTechnology);
     56        return gameState.isResearched(this.get("Identity/RequiredTechnology"));
    4357    },
    44                            
     58                         
    4559    // specifically
    4660    phase: function() {
    47         if (!this._template.Identity || !this._template.Identity.RequiredTechnology)
     61        if (!this.get("Identity/RequiredTechnology"))
    4862            return 0;
    49         if (this.template.Identity.RequiredTechnology == "phase_village")
     63        if (this.get("Identity/RequiredTechnology") == "phase_village")
    5064            return 1;
    51         if (this.template.Identity.RequiredTechnology == "phase_town")
     65        if (this.get("Identity/RequiredTechnology") == "phase_town")
    5266            return 2;
    53         if (this.template.Identity.RequiredTechnology == "phase_city")
     67        if (this.get("Identity/RequiredTechnology") == "phase_city")
    5468            return 3;
    5569        return 0;
    5670    },
     
    7286    },
    7387
    7488    civ: function() {
    75         if (!this._template.Identity)
    76             return undefined;
    77         return this._template.Identity.Civ;
     89        return this.get("Identity/Civ");
    7890    },
    7991
    8092    cost: function() {
    81         if (!this._template.Cost)
     93        if (!this.get("Cost"))
    8294            return undefined;
    8395
    8496        var ret = {};
    85         for (var type in this._template.Cost.Resources)
    86             ret[type] = GetTechModifiedProperty(this._techModifications, this._template, "Cost/Resources/"+type, +this._template.Cost.Resources[type]);
     97        for (var type in this.get("Cost/Resources"))
     98            ret[type] = +this.get("Cost/Resources/" + type);
    8799        return ret;
    88100    },
    89101   
    90102    costSum: function() {
    91         if (!this._template.Cost)
     103        if (!this.get("Cost"))
    92104            return undefined;
    93105       
    94106        var ret = 0;
    95         for (var type in this._template.Cost.Resources)
    96             ret += +this._template.Cost.Resources[type];
     107        for (var type in this.get("Cost/Resources"))
     108            ret += +this.get("Cost/Resources/" + type);
    97109        return ret;
    98110    },
    99111
     
    102114     * obstruction shape, or undefined if no obstruction.
    103115     */
    104116    obstructionRadius: function() {
    105         if (!this._template.Obstruction)
     117        if (!this.get("Obstruction"))
    106118            return undefined;
    107119
    108         if (this._template.Obstruction.Static)
     120        if (this.get("Obstruction/Static"))
    109121        {
    110             var w = +this._template.Obstruction.Static["@width"];
    111             var h = +this._template.Obstruction.Static["@depth"];
     122            var w = +this.get("Obstruction/Static/@width");
     123            var h = +this.get("Obstruction/Static/@depth");
    112124            return Math.sqrt(w*w + h*h) / 2;
    113125        }
    114126
    115         if (this._template.Obstruction.Unit)
    116             return +this._template.Obstruction.Unit["@radius"];
     127        if (this.get("Obstruction/Unit"))
     128            return +this.get("Obstruction/Unit/@radius");
    117129
    118130        return 0; // this should never happen
    119131    },
    120                            
     132                         
    121133    /**
    122134     * Returns the radius of a circle surrounding this entity's
    123135     * footprint.
    124136     */
    125137    footprintRadius: function() {
    126         if (!this._template.Footprint)
     138        if (!this.get("Footprint"))
    127139            return undefined;
    128140       
    129         if (this._template.Footprint.Square)
     141        if (this.get("Footprint/Square"))
    130142        {
    131             var w = +this._template.Footprint.Square["@width"];
    132             var h = +this._template.Footprint.Square["@depth"];
     143            var w = +this.get("Footprint/Square/@width");
     144            var h = +this.get("Footprint/Square/@depth");
    133145            return Math.sqrt(w*w + h*h) / 2;
    134146        }
    135147       
    136         if (this._template.Footprint.Circle)
    137             return +this._template.Footprint.Circle["@radius"];
     148        if (this.get("Footprint/Circle"))
     149            return +this.get("Footprint/Circle/@radius");
    138150       
    139151        return 0; // this should never happen
    140152    },
    141153
    142154    maxHitpoints: function()
    143155    {
    144         if (this._template.Health !== undefined)
    145             return GetTechModifiedProperty(this._techModifications, this._template, "Health/Max",+this._template.Health.Max);
     156        if (this.get("Health") !== undefined)
     157            return +this.get("Health/Max");
    146158        return 0;
    147159    },
     160
    148161    isHealable: function()
    149162    {
    150         if (this._template.Health !== undefined)
    151             return this._template.Health.Unhealable !== "true";
     163        if (this.get("Health") !== undefined)
     164            return this.get("Health/Unhealable") !== "true";
    152165        return false;
    153166    },
     167
    154168    isRepairable: function()
    155169    {
    156         if (this._template.Health !== undefined)
    157             return this._template.Health.Repairable === "true";
     170        if (this.get("Health") !== undefined)
     171            return this.get("Health/Repairable") === "true";
    158172        return false;
    159173    },
    160174
    161175    getPopulationBonus: function() {
    162         if (!this._template.Cost || !this._template.Cost.PopulationBonus)
    163             return undefined;
    164         return this._template.Cost.PopulationBonus;
     176        return this.get("Cost/PopulationBonus");
    165177    },
    166178
    167179    armourStrengths: function() {
    168         if (!this._template.Armour)
     180        if (!this.get("Armour"))
    169181            return undefined;
    170182
    171183        return {
    172             hack: GetTechModifiedProperty(this._techModifications, this._template, "Armour/Hack", +this._template.Armour.Hack),
    173             pierce: GetTechModifiedProperty(this._techModifications, this._template, "Armour/Pierce", +this._template.Armour.Pierce),
    174             crush: GetTechModifiedProperty(this._techModifications, this._template, "Armour/Crush", +this._template.Armour.Crush)
     184            hack: +this.get("Armour/Hack"),
     185            pierce: +this.get("Armour/Pierce"),
     186            crush: +this.get("Armour/Crush")
    175187        };
    176188    },
    177189
    178190    attackTypes: function() {
    179         if (!this._template.Attack)
     191        if (!this.get("Attack"))
    180192            return undefined;
    181193
    182194        var ret = [];
    183         for (var type in this._template.Attack)
     195        for (var type in this.get("Attack"))
    184196            ret.push(type);
    185197
    186198        return ret;
    187199    },
    188200
    189201    attackRange: function(type) {
    190         if (!this._template.Attack || !this._template.Attack[type])
     202        if (!this.get("Attack/" + type +""))
    191203            return undefined;
    192204
    193205        return {
    194                 max: GetTechModifiedProperty(this._techModifications, this._template, "Attack/MaxRange", +this._template.Attack[type].MaxRange),
    195                 min: GetTechModifiedProperty(this._techModifications, this._template, "Attack/MinRange", +(this._template.Attack[type].MinRange || 0))
     206                max: +this.get("Attack/" + type +"/MaxRange"),
     207                min: +(this.get("Attack/" + type +"/MinRange") || 0)
    196208        };
    197209    },
    198210
    199211    attackStrengths: function(type) {
    200         if (!this._template.Attack || !this._template.Attack[type])
     212        if (!this.get("Attack/" + type +""))
    201213            return undefined;
    202214
    203215        return {
    204             hack: GetTechModifiedProperty(this._techModifications, this._template, "Attack/"+type+"/Hack", +(this._template.Attack[type].Hack || 0)),
    205             pierce: GetTechModifiedProperty(this._techModifications, this._template, "Attack/"+type+"/Pierce", +(this._template.Attack[type].Pierce || 0)),
    206             crush: GetTechModifiedProperty(this._techModifications, this._template, "Attack/"+type+"/Crush", +(this._template.Attack[type].Crush || 0))
     216            hack: +(this.get("Attack/" + type + "/Hack") || 0),
     217            pierce: +(this.get("Attack/" + type + "/Pierce") || 0),
     218            crush: +(this.get("Attack/" + type + "/Crush") || 0)
    207219        };
    208220    },
    209221   
    210222    attackTimes: function(type) {
    211         if (!this._template.Attack || !this._template.Attack[type])
     223        if (!this.get("Attack/" + type +""))
    212224            return undefined;
    213225
    214226        return {
    215             prepare: GetTechModifiedProperty(this._techModifications, this._template, "Attack/"+type+"/PrepareTime", +(this._template.Attack[type].PrepareTime || 0)),
    216             repeat: GetTechModifiedProperty(this._techModifications, this._template, "Attack/"+type+"/RepeatTime", +(this._template.Attack[type].RepeatTime || 1000))
     227            prepare: +(this.get("Attack/" + type + "/PrepareTime") || 0),
     228            repeat: +(this.get("Attack/" + type + "/RepeatTime") || 1000)
    217229        };
    218230    },
    219231
    220232    // returns the classes this templates counters:
    221     // Return type is [ [-neededClasses-] , multiplier ].
     233    // Return type is [ [-neededClasses- , multiplier], … ].
    222234    getCounteredClasses: function() {
    223         if (!this._template.Attack)
     235        if (!this.get("Attack"))
    224236            return undefined;
    225237       
    226238        var Classes = [];
    227         for (var i in this._template.Attack) {
    228             if (!this._template.Attack[i].Bonuses)
     239        for (var i in this.get("Attack")) {
     240            if (!this.get("Attack/" + i + "/Bonuses"))
    229241                continue;
    230             for (var o in this._template.Attack[i].Bonuses)
    231                 if (this._template.Attack[i].Bonuses[o].Classes)
    232                     Classes.push([this._template.Attack[i].Bonuses[o].Classes.split(" "), +this._template.Attack[i].Bonuses[o].Multiplier]);
     242            for (var o in this.get("Attack/" + i + "/Bonuses"))
     243                if (this.get("Attack/" + i + "/Bonuses/" + o + "/Classes"))
     244                    Classes.push([this.get("Attack/" + i +"/Bonuses/" + o +"/Classes").split(" "), +this.get("Attack/" + i +"/Bonuses" +o +"/Multiplier")]);
    233245        }
    234246        return Classes;
    235247    },
     
    237249    // returns true if the entity counters those classes.
    238250    // TODO: refine using the multiplier
    239251    countersClasses: function(classes) {
    240         if (!this._template.Attack)
     252        if (!this.get("Attack"))
    241253            return false;
    242254        var mcounter = [];
    243         for (var i in this._template.Attack) {
    244             if (!this._template.Attack[i].Bonuses)
     255        for (var i in this.get("Attack")) {
     256            if (!this.get("Attack/" + i + "/Bonuses"))
    245257                continue;
    246             for (var o in this._template.Attack[i].Bonuses)
    247                 if (this._template.Attack[i].Bonuses[o].Classes)
    248                     mcounter.concat(this._template.Attack[i].Bonuses[o].Classes.split(" "));
     258            for (var o in this.get("Attack/" + i + "/Bonuses"))
     259                if (this.get("Attack/" + i + "/Bonuses/" + o + "/Classes"))
     260                    mcounter.concat(this.get("Attack/" + i + "/Bonuses/" + o + "/Classes").split(" "));
    249261        }
    250262        for (var i in classes)
    251263        {
     
    257269
    258270    // returns, if it exists, the multiplier from each attack against a given class
    259271    getMultiplierAgainst: function(type, againstClass) {
    260         if (!this._template.Attack || !this._template.Attack[type])
     272        if (!this.get("Attack/" + type +""))
    261273            return undefined;
    262274
    263         if (this._template.Attack[type].Bonuses)
    264             for (var o in this._template.Attack[type].Bonuses) {
    265                 if (!this._template.Attack[type].Bonuses[o].Classes)
     275        if (this.get("Attack/" + type + "/Bonuses"))
     276            for (var o in this.get("Attack/" + type + "/Bonuses")) {
     277                if (!this.get("Attack/" + type + "/Bonuses/" + o + "/Classes"))
    266278                    continue;
    267                 var total = this._template.Attack[type].Bonuses[o].Classes.split(" ");
     279                var total = this.get("Attack/" + type + "/Bonuses/" + o + "/Classes").split(" ");
    268280                for (var j in total)
    269281                    if (total[j] === againstClass)
    270                         return this._template.Attack[type].Bonuses[o].Multiplier;
     282                        return this.get("Attack/" + type + "/Bonuses/" + o + "/Multiplier");
    271283            }
    272284        return 1;
    273285    },
    274286
    275287    // returns true if the entity can attack the given class
    276288    canAttackClass: function(saidClass) {
    277         if (!this._template.Attack)
     289        if (!this.get("Attack"))
    278290            return false;
    279291       
    280         for (var i in this._template.Attack) {
    281             if (!this._template.Attack[i].RestrictedClasses || !this._template.Attack[i].RestrictedClasses._string)
     292        for (var i in this.get("Attack")) {
     293            if (!this.get("Attack/" + i + "/RestrictedClasses") || !this.get("Attack/" + i + "/RestrictedClasses/_string"))
    282294                continue;
    283             var cannotAttack = this._template.Attack[i].RestrictedClasses._string.split(" ");
     295            var cannotAttack = this.get("Attack/" + i + "/RestrictedClasses/_string").split(" ");
    284296            if (cannotAttack.indexOf(saidClass) !== -1)
    285297                return false;
    286298        }
     
    288300    },
    289301
    290302    buildableEntities: function() {
    291         if (!this._template.Builder)
    292             return undefined;
    293         if (!this._template.Builder.Entities._string)
     303        if (!this.get("Builder/Entities/_string"))
    294304            return [];
    295305        var civ = this.civ();
    296         var templates = this._template.Builder.Entities._string.replace(/\{civ\}/g, civ).split(/\s+/);
     306        var templates = this.get("Builder/Entities/_string").replace(/\{civ\}/g, civ).split(/\s+/);
    297307        return templates; // TODO: map to Entity?
    298308    },
    299309
    300310    trainableEntities: function() {
    301         if (!this._template.ProductionQueue || !this._template.ProductionQueue.Entities || !this._template.ProductionQueue.Entities._string)
     311        if (!this.get("ProductionQueue/Entities/_string"))
    302312            return undefined;
    303313        var civ = this.civ();
    304         var templates = this._template.ProductionQueue.Entities._string.replace(/\{civ\}/g, civ).split(/\s+/);
     314        var templates = this.get("ProductionQueue/Entities/_string").replace(/\{civ\}/g, civ).split(/\s+/);
    305315        return templates;
    306316    },
    307317
    308318    researchableTechs: function() {
    309         if (!this._template.ProductionQueue || !this._template.ProductionQueue.Technologies || !this._template.ProductionQueue.Technologies._string)
     319        if (!this.get("ProductionQueue/Technologies/_string"))
    310320            return undefined;
    311         var templates = this._template.ProductionQueue.Technologies._string.split(/\s+/);
     321        var templates = this.get("ProductionQueue/Technologies/_string").split(/\s+/);
    312322        return templates;
    313323    },
    314324
    315325    resourceSupplyType: function() {
    316         if (!this._template.ResourceSupply)
     326        if (!this.get("ResourceSupply"))
    317327            return undefined;
    318         var [type, subtype] = this._template.ResourceSupply.Type.split('.');
     328        var [type, subtype] = this.get("ResourceSupply/Type").split('.');
    319329        return { "generic": type, "specific": subtype };
    320330    },
    321331    // will return either "food", "wood", "stone", "metal" and not treasure.
    322332    getResourceType: function() {
    323         if (!this._template.ResourceSupply)
     333        if (!this.get("ResourceSupply"))
    324334            return undefined;
    325         var [type, subtype] = this._template.ResourceSupply.Type.split('.');
     335        var [type, subtype] = this.get("ResourceSupply/Type").split('.');
    326336        if (type == "treasure")
    327337            return subtype;
    328338        return type;
    329339    },
    330340
    331341    resourceSupplyMax: function() {
    332         if (!this._template.ResourceSupply)
     342        if (!this.get("ResourceSupply"))
    333343            return undefined;
    334         return +this._template.ResourceSupply.Amount;
     344        return +this.get("ResourceSupply/Amount");
    335345    },
    336346
    337347    maxGatherers: function()
    338348    {
    339         if (this._template.ResourceSupply !== undefined)
    340             return +this._template.ResourceSupply.MaxGatherers;
     349        if (this.get("ResourceSupply") !== undefined)
     350            return +this.get("ResourceSupply/MaxGatherers");
    341351        return 0;
    342352    },
    343353   
    344354    resourceGatherRates: function() {
    345         if (!this._template.ResourceGatherer)
     355        if (!this.get("ResourceGatherer"))
    346356            return undefined;
    347357        var ret = {};
    348         var baseSpeed = GetTechModifiedProperty(this._techModifications, this._template, "ResourceGatherer/BaseSpeed", +this._template.ResourceGatherer.BaseSpeed);
    349         for (var r in this._template.ResourceGatherer.Rates)
    350             ret[r] = GetTechModifiedProperty(this._techModifications, this._template, "ResourceGatherer/Rates/"+r, +this._template.ResourceGatherer.Rates[r]) * baseSpeed;
     358        var baseSpeed = +this.get("ResourceGatherer/BaseSpeed");
     359        for (var r in this.get("ResourceGatherer/Rates"))
     360            ret[r] = +this.get("ResourceGatherer/Rates/" + r) * baseSpeed;
    351361        return ret;
    352362    },
    353363
    354364    resourceDropsiteTypes: function() {
    355         if (!this._template.ResourceDropsite)
     365        if (!this.get("ResourceDropsite"))
    356366            return undefined;
    357         return this._template.ResourceDropsite.Types.split(/\s+/);
     367        return this.get("ResourceDropsite/Types").split(/\s+/);
    358368    },
    359369
    360370
    361371    garrisonableClasses: function() {
    362         if (!this._template.GarrisonHolder || !this._template.GarrisonHolder.List._string)
     372        if (!this.get("GarrisonHolder") || !this.get("GarrisonHolder/List/_string"))
    363373            return undefined;
    364         return this._template.GarrisonHolder.List._string.split(/\s+/);
     374        return this.get("GarrisonHolder/List/_string").split(/\s+/);
    365375    },
    366376
    367377    garrisonMax: function() {
    368         if (!this._template.GarrisonHolder)
     378        if (!this.get("GarrisonHolder"))
    369379            return undefined;
    370         return this._template.GarrisonHolder.Max;
     380        return this.get("GarrisonHolder/Max");
    371381    },
    372382   
    373383    /**
     
    375385     * (Any non domestic currently.)
    376386     */
    377387    isUnhuntable: function() {
    378         if (!this._template.UnitAI || !this._template.UnitAI.NaturalBehaviour)
     388        if (!this.get("UnitAI") || !this.get("UnitAI/NaturalBehaviour"))
    379389            return false;
    380390
    381391        // only attack domestic animals since they won't flee nor retaliate.
    382         return this._template.UnitAI.NaturalBehaviour !== "domestic";
     392        return this.get("UnitAI/NaturalBehaviour") !== "domestic";
    383393    },
    384                            
     394                         
    385395    walkSpeed: function() {
    386         if (!this._template.UnitMotion || !this._template.UnitMotion.WalkSpeed)
     396        if (!this.get("UnitMotion") || !this.get("UnitMotion/WalkSpeed"))
    387397             return undefined;
    388         return this._template.UnitMotion.WalkSpeed;
     398        return this.get("UnitMotion/WalkSpeed");
    389399    },
    390400
    391401    buildCategory: function() {
    392         if (!this._template.BuildRestrictions || !this._template.BuildRestrictions.Category)
     402        if (!this.get("BuildRestrictions") || !this.get("BuildRestrictions/Category"))
    393403            return undefined;
    394         return this._template.BuildRestrictions.Category;
     404        return this.get("BuildRestrictions/Category");
    395405    },
    396406   
    397407    buildTime: function() {
    398         if (!this._template.Cost || !this._template.Cost.BuildTime)
     408        if (!this.get("Cost") || !this.get("Cost/BuildTime"))
    399409            return undefined;
    400         return this._template.Cost.BuildTime;
     410        return this.get("Cost/BuildTime");
    401411    },
    402412
    403413    buildDistance: function() {
    404         if (!this._template.BuildRestrictions || !this._template.BuildRestrictions.Distance)
     414        if (!this.get("BuildRestrictions") || !this.get("BuildRestrictions/Distance"))
    405415            return undefined;
    406         return this._template.BuildRestrictions.Distance;
     416        return this.get("BuildRestrictions/Distance");
    407417    },
    408418
    409419    buildPlacementType: function() {
    410         if (!this._template.BuildRestrictions || !this._template.BuildRestrictions.PlacementType)
     420        if (!this.get("BuildRestrictions") || !this.get("BuildRestrictions/PlacementType"))
    411421            return undefined;
    412         return this._template.BuildRestrictions.PlacementType;
     422        return this.get("BuildRestrictions/PlacementType");
    413423    },
    414424
    415425    buildTerritories: function() {
    416         if (!this._template.BuildRestrictions || !this._template.BuildRestrictions.Territory)
     426        if (!this.get("BuildRestrictions") || !this.get("BuildRestrictions/Territory"))
    417427            return undefined;
    418         return this._template.BuildRestrictions.Territory.split(/\s+/);
     428        return this.get("BuildRestrictions/Territory").split(/\s+/);
    419429    },
    420430
    421431    hasBuildTerritory: function(territory) {
     
    424434    },
    425435
    426436    hasTerritoryInfluence: function() {
    427         return (this._template.TerritoryInfluence !== undefined);
     437        return (this.get("TerritoryInfluence") !== undefined);
    428438    },
    429439
    430440    territoryInfluenceRadius: function() {
    431         if (this._template.TerritoryInfluence !== undefined)
    432             return (this._template.TerritoryInfluence.Radius);
     441        if (this.get("TerritoryInfluence") !== undefined)
     442            return (this.get("TerritoryInfluence/Radius"));
    433443        else
    434444            return -1;
    435445    },
    436446
    437447    territoryInfluenceWeight: function() {
    438         if (this._template.TerritoryInfluence !== undefined)
    439             return (this._template.TerritoryInfluence.Weight);
     448        if (this.get("TerritoryInfluence") !== undefined)
     449            return (this.get("TerritoryInfluence/Weight"));
    440450        else
    441451            return -1;
    442452    },
    443453
    444454    visionRange: function() {
    445         if (!this._template.Vision)
    446             return undefined;
    447         return this._template.Vision.Range;
     455        return this.get("Vision/Range");
    448456    }
    449457});
    450458
    451459
    452 
     460// defines an entity, with a super Template.
     461// also redefines several of the template functions where the only change is applying aura and tech modifications.
    453462m.Entity = m.Class({
    454     _super: m.EntityTemplate,
     463    _super: m.Template,
    455464
    456465    _init: function(sharedAI, entity)
    457466    {
    458         this._super.call(this, sharedAI.GetTemplate(entity.template), sharedAI._techModifications[entity.owner]);
     467        this._super.call(this, sharedAI.GetTemplate(entity.template));
    459468
    460         this._ai = sharedAI;
    461469        this._templateName = entity.template;
    462470        this._entity = entity;
     471        this._auraTemplateModif = {};   // template modification from auras. this is only for this entity.
     472        this._ai = sharedAI;
     473        if (!sharedAI._techModifications[entity.owner][this._templateName])
     474            sharedAI._techModifications[entity.owner][this._templateName] = {};
     475        this._techModif = sharedAI._techModifications[entity.owner][this._templateName]; // save a reference to the template tech modifications
    463476    },
    464477
    465478    toString: function() {
     
    477490    /**
    478491     * Returns extra data that the AI scripts have associated with this entity,
    479492     * for arbitrary local annotations.
    480      * (This data is not shared with any other AI scripts.)
     493     * (This data should not be shared with any other AI scripts.)
    481494     */
    482495    getMetadata: function(player, key) {
    483496        return this._ai.getMetadata(player, this, key);
     
    493506    deleteAllMetadata: function(player) {
    494507        delete this._ai._entityMetadata[player][this.id()];
    495508    },
    496                    
     509                 
    497510    deleteMetadata: function(player, key) {
    498511        this._ai.deleteMetadata(player, this, key);
    499512    },
     
    508521   
    509522    unitAIState: function() { return this._entity.unitAIState; },
    510523    unitAIOrderData: function() { return this._entity.unitAIOrderData; },
    511     hitpoints: function() { if (this._entity.hitpoints !== undefined) return this._entity.hitpoints; return undefined; },
     524   
     525    hitpoints: function() {if (this._entity.hitpoints !== undefined) return this._entity.hitpoints; return undefined; },
    512526    isHurt: function() { return this.hitpoints() < this.maxHitpoints(); },
    513527    healthLevel: function() { return (this.hitpoints() / this.maxHitpoints()); },
    514528    needsHeal: function() { return this.isHurt() && this.isHealable(); },
     
    540554    owner: function() {
    541555        return this._entity.owner;
    542556    },
     557
    543558    isOwn: function(player) {
    544559        if (typeof(this._entity.owner) === "undefined")
    545560            return false;
    546561        return this._entity.owner === player;
    547562    },
     563   
    548564    isFriendly: function(player) {
    549565        return this.isOwn(player); // TODO: diplomacy
    550566    },
     567   
    551568    isEnemy: function(player) {
    552569        return !this.isOwn(player); // TODO: diplomacy
    553570    },
     
    557574            return undefined;
    558575        return this._entity.resourceSupplyAmount;
    559576    },
    560                    
     577                 
    561578    resourceSupplyGatherers: function(player)
    562579    {
    563580        if (this._entity.resourceSupplyGatherers !== undefined)
    564             return this._entity.resourceSupplyGatherers[player-1];
     581            return this._entity.resourceSupplyGatherers[player];
    565582        return [];
    566583    },
    567                    
     584                 
    568585    isFull: function(player)
    569586    {
    570587        if (this._entity.resourceSupplyGatherers !== undefined)
    571             return (this.maxGatherers() === this._entity.resourceSupplyGatherers[player-1].length);
     588            return (this.maxGatherers() === this._entity.resourceSupplyGatherers[player].length);
    572589
    573590        return undefined;
    574591    },
     
    578595            return undefined;
    579596        return this._entity.resourceCarrying;
    580597    },
    581                    
     598                 
    582599    currentGatherRate: function() {
    583600        // returns the gather rate for the current target if applicable.
    584         if (!this._template.ResourceGatherer)
     601        if (!this.get("ResourceGatherer"));
    585602            return undefined;
    586603       
    587604        if (this.unitAIOrderData().length &&
     
    599616           
    600617            var type = ress.resourceSupplyType();
    601618            var tstring = type.generic + "." + type.specific;
    602                    
     619                 
    603620            if (type.generic == "treasure")
    604621                return 1000;
    605622               
    606             var speed = GetTechModifiedProperty(this._techModifications, this._template, "ResourceGatherer/BaseSpeed", +this._template.ResourceGatherer.BaseSpeed);
    607             speed *= GetTechModifiedProperty(this._techModifications, this._template, "ResourceGatherer/Rates/"+tstring, +this._template.ResourceGatherer.Rates[tstring]);
    608                    
     623            var speed = +this.get("ResourceGatherer/BaseSpeed");
     624            speed *= +this.get("ResourceGatherer/Rates/" +tstring);
     625                 
    609626            if (speed)
    610627                return speed;
    611628            return 0;
     
    644661    },
    645662
    646663    unload: function(id) {
    647         if (!this._template.GarrisonHolder)
     664        if (!this.get("GarrisonHolder"))
    648665            return undefined;
    649666        Engine.PostCommand(PlayerID,{"type": "unload", "garrisonHolder": this.id(), "entities": [id]});
    650667        return this;
     
    652669
    653670    // Unloads all owned units, don't unload allies
    654671    unloadAll: function() {
    655         if (!this._template.GarrisonHolder)
     672        if (!this.get("GarrisonHolder"))
    656673            return undefined;
    657674        Engine.PostCommand(PlayerID,{"type": "unload-all-own", "garrisonHolders": [this.id()]});
    658675        return this;
     
    751768        });
    752769        return this;
    753770    },
    754                    
     771                 
    755772     research: function(template) {
    756773        Engine.PostCommand(PlayerID,{ "type": "research", "entity": this.id(), "template": template });
    757774        return this;
  • Users/Lancelot/Desktop/0ad-svn/trunk/binaries/data/mods/public/simulation/ai/common-api/gamestate.js

     
    126126    if (!this.templates[type])
    127127        return null;
    128128   
    129     return new m.EntityTemplate(this.templates[type], this.techModifications);
     129    return new m.Template(this.templates[type], this.techModifications);
    130130};
    131131
    132132m.GameState.prototype.applyCiv = function(str) {
  • Users/Lancelot/Desktop/0ad-svn/trunk/binaries/data/mods/public/simulation/ai/common-api/shared.js

     
    5858// Components that will be disabled in foundation entity templates.
    5959// (This is a bit yucky and fragile since it's the inverse of
    6060// CCmpTemplateManager::CopyFoundationSubset and only includes components
    61 // that our EntityTemplate class currently uses.)
     61// that our Template class currently uses.)
    6262m.g_FoundationForbiddenComponents = {
    6363    "ProductionQueue": 1,
    6464    "ResourceSupply": 1,
     
    119119// We need to now the initial state of the game for this, as we will use it.
    120120// This is called right at the end of the map generation.
    121121m.SharedScript.prototype.init = function(state) {
     122    this.ApplyTemplatesDelta(state);
     123
    122124    this.passabilityClasses = state.passabilityClasses;
    123125    this.passabilityMap = state.passabilityMap;
    124126    this.players = this._players;
     
    127129    this.timeElapsed = state.timeElapsed;
    128130    this.barterPrices = state.barterPrices;
    129131
    130     for (var o in state.players)
    131         this._techModifications[o] = state.players[o].techModifications;
    132    
    133132    this._entities = {};
    134133    for (var id in state.entities)
    135134        this._entities[id] = new m.Entity(this, state.entities[id]);
     
    166165        return;
    167166    // deals with updating based on create and destroy messages.
    168167    this.ApplyEntitiesDelta(state);
     168    this.ApplyTemplatesDelta(state);
    169169
    170170    Engine.ProfileStart("onUpdate");
    171171
     
    178178    this.timeElapsed = state.timeElapsed;
    179179    this.barterPrices = state.barterPrices;
    180180   
    181     for (var o in state.players)
    182         this._techModifications[o] = state.players[o].techModifications;
    183 
    184181    for (var i in this.gameState)
    185182        this.gameState[i].update(this,state);
    186183
     
    313310            this.updateEntityCollections(prop, this._entities[id]);
    314311        }
    315312    }
     313
     314    // apply per-entity aura-related changes.
     315    // this supersedes tech-related changes.
     316    for (var id in state.changedEntityTemplateInfo)
     317    {
     318        var changes = state.changedEntityTemplateInfo[id];
     319        for each (var change in changes)
     320            this._entities[id]._auraTemplateModif[change.variable] = change.value;
     321    }
    316322    Engine.ProfileStop();
    317323};
    318324
     325m.SharedScript.prototype.ApplyTemplatesDelta = function(state)
     326{
     327    Engine.ProfileStart("Shared ApplyTemplatesDelta");
     328
     329    for (var player in state.changedTemplateInfo)
     330    {
     331        var playerDiff = state.changedTemplateInfo[player];
     332        for (var template in playerDiff)
     333        {
     334            var changes = playerDiff[template];
     335            if (!this._techModifications[player][template])
     336                this._techModifications[player][template] = {};
     337            for each (var change in changes)
     338                this._techModifications[player][template][change.variable] = change.value;
     339        }
     340    }
     341    Engine.ProfileStop();
     342};
     343
     344m.SharedScript.prototype.registerUpdatingEntityCollection = function(entCollection, noPush)
     345{
     346    if (!noPush) {
     347        this._entityCollections.push(entCollection);
     348    }
     349    entCollection.setUID(this._entityCollectionsUID);
     350    for each (var prop in entCollection.dynamicProperties())
     351    {
     352        this._entityCollectionsByDynProp[prop] = this._entityCollectionsByDynProp[prop] || [];
     353        this._entityCollectionsByDynProp[prop].push(entCollection);
     354    }
     355    this._entityCollectionsUID++;
     356};
     357
     358m.SharedScript.prototype.removeUpdatingEntityCollection = function(entCollection)
     359{
     360    for (var i in this._entityCollections)
     361    {
     362        if (this._entityCollections[i].getUID() === entCollection.getUID())
     363        {
     364            this._entityCollections.splice(i, 1);
     365        }
     366    }
     367   
     368    for each (var prop in entCollection.dynamicProperties())
     369    {
     370        for (var i in this._entityCollectionsByDynProp[prop])
     371        {
     372            if (this._entityCollectionsByDynProp[prop][i].getUID() === entCollection.getUID())
     373            {
     374                this._entityCollectionsByDynProp[prop].splice(i, 1);
     375            }
     376        }
     377    }
     378};
    319379m.SharedScript.prototype.registerUpdatingEntityCollection = function(entCollection, noPush)
    320380{
    321381    if (!noPush) {
  • Users/Lancelot/Desktop/0ad-svn/trunk/binaries/data/mods/public/simulation/components/AIInterface.js

     
    1818    this.events["OwnershipChanged"] = [];
    1919
    2020    this.changedEntities = {};
     21
     22    // cache for technology changes;
     23    // this one is PlayerID->TemplateName->{StringForTheValue, ActualValue}
     24    this.changedTemplateInfo = {};
     25    // this is for auras and is EntityID->{StringForTheValue, ActualValue}
     26    this.changedEntityTemplateInfo = {};
    2127};
    2228
    23 AIInterface.prototype.GetRepresentation = function()
     29AIInterface.prototype.GetNonEntityRepresentation = function()
    2430{
    2531    var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
    26 
     32   
    2733    // Return the same game state as the GUI uses
    2834    var state = cmpGuiInterface.GetExtendedSimulationState(-1);
    29 
     35   
    3036    // Add some extra AI-specific data
    3137    state.events = {};
    3238    state.events["Create"] = this.events["Create"];
     
    3945    state.events["PlayerDefeated"] = this.events["PlayerDefeated"];
    4046    state.events["EntityRenamed"] = this.events["EntityRenamed"];
    4147    state.events["OwnershipChanged"] = this.events["OwnershipChanged"];
    42 
    4348    // Reset the event list for the next turn
    4449    this.events["Create"] = [];
    4550    this.events["Destroy"] = [];
     
    5156    this.events["PlayerDefeated"] = [];
    5257    this.events["EntityRenamed"] = [];
    5358    this.events["OwnershipChanged"] = [];
    54    
     59
     60    return state;
     61}
     62
     63AIInterface.prototype.GetRepresentation = function()
     64{
     65    var state = this.GetNonEntityRepresentation();
     66
    5567    // Add entity representations
    5668    Engine.ProfileStart("proxy representations");
    5769    state.entities = {};
     
    6476    this.changedEntities = {};
    6577    Engine.ProfileStop();
    6678
     79    state.changedTemplateInfo = this.changedTemplateInfo;
     80    this.changedTemplateInfo = {};
     81    state.changedEntityTemplateInfo = this.changedEntityTemplateInfo;
     82    this.changedEntityTemplateInfo = {};
     83
    6784    return state;
    6885};
     86
    6987// Intended to be called first, during the map initialization: no caching
    7088AIInterface.prototype.GetFullRepresentation = function(flushEvents)
    71 {
    72     var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
    73    
    74     // Return the same game state as the GUI uses
    75     var state = cmpGuiInterface.GetExtendedSimulationState(-1);
    76    
    77     // Add some extra AI-specific data
    78     state.events = {};
    79     state.events["Create"] = this.events["Create"];
    80     state.events["Destroy"] = this.events["Destroy"];
    81     state.events["Attacked"] = this.events["Attacked"];
    82     state.events["RangeUpdate"] = this.events["RangeUpdate"];
    83     state.events["ConstructionFinished"] = this.events["ConstructionFinished"];
    84     state.events["TrainingFinished"] = this.events["TrainingFinished"];
    85     state.events["AIMetadata"] = this.events["AIMetadata"];
    86     state.events["PlayerDefeated"] = this.events["PlayerDefeated"];
    87     state.events["EntityRenamed"] = this.events["EntityRenamed"];
    88     state.events["OwnershipChanged"] = this.events["OwnershipChanged"];
    89    
     89{   
     90    var state = this.GetNonEntityRepresentation();
    9091
    9192    if (flushEvents)
    9293    {
     
    102103        state.events["OwnershipChanged"] = [];
    103104    }
    104105
    105     // Reset the event list for the next turn
    106     this.events["Create"] = [];
    107     this.events["Destroy"] = [];
    108     this.events["Attacked"] = [];
    109     this.events["RangeUpdate"] = [];
    110     this.events["ConstructionFinished"] = [];
    111     this.events["TrainingFinished"] = [];
    112     this.events["AIMetadata"] = [];
    113     this.events["PlayerDefeated"] = [];
    114     this.events["EntityRenamed"] = [];
    115     this.events["OwnershipChanged"] = [];
    116 
    117 
    118106    // Add entity representations
    119107    Engine.ProfileStart("proxy representations");
    120108    state.entities = {};
     
    127115    }
    128116    Engine.ProfileStop();
    129117   
     118    state.changedTemplateInfo = this.changedTemplateInfo;
     119    this.changedTemplateInfo = {};
     120    state.changedEntityTemplateInfo = this.changedEntityTemplateInfo;
     121    this.changedEntityTemplateInfo = {};
     122
    130123    return state;
    131124};
    132125
     
    156149    this.events["EntityRenamed"].push(msg);
    157150};
    158151
     152// When a new technology is researched, check which templates it affects,
     153// and send the updated values to the AI.
     154// this relies on the fact that any "value" in a technology can only ever change
     155// one template value, and that the naming is the same (with / in place of .)
     156// it's not incredibly fast but it's not incredibly slow.
     157AIInterface.prototype.OnValueModification = function(msg)
     158{
     159    var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     160    if (!this.templates)
     161        this.templates = cmpTemplateManager.FindAllTemplates(false);
     162    for (var o = 0; o < this.templates.length; ++o)
     163    {
     164        var tmp = this.templates[o];
     165        var template = cmpTemplateManager.GetTemplateWithoutValidation(this.templates[o]);
     166        // remove templates that we obviously don't care about.
     167        if (!template || !template.Identity || ! template.Identity.Civ)
     168        {
     169            this.templates.splice(o--,1);
     170            continue;
     171        }
     172        for each (var value in msg.valueNames)
     173        {
     174            // let's get the base template value.
     175            var strings = value.split("/");
     176            var item = template;
     177            var ended = true;
     178            for (var i = 0; i < strings.length; ++i)
     179            {
     180                if (item !== undefined && item[strings[i]] !== undefined)
     181                    item = item[strings[i]];
     182                else
     183                    ended = false;
     184            }
     185            if (!ended)
     186                continue;
     187            // item now contains the template value for this.
     188            var newValue = ApplyValueModificationsToTemplate(value, +item, msg.player, template);
     189            newValue = typeof(newValue) === "Number" ? Math.round(newValue) : newValue;
     190            if(item != newValue)
     191            {
     192                if (!this.changedTemplateInfo[msg.player])
     193                    this.changedTemplateInfo[msg.player] = {};
     194                if (!this.changedTemplateInfo[msg.player][this.templates[o]])
     195                    this.changedTemplateInfo[msg.player][this.templates[o]] = [ { "variable" : value, "value" : newValue} ];
     196                else
     197                    this.changedTemplateInfo[msg.player][this.templates[o]].push({ "variable" : value, "value" : newValue });
     198            }
     199        }
     200    }
     201};
     202
     203AIInterface.prototype.AuraChange = function(msg, ent)
     204{
     205    var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
     206    var template = cmpTemplateManager.GetTemplateWithoutValidation(cmpTemplateManager.GetCurrentTemplateName(ent));
     207    for each (var value in msg.valueNames)
     208    {
     209        // let's get the base template value.
     210        var strings = value.split("/");
     211        var item = template;
     212        var ended = true;
     213        for (var i = 0; i < strings.length; ++i)
     214        {
     215            if (item !== undefined && item[strings[i]] !== undefined)
     216                item = item[strings[i]];
     217            else
     218                ended = false;
     219        }
     220        if (!ended)
     221            continue;
     222        // "item" now contains the unmodified template value for this.
     223        var newValue = ApplyValueModificationsToEntity(value, +item, ent);
     224        newValue = typeof(newValue) === "Number" ? Math.round(newValue) : newValue;
     225        if(item != newValue)
     226        {
     227            if (!this.changedEntityTemplateInfo[ent])
     228                this.changedEntityTemplateInfo[ent] = [{ "variable" : value, "value" : newValue }];
     229            else
     230                this.changedEntityTemplateInfo[ent].push({ "variable" : value, "value" : newValue });
     231        }
     232    }
     233};
     234
    159235Engine.RegisterComponentType(IID_AIInterface, "AIInterface", AIInterface);
  • Users/Lancelot/Desktop/0ad-svn/trunk/binaries/data/mods/public/simulation/components/AIProxy.js

     
    3636    this.needsFullGet = true;
    3737    this.owner = -1;    // for convenience now and then.
    3838   
     39    this.cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
     40
    3941    // Let the AIInterface know that we exist and that it should query us
    4042    this.NotifyChange();
    4143};
     
    6769    if (!this.changes)
    6870    {
    6971        this.changes = {};
    70 
    71         var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
    72         cmpAIInterface.ChangedEntity(this.entity);
     72    this.cmpAIInterface.ChangedEntity(this.entity);
    7373    }
    7474};
    7575
     
    261261   
    262262    if (msg.from === -1)
    263263    {
    264         var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
    265         cmpAIInterface.PushEvent("Create", {"entity" : msg.entity});
     264        this.cmpAIInterface.PushEvent("Create", {"entity" : msg.entity});
    266265        return;
    267266    } else if (msg.to === -1)
    268267    {
    269         var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
    270         cmpAIInterface.PushEvent("Destroy", {"entity" : msg.entity});
     268        this.cmpAIInterface.PushEvent("Destroy", {"entity" : msg.entity});
    271269        return;
    272270    }
    273271   
    274272    this.owner = msg.to;
    275273    this.changes.owner = msg.to;
    276274   
    277     var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
    278     cmpAIInterface.PushEvent("OwnershipChanged", msg);
     275this.cmpAIInterface.PushEvent("OwnershipChanged", msg);
    279276};
    280277
    281278AIProxy.prototype.OnAttacked = function(msg)
    282279{
    283     var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
    284     cmpAIInterface.PushEvent("Attacked", msg);
     280this.cmpAIInterface.PushEvent("Attacked", msg);
    285281};
    286282
    287283/*
    288284 Deactivated for actually not really being practical for most uses.
    289285 AIProxy.prototype.OnRangeUpdate = function(msg)
    290286{
    291     var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
    292287    msg.owner = this.owner;
    293     cmpAIInterface.PushEvent("RangeUpdate", msg);
     288this.cmpAIInterface.PushEvent("RangeUpdate", msg);
    294289    warn(uneval(msg));
    295290};*/
    296291
    297292AIProxy.prototype.OnConstructionFinished = function(msg)
    298293{
    299     var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
    300     cmpAIInterface.PushEvent("ConstructionFinished", msg);
     294    this.cmpAIInterface.PushEvent("ConstructionFinished", msg);
    301295};
    302296
    303297AIProxy.prototype.OnTrainingFinished = function(msg)
    304298{
    305     var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
    306     cmpAIInterface.PushEvent("TrainingFinished", msg);
     299    this.cmpAIInterface.PushEvent("TrainingFinished", msg);
    307300};
    308301
    309302AIProxy.prototype.OnAIMetadata = function(msg)
    310303{
    311     var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
    312     cmpAIInterface.PushEvent("AIMetadata", msg);
     304    this.cmpAIInterface.PushEvent("AIMetadata", msg);
     305};
     306
     307AIProxy.prototype.OnAI_AuraChange = function(msg)
     308{
     309    this.cmpAIInterface.AuraChange(msg, this.entity);
    313310};
    314311
    315312Engine.RegisterComponentType(IID_AIProxy, "AIProxy", AIProxy);
  • Users/Lancelot/Desktop/0ad-svn/trunk/binaries/data/mods/public/simulation/components/AuraManager.js

     
    4646        this.modificationsCache[value][ent].add += data.add;
    4747
    4848    // post message to the entity to notify it about the change
    49     Engine.PostMessage(ent, MT_ValueModification, { "component": value.split("/")[0] });
     49    Engine.PostMessage(ent, MT_AI_AuraChange, { "valueNames": [value] });
     50    Engine.PostMessage(ent, MT_ValueModification, { "player": 0, "component": value.split("/")[0], "valueNames": [value] });
    5051};
    5152
    5253AuraManager.prototype.ApplyTemplateBonus = function(value, player, classes, data, key)
     
    9899        this.modificationsCache[value][ent].multiply /= data.multiply;
    99100
    100101    // post message to the entity to notify it about the change
    101     Engine.PostMessage(ent, MT_ValueModification, { "component": value.split("/")[0] });
     102    var effects = {};
     103    effects[value] = this.modificationsCache[value][ent];
     104    Engine.PostMessage(ent, MT_AI_AuraChange, { "valueNames": [value] });
     105    Engine.PostMessage(ent, MT_ValueModification, { "player": Engine.QueryInterface(ent, IID_Ownership).GetOwner(), "component": value.split("/")[0], "valueNames": [value] });
    102106};
    103107
    104108AuraManager.prototype.RemoveTemplateBonus = function(value, player, classes, key)
  • Users/Lancelot/Desktop/0ad-svn/trunk/binaries/data/mods/public/simulation/components/GuiInterface.js

     
    9797            "entityLimits": cmpPlayerEntityLimits.GetLimits(),
    9898            "entityCounts": cmpPlayerEntityLimits.GetCounts(),
    9999            "entityLimitChangers": cmpPlayerEntityLimits.GetLimitChangers(),
    100             "techModifications": cmpTechnologyManager.GetTechModifications(),
    101100            "researchQueued": cmpTechnologyManager.GetQueuedResearch(),
    102101            "researchStarted": cmpTechnologyManager.GetStartedResearch(),
    103102            "researchedTechs": cmpTechnologyManager.GetResearchedTechs(),
     
    475474    {
    476475        ret.armour = {
    477476            "hack": ApplyValueModificationsToTemplate("Armour/Hack", +template.Armour.Hack, player, template),
    478             "pierce": ApplyValueModificationsToTemplate("Armour/Pierce", +template.Armour.Hack, player, template),
    479             "crush": ApplyValueModificationsToTemplate("Armour/Crush", +template.Armour.Hack, player, template),
     477            "pierce": ApplyValueModificationsToTemplate("Armour/Pierce", +template.Armour.Pierce, player, template),
     478            "crush": ApplyValueModificationsToTemplate("Armour/Crush", +template.Armour.Crush, player, template),
    480479        };
    481480    }
    482481   
  • Users/Lancelot/Desktop/0ad-svn/trunk/binaries/data/mods/public/simulation/components/TechnologyManager.js

     
    226226                var modifications = this.modifications[name];
    227227                var component = name.split("/")[0];
    228228                for (var i in modifications)
    229                     if (!modifiedComponents[component] && DoesModificationApply(modifications[i], classes))
    230                         modifiedComponents[component] = true;
     229                    if (DoesModificationApply(modifications[i], classes))
     230                    {
     231                        if (!modifiedComponents[component])
     232                            modifiedComponents[component] = [];
     233                        modifiedComponents[component].push(name);
     234                    }
    231235            }
    232236
    233237            // Send mesage(s) to the entity so it knows about researched techs
    234238            for (var component in modifiedComponents)
    235                 Engine.PostMessage(msg.entity, MT_ValueModification, { "component": component });
     239                Engine.PostMessage(msg.entity, MT_ValueModification, { "player": playerID, "component": component, "valueNames": modifiedComponents[component] });
    236240        }
    237241    }
    238242    if (msg.from == playerID)
     
    322326                    mod[j] = modification[j];
    323327           
    324328            this.modifications[modification.value].push(mod);
    325             modifiedComponents[modification.value.split("/")[0]] = true;
     329            var component = modification.value.split("/")[0];
     330            if (!modifiedComponents[component])
     331                modifiedComponents[component] = [];
     332            modifiedComponents[component].push(modification.value);
    326333            this.modificationCache[modification.value] = {};
    327334        }
    328335    }
    329336   
    330337    this.UpdateAutoResearch();
    331338   
     339
     340    var player = +(+this.entity - 2);
     341    // it appears that this.entity - 2 = playerID
     342    // now this is just ugly but because of below's TODO it works.
    332343    // TODO: Handle technology broadcasting for autoresearch properly (some components might not be initialized currently)
    333344    for (var component in modifiedComponents)
    334         Engine.BroadcastMessage(MT_ValueModification, { "component": component });
     345        Engine.BroadcastMessage(MT_ValueModification, { "player": player, "component": component, "valueNames": modifiedComponents[component]});
    335346};
    336347
    337348// Clears the cached data for an entity from the modifications cache
  • Users/Lancelot/Desktop/0ad-svn/trunk/binaries/data/mods/public/simulation/components/interfaces/AuraManager.js

     
    11Engine.RegisterInterface("AuraManager");
     2
     3// Message of the form { "value" : whatever }.
     4// intended for AIProxy so it won't clutter everything.
     5Engine.RegisterMessageType("AI_AuraChange");
  • Users/Lancelot/Desktop/0ad-svn/trunk/binaries/data/mods/public/simulation/helpers/Commands.js

     
    11// Setting this to true will display some warnings when commands
    22//  are likely to fail, which may be useful for debugging AIs
    3 var g_DebugCommands = false;
     3var g_DebugCommands = true;
    44
    55function ProcessCommand(player, cmd)
    66{
  • Users/Lancelot/Desktop/0ad-svn/trunk/source/simulation2/MessageTypes.h

     
    373373public:
    374374    DEFAULT_MESSAGE_IMPL(ValueModification)
    375375
    376     CMessageValueModification(std::wstring component) :
    377         component(component)
     376    CMessageValueModification(player_id_t player, std::wstring component, const std::vector<std::wstring>& valueNames) :
     377        player(player),
     378        component(component),
     379        valueNames(valueNames)
    378380    {
    379381    }
    380382
     383    player_id_t player;
    381384    std::wstring component;
     385    std::vector<std::wstring> valueNames;
    382386};
    383387
    384388/**
  • Users/Lancelot/Desktop/0ad-svn/trunk/source/simulation2/components/ICmpTemplateManager.cpp

     
    2323
    2424BEGIN_INTERFACE_WRAPPER(TemplateManager)
    2525DEFINE_INTERFACE_METHOD_1("GetTemplate", const CParamNode*, ICmpTemplateManager, GetTemplate, std::string)
     26DEFINE_INTERFACE_METHOD_1("GetTemplateWithoutValidation", const CParamNode*, ICmpTemplateManager, GetTemplateWithoutValidation, std::string)
    2627DEFINE_INTERFACE_METHOD_1("GetCurrentTemplateName", std::string, ICmpTemplateManager, GetCurrentTemplateName, entity_id_t)
    2728DEFINE_INTERFACE_METHOD_1("FindAllTemplates", std::vector<std::string>, ICmpTemplateManager, FindAllTemplates, bool)
    2829DEFINE_INTERFACE_METHOD_1("GetEntitiesUsingTemplate", std::vector<entity_id_t>, ICmpTemplateManager, GetEntitiesUsingTemplate, std::string)
  • Users/Lancelot/Desktop/0ad-svn/trunk/source/simulation2/scripting/MessageTypeConversions.cpp

     
    303303jsval CMessageValueModification::ToJSVal(ScriptInterface& scriptInterface) const
    304304{
    305305    TOJSVAL_SETUP();
     306    SET_MSG_PROPERTY(player);
    306307    SET_MSG_PROPERTY(component);
     308    SET_MSG_PROPERTY(valueNames);
    307309    return OBJECT_TO_JSVAL(obj);
    308310}
    309311
    310312CMessage* CMessageValueModification::FromJSVal(ScriptInterface& scriptInterface, jsval val)
    311313{
    312314    FROMJSVAL_SETUP();
     315    GET_MSG_PROPERTY(player_id_t, player);
    313316    GET_MSG_PROPERTY(std::wstring, component);
    314     return new CMessageValueModification(component);
     317    GET_MSG_PROPERTY(std::vector<std::wstring>, valueNames);
     318    return new CMessageValueModification(player, component, valueNames);
    315319}
    316320
    317321////////////////////////////////