AIs now properly receive aura and technology updates. Fixes #2377, Refs #1520 . Consequently reimplement repairing for AIs.
Fix a few style issues and a bug with the gatherer count. Still need to fix the entity.js file to handle properly some things as this uses raw templates values. Cache the AIinterface in AIProxy.js, please report if this works properly. This was SVN commit r14588.
This commit is contained in:
parent
4b828ae6bf
commit
c1e86161b5
@ -544,6 +544,8 @@ m.CityAttack.prototype.updatePreparation = function(gameState, HQ,events) {
|
||||
count++;
|
||||
if (count > 1000){
|
||||
m.debug("No target with a valid position found");
|
||||
Engine.ProfileStop();
|
||||
Engine.ProfileStop();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -908,10 +908,6 @@ m.BaseManager.prototype.assignToFoundations = function(gameState, noRepair) {
|
||||
}
|
||||
}
|
||||
|
||||
// auras/techs are buggy and the AI tries to repair healthy buildings.
|
||||
// TODO: reimplement once that's fixed.
|
||||
return;
|
||||
|
||||
// don't repair if we're still under attack, unless it's like a vital (civcentre or wall) building that's getting destroyed.
|
||||
for (var i in damagedBuildings) {
|
||||
var target = damagedBuildings[i];
|
||||
@ -955,7 +951,7 @@ m.BaseManager.prototype.update = function(gameState, queues, events) {
|
||||
|
||||
Engine.ProfileStart("Assign builders");
|
||||
this.assignToFoundations(gameState);
|
||||
Engine.ProfileStop()
|
||||
Engine.ProfileStop();
|
||||
|
||||
if (this.constructing && this.anchor)
|
||||
{
|
||||
|
@ -1121,7 +1121,6 @@ m.HQ.prototype.update = function(gameState, queues, events) {
|
||||
this.checkEvents(gameState,events,queues);
|
||||
//this.buildMoreHouses(gameState);
|
||||
|
||||
//Engine.ProfileStart("Train workers and build farms, houses. Research techs.");
|
||||
this.trainMoreWorkers(gameState, queues);
|
||||
|
||||
// sandbox doesn't expand.
|
||||
|
@ -1,56 +1,78 @@
|
||||
var API3 = function(m)
|
||||
{
|
||||
|
||||
m.EntityTemplate = m.Class({
|
||||
// defines a template.
|
||||
// It's completely raw data, except it's slightly cleverer now and then.
|
||||
m.Template = m.Class({
|
||||
|
||||
// techModifications should be the tech modifications of only one player.
|
||||
// gamestates handle "GetTemplate" and should push the player's
|
||||
// while entities should push the owner's
|
||||
_init: function(template, techModifications)
|
||||
_init: function(template)
|
||||
{
|
||||
this._techModifications = techModifications;
|
||||
this._template = template;
|
||||
this._tpCache = {};
|
||||
},
|
||||
|
||||
// helper function to return a template value, optionally adjusting for tech.
|
||||
// TODO: there's no support for "_string" values here.
|
||||
get: function(string)
|
||||
{
|
||||
var value = this._template;
|
||||
if (this._auraTemplateModif && this._auraTemplateModif[string]) {
|
||||
return this._auraTemplateModif[string];
|
||||
} else if (this._techModif && this._techModif[string]) {
|
||||
return this._techModif[string];
|
||||
} else {
|
||||
if (this._tpCache[string] === undefined)
|
||||
{
|
||||
var args = string.split("/");
|
||||
for (var i = 0; i < args.length; ++i)
|
||||
if (value[args[i]])
|
||||
value = value[args[i]];
|
||||
else
|
||||
{
|
||||
value = undefined;
|
||||
break;
|
||||
}
|
||||
this._tpCache[string] = value;
|
||||
}
|
||||
return this._tpCache[string];
|
||||
}
|
||||
},
|
||||
|
||||
genericName: function() {
|
||||
if (!this._template.Identity || !this._template.Identity.GenericName)
|
||||
if (!this.get("Identity") || !this.get("Identity/GenericName"))
|
||||
return undefined;
|
||||
return this._template.Identity.GenericName;
|
||||
return this.get("Identity/GenericName");
|
||||
},
|
||||
|
||||
rank: function() {
|
||||
if (!this._template.Identity)
|
||||
if (!this.get("Identity"))
|
||||
return undefined;
|
||||
return this._template.Identity.Rank;
|
||||
return this.get("Identity/Rank");
|
||||
},
|
||||
|
||||
classes: function() {
|
||||
if (!this._template.Identity || !this._template.Identity.Classes || !this._template.Identity.Classes._string)
|
||||
if (!this.get("Identity") || !this.get("Identity/Classes") || !this.get("Identity/Classes/_string"))
|
||||
return undefined;
|
||||
return this._template.Identity.Classes._string.split(/\s+/);
|
||||
return this.get("Identity/Classes/_string").split(/\s+/);
|
||||
},
|
||||
|
||||
requiredTech: function() {
|
||||
if (!this._template.Identity || !this._template.Identity.RequiredTechnology)
|
||||
return undefined;
|
||||
return this._template.Identity.RequiredTechnology;
|
||||
return this.get("Identity/RequiredTechnology");
|
||||
},
|
||||
|
||||
available: function(gameState) {
|
||||
if (!this._template.Identity || !this._template.Identity.RequiredTechnology)
|
||||
return true;
|
||||
return gameState.isResearched(this._template.Identity.RequiredTechnology);
|
||||
return gameState.isResearched(this.get("Identity/RequiredTechnology"));
|
||||
},
|
||||
|
||||
// specifically
|
||||
phase: function() {
|
||||
if (!this._template.Identity || !this._template.Identity.RequiredTechnology)
|
||||
if (!this.get("Identity/RequiredTechnology"))
|
||||
return 0;
|
||||
if (this.template.Identity.RequiredTechnology == "phase_village")
|
||||
if (this.get("Identity/RequiredTechnology") == "phase_village")
|
||||
return 1;
|
||||
if (this.template.Identity.RequiredTechnology == "phase_town")
|
||||
if (this.get("Identity/RequiredTechnology") == "phase_town")
|
||||
return 2;
|
||||
if (this.template.Identity.RequiredTechnology == "phase_city")
|
||||
if (this.get("Identity/RequiredTechnology") == "phase_city")
|
||||
return 3;
|
||||
return 0;
|
||||
},
|
||||
@ -72,28 +94,26 @@ m.EntityTemplate = m.Class({
|
||||
},
|
||||
|
||||
civ: function() {
|
||||
if (!this._template.Identity)
|
||||
return undefined;
|
||||
return this._template.Identity.Civ;
|
||||
return this.get("Identity/Civ");
|
||||
},
|
||||
|
||||
cost: function() {
|
||||
if (!this._template.Cost)
|
||||
if (!this.get("Cost"))
|
||||
return undefined;
|
||||
|
||||
var ret = {};
|
||||
for (var type in this._template.Cost.Resources)
|
||||
ret[type] = GetTechModifiedProperty(this._techModifications, this._template, "Cost/Resources/"+type, +this._template.Cost.Resources[type]);
|
||||
for (var type in this.get("Cost/Resources"))
|
||||
ret[type] = +this.get("Cost/Resources/" + type);
|
||||
return ret;
|
||||
},
|
||||
|
||||
costSum: function() {
|
||||
if (!this._template.Cost)
|
||||
if (!this.get("Cost"))
|
||||
return undefined;
|
||||
|
||||
var ret = 0;
|
||||
for (var type in this._template.Cost.Resources)
|
||||
ret += +this._template.Cost.Resources[type];
|
||||
for (var type in this.get("Cost/Resources"))
|
||||
ret += +this.get("Cost/Resources/" + type);
|
||||
return ret;
|
||||
},
|
||||
|
||||
@ -102,18 +122,18 @@ m.EntityTemplate = m.Class({
|
||||
* obstruction shape, or undefined if no obstruction.
|
||||
*/
|
||||
obstructionRadius: function() {
|
||||
if (!this._template.Obstruction)
|
||||
if (!this.get("Obstruction"))
|
||||
return undefined;
|
||||
|
||||
if (this._template.Obstruction.Static)
|
||||
if (this.get("Obstruction/Static"))
|
||||
{
|
||||
var w = +this._template.Obstruction.Static["@width"];
|
||||
var h = +this._template.Obstruction.Static["@depth"];
|
||||
var w = +this.get("Obstruction/Static/@width");
|
||||
var h = +this.get("Obstruction/Static/@depth");
|
||||
return Math.sqrt(w*w + h*h) / 2;
|
||||
}
|
||||
|
||||
if (this._template.Obstruction.Unit)
|
||||
return +this._template.Obstruction.Unit["@radius"];
|
||||
if (this.get("Obstruction/Unit"))
|
||||
return +this.get("Obstruction/Unit/@radius");
|
||||
|
||||
return 0; // this should never happen
|
||||
},
|
||||
@ -123,113 +143,113 @@ m.EntityTemplate = m.Class({
|
||||
* footprint.
|
||||
*/
|
||||
footprintRadius: function() {
|
||||
if (!this._template.Footprint)
|
||||
if (!this.get("Footprint"))
|
||||
return undefined;
|
||||
|
||||
if (this._template.Footprint.Square)
|
||||
if (this.get("Footprint/Square"))
|
||||
{
|
||||
var w = +this._template.Footprint.Square["@width"];
|
||||
var h = +this._template.Footprint.Square["@depth"];
|
||||
var w = +this.get("Footprint/Square/@width");
|
||||
var h = +this.get("Footprint/Square/@depth");
|
||||
return Math.sqrt(w*w + h*h) / 2;
|
||||
}
|
||||
|
||||
if (this._template.Footprint.Circle)
|
||||
return +this._template.Footprint.Circle["@radius"];
|
||||
if (this.get("Footprint/Circle"))
|
||||
return +this.get("Footprint/Circle/@radius");
|
||||
|
||||
return 0; // this should never happen
|
||||
},
|
||||
|
||||
maxHitpoints: function()
|
||||
{
|
||||
if (this._template.Health !== undefined)
|
||||
return GetTechModifiedProperty(this._techModifications, this._template, "Health/Max",+this._template.Health.Max);
|
||||
if (this.get("Health") !== undefined)
|
||||
return +this.get("Health/Max");
|
||||
return 0;
|
||||
},
|
||||
|
||||
isHealable: function()
|
||||
{
|
||||
if (this._template.Health !== undefined)
|
||||
return this._template.Health.Unhealable !== "true";
|
||||
if (this.get("Health") !== undefined)
|
||||
return this.get("Health/Unhealable") !== "true";
|
||||
return false;
|
||||
},
|
||||
|
||||
isRepairable: function()
|
||||
{
|
||||
if (this._template.Health !== undefined)
|
||||
return this._template.Health.Repairable === "true";
|
||||
if (this.get("Health") !== undefined)
|
||||
return this.get("Health/Repairable") === "true";
|
||||
return false;
|
||||
},
|
||||
|
||||
getPopulationBonus: function() {
|
||||
if (!this._template.Cost || !this._template.Cost.PopulationBonus)
|
||||
return undefined;
|
||||
return this._template.Cost.PopulationBonus;
|
||||
return this.get("Cost/PopulationBonus");
|
||||
},
|
||||
|
||||
armourStrengths: function() {
|
||||
if (!this._template.Armour)
|
||||
if (!this.get("Armour"))
|
||||
return undefined;
|
||||
|
||||
return {
|
||||
hack: GetTechModifiedProperty(this._techModifications, this._template, "Armour/Hack", +this._template.Armour.Hack),
|
||||
pierce: GetTechModifiedProperty(this._techModifications, this._template, "Armour/Pierce", +this._template.Armour.Pierce),
|
||||
crush: GetTechModifiedProperty(this._techModifications, this._template, "Armour/Crush", +this._template.Armour.Crush)
|
||||
hack: +this.get("Armour/Hack"),
|
||||
pierce: +this.get("Armour/Pierce"),
|
||||
crush: +this.get("Armour/Crush")
|
||||
};
|
||||
},
|
||||
|
||||
attackTypes: function() {
|
||||
if (!this._template.Attack)
|
||||
if (!this.get("Attack"))
|
||||
return undefined;
|
||||
|
||||
var ret = [];
|
||||
for (var type in this._template.Attack)
|
||||
for (var type in this.get("Attack"))
|
||||
ret.push(type);
|
||||
|
||||
return ret;
|
||||
},
|
||||
|
||||
attackRange: function(type) {
|
||||
if (!this._template.Attack || !this._template.Attack[type])
|
||||
if (!this.get("Attack/" + type +""))
|
||||
return undefined;
|
||||
|
||||
return {
|
||||
max: GetTechModifiedProperty(this._techModifications, this._template, "Attack/MaxRange", +this._template.Attack[type].MaxRange),
|
||||
min: GetTechModifiedProperty(this._techModifications, this._template, "Attack/MinRange", +(this._template.Attack[type].MinRange || 0))
|
||||
max: +this.get("Attack/" + type +"/MaxRange"),
|
||||
min: +(this.get("Attack/" + type +"/MinRange") || 0)
|
||||
};
|
||||
},
|
||||
|
||||
attackStrengths: function(type) {
|
||||
if (!this._template.Attack || !this._template.Attack[type])
|
||||
if (!this.get("Attack/" + type +""))
|
||||
return undefined;
|
||||
|
||||
return {
|
||||
hack: GetTechModifiedProperty(this._techModifications, this._template, "Attack/"+type+"/Hack", +(this._template.Attack[type].Hack || 0)),
|
||||
pierce: GetTechModifiedProperty(this._techModifications, this._template, "Attack/"+type+"/Pierce", +(this._template.Attack[type].Pierce || 0)),
|
||||
crush: GetTechModifiedProperty(this._techModifications, this._template, "Attack/"+type+"/Crush", +(this._template.Attack[type].Crush || 0))
|
||||
hack: +(this.get("Attack/" + type + "/Hack") || 0),
|
||||
pierce: +(this.get("Attack/" + type + "/Pierce") || 0),
|
||||
crush: +(this.get("Attack/" + type + "/Crush") || 0)
|
||||
};
|
||||
},
|
||||
|
||||
attackTimes: function(type) {
|
||||
if (!this._template.Attack || !this._template.Attack[type])
|
||||
if (!this.get("Attack/" + type +""))
|
||||
return undefined;
|
||||
|
||||
return {
|
||||
prepare: GetTechModifiedProperty(this._techModifications, this._template, "Attack/"+type+"/PrepareTime", +(this._template.Attack[type].PrepareTime || 0)),
|
||||
repeat: GetTechModifiedProperty(this._techModifications, this._template, "Attack/"+type+"/RepeatTime", +(this._template.Attack[type].RepeatTime || 1000))
|
||||
prepare: +(this.get("Attack/" + type + "/PrepareTime") || 0),
|
||||
repeat: +(this.get("Attack/" + type + "/RepeatTime") || 1000)
|
||||
};
|
||||
},
|
||||
|
||||
// returns the classes this templates counters:
|
||||
// Return type is [ [-neededClasses-] , multiplier ].
|
||||
// Return type is [ [-neededClasses- , multiplier], … ].
|
||||
getCounteredClasses: function() {
|
||||
if (!this._template.Attack)
|
||||
if (!this.get("Attack"))
|
||||
return undefined;
|
||||
|
||||
var Classes = [];
|
||||
for (var i in this._template.Attack) {
|
||||
if (!this._template.Attack[i].Bonuses)
|
||||
for (var i in this.get("Attack")) {
|
||||
if (!this.get("Attack/" + i + "/Bonuses"))
|
||||
continue;
|
||||
for (var o in this._template.Attack[i].Bonuses)
|
||||
if (this._template.Attack[i].Bonuses[o].Classes)
|
||||
Classes.push([this._template.Attack[i].Bonuses[o].Classes.split(" "), +this._template.Attack[i].Bonuses[o].Multiplier]);
|
||||
for (var o in this.get("Attack/" + i + "/Bonuses"))
|
||||
if (this.get("Attack/" + i + "/Bonuses/" + o + "/Classes"))
|
||||
Classes.push([this.get("Attack/" + i +"/Bonuses/" + o +"/Classes").split(" "), +this.get("Attack/" + i +"/Bonuses" +o +"/Multiplier")]);
|
||||
}
|
||||
return Classes;
|
||||
},
|
||||
@ -237,15 +257,15 @@ m.EntityTemplate = m.Class({
|
||||
// returns true if the entity counters those classes.
|
||||
// TODO: refine using the multiplier
|
||||
countersClasses: function(classes) {
|
||||
if (!this._template.Attack)
|
||||
if (!this.get("Attack"))
|
||||
return false;
|
||||
var mcounter = [];
|
||||
for (var i in this._template.Attack) {
|
||||
if (!this._template.Attack[i].Bonuses)
|
||||
for (var i in this.get("Attack")) {
|
||||
if (!this.get("Attack/" + i + "/Bonuses"))
|
||||
continue;
|
||||
for (var o in this._template.Attack[i].Bonuses)
|
||||
if (this._template.Attack[i].Bonuses[o].Classes)
|
||||
mcounter.concat(this._template.Attack[i].Bonuses[o].Classes.split(" "));
|
||||
for (var o in this.get("Attack/" + i + "/Bonuses"))
|
||||
if (this.get("Attack/" + i + "/Bonuses/" + o + "/Classes"))
|
||||
mcounter.concat(this.get("Attack/" + i + "/Bonuses/" + o + "/Classes").split(" "));
|
||||
}
|
||||
for (var i in classes)
|
||||
{
|
||||
@ -257,30 +277,30 @@ m.EntityTemplate = m.Class({
|
||||
|
||||
// returns, if it exists, the multiplier from each attack against a given class
|
||||
getMultiplierAgainst: function(type, againstClass) {
|
||||
if (!this._template.Attack || !this._template.Attack[type])
|
||||
if (!this.get("Attack/" + type +""))
|
||||
return undefined;
|
||||
|
||||
if (this._template.Attack[type].Bonuses)
|
||||
for (var o in this._template.Attack[type].Bonuses) {
|
||||
if (!this._template.Attack[type].Bonuses[o].Classes)
|
||||
if (this.get("Attack/" + type + "/Bonuses"))
|
||||
for (var o in this.get("Attack/" + type + "/Bonuses")) {
|
||||
if (!this.get("Attack/" + type + "/Bonuses/" + o + "/Classes"))
|
||||
continue;
|
||||
var total = this._template.Attack[type].Bonuses[o].Classes.split(" ");
|
||||
var total = this.get("Attack/" + type + "/Bonuses/" + o + "/Classes").split(" ");
|
||||
for (var j in total)
|
||||
if (total[j] === againstClass)
|
||||
return this._template.Attack[type].Bonuses[o].Multiplier;
|
||||
return this.get("Attack/" + type + "/Bonuses/" + o + "/Multiplier");
|
||||
}
|
||||
return 1;
|
||||
},
|
||||
|
||||
// returns true if the entity can attack the given class
|
||||
canAttackClass: function(saidClass) {
|
||||
if (!this._template.Attack)
|
||||
if (!this.get("Attack"))
|
||||
return false;
|
||||
|
||||
for (var i in this._template.Attack) {
|
||||
if (!this._template.Attack[i].RestrictedClasses || !this._template.Attack[i].RestrictedClasses._string)
|
||||
for (var i in this.get("Attack")) {
|
||||
if (!this.get("Attack/" + i + "/RestrictedClasses") || !this.get("Attack/" + i + "/RestrictedClasses/_string"))
|
||||
continue;
|
||||
var cannotAttack = this._template.Attack[i].RestrictedClasses._string.split(" ");
|
||||
var cannotAttack = this.get("Attack/" + i + "/RestrictedClasses/_string").split(" ");
|
||||
if (cannotAttack.indexOf(saidClass) !== -1)
|
||||
return false;
|
||||
}
|
||||
@ -288,86 +308,84 @@ m.EntityTemplate = m.Class({
|
||||
},
|
||||
|
||||
buildableEntities: function() {
|
||||
if (!this._template.Builder)
|
||||
return undefined;
|
||||
if (!this._template.Builder.Entities._string)
|
||||
if (!this.get("Builder/Entities/_string"))
|
||||
return [];
|
||||
var civ = this.civ();
|
||||
var templates = this._template.Builder.Entities._string.replace(/\{civ\}/g, civ).split(/\s+/);
|
||||
var templates = this.get("Builder/Entities/_string").replace(/\{civ\}/g, civ).split(/\s+/);
|
||||
return templates; // TODO: map to Entity?
|
||||
},
|
||||
|
||||
trainableEntities: function() {
|
||||
if (!this._template.ProductionQueue || !this._template.ProductionQueue.Entities || !this._template.ProductionQueue.Entities._string)
|
||||
if (!this.get("ProductionQueue/Entities/_string"))
|
||||
return undefined;
|
||||
var civ = this.civ();
|
||||
var templates = this._template.ProductionQueue.Entities._string.replace(/\{civ\}/g, civ).split(/\s+/);
|
||||
var templates = this.get("ProductionQueue/Entities/_string").replace(/\{civ\}/g, civ).split(/\s+/);
|
||||
return templates;
|
||||
},
|
||||
|
||||
researchableTechs: function() {
|
||||
if (!this._template.ProductionQueue || !this._template.ProductionQueue.Technologies || !this._template.ProductionQueue.Technologies._string)
|
||||
if (!this.get("ProductionQueue/Technologies/_string"))
|
||||
return undefined;
|
||||
var templates = this._template.ProductionQueue.Technologies._string.split(/\s+/);
|
||||
var templates = this.get("ProductionQueue/Technologies/_string").split(/\s+/);
|
||||
return templates;
|
||||
},
|
||||
|
||||
resourceSupplyType: function() {
|
||||
if (!this._template.ResourceSupply)
|
||||
if (!this.get("ResourceSupply"))
|
||||
return undefined;
|
||||
var [type, subtype] = this._template.ResourceSupply.Type.split('.');
|
||||
var [type, subtype] = this.get("ResourceSupply/Type").split('.');
|
||||
return { "generic": type, "specific": subtype };
|
||||
},
|
||||
// will return either "food", "wood", "stone", "metal" and not treasure.
|
||||
getResourceType: function() {
|
||||
if (!this._template.ResourceSupply)
|
||||
if (!this.get("ResourceSupply"))
|
||||
return undefined;
|
||||
var [type, subtype] = this._template.ResourceSupply.Type.split('.');
|
||||
var [type, subtype] = this.get("ResourceSupply/Type").split('.');
|
||||
if (type == "treasure")
|
||||
return subtype;
|
||||
return type;
|
||||
},
|
||||
|
||||
resourceSupplyMax: function() {
|
||||
if (!this._template.ResourceSupply)
|
||||
if (!this.get("ResourceSupply"))
|
||||
return undefined;
|
||||
return +this._template.ResourceSupply.Amount;
|
||||
return +this.get("ResourceSupply/Amount");
|
||||
},
|
||||
|
||||
maxGatherers: function()
|
||||
{
|
||||
if (this._template.ResourceSupply !== undefined)
|
||||
return +this._template.ResourceSupply.MaxGatherers;
|
||||
if (this.get("ResourceSupply") !== undefined)
|
||||
return +this.get("ResourceSupply/MaxGatherers");
|
||||
return 0;
|
||||
},
|
||||
|
||||
resourceGatherRates: function() {
|
||||
if (!this._template.ResourceGatherer)
|
||||
if (!this.get("ResourceGatherer"))
|
||||
return undefined;
|
||||
var ret = {};
|
||||
var baseSpeed = GetTechModifiedProperty(this._techModifications, this._template, "ResourceGatherer/BaseSpeed", +this._template.ResourceGatherer.BaseSpeed);
|
||||
for (var r in this._template.ResourceGatherer.Rates)
|
||||
ret[r] = GetTechModifiedProperty(this._techModifications, this._template, "ResourceGatherer/Rates/"+r, +this._template.ResourceGatherer.Rates[r]) * baseSpeed;
|
||||
var baseSpeed = +this.get("ResourceGatherer/BaseSpeed");
|
||||
for (var r in this.get("ResourceGatherer/Rates"))
|
||||
ret[r] = +this.get("ResourceGatherer/Rates/" + r) * baseSpeed;
|
||||
return ret;
|
||||
},
|
||||
|
||||
resourceDropsiteTypes: function() {
|
||||
if (!this._template.ResourceDropsite)
|
||||
if (!this.get("ResourceDropsite"))
|
||||
return undefined;
|
||||
return this._template.ResourceDropsite.Types.split(/\s+/);
|
||||
return this.get("ResourceDropsite/Types").split(/\s+/);
|
||||
},
|
||||
|
||||
|
||||
garrisonableClasses: function() {
|
||||
if (!this._template.GarrisonHolder || !this._template.GarrisonHolder.List._string)
|
||||
if (!this.get("GarrisonHolder") || !this.get("GarrisonHolder/List/_string"))
|
||||
return undefined;
|
||||
return this._template.GarrisonHolder.List._string.split(/\s+/);
|
||||
return this.get("GarrisonHolder/List/_string").split(/\s+/);
|
||||
},
|
||||
|
||||
garrisonMax: function() {
|
||||
if (!this._template.GarrisonHolder)
|
||||
if (!this.get("GarrisonHolder"))
|
||||
return undefined;
|
||||
return this._template.GarrisonHolder.Max;
|
||||
return this.get("GarrisonHolder/Max");
|
||||
},
|
||||
|
||||
/**
|
||||
@ -375,47 +393,47 @@ m.EntityTemplate = m.Class({
|
||||
* (Any non domestic currently.)
|
||||
*/
|
||||
isUnhuntable: function() {
|
||||
if (!this._template.UnitAI || !this._template.UnitAI.NaturalBehaviour)
|
||||
if (!this.get("UnitAI") || !this.get("UnitAI/NaturalBehaviour"))
|
||||
return false;
|
||||
|
||||
// only attack domestic animals since they won't flee nor retaliate.
|
||||
return this._template.UnitAI.NaturalBehaviour !== "domestic";
|
||||
return this.get("UnitAI/NaturalBehaviour") !== "domestic";
|
||||
},
|
||||
|
||||
walkSpeed: function() {
|
||||
if (!this._template.UnitMotion || !this._template.UnitMotion.WalkSpeed)
|
||||
if (!this.get("UnitMotion") || !this.get("UnitMotion/WalkSpeed"))
|
||||
return undefined;
|
||||
return this._template.UnitMotion.WalkSpeed;
|
||||
return this.get("UnitMotion/WalkSpeed");
|
||||
},
|
||||
|
||||
buildCategory: function() {
|
||||
if (!this._template.BuildRestrictions || !this._template.BuildRestrictions.Category)
|
||||
if (!this.get("BuildRestrictions") || !this.get("BuildRestrictions/Category"))
|
||||
return undefined;
|
||||
return this._template.BuildRestrictions.Category;
|
||||
return this.get("BuildRestrictions/Category");
|
||||
},
|
||||
|
||||
buildTime: function() {
|
||||
if (!this._template.Cost || !this._template.Cost.BuildTime)
|
||||
if (!this.get("Cost") || !this.get("Cost/BuildTime"))
|
||||
return undefined;
|
||||
return this._template.Cost.BuildTime;
|
||||
return this.get("Cost/BuildTime");
|
||||
},
|
||||
|
||||
buildDistance: function() {
|
||||
if (!this._template.BuildRestrictions || !this._template.BuildRestrictions.Distance)
|
||||
if (!this.get("BuildRestrictions") || !this.get("BuildRestrictions/Distance"))
|
||||
return undefined;
|
||||
return this._template.BuildRestrictions.Distance;
|
||||
return this.get("BuildRestrictions/Distance");
|
||||
},
|
||||
|
||||
buildPlacementType: function() {
|
||||
if (!this._template.BuildRestrictions || !this._template.BuildRestrictions.PlacementType)
|
||||
if (!this.get("BuildRestrictions") || !this.get("BuildRestrictions/PlacementType"))
|
||||
return undefined;
|
||||
return this._template.BuildRestrictions.PlacementType;
|
||||
return this.get("BuildRestrictions/PlacementType");
|
||||
},
|
||||
|
||||
buildTerritories: function() {
|
||||
if (!this._template.BuildRestrictions || !this._template.BuildRestrictions.Territory)
|
||||
if (!this.get("BuildRestrictions") || !this.get("BuildRestrictions/Territory"))
|
||||
return undefined;
|
||||
return this._template.BuildRestrictions.Territory.split(/\s+/);
|
||||
return this.get("BuildRestrictions/Territory").split(/\s+/);
|
||||
},
|
||||
|
||||
hasBuildTerritory: function(territory) {
|
||||
@ -424,42 +442,45 @@ m.EntityTemplate = m.Class({
|
||||
},
|
||||
|
||||
hasTerritoryInfluence: function() {
|
||||
return (this._template.TerritoryInfluence !== undefined);
|
||||
return (this.get("TerritoryInfluence") !== undefined);
|
||||
},
|
||||
|
||||
territoryInfluenceRadius: function() {
|
||||
if (this._template.TerritoryInfluence !== undefined)
|
||||
return (this._template.TerritoryInfluence.Radius);
|
||||
if (this.get("TerritoryInfluence") !== undefined)
|
||||
return (this.get("TerritoryInfluence/Radius"));
|
||||
else
|
||||
return -1;
|
||||
},
|
||||
|
||||
territoryInfluenceWeight: function() {
|
||||
if (this._template.TerritoryInfluence !== undefined)
|
||||
return (this._template.TerritoryInfluence.Weight);
|
||||
if (this.get("TerritoryInfluence") !== undefined)
|
||||
return (this.get("TerritoryInfluence/Weight"));
|
||||
else
|
||||
return -1;
|
||||
},
|
||||
|
||||
visionRange: function() {
|
||||
if (!this._template.Vision)
|
||||
return undefined;
|
||||
return this._template.Vision.Range;
|
||||
return this.get("Vision/Range");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
// defines an entity, with a super Template.
|
||||
// also redefines several of the template functions where the only change is applying aura and tech modifications.
|
||||
m.Entity = m.Class({
|
||||
_super: m.EntityTemplate,
|
||||
_super: m.Template,
|
||||
|
||||
_init: function(sharedAI, entity)
|
||||
{
|
||||
this._super.call(this, sharedAI.GetTemplate(entity.template), sharedAI._techModifications[entity.owner]);
|
||||
this._super.call(this, sharedAI.GetTemplate(entity.template));
|
||||
|
||||
this._ai = sharedAI;
|
||||
this._templateName = entity.template;
|
||||
this._entity = entity;
|
||||
this._auraTemplateModif = {}; // template modification from auras. this is only for this entity.
|
||||
this._ai = sharedAI;
|
||||
if (!sharedAI._techModifications[entity.owner][this._templateName])
|
||||
sharedAI._techModifications[entity.owner][this._templateName] = {};
|
||||
this._techModif = sharedAI._techModifications[entity.owner][this._templateName]; // save a reference to the template tech modifications
|
||||
},
|
||||
|
||||
toString: function() {
|
||||
@ -477,7 +498,7 @@ m.Entity = m.Class({
|
||||
/**
|
||||
* Returns extra data that the AI scripts have associated with this entity,
|
||||
* for arbitrary local annotations.
|
||||
* (This data is not shared with any other AI scripts.)
|
||||
* (This data should not be shared with any other AI scripts.)
|
||||
*/
|
||||
getMetadata: function(player, key) {
|
||||
return this._ai.getMetadata(player, this, key);
|
||||
@ -508,6 +529,7 @@ m.Entity = m.Class({
|
||||
|
||||
unitAIState: function() { return this._entity.unitAIState; },
|
||||
unitAIOrderData: function() { return this._entity.unitAIOrderData; },
|
||||
|
||||
hitpoints: function() {if (this._entity.hitpoints !== undefined) return this._entity.hitpoints; return undefined; },
|
||||
isHurt: function() { return this.hitpoints() < this.maxHitpoints(); },
|
||||
healthLevel: function() { return (this.hitpoints() / this.maxHitpoints()); },
|
||||
@ -540,14 +562,17 @@ m.Entity = m.Class({
|
||||
owner: function() {
|
||||
return this._entity.owner;
|
||||
},
|
||||
|
||||
isOwn: function(player) {
|
||||
if (typeof(this._entity.owner) === "undefined")
|
||||
return false;
|
||||
return this._entity.owner === player;
|
||||
},
|
||||
|
||||
isFriendly: function(player) {
|
||||
return this.isOwn(player); // TODO: diplomacy
|
||||
},
|
||||
|
||||
isEnemy: function(player) {
|
||||
return !this.isOwn(player); // TODO: diplomacy
|
||||
},
|
||||
@ -561,14 +586,14 @@ m.Entity = m.Class({
|
||||
resourceSupplyGatherers: function(player)
|
||||
{
|
||||
if (this._entity.resourceSupplyGatherers !== undefined)
|
||||
return this._entity.resourceSupplyGatherers[player-1];
|
||||
return this._entity.resourceSupplyGatherers[player];
|
||||
return [];
|
||||
},
|
||||
|
||||
isFull: function(player)
|
||||
{
|
||||
if (this._entity.resourceSupplyGatherers !== undefined)
|
||||
return (this.maxGatherers() === this._entity.resourceSupplyGatherers[player-1].length);
|
||||
return (this.maxGatherers() === this._entity.resourceSupplyGatherers[player].length);
|
||||
|
||||
return undefined;
|
||||
},
|
||||
@ -581,7 +606,7 @@ m.Entity = m.Class({
|
||||
|
||||
currentGatherRate: function() {
|
||||
// returns the gather rate for the current target if applicable.
|
||||
if (!this._template.ResourceGatherer)
|
||||
if (!this.get("ResourceGatherer"));
|
||||
return undefined;
|
||||
|
||||
if (this.unitAIOrderData().length &&
|
||||
@ -603,8 +628,8 @@ m.Entity = m.Class({
|
||||
if (type.generic == "treasure")
|
||||
return 1000;
|
||||
|
||||
var speed = GetTechModifiedProperty(this._techModifications, this._template, "ResourceGatherer/BaseSpeed", +this._template.ResourceGatherer.BaseSpeed);
|
||||
speed *= GetTechModifiedProperty(this._techModifications, this._template, "ResourceGatherer/Rates/"+tstring, +this._template.ResourceGatherer.Rates[tstring]);
|
||||
var speed = +this.get("ResourceGatherer/BaseSpeed");
|
||||
speed *= +this.get("ResourceGatherer/Rates/" +tstring);
|
||||
|
||||
if (speed)
|
||||
return speed;
|
||||
@ -644,7 +669,7 @@ m.Entity = m.Class({
|
||||
},
|
||||
|
||||
unload: function(id) {
|
||||
if (!this._template.GarrisonHolder)
|
||||
if (!this.get("GarrisonHolder"))
|
||||
return undefined;
|
||||
Engine.PostCommand(PlayerID,{"type": "unload", "garrisonHolder": this.id(), "entities": [id]});
|
||||
return this;
|
||||
@ -652,7 +677,7 @@ m.Entity = m.Class({
|
||||
|
||||
// Unloads all owned units, don't unload allies
|
||||
unloadAll: function() {
|
||||
if (!this._template.GarrisonHolder)
|
||||
if (!this.get("GarrisonHolder"))
|
||||
return undefined;
|
||||
Engine.PostCommand(PlayerID,{"type": "unload-all-own", "garrisonHolders": [this.id()]});
|
||||
return this;
|
||||
|
@ -126,7 +126,7 @@ m.GameState.prototype.getTemplate = function(type)
|
||||
if (!this.templates[type])
|
||||
return null;
|
||||
|
||||
return new m.EntityTemplate(this.templates[type], this.techModifications);
|
||||
return new m.Template(this.templates[type], this.techModifications);
|
||||
};
|
||||
|
||||
m.GameState.prototype.applyCiv = function(str) {
|
||||
|
@ -58,7 +58,7 @@ m.SharedScript.prototype.Deserialize = function(data)
|
||||
// Components that will be disabled in foundation entity templates.
|
||||
// (This is a bit yucky and fragile since it's the inverse of
|
||||
// CCmpTemplateManager::CopyFoundationSubset and only includes components
|
||||
// that our EntityTemplate class currently uses.)
|
||||
// that our Template class currently uses.)
|
||||
m.g_FoundationForbiddenComponents = {
|
||||
"ProductionQueue": 1,
|
||||
"ResourceSupply": 1,
|
||||
@ -119,6 +119,8 @@ m.SharedScript.prototype.GetTemplate = function(name)
|
||||
// We need to now the initial state of the game for this, as we will use it.
|
||||
// This is called right at the end of the map generation.
|
||||
m.SharedScript.prototype.init = function(state) {
|
||||
this.ApplyTemplatesDelta(state);
|
||||
|
||||
this.passabilityClasses = state.passabilityClasses;
|
||||
this.passabilityMap = state.passabilityMap;
|
||||
this.players = this._players;
|
||||
@ -127,9 +129,6 @@ m.SharedScript.prototype.init = function(state) {
|
||||
this.timeElapsed = state.timeElapsed;
|
||||
this.barterPrices = state.barterPrices;
|
||||
|
||||
for (var o in state.players)
|
||||
this._techModifications[o] = state.players[o].techModifications;
|
||||
|
||||
this._entities = {};
|
||||
for (var id in state.entities)
|
||||
this._entities[id] = new m.Entity(this, state.entities[id]);
|
||||
@ -166,6 +165,7 @@ m.SharedScript.prototype.onUpdate = function(state)
|
||||
return;
|
||||
// deals with updating based on create and destroy messages.
|
||||
this.ApplyEntitiesDelta(state);
|
||||
this.ApplyTemplatesDelta(state);
|
||||
|
||||
Engine.ProfileStart("onUpdate");
|
||||
|
||||
@ -178,9 +178,6 @@ m.SharedScript.prototype.onUpdate = function(state)
|
||||
this.timeElapsed = state.timeElapsed;
|
||||
this.barterPrices = state.barterPrices;
|
||||
|
||||
for (var o in state.players)
|
||||
this._techModifications[o] = state.players[o].techModifications;
|
||||
|
||||
for (var i in this.gameState)
|
||||
this.gameState[i].update(this,state);
|
||||
|
||||
@ -313,6 +310,34 @@ m.SharedScript.prototype.ApplyEntitiesDelta = function(state)
|
||||
this.updateEntityCollections(prop, this._entities[id]);
|
||||
}
|
||||
}
|
||||
|
||||
// apply per-entity aura-related changes.
|
||||
// this supersedes tech-related changes.
|
||||
for (var id in state.changedEntityTemplateInfo)
|
||||
{
|
||||
var changes = state.changedEntityTemplateInfo[id];
|
||||
for each (var change in changes)
|
||||
this._entities[id]._auraTemplateModif[change.variable] = change.value;
|
||||
}
|
||||
Engine.ProfileStop();
|
||||
};
|
||||
|
||||
m.SharedScript.prototype.ApplyTemplatesDelta = function(state)
|
||||
{
|
||||
Engine.ProfileStart("Shared ApplyTemplatesDelta");
|
||||
|
||||
for (var player in state.changedTemplateInfo)
|
||||
{
|
||||
var playerDiff = state.changedTemplateInfo[player];
|
||||
for (var template in playerDiff)
|
||||
{
|
||||
var changes = playerDiff[template];
|
||||
if (!this._techModifications[player][template])
|
||||
this._techModifications[player][template] = {};
|
||||
for each (var change in changes)
|
||||
this._techModifications[player][template][change.variable] = change.value;
|
||||
}
|
||||
}
|
||||
Engine.ProfileStop();
|
||||
};
|
||||
|
||||
|
@ -18,9 +18,15 @@ AIInterface.prototype.Init = function()
|
||||
this.events["OwnershipChanged"] = [];
|
||||
|
||||
this.changedEntities = {};
|
||||
|
||||
// cache for technology changes;
|
||||
// this one is PlayerID->TemplateName->{StringForTheValue, ActualValue}
|
||||
this.changedTemplateInfo = {};
|
||||
// this is for auras and is EntityID->{StringForTheValue, ActualValue}
|
||||
this.changedEntityTemplateInfo = {};
|
||||
};
|
||||
|
||||
AIInterface.prototype.GetRepresentation = function()
|
||||
AIInterface.prototype.GetNonEntityRepresentation = function()
|
||||
{
|
||||
var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
|
||||
|
||||
@ -39,7 +45,6 @@ AIInterface.prototype.GetRepresentation = function()
|
||||
state.events["PlayerDefeated"] = this.events["PlayerDefeated"];
|
||||
state.events["EntityRenamed"] = this.events["EntityRenamed"];
|
||||
state.events["OwnershipChanged"] = this.events["OwnershipChanged"];
|
||||
|
||||
// Reset the event list for the next turn
|
||||
this.events["Create"] = [];
|
||||
this.events["Destroy"] = [];
|
||||
@ -52,6 +57,13 @@ AIInterface.prototype.GetRepresentation = function()
|
||||
this.events["EntityRenamed"] = [];
|
||||
this.events["OwnershipChanged"] = [];
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
AIInterface.prototype.GetRepresentation = function()
|
||||
{
|
||||
var state = this.GetNonEntityRepresentation();
|
||||
|
||||
// Add entity representations
|
||||
Engine.ProfileStart("proxy representations");
|
||||
state.entities = {};
|
||||
@ -64,29 +76,18 @@ AIInterface.prototype.GetRepresentation = function()
|
||||
this.changedEntities = {};
|
||||
Engine.ProfileStop();
|
||||
|
||||
state.changedTemplateInfo = this.changedTemplateInfo;
|
||||
this.changedTemplateInfo = {};
|
||||
state.changedEntityTemplateInfo = this.changedEntityTemplateInfo;
|
||||
this.changedEntityTemplateInfo = {};
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
// Intended to be called first, during the map initialization: no caching
|
||||
AIInterface.prototype.GetFullRepresentation = function(flushEvents)
|
||||
{
|
||||
var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
|
||||
|
||||
// Return the same game state as the GUI uses
|
||||
var state = cmpGuiInterface.GetExtendedSimulationState(-1);
|
||||
|
||||
// Add some extra AI-specific data
|
||||
state.events = {};
|
||||
state.events["Create"] = this.events["Create"];
|
||||
state.events["Destroy"] = this.events["Destroy"];
|
||||
state.events["Attacked"] = this.events["Attacked"];
|
||||
state.events["RangeUpdate"] = this.events["RangeUpdate"];
|
||||
state.events["ConstructionFinished"] = this.events["ConstructionFinished"];
|
||||
state.events["TrainingFinished"] = this.events["TrainingFinished"];
|
||||
state.events["AIMetadata"] = this.events["AIMetadata"];
|
||||
state.events["PlayerDefeated"] = this.events["PlayerDefeated"];
|
||||
state.events["EntityRenamed"] = this.events["EntityRenamed"];
|
||||
state.events["OwnershipChanged"] = this.events["OwnershipChanged"];
|
||||
|
||||
var state = this.GetNonEntityRepresentation();
|
||||
|
||||
if (flushEvents)
|
||||
{
|
||||
@ -102,19 +103,6 @@ AIInterface.prototype.GetFullRepresentation = function(flushEvents)
|
||||
state.events["OwnershipChanged"] = [];
|
||||
}
|
||||
|
||||
// Reset the event list for the next turn
|
||||
this.events["Create"] = [];
|
||||
this.events["Destroy"] = [];
|
||||
this.events["Attacked"] = [];
|
||||
this.events["RangeUpdate"] = [];
|
||||
this.events["ConstructionFinished"] = [];
|
||||
this.events["TrainingFinished"] = [];
|
||||
this.events["AIMetadata"] = [];
|
||||
this.events["PlayerDefeated"] = [];
|
||||
this.events["EntityRenamed"] = [];
|
||||
this.events["OwnershipChanged"] = [];
|
||||
|
||||
|
||||
// Add entity representations
|
||||
Engine.ProfileStart("proxy representations");
|
||||
state.entities = {};
|
||||
@ -127,6 +115,11 @@ AIInterface.prototype.GetFullRepresentation = function(flushEvents)
|
||||
}
|
||||
Engine.ProfileStop();
|
||||
|
||||
state.changedTemplateInfo = this.changedTemplateInfo;
|
||||
this.changedTemplateInfo = {};
|
||||
state.changedEntityTemplateInfo = this.changedEntityTemplateInfo;
|
||||
this.changedEntityTemplateInfo = {};
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
@ -156,4 +149,97 @@ AIInterface.prototype.OnGlobalEntityRenamed = function(msg)
|
||||
this.events["EntityRenamed"].push(msg);
|
||||
};
|
||||
|
||||
// When a new technology is researched, check which templates it affects,
|
||||
// and send the updated values to the AI.
|
||||
// this relies on the fact that any "value" in a technology can only ever change
|
||||
// one template value, and that the naming is the same (with / in place of .)
|
||||
// it's not incredibly fast but it's not incredibly slow.
|
||||
AIInterface.prototype.OnTemplateModification = function(msg)
|
||||
{
|
||||
var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
|
||||
if (!this.templates)
|
||||
this.templates = cmpTemplateManager.FindAllTemplates(false);
|
||||
|
||||
for each (var value in msg.valueNames)
|
||||
{
|
||||
for (var o = 0; o < this.templates.length; ++o)
|
||||
{
|
||||
var tmp = this.templates[o];
|
||||
var template = cmpTemplateManager.GetTemplateWithoutValidation(this.templates[o]);
|
||||
// remove templates that we obviously don't care about.
|
||||
if (!template || !template.Identity || ! template.Identity.Civ)
|
||||
{
|
||||
this.templates.splice(o--,1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// let's get the base template value.
|
||||
var strings = value.split("/");
|
||||
var item = template;
|
||||
var ended = true;
|
||||
for (var i = 0; i < strings.length; ++i)
|
||||
{
|
||||
if (item !== undefined && item[strings[i]] !== undefined)
|
||||
item = item[strings[i]];
|
||||
else
|
||||
ended = false;
|
||||
}
|
||||
if (!ended)
|
||||
continue;
|
||||
// item now contains the template value for this.
|
||||
|
||||
// check for numerals, they need to be handled properly
|
||||
item = !isNaN(+item) ? +item : item;
|
||||
var newValue = ApplyValueModificationsToTemplate(value, item, msg.player, template);
|
||||
// round the value to 5th decimal or so.
|
||||
newValue = !isNaN(+newValue) ? (Math.abs((+newValue) - Math.round(+newValue)) < 0.0001 ? Math.round(+newValue) : +newValue) : newValue;
|
||||
|
||||
if(item != newValue)
|
||||
{
|
||||
if (!this.changedTemplateInfo[msg.player])
|
||||
this.changedTemplateInfo[msg.player] = {};
|
||||
if (!this.changedTemplateInfo[msg.player][this.templates[o]])
|
||||
this.changedTemplateInfo[msg.player][this.templates[o]] = [ { "variable" : value, "value" : newValue} ];
|
||||
else
|
||||
this.changedTemplateInfo[msg.player][this.templates[o]].push({ "variable" : value, "value" : newValue });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AIInterface.prototype.OnGlobalValueModification = function(msg)
|
||||
{
|
||||
var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
|
||||
for each (var ent in msg.entities)
|
||||
{
|
||||
var template = cmpTemplateManager.GetTemplateWithoutValidation(cmpTemplateManager.GetCurrentTemplateName(ent));
|
||||
for each (var value in msg.valueNames)
|
||||
{
|
||||
// let's get the base template value.
|
||||
var strings = value.split("/");
|
||||
var item = template;
|
||||
var ended = true;
|
||||
for (var i = 0; i < strings.length; ++i)
|
||||
{
|
||||
if (item !== undefined && item[strings[i]] !== undefined)
|
||||
item = item[strings[i]];
|
||||
else
|
||||
ended = false;
|
||||
}
|
||||
if (!ended)
|
||||
continue;
|
||||
// "item" now contains the unmodified template value for this.
|
||||
var newValue = ApplyValueModificationsToEntity(value, +item, ent);
|
||||
newValue = typeof(newValue) === "Number" ? Math.round(newValue) : newValue;
|
||||
if(item != newValue)
|
||||
{
|
||||
if (!this.changedEntityTemplateInfo[ent])
|
||||
this.changedEntityTemplateInfo[ent] = [{ "variable" : value, "value" : newValue }];
|
||||
else
|
||||
this.changedEntityTemplateInfo[ent].push({ "variable" : value, "value" : newValue });
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Engine.RegisterComponentType(IID_AIInterface, "AIInterface", AIInterface);
|
||||
|
@ -36,10 +36,19 @@ AIProxy.prototype.Init = function()
|
||||
this.needsFullGet = true;
|
||||
this.owner = -1; // for convenience now and then.
|
||||
|
||||
this.cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
|
||||
|
||||
// Let the AIInterface know that we exist and that it should query us
|
||||
this.NotifyChange();
|
||||
};
|
||||
|
||||
AIProxy.prototype.Serialize = null; // we have no dynamic state to save
|
||||
|
||||
AIProxy.prototype.Deserialize = function ()
|
||||
{
|
||||
this.cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
|
||||
};
|
||||
|
||||
AIProxy.prototype.GetRepresentation = function()
|
||||
{
|
||||
// Return the full representation the first time we're called
|
||||
@ -67,9 +76,7 @@ AIProxy.prototype.NotifyChange = function()
|
||||
if (!this.changes)
|
||||
{
|
||||
this.changes = {};
|
||||
|
||||
var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
|
||||
cmpAIInterface.ChangedEntity(this.entity);
|
||||
this.cmpAIInterface.ChangedEntity(this.entity);
|
||||
}
|
||||
};
|
||||
|
||||
@ -261,55 +268,47 @@ AIProxy.prototype.OnOwnershipChanged = function(msg)
|
||||
|
||||
if (msg.from === -1)
|
||||
{
|
||||
var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
|
||||
cmpAIInterface.PushEvent("Create", {"entity" : msg.entity});
|
||||
this.cmpAIInterface.PushEvent("Create", {"entity" : msg.entity});
|
||||
return;
|
||||
} else if (msg.to === -1)
|
||||
{
|
||||
var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
|
||||
cmpAIInterface.PushEvent("Destroy", {"entity" : msg.entity});
|
||||
this.cmpAIInterface.PushEvent("Destroy", {"entity" : msg.entity});
|
||||
return;
|
||||
}
|
||||
|
||||
this.owner = msg.to;
|
||||
this.changes.owner = msg.to;
|
||||
|
||||
var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
|
||||
cmpAIInterface.PushEvent("OwnershipChanged", msg);
|
||||
this.cmpAIInterface.PushEvent("OwnershipChanged", msg);
|
||||
};
|
||||
|
||||
AIProxy.prototype.OnAttacked = function(msg)
|
||||
{
|
||||
var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
|
||||
cmpAIInterface.PushEvent("Attacked", msg);
|
||||
this.cmpAIInterface.PushEvent("Attacked", msg);
|
||||
};
|
||||
|
||||
/*
|
||||
Deactivated for actually not really being practical for most uses.
|
||||
AIProxy.prototype.OnRangeUpdate = function(msg)
|
||||
{
|
||||
var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
|
||||
msg.owner = this.owner;
|
||||
cmpAIInterface.PushEvent("RangeUpdate", msg);
|
||||
this.cmpAIInterface.PushEvent("RangeUpdate", msg);
|
||||
warn(uneval(msg));
|
||||
};*/
|
||||
|
||||
AIProxy.prototype.OnConstructionFinished = function(msg)
|
||||
{
|
||||
var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
|
||||
cmpAIInterface.PushEvent("ConstructionFinished", msg);
|
||||
this.cmpAIInterface.PushEvent("ConstructionFinished", msg);
|
||||
};
|
||||
|
||||
AIProxy.prototype.OnTrainingFinished = function(msg)
|
||||
{
|
||||
var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
|
||||
cmpAIInterface.PushEvent("TrainingFinished", msg);
|
||||
this.cmpAIInterface.PushEvent("TrainingFinished", msg);
|
||||
};
|
||||
|
||||
AIProxy.prototype.OnAIMetadata = function(msg)
|
||||
{
|
||||
var cmpAIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_AIInterface);
|
||||
cmpAIInterface.PushEvent("AIMetadata", msg);
|
||||
this.cmpAIInterface.PushEvent("AIMetadata", msg);
|
||||
};
|
||||
|
||||
Engine.RegisterComponentType(IID_AIProxy, "AIProxy", AIProxy);
|
||||
|
@ -46,7 +46,7 @@ AuraManager.prototype.ApplyBonus = function(value, ent, data, key)
|
||||
this.modificationsCache[value][ent].add += data.add;
|
||||
|
||||
// post message to the entity to notify it about the change
|
||||
Engine.PostMessage(ent, MT_ValueModification, { "component": value.split("/")[0] });
|
||||
Engine.PostMessage(ent, MT_ValueModification, { "entities": [ent], "component": value.split("/")[0], "valueNames": [value] });
|
||||
};
|
||||
|
||||
AuraManager.prototype.ApplyTemplateBonus = function(value, player, classes, data, key)
|
||||
@ -73,6 +73,7 @@ AuraManager.prototype.ApplyTemplateBonus = function(value, player, classes, data
|
||||
if (data.add)
|
||||
this.templateModificationsCache[value][player][c][key].add += data.add;
|
||||
|
||||
Engine.PostMessage(SYSTEM_ENTITY, MT_TemplateModification, { "player": player, "component": value.split("/")[0], "valueNames": [value] });
|
||||
}
|
||||
};
|
||||
|
||||
@ -98,7 +99,9 @@ AuraManager.prototype.RemoveBonus = function(value, ent, key)
|
||||
this.modificationsCache[value][ent].multiply /= data.multiply;
|
||||
|
||||
// post message to the entity to notify it about the change
|
||||
Engine.PostMessage(ent, MT_ValueModification, { "component": value.split("/")[0] });
|
||||
var effects = {};
|
||||
effects[value] = this.modificationsCache[value][ent];
|
||||
Engine.PostMessage(ent, MT_ValueModification, { "entities": [ent], "component": value.split("/")[0], "valueNames": [value] });
|
||||
};
|
||||
|
||||
AuraManager.prototype.RemoveTemplateBonus = function(value, player, classes, key)
|
||||
@ -119,6 +122,7 @@ AuraManager.prototype.RemoveTemplateBonus = function(value, player, classes, key
|
||||
this.templateModificationsCache[value][player][c][key].multiply = 1;
|
||||
this.templateModificationsCache[value][player][c][key].add = 0;
|
||||
}
|
||||
Engine.PostMessage(SYSTEM_ENTITY, MT_TemplateModification, { "player": player, "component": value.split("/")[0], "valueNames": [value] });
|
||||
};
|
||||
|
||||
AuraManager.prototype.ApplyModifications = function(valueName, value, ent)
|
||||
|
@ -97,7 +97,6 @@ GuiInterface.prototype.GetSimulationState = function(player)
|
||||
"entityLimits": cmpPlayerEntityLimits.GetLimits(),
|
||||
"entityCounts": cmpPlayerEntityLimits.GetCounts(),
|
||||
"entityLimitChangers": cmpPlayerEntityLimits.GetLimitChangers(),
|
||||
"techModifications": cmpTechnologyManager.GetTechModifications(),
|
||||
"researchQueued": cmpTechnologyManager.GetQueuedResearch(),
|
||||
"researchStarted": cmpTechnologyManager.GetStartedResearch(),
|
||||
"researchedTechs": cmpTechnologyManager.GetResearchedTechs(),
|
||||
@ -475,8 +474,8 @@ GuiInterface.prototype.GetTemplateData = function(player, extendedName)
|
||||
{
|
||||
ret.armour = {
|
||||
"hack": ApplyValueModificationsToTemplate("Armour/Hack", +template.Armour.Hack, player, template),
|
||||
"pierce": ApplyValueModificationsToTemplate("Armour/Pierce", +template.Armour.Hack, player, template),
|
||||
"crush": ApplyValueModificationsToTemplate("Armour/Crush", +template.Armour.Hack, player, template),
|
||||
"pierce": ApplyValueModificationsToTemplate("Armour/Pierce", +template.Armour.Pierce, player, template),
|
||||
"crush": ApplyValueModificationsToTemplate("Armour/Crush", +template.Armour.Crush, player, template),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -226,13 +226,17 @@ TechnologyManager.prototype.OnGlobalOwnershipChanged = function (msg)
|
||||
var modifications = this.modifications[name];
|
||||
var component = name.split("/")[0];
|
||||
for (var i in modifications)
|
||||
if (!modifiedComponents[component] && DoesModificationApply(modifications[i], classes))
|
||||
modifiedComponents[component] = true;
|
||||
if (DoesModificationApply(modifications[i], classes))
|
||||
{
|
||||
if (!modifiedComponents[component])
|
||||
modifiedComponents[component] = [];
|
||||
modifiedComponents[component].push(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Send mesage(s) to the entity so it knows about researched techs
|
||||
for (var component in modifiedComponents)
|
||||
Engine.PostMessage(msg.entity, MT_ValueModification, { "component": component });
|
||||
Engine.PostMessage(msg.entity, MT_ValueModification, { "entities": [msg.entity], "component": component, "valueNames": modifiedComponents[component] });
|
||||
}
|
||||
}
|
||||
if (msg.from == playerID)
|
||||
@ -322,16 +326,28 @@ TechnologyManager.prototype.ResearchTechnology = function (tech)
|
||||
mod[j] = modification[j];
|
||||
|
||||
this.modifications[modification.value].push(mod);
|
||||
modifiedComponents[modification.value.split("/")[0]] = true;
|
||||
var component = modification.value.split("/")[0];
|
||||
if (!modifiedComponents[component])
|
||||
modifiedComponents[component] = [];
|
||||
modifiedComponents[component].push(modification.value);
|
||||
this.modificationCache[modification.value] = {};
|
||||
}
|
||||
}
|
||||
|
||||
this.UpdateAutoResearch();
|
||||
|
||||
var cmpPlayer = Engine.QueryInterface(this.entity, IID_Player);
|
||||
if (!cmpPlayer || ! cmpPlayer.GetPlayerID())
|
||||
return;
|
||||
var playerID = cmpPlayer.GetPlayerID();
|
||||
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
var ents = cmpRangeManager.GetEntitiesByPlayer(playerID);
|
||||
// TODO: Handle technology broadcasting for autoresearch properly (some components might not be initialized currently)
|
||||
for (var component in modifiedComponents)
|
||||
Engine.BroadcastMessage(MT_ValueModification, { "component": component });
|
||||
{
|
||||
Engine.PostMessage(SYSTEM_ENTITY, MT_TemplateModification, { "player": playerID, "component": component, "valueNames": modifiedComponents[component]});
|
||||
Engine.BroadcastMessage(MT_ValueModification, { "entities": ents, "component": component, "valueNames": modifiedComponents[component]});
|
||||
}
|
||||
};
|
||||
|
||||
// Clears the cached data for an entity from the modifications cache
|
||||
|
@ -366,19 +366,43 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* Sent by value modification manager when a value of a certain component is changed
|
||||
* Sent by aura manager when a value of a certain entity's component is changed
|
||||
*/
|
||||
class CMessageValueModification : public CMessage
|
||||
{
|
||||
public:
|
||||
DEFAULT_MESSAGE_IMPL(ValueModification)
|
||||
|
||||
CMessageValueModification(std::wstring component) :
|
||||
component(component)
|
||||
CMessageValueModification(const std::vector<entity_id_t>& entities, std::wstring component, const std::vector<std::wstring>& valueNames) :
|
||||
entities(entities),
|
||||
component(component),
|
||||
valueNames(valueNames)
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<entity_id_t> entities;
|
||||
std::wstring component;
|
||||
std::vector<std::wstring> valueNames;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sent by aura and tech managers when a value of a certain template's component is changed
|
||||
*/
|
||||
class CMessageTemplateModification : public CMessage
|
||||
{
|
||||
public:
|
||||
DEFAULT_MESSAGE_IMPL(TemplateModification)
|
||||
|
||||
CMessageTemplateModification(player_id_t player, std::wstring component, const std::vector<std::wstring>& valueNames) :
|
||||
player(player),
|
||||
component(component),
|
||||
valueNames(valueNames)
|
||||
{
|
||||
}
|
||||
|
||||
player_id_t player;
|
||||
std::wstring component;
|
||||
std::vector<std::wstring> valueNames;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -48,6 +48,7 @@ MESSAGE(TerrainChanged)
|
||||
MESSAGE(TerritoriesChanged)
|
||||
MESSAGE(PathResult)
|
||||
MESSAGE(ValueModification)
|
||||
MESSAGE(TemplateModification)
|
||||
MESSAGE(VisionRangeChanged)
|
||||
MESSAGE(MinimapPing)
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
BEGIN_INTERFACE_WRAPPER(TemplateManager)
|
||||
DEFINE_INTERFACE_METHOD_1("GetTemplate", const CParamNode*, ICmpTemplateManager, GetTemplate, std::string)
|
||||
DEFINE_INTERFACE_METHOD_1("GetTemplateWithoutValidation", const CParamNode*, ICmpTemplateManager, GetTemplateWithoutValidation, std::string)
|
||||
DEFINE_INTERFACE_METHOD_1("GetCurrentTemplateName", std::string, ICmpTemplateManager, GetCurrentTemplateName, entity_id_t)
|
||||
DEFINE_INTERFACE_METHOD_1("FindAllTemplates", std::vector<std::string>, ICmpTemplateManager, FindAllTemplates, bool)
|
||||
DEFINE_INTERFACE_METHOD_1("GetEntitiesUsingTemplate", std::vector<entity_id_t>, ICmpTemplateManager, GetEntitiesUsingTemplate, std::string)
|
||||
|
@ -303,15 +303,39 @@ CMessage* CMessagePathResult::FromJSVal(ScriptInterface& UNUSED(scriptInterface)
|
||||
jsval CMessageValueModification::ToJSVal(ScriptInterface& scriptInterface) const
|
||||
{
|
||||
TOJSVAL_SETUP();
|
||||
SET_MSG_PROPERTY(entities);
|
||||
SET_MSG_PROPERTY(component);
|
||||
SET_MSG_PROPERTY(valueNames);
|
||||
return OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
|
||||
CMessage* CMessageValueModification::FromJSVal(ScriptInterface& scriptInterface, jsval val)
|
||||
{
|
||||
FROMJSVAL_SETUP();
|
||||
GET_MSG_PROPERTY(std::vector<entity_id_t>, entities);
|
||||
GET_MSG_PROPERTY(std::wstring, component);
|
||||
return new CMessageValueModification(component);
|
||||
GET_MSG_PROPERTY(std::vector<std::wstring>, valueNames);
|
||||
return new CMessageValueModification(entities, component, valueNames);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
jsval CMessageTemplateModification::ToJSVal(ScriptInterface& scriptInterface) const
|
||||
{
|
||||
TOJSVAL_SETUP();
|
||||
SET_MSG_PROPERTY(player);
|
||||
SET_MSG_PROPERTY(component);
|
||||
SET_MSG_PROPERTY(valueNames);
|
||||
return OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
|
||||
CMessage* CMessageTemplateModification::FromJSVal(ScriptInterface& scriptInterface, jsval val)
|
||||
{
|
||||
FROMJSVAL_SETUP();
|
||||
GET_MSG_PROPERTY(player_id_t, player);
|
||||
GET_MSG_PROPERTY(std::wstring, component);
|
||||
GET_MSG_PROPERTY(std::vector<std::wstring>, valueNames);
|
||||
return new CMessageTemplateModification(player, component, valueNames);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
Loading…
Reference in New Issue
Block a user