2011-01-12 13:29:00 +01:00
|
|
|
function AIInterface() {}
|
|
|
|
|
|
|
|
AIInterface.prototype.Schema =
|
|
|
|
"<a:component type='system'/><empty/>";
|
|
|
|
|
2014-01-18 21:26:52 +01:00
|
|
|
AIInterface.prototype.EventNames = [
|
|
|
|
"Create",
|
|
|
|
"Destroy",
|
|
|
|
"Attacked",
|
|
|
|
"RangeUpdate",
|
|
|
|
"ConstructionFinished",
|
2014-06-14 16:34:37 +02:00
|
|
|
"TrainingStarted",
|
2014-01-18 21:26:52 +01:00
|
|
|
"TrainingFinished",
|
|
|
|
"AIMetadata",
|
|
|
|
"PlayerDefeated",
|
|
|
|
"EntityRenamed",
|
|
|
|
"OwnershipChanged",
|
|
|
|
"Garrison",
|
|
|
|
"UnGarrison"
|
|
|
|
];
|
|
|
|
|
2011-01-12 13:29:00 +01:00
|
|
|
AIInterface.prototype.Init = function()
|
|
|
|
{
|
2014-01-10 02:46:27 +01:00
|
|
|
this.events = {};
|
2014-01-18 21:26:52 +01:00
|
|
|
for each (var i in this.EventNames)
|
|
|
|
this.events[i] = [];
|
2014-01-10 02:46:27 +01:00
|
|
|
|
2011-03-03 01:16:14 +01:00
|
|
|
this.changedEntities = {};
|
2014-01-16 21:32:44 +01:00
|
|
|
|
|
|
|
// cache for technology changes;
|
|
|
|
// this one is PlayerID->TemplateName->{StringForTheValue, ActualValue}
|
|
|
|
this.changedTemplateInfo = {};
|
|
|
|
// this is for auras and is EntityID->{StringForTheValue, ActualValue}
|
|
|
|
this.changedEntityTemplateInfo = {};
|
2011-01-12 13:29:00 +01:00
|
|
|
};
|
|
|
|
|
2014-01-16 21:32:44 +01:00
|
|
|
AIInterface.prototype.GetNonEntityRepresentation = function()
|
2011-01-12 13:29:00 +01:00
|
|
|
{
|
|
|
|
var cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
|
2014-01-16 21:32:44 +01:00
|
|
|
|
2011-01-12 13:29:00 +01:00
|
|
|
// Return the same game state as the GUI uses
|
2013-03-05 23:52:48 +01:00
|
|
|
var state = cmpGuiInterface.GetExtendedSimulationState(-1);
|
2014-01-16 21:32:44 +01:00
|
|
|
|
2011-01-12 13:29:00 +01:00
|
|
|
// Add some extra AI-specific data
|
2014-01-18 21:26:52 +01:00
|
|
|
// add custom events and reset them for the next turn
|
2014-01-10 02:46:27 +01:00
|
|
|
state.events = {};
|
2014-01-18 21:26:52 +01:00
|
|
|
for each (var i in this.EventNames)
|
|
|
|
{
|
|
|
|
state.events[i] = this.events[i];
|
|
|
|
this.events[i] = [];
|
|
|
|
}
|
2014-01-16 21:32:44 +01:00
|
|
|
|
|
|
|
return state;
|
|
|
|
};
|
|
|
|
|
|
|
|
AIInterface.prototype.GetRepresentation = function()
|
|
|
|
{
|
|
|
|
var state = this.GetNonEntityRepresentation();
|
|
|
|
|
2011-01-16 00:35:20 +01:00
|
|
|
// Add entity representations
|
2011-03-03 01:16:14 +01:00
|
|
|
Engine.ProfileStart("proxy representations");
|
2011-01-16 00:35:20 +01:00
|
|
|
state.entities = {};
|
2011-03-03 01:16:14 +01:00
|
|
|
for (var id in this.changedEntities)
|
2011-01-16 00:35:20 +01:00
|
|
|
{
|
2011-03-03 01:16:14 +01:00
|
|
|
var aiProxy = Engine.QueryInterface(+id, IID_AIProxy);
|
|
|
|
if (aiProxy)
|
|
|
|
state.entities[id] = aiProxy.GetRepresentation();
|
2011-01-16 00:35:20 +01:00
|
|
|
}
|
2011-03-03 01:16:14 +01:00
|
|
|
this.changedEntities = {};
|
|
|
|
Engine.ProfileStop();
|
2011-01-16 00:35:20 +01:00
|
|
|
|
2014-01-16 21:32:44 +01:00
|
|
|
state.changedTemplateInfo = this.changedTemplateInfo;
|
|
|
|
this.changedTemplateInfo = {};
|
|
|
|
state.changedEntityTemplateInfo = this.changedEntityTemplateInfo;
|
|
|
|
this.changedEntityTemplateInfo = {};
|
|
|
|
|
2011-01-12 13:29:00 +01:00
|
|
|
return state;
|
|
|
|
};
|
2014-01-16 21:32:44 +01:00
|
|
|
|
2013-03-05 23:52:48 +01:00
|
|
|
// Intended to be called first, during the map initialization: no caching
|
2013-12-04 17:52:44 +01:00
|
|
|
AIInterface.prototype.GetFullRepresentation = function(flushEvents)
|
2014-01-16 21:32:44 +01:00
|
|
|
{
|
|
|
|
var state = this.GetNonEntityRepresentation();
|
2014-01-10 02:46:27 +01:00
|
|
|
|
2013-12-04 17:52:44 +01:00
|
|
|
if (flushEvents)
|
2014-01-18 21:26:52 +01:00
|
|
|
for each (var i in this.EventNames)
|
|
|
|
state.events[i] = [];
|
2014-01-10 02:46:27 +01:00
|
|
|
|
2013-03-05 23:52:48 +01:00
|
|
|
// 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();
|
|
|
|
|
2014-01-16 21:32:44 +01:00
|
|
|
state.changedTemplateInfo = this.changedTemplateInfo;
|
|
|
|
this.changedTemplateInfo = {};
|
|
|
|
state.changedEntityTemplateInfo = this.changedEntityTemplateInfo;
|
|
|
|
this.changedEntityTemplateInfo = {};
|
|
|
|
|
2013-03-05 23:52:48 +01:00
|
|
|
return state;
|
|
|
|
};
|
2011-01-12 13:29:00 +01:00
|
|
|
|
2011-03-03 01:16:14 +01:00
|
|
|
AIInterface.prototype.ChangedEntity = function(ent)
|
|
|
|
{
|
|
|
|
this.changedEntities[ent] = 1;
|
|
|
|
};
|
|
|
|
|
2011-02-05 21:35:34 +01:00
|
|
|
// 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.
|
2011-01-12 13:29:00 +01:00
|
|
|
|
2011-02-05 21:35:34 +01:00
|
|
|
AIInterface.prototype.PushEvent = function(type, msg)
|
2011-01-12 13:29:00 +01:00
|
|
|
{
|
2014-01-10 02:46:27 +01:00
|
|
|
if (this.events[type] === undefined)
|
|
|
|
warn("Tried to push unknown event type " + type +", please add it to AIInterface.js");
|
|
|
|
this.events[type].push(msg);
|
2011-01-12 13:29:00 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
AIInterface.prototype.OnGlobalPlayerDefeated = function(msg)
|
|
|
|
{
|
2014-01-10 02:46:27 +01:00
|
|
|
this.events["PlayerDefeated"].push(msg);
|
2011-01-12 13:29:00 +01:00
|
|
|
};
|
|
|
|
|
2013-12-04 17:52:44 +01:00
|
|
|
AIInterface.prototype.OnGlobalEntityRenamed = function(msg)
|
|
|
|
{
|
2014-01-10 02:46:27 +01:00
|
|
|
this.events["EntityRenamed"].push(msg);
|
2013-12-04 17:52:44 +01:00
|
|
|
};
|
|
|
|
|
2014-01-16 21:32:44 +01:00
|
|
|
// 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)
|
|
|
|
{
|
2014-01-18 21:56:21 +01:00
|
|
|
var templateName = cmpTemplateManager.GetCurrentTemplateName(ent);
|
|
|
|
// if there's no template name, the unit is probably killed, ignore it.
|
|
|
|
if (!templateName || !templateName.length)
|
|
|
|
continue;
|
|
|
|
var template = cmpTemplateManager.GetTemplateWithoutValidation(templateName);
|
2014-01-16 21:32:44 +01:00
|
|
|
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 });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-05-18 15:44:08 +02:00
|
|
|
Engine.RegisterSystemComponentType(IID_AIInterface, "AIInterface", AIInterface);
|