forked from 0ad/0ad
wraitii
c1e86161b5
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.
246 lines
7.9 KiB
JavaScript
246 lines
7.9 KiB
JavaScript
function AIInterface() {}
|
|
|
|
AIInterface.prototype.Schema =
|
|
"<a:component type='system'/><empty/>";
|
|
|
|
AIInterface.prototype.Init = function()
|
|
{
|
|
this.events = {};
|
|
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"] = [];
|
|
|
|
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.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"];
|
|
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"];
|
|
// 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"] = [];
|
|
|
|
return state;
|
|
};
|
|
|
|
AIInterface.prototype.GetRepresentation = function()
|
|
{
|
|
var state = this.GetNonEntityRepresentation();
|
|
|
|
// Add entity representations
|
|
Engine.ProfileStart("proxy representations");
|
|
state.entities = {};
|
|
for (var id in this.changedEntities)
|
|
{
|
|
var aiProxy = Engine.QueryInterface(+id, IID_AIProxy);
|
|
if (aiProxy)
|
|
state.entities[id] = aiProxy.GetRepresentation();
|
|
}
|
|
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 state = this.GetNonEntityRepresentation();
|
|
|
|
if (flushEvents)
|
|
{
|
|
state.events["Create"] = [];
|
|
state.events["Destroy"] = [];
|
|
state.events["Attacked"] = [];
|
|
state.events["RangeUpdate"] = [];
|
|
state.events["ConstructionFinished"] = [];
|
|
state.events["TrainingFinished"] = [];
|
|
state.events["AIMetadata"] = [];
|
|
state.events["PlayerDefeated"] = [];
|
|
state.events["EntityRenamed"] = [];
|
|
state.events["OwnershipChanged"] = [];
|
|
}
|
|
|
|
// Add entity representations
|
|
Engine.ProfileStart("proxy representations");
|
|
state.entities = {};
|
|
// all entities are changed in the initial state.
|
|
for (var id in this.changedEntities)
|
|
{
|
|
var aiProxy = Engine.QueryInterface(+id, IID_AIProxy);
|
|
if (aiProxy)
|
|
state.entities[id] = aiProxy.GetFullRepresentation();
|
|
}
|
|
Engine.ProfileStop();
|
|
|
|
state.changedTemplateInfo = this.changedTemplateInfo;
|
|
this.changedTemplateInfo = {};
|
|
state.changedEntityTemplateInfo = this.changedEntityTemplateInfo;
|
|
this.changedEntityTemplateInfo = {};
|
|
|
|
return state;
|
|
};
|
|
|
|
AIInterface.prototype.ChangedEntity = function(ent)
|
|
{
|
|
this.changedEntities[ent] = 1;
|
|
};
|
|
|
|
// AIProxy sets up a load of event handlers to capture interesting things going on
|
|
// in the world, which we will report to AI. Handle those, and add a few more handlers
|
|
// for events that AIProxy won't capture.
|
|
|
|
AIInterface.prototype.PushEvent = function(type, msg)
|
|
{
|
|
if (this.events[type] === undefined)
|
|
warn("Tried to push unknown event type " + type +", please add it to AIInterface.js");
|
|
this.events[type].push(msg);
|
|
};
|
|
|
|
AIInterface.prototype.OnGlobalPlayerDefeated = function(msg)
|
|
{
|
|
this.events["PlayerDefeated"].push(msg);
|
|
};
|
|
|
|
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);
|