1
0
forked from 0ad/0ad

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:
wraitii 2014-01-16 20:32:44 +00:00
parent 4b828ae6bf
commit c1e86161b5
15 changed files with 453 additions and 252 deletions

View File

@ -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;
}
}

View File

@ -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)
{

View File

@ -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.

View File

@ -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 = {};
},
genericName: function() {
if (!this._template.Identity || !this._template.Identity.GenericName)
return undefined;
return this._template.Identity.GenericName;
// 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];
}
},
rank: function() {
if (!this._template.Identity)
genericName: function() {
if (!this.get("Identity") || !this.get("Identity/GenericName"))
return undefined;
return this._template.Identity.Rank;
return this.get("Identity/GenericName");
},
rank: function() {
if (!this.get("Identity"))
return undefined;
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,134 +122,134 @@ 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
},
/**
* Returns the radius of a circle surrounding this entity's
* 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);
@ -493,7 +514,7 @@ m.Entity = m.Class({
deleteAllMetadata: function(player) {
delete this._ai._entityMetadata[player][this.id()];
},
deleteMetadata: function(player, key) {
this._ai.deleteMetadata(player, this, key);
},
@ -508,7 +529,8 @@ 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; },
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()); },
needsHeal: function() { return this.isHurt() && this.isHealable(); },
@ -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
},
@ -557,18 +582,18 @@ m.Entity = m.Class({
return undefined;
return this._entity.resourceSupplyAmount;
},
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;
},
@ -578,10 +603,10 @@ m.Entity = m.Class({
return undefined;
return this._entity.resourceCarrying;
},
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 &&
@ -599,13 +624,13 @@ m.Entity = m.Class({
var type = ress.resourceSupplyType();
var tstring = type.generic + "." + type.specific;
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;
return 0;
@ -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;
@ -751,7 +776,7 @@ m.Entity = m.Class({
});
return this;
},
research: function(template) {
Engine.PostCommand(PlayerID,{ "type": "research", "entity": this.id(), "template": template });
return this;

View File

@ -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) {

View File

@ -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();
};

View File

@ -18,15 +18,21 @@ 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);
// 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"];
@ -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"] = [];
@ -51,7 +56,14 @@ AIInterface.prototype.GetRepresentation = function()
this.events["PlayerDefeated"] = [];
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);

View File

@ -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);

View File

@ -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)

View File

@ -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),
};
}

View File

@ -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

View File

@ -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;
};
/**

View File

@ -48,6 +48,7 @@ MESSAGE(TerrainChanged)
MESSAGE(TerritoriesChanged)
MESSAGE(PathResult)
MESSAGE(ValueModification)
MESSAGE(TemplateModification)
MESSAGE(VisionRangeChanged)
MESSAGE(MinimapPing)

View File

@ -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)

View File

@ -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);
}
////////////////////////////////