Implement the js side of auras. Refs #2048. Patch with the help of Alpha123. Only the temple aura is added as example, all other aura components are removed from the templates to be created from scratch again.

This was SVN commit r13998.
This commit is contained in:
sanderd17 2013-10-14 15:51:21 +00:00
parent 57d47f23c9
commit 379a7b208f
49 changed files with 610 additions and 268 deletions

View File

@ -0,0 +1,179 @@
function AuraManager() {}
AuraManager.prototype.Schema =
"<a:component type='system'/><empty/>";
AuraManager.prototype.Init = function()
{
this.modificationsCache = {};
this.modifications = {};
this.templateModificationsCache = {};
this.templateModifications = {};
};
AuraManager.prototype.ensureExists = function(name, value, id, key, defaultData)
{
if (!this[name][value])
{
this[name][value] = {};
this[name+'Cache'][value] = {};
}
if (!this[name][value][id])
{
this[name][value][id] = {};
this[name+'Cache'][value][id] = defaultData;
}
if (!this[name][value][id][key])
this[name][value][id][key] = [];
}
AuraManager.prototype.ApplyBonus = function(value, ent, data, key)
{
this.ensureExists("modifications", value, ent, key, {"add":0, "multiply":1});
this.modifications[value][ent][key].push(data);
if (this.modifications[value][ent][key].length > 1)
return;
// first time added this aura
if (data.multiply)
this.modificationsCache[value][ent].multiply *= data.multiply;
if (data.add)
this.modificationsCache[value][ent].add += data.add;
// post message to the entity to notify it about the change
// TODO MT_TechnologyModification expects a player ID, so we have to provide something.
// Use -1 until this is changed not to require one.
// This player info is not needed, as the message gets send to the correct entities immediately
// A better way of handling this would be to remove the player info from the message data.
var component = value.split("/")[0];
Engine.PostMessage(ent, MT_TechnologyModification, { "component": component, "player": -1 });
};
AuraManager.prototype.ApplyTemplateBonus = function(value, player, classes, data, key)
{
this.ensureExists("templateModifications", value, player, key, {});
this.templateModifications[value][player][key].push(data);
if (this.templateModifications[value][player][key].length > 1)
return;
// first time added this aura
for each (var c in classes)
{
if (!this.templateModificationsCache[value][player][c])
this.templateModificationsCache[value][player][c] = [];
if (!this.templateModificationsCache[value][player][c][key])
this.templateModificationsCache[value][player][c][key] = { "add": 0, "multiply": 1};
if (data.multiply)
this.templateModificationsCache[value][player][c][key].multiply *= data.multiply;
if (data.add)
this.templateModificationsCache[value][player][c][key].add += data.add;
}
// post message to notify about the change
var component = value.split("/")[0];
Engine.BroadcastMessage(MT_TechnologyModification, { "component": component, "player": player});
};
AuraManager.prototype.RemoveBonus = function(value, ent, key)
{
if (!this.modifications[value] ||
!this.modifications[value][ent] ||
!this.modifications[value][ent][key] ||
!this.modifications[value][ent][key].length)
return;
// get the applied data to remove again
var data = this.modifications[value][ent][key].pop();
if (this.modifications[value][ent][key].length > 0)
return;
// out of last aura of this kind, remove modifications
if (data.add)
this.modificationsCache[value][ent].add -= data.add;
if (data.multiply)
this.modificationsCache[value][ent].multiply /= data.multiply;
// post message to the entity to notify it about the change
// TODO MT_TechnologyModification expects a player ID, so we have to provide something.
// Use -1 until this is changed not to require one.
// This player info is not needed, as the message gets send to the correct entities immediately
// A better way of handling this would be to remove the player info from the message data.
var component = value.split("/")[0];
Engine.PostMessage(ent, MT_TechnologyModification, { "component": component, "player": -1 });
};
AuraManager.prototype.RemoveTemplateBonus = function(value, player, classes, key)
{
if (!this.templateModifications[value] ||
!this.templateModifications[value][player] ||
!this.templateModifications[value][player][key] ||
!this.templateModifications[value][player][key].length)
return;
this.templateModifications[value][player][key].pop();
if (this.templateModifications[value][player][key].length > 0)
return;
for each (var c in classes)
{
this.templateModificationsCache[value][player][c][key].multiply = 1;
this.templateModificationsCache[value][player][c][key].add = 0;
}
// post message to notify about the change
var component = value.split("/")[0];
Engine.BroadcastMessage(MT_TechnologyModification, { "component": component, "player": player });
};
AuraManager.prototype.ApplyModifications = function(valueName, value, ent)
{
if (!this.modificationsCache[valueName] || !this.modificationsCache[valueName][ent])
return value;
value *= this.modificationsCache[valueName][ent].multiply;
value += this.modificationsCache[valueName][ent].add;
return value;
};
AuraManager.prototype.ApplyTemplateModifications = function(valueName, value, player, template)
{
if (!this.templateModificationsCache[valueName] || !this.templateModificationsCache[valueName][player])
return value;
var classes = template.Identity.Classes._string.split(/\s+/);
var keyList = [];
for (var c in this.templateModificationsCache[valueName][player])
{
if (classes.indexOf(c) == -1)
continue;
for (var key in this.templateModificationsCache[valueName][player][c])
{
// don't add an aura with the same key twice
if (keyList.indexOf(key) != -1)
continue;
value *= this.templateModificationsCache[valueName][player][c][key].multiply;
value += this.templateModificationsCache[valueName][player][c][key].add;
keyList.push(key);
}
}
return value;
};
Engine.RegisterComponentType(IID_AuraManager, "AuraManager", AuraManager);

View File

@ -2,41 +2,362 @@ function Auras() {}
Auras.prototype.Schema =
"<oneOrMore>" +
"<element>" +
"<choice>" +
"<name>Allure</name>" +
"<name>Infidelity</name>" +
"<name>Heal</name>" +
"<name>Courage</name>" +
"<name>Fear</name>" +
"</choice>" +
"<interleave>" +
"<element name='Radius'>" +
"<element a:help='Name of the aura JSON file to use, case-insensitive'>" +
"<anyName/>" +
"<optional>" +
"<element name='Radius' a:help='Define the radius this aura affects, if it is a range aura'>" +
"<data type='nonNegativeInteger'/>" +
"</element>" +
"<optional>" +
"<element name='Bonus'>" +
"<data type='positiveInteger'/>" +
"</element>" +
"</optional>" +
"<optional>" +
"<element name='Time'>" +
"<data type='nonNegativeInteger'/>" +
"</element>" +
"</optional>" +
"<optional>" +
"<element name='Speed'>" +
"<data type='positiveInteger'/>" +
"</element>" +
"</optional>" +
"</interleave>" +
"</optional>" +
"<element name='Type' a:help='Controls how this aura affects nearby units'>" +
"<choice>" +
"<value a:help='Affects units in the same formation'>formation</value>" +
"<value a:help='Affects units in a certain range'>range</value>" +
"<value a:help='Affects the structure or unit this unit is garrisoned in'>garrison</value>" +
"<value a:help='Affects all units while this unit is alive'>global</value>" +
"</choice>" +
"</element>" +
"</element>" +
"</oneOrMore>";
/*
* TODO: this all needs to be designed and implemented
*/
Auras.prototype.Init = function()
{
var cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
this.templateName = cmpTemplateManager.GetCurrentTemplateName(this.entity);
var auraNames = this.GetAuraNames();
this.auras = {};
var cmpTechnologyTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TechnologyTemplateManager);
for each (var name in auraNames)
this.auras[name] = cmpTechnologyTemplateManager.GetAuraTemplate(name);
};
Auras.prototype.Serialize = null; // we have no dynamic state to save
Auras.prototype.GetAuraNames = function()
{
return Object.keys(this.template);
};
Auras.prototype.GetRange = function(name)
{
if (!this.IsRangeAura(name))
return undefined;
if (this.IsGlobalAura(name))
return -1; // -1 is infinite range
return +this.template[name].Radius;
};
Auras.prototype.GetClasses = function(name)
{
return this.auras[name].affects;
};
Auras.prototype.GetModifications = function(name)
{
return this.auras[name].modifications;
};
Auras.prototype.GetAffectedPlayers = function(name)
{
if (this.auras[name].affectedPlayers)
var affectedPlayers = this.auras[name].affectedPlayers;
else
var affectedPlayers = ["Player"];
var ret = [];
var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
if (!cmpPlayer)
return ret;
var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
var numPlayers = cmpPlayerManager.GetNumPlayers();
for (var i = 0; i < numPlayers; ++i)
{
for each (var p in affectedPlayers)
{
if (p == "Player" ? cmpPlayer.GetPlayerID() == i : cmpPlayer["Is" + p](i))
{
ret.push(i);
break;
}
}
}
return ret;
};
Auras.prototype.HasFormationAura = function()
{
return this.GetAuraNames().some(this.IsFormationAura.bind(this));
};
Auras.prototype.HasGarrisonAura = function()
{
return this.GetAuraNames().some(this.IsGarrisonAura.bind(this));
};
Auras.prototype.GetType = function(name)
{
return this.template[name].Type;
};
Auras.prototype.IsFormationAura = function(name)
{
return this.GetType(name) == "Formation";
};
Auras.prototype.IsGarrisonAura = function(name)
{
return this.GetType(name) == "GarrisoningStructure";
};
Auras.prototype.IsRangeAura = function(name)
{
// A global aura is also treated as a range aura with infinite range.
return ["range", "global"].indexOf(this.GetType(name)) != -1;
};
Auras.prototype.IsGlobalAura = function(name)
{
return this.GetType(name) == "global";
};
/**
* clean all bonuses. Remove the old ones and re-apply the new ones
*/
Auras.prototype.Clean = function()
{
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
var auraNames = this.GetAuraNames();
// remove all bonuses
for each (var name in auraNames)
{
if (!this[name])
continue;
if (this.IsGlobalAura(name))
this.RemoveTemplateBonus(name);
for each(var ent in this[name].targetUnits)
this.RemoveBonus(name, ent);
if (this[name].rangeQuery)
cmpRangeManager.DestroyActiveQuery(this[name].rangeQuery);
}
for each (var name in auraNames)
{
// initialise range query
this[name] = {};
this[name].targetUnits = [];
var affectedPlayers = this.GetAffectedPlayers(name);
if (!affectedPlayers.length)
continue;
if (this.IsGlobalAura(name))
this.ApplyTemplateBonus(name, affectedPlayers);
if (!this.IsRangeAura(name))
continue;
this[name].rangeQuery = cmpRangeManager.CreateActiveQuery(
this.entity,
0,
this.GetRange(name),
affectedPlayers,
IID_Identity,
cmpRangeManager.GetEntityFlagMask("normal")
);
cmpRangeManager.EnableActiveQuery(this[name].rangeQuery);
// Add self to your own query for consistency with templates.
this.OnRangeUpdate({"tag":this[name].rangeQuery, "added":[this.entity], "removed":[]});
}
};
Auras.prototype.GiveMembersWithValidClass = function(auraName, entityList)
{
var validClasses = this.GetClasses(auraName);
var r = [];
for each (var ent in entityList)
{
var cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
var targetClasses = cmpIdentity.GetClassesList();
for each (var classCollection in validClasses)
{
if (classCollection.split(/\s+/).every(function(c) {return targetClasses.indexOf(c) > -1}))
{
r.push(ent);
break;
}
}
}
return r;
}
Auras.prototype.OnRangeUpdate = function(msg)
{
var auraNames = this.GetAuraNames();
for each (var n in auraNames)
{
if (msg.tag == this[n].rangeQuery)
{
var name = n;
break;
}
}
if (!name)
return;
var targetUnits = this[name].targetUnits;
var classes = this.GetClasses(name);
if (msg.added.length > 0)
{
var validList = this.GiveMembersWithValidClass(name, msg.added);
for each (var e in validList)
{
targetUnits.push(e);
this.ApplyBonus(name, e);
}
}
if (msg.removed.length > 0)
{
for each (var e in msg.removed)
{
targetUnits.splice(targetUnits.indexOf(e), 1);
this.RemoveBonus(name, e);
}
}
};
Auras.prototype.ApplyFormationBonus = function(memberList)
{
var auraNames = this.GetAuraNames();
for each (var name in auraNames)
{
if (!this.IsFormationAura(name))
continue;
var validList = this.GiveMembersWithValidClass(name, memberList);
for each (var ent in validList)
{
targetUnits.push(e);
this.ApplyBonus(name,e);
}
}
};
Auras.prototype.ApplyGarrisonBonus = function(structure)
{
var auraNames = this.GetAuraNames();
for each (var name in auraNames)
{
if (!this.IsGarrisonAura(name))
continue;
var validList = this.GiveMembersWithValidClass(name, [structure]);
if (validList.length)
{
targetUnits.push(validList[0]);
this.ApplyBonus(name,validList[0]);
}
}
};
Auras.prototype.ApplyTemplateBonus = function(name, players)
{
if (!this.IsGlobalAura(name))
return;
var modifications = this.GetModifications(name);
var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
var classes = this.GetClasses(name);
for each (var mod in modifications)
for each (var player in players)
cmpAuraManager.ApplyTemplateBonus(mod.value, player, classes, mod, this.templateName + "/" + name + "/" + mod.value);
};
Auras.prototype.RemoveFormationBonus = function(memberList)
{
var auraNames = this.GetAuraNames();
for each (var name in auraName)
{
if (!this.IsFormationAura(name))
continue;
for each (var ent in memberList)
{
this.RemoveBonus(name,ent);
this[name].targetUnits.splice(this[name].targetUnits.indexOf(ent), 1);
}
}
};
Auras.prototype.RemoveGarrisonBonus = function(structure)
{
var auraNames = this.GetAuraNames();
for each (var name in auraNames)
{
if (!this.IsGarrisonAura(name))
continue;
this.RemoveBonus(name,structure);
this[name].targetUnits.splice(this[name].targetUnits.indexOf(structure), 1);
}
};
Auras.prototype.RemoveTemplateBonus = function(name)
{
if (!this.IsGlobalAura(name))
return;
var modifications = this.GetModifications(name);
var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
var classes = this.GetClasses(name);
for each (var mod in modifications)
for each (var player in this.GetAffectedPlayers())
cmpAuraManager.RemoveTemplateBonus(mod.value, player, classes, this.templateName + "/" + name + "/" + mod.value);
};
Auras.prototype.ApplyBonus = function(name, ent)
{
var modifications = this.GetModifications(name);
var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
for each (mod in modifications)
cmpAuraManager.ApplyBonus(mod.value, ent, mod, this.templateName + "/" + name + "/" + mod.value);
};
Auras.prototype.RemoveBonus = function(name, ent)
{
var modifications = this.GetModifications(name);
var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
for each (mod in modifications)
cmpAuraManager.RemoveBonus(mod.value, ent, this.templateName + "/" + name + "/" + mod.value);
};
Auras.prototype.OnOwnershipChanged = function(msg)
{
this.Clean();
};
Auras.prototype.OnDiplomacyChanged = function(msg)
{
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
if (cmpOwnership && cmpOwnership.GetOwner() == msg.player)
this.Clean();
};
Auras.prototype.OnTechnologyModification = function(msg)
{
if (msg.component =="Auras")
this.Clean();
};
Engine.RegisterComponentType(IID_Auras, "Auras", Auras);

View File

@ -12,6 +12,7 @@ Formation.prototype.Init = function()
this.columnar = false; // whether we're travelling in column (vs box) formation
this.formationName = "Line Closed";
this.rearrange = true; // whether we should rearrange all formation members
this.formationMemebersWithAura = []; // Members with a formation aura
};
Formation.prototype.GetMemberCount = function()
@ -86,12 +87,20 @@ Formation.prototype.SetMembers = function(ents)
{
var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
cmpUnitAI.SetFormationController(this.entity);
var cmpAuras = Engine.QueryInterface(ent, IID_Auras);
if (cmpAuras && cmpAuras.HasFormationAura())
{
this.formationMemebersWithAura.push(ent);
cmpAuras.ApplyFormationBonus(ents);
}
}
// Locate this formation controller in the middle of its members
this.MoveToMembersCenter();
this.ComputeMotionParameters();
};
/**
@ -109,6 +118,18 @@ Formation.prototype.RemoveMembers = function(ents)
cmpUnitAI.SetFormationController(INVALID_ENTITY);
}
for each (var ent in this.formationMemebersWithAura)
{
var cmpAuras = Engine.QueryInterface(ent, IID_Auras);
cmpAuras.RemoveFormationBonus(ents);
// the unit with the aura is also removed from the formation
if (ents.indexOf(ent) !== -1)
cmpAuras.RemoveFormationBonus(this.members);
}
this.formationMemebersWithAura = this.formationMemebersWithAura.filter(function(e) { return ents.indexOf(e) == -1; });
// If there's nobody left, destroy the formation
if (this.members.length == 0)
{
@ -155,8 +176,16 @@ Formation.prototype.Disband = function()
cmpUnitAI.SetFormationController(INVALID_ENTITY);
}
for each (var ent in this.formationMemebersWithAura)
{
var cmpAuras = Engine.QueryInterface(ent, IID_Auras);
cmpAuras.RemoveFormationBonus(this.members);
}
this.members = [];
this.inPosition = [];
this.formationMemebersWithAura = [];
Engine.DestroyEntity(this.entity);
};

View File

@ -185,6 +185,10 @@ GarrisonHolder.prototype.Garrison = function(entity)
if (cmpProductionQueue)
cmpProductionQueue.PauseProduction();
var cmpAura = Engine.QueryInterface(entity, IID_Auras);
if (cmpAura && cmpAura.HasGarrisonAura())
cmpAura.ApplyGarrisonBonus(this.entity);
Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {});
return true;
};
@ -228,6 +232,11 @@ GarrisonHolder.prototype.Eject = function(entity, forced)
var cmpProductionQueue = Engine.QueryInterface(entity, IID_ProductionQueue);
if (cmpProductionQueue)
cmpProductionQueue.UnpauseProduction();
var cmpAura = Engine.QueryInterface(entity, IID_Auras);
if (cmpAura && cmpAura.HasGarrisonAura())
cmpAura.RemoveGarrisonBonus(this.entity);
var cmpNewPosition = Engine.QueryInterface(entity, IID_Position);
cmpNewPosition.JumpTo(pos.x, pos.z);

View File

@ -9,6 +9,7 @@ TechnologyTemplateManager.prototype.Schema =
TechnologyTemplateManager.prototype.Init = function()
{
this.allTechs = {};
this.allAuras = {};
var techNames = this.ListAllTechs();
for (var i in techNames)
this.GetTemplate(techNames[i]);
@ -26,6 +27,18 @@ TechnologyTemplateManager.prototype.GetTemplate = function(template)
return this.allTechs[template];
};
TechnologyTemplateManager.prototype.GetAuraTemplate = function(template)
{
if (!this.allAuras[template])
{
this.allAuras[template] = Engine.ReadJSONFile("auras/" + template + ".json");
if (! this.allAuras[template])
error("Failed to load aura \"" + template + "\"");
}
return this.allAuras[template];
};
TechnologyTemplateManager.prototype.ListAllTechs = function()
{
return Engine.FindJSONFiles("technologies", true);

View File

@ -0,0 +1 @@
Engine.RegisterInterface("AuraManager");

View File

@ -2,6 +2,7 @@ Engine.LoadHelperScript("FSM.js");
Engine.LoadHelperScript("Entity.js");
Engine.LoadHelperScript("Player.js");
Engine.LoadComponentScript("interfaces/Attack.js");
Engine.LoadComponentScript("interfaces/Auras.js");
Engine.LoadComponentScript("interfaces/DamageReceiver.js");
Engine.LoadComponentScript("interfaces/Formation.js");
Engine.LoadComponentScript("interfaces/Heal.js");

View File

@ -0,0 +1,5 @@
{
"affects":["Unit"],
"affectedPlayers":["Player"],
"modifications":[{"value":"Health/RegenRate","add":1}]
}

View File

@ -3,11 +3,15 @@
function ApplyTechModificationsToEntity(tech_type, current_value, entity)
{
var cmpTechMan = QueryOwnerInterface(entity, IID_TechnologyManager);
if (cmpTechMan)
var value = cmpTechMan.ApplyModificationsTemplate(tech_type, current_value, entity);
else
var value = current_value;
if (!cmpTechMan)
return current_value;
return cmpTechMan.ApplyModifications(tech_type, current_value, entity);
var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
if (!cmpAuraManager)
return value;
return cmpAuraManager.ApplyModifications(tech_type, value, entity);
}
function ApplyTechModificationsToPlayer(tech_type, current_value, player_entity)
@ -23,11 +27,15 @@ function ApplyTechModificationsToPlayer(tech_type, current_value, player_entity)
function ApplyTechModificationsToTemplate(tech_type, current_value, playerID, template)
{
var cmpTechMan = QueryPlayerIDInterface(playerID, IID_TechnologyManager);
if (cmpTechMan)
var value = cmpTechMan.ApplyModificationsTemplate(tech_type, current_value, template);
else
var value = current_value;
if (!cmpTechMan)
return current_value;
return cmpTechMan.ApplyModificationsTemplate(tech_type, current_value, template);
var cmpAuraManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_AuraManager);
if (!cmpAuraManager)
return value;
return cmpAuraManager.ApplyTemplateModifications(tech_type, value, playerID, template);
}
Engine.RegisterGlobal("ApplyTechModificationsToEntity", ApplyTechModificationsToEntity);

View File

@ -8,12 +8,6 @@
<MaxRange>7.0</MaxRange>
</Melee>
</Attack>
<Auras>
<Fear>
<Radius>80</Radius>
<Bonus>15</Bonus>
</Fear>
</Auras>
<Cost>
<Resources>
<metal>300</metal>

View File

@ -15,7 +15,7 @@
<ResourceSupply>
<Amount>40</Amount>
<Type>food.meat</Type>
<MaxGatherers>5</MaxGatherers>
<MaxGatherers>5</MaxGatherers>
</ResourceSupply>
<Sound>
<SoundGroups>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_structure_civic_house">
<Auras>
<Heal>
<Radius>30</Radius>
<Speed>1000</Speed>
</Heal>
</Auras>
<Cost>
<PopulationBonus>10</PopulationBonus>
<BuildTime>200</BuildTime>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_structure_civic_house">
<Auras>
<Heal>
<Radius>30</Radius>
<Speed>1000</Speed>
</Heal>
</Auras>
<Cost>
<PopulationBonus>10</PopulationBonus>
<BuildTime>200</BuildTime>

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_structure_civic">
<Auras>
<Heal>
<heal>
<Type>range</Type>
<Radius>40</Radius>
<Speed>1000</Speed>
</Heal>
</heal>
</Auras>
<BuildRestrictions>
<Category>Temple</Category>
@ -34,7 +34,7 @@
</Health>
<Identity>
<GenericName>Temple</GenericName>
<Tooltip>Train healers. Garrison up to 20 units to heal them at a quick rate. Research healing and religious improvements.</Tooltip>
<Tooltip>Train healers. Garrison up to 20 units to heal them at a quick rate. Research healing and religious improvements. Heals nearby units, but slower than garrisoned units.</Tooltip>
<Classes datatype="tokens">
Town
Temple

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_fauna">
<Auras>
<Infidelity>
<Radius>20</Radius>
<Time>0</Time>
</Infidelity>
</Auras>
<Identity>
</Identity>
<Vision>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_fauna">
<Auras>
<Infidelity>
<Radius>20</Radius>
<Time>0</Time>
</Infidelity>
</Auras>
<Health>
<DeathType>remain</DeathType>
</Health>

View File

@ -16,15 +16,6 @@
<MaxRange>4.0</MaxRange>
</Slaughter>
</Attack>
<Auras>
<Allure>
<Radius>25</Radius>
</Allure>
<Infidelity>
<Radius>10</Radius>
<Time>10</Time>
</Infidelity>
</Auras>
<Builder>
<Rate>1.0</Rate>
<Entities datatype="tokens">

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_infantry_javelinist">
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Identity>
<Civ>athen</Civ>
<GenericName>Iphicrates</GenericName>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_infantry_spearman">
<Auras>
<Fear>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Fear>
</Auras>
<Identity>
<Civ>athen</Civ>
<GenericName>Pericles</GenericName>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_infantry_swordsman">
<Auras>
<Fear>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Fear>
</Auras>
<Identity>
<Civ>athen</Civ>
<GenericName>Themistocles</GenericName>

View File

@ -5,12 +5,6 @@
<Pierce>7</Pierce>
<Crush>8</Crush>
</Armour>
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Cost>
<Population>4</Population>
<BuildTime>50</BuildTime>

View File

@ -5,12 +5,6 @@
<Pierce>6</Pierce>
<Crush>6</Crush>
</Armour>
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Identity>
<Civ>brit</Civ>
<SpecificName>Boudicca</SpecificName>

View File

@ -13,12 +13,6 @@
<Hack>54.0</Hack>
</Charge>
</Attack>
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Identity>
<Civ>brit</Civ>
<SpecificName>Caratacos</SpecificName>

View File

@ -3,12 +3,6 @@
<Armour>
<Hack>10</Hack>
</Armour>
<Auras>
<Heal>
<Radius>25</Radius>
<Speed>1000</Speed>
</Heal>
</Auras>
<Identity>
<Civ>brit</Civ>
<SpecificName>Cynvelin</SpecificName>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_cavalry_javelinist">
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Cost>
<Population>4</Population>
<BuildTime>50</BuildTime>

View File

@ -3,12 +3,6 @@
<Armour>
<Hack>9</Hack>
</Armour>
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Identity>
<Civ>celt</Civ>
<SpecificName>Brennus</SpecificName>

View File

@ -3,12 +3,6 @@
<Armour>
<Hack>9</Hack>
</Armour>
<Auras>
<Fear>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Fear>
</Auras>
<Identity>
<Civ>celt</Civ>
<SpecificName>Britomartus</SpecificName>

View File

@ -8,12 +8,6 @@
<Hack>54.0</Hack>
</Charge>
</Attack>
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Identity>
<Civ>celt</Civ>
<SpecificName>Caratacos</SpecificName>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_cavalry_swordsman">
<Auras>
<Heal>
<Radius>25</Radius>
<Speed>1000</Speed>
</Heal>
</Auras>
<Identity>
<Civ>celt</Civ>
<SpecificName>Cynvelin</SpecificName>

View File

@ -8,12 +8,6 @@
<Hack>54.0</Hack>
</Charge>
</Attack>
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Cost>
<Resources>
<metal>260</metal>

View File

@ -3,12 +3,6 @@
<Armour>
<Hack>7</Hack>
</Armour>
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Identity>
<Civ>gaul</Civ>
<SpecificName>Brennus</SpecificName>

View File

@ -3,12 +3,6 @@
<Armour>
<Hack>9</Hack>
</Armour>
<Auras>
<Fear>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Fear>
</Auras>
<Identity>
<Civ>gaul</Civ>
<SpecificName>Britomartus</SpecificName>

View File

@ -8,12 +8,6 @@
<Hack>54.0</Hack>
</Charge>
</Attack>
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Cost>
<Resources>
<metal>260</metal>

View File

@ -3,12 +3,6 @@
<Armour>
<Crush>20</Crush>
</Armour>
<Auras>
<Fear>
<Radius>80</Radius>
<Bonus>15</Bonus>
</Fear>
</Auras>
<Cost>
<Resources>
<metal>300</metal>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_infantry_pikeman">
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Identity>
<Civ>hele</Civ>
<GenericName>Demetrius The Besieger</GenericName>

View File

@ -17,12 +17,6 @@
<MaxRange>6.0</MaxRange>
</Charge>
</Attack>
<Auras>
<Fear>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Fear>
</Auras>
<Cost>
<Resources>
<metal>225</metal>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_cavalry_spearman">
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Identity>
<Civ>hele</Civ>
<GenericName>Philip II of Macedon</GenericName>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_infantry_swordsman">
<Auras>
<Fear>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Fear>
</Auras>
<Identity>
<Civ>hele</Civ>
<GenericName>Themistocles</GenericName>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_infantry_javelinist">
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Identity>
<Civ>hele</Civ>
<GenericName>Xenophon</GenericName>

View File

@ -21,12 +21,6 @@
</Bonuses>
</Charge>
</Attack>
<Auras>
<Fear>
<Radius>80</Radius>
<Bonus>15</Bonus>
</Fear>
</Auras>
<Cost>
<Resources>
<metal>300</metal>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_infantry_swordsman">
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Identity>
<Civ>mace</Civ>
<GenericName>Crateros</GenericName>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_infantry_swordsman">
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Identity>
<Civ>mace</Civ>
<GenericName>Demetrius The Besieger</GenericName>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_cavalry_spearman">
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Courage>
</Auras>
<Identity>
<Civ>mace</Civ>
<GenericName>Philip II of Macedon</GenericName>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_cavalry_swordsman">
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>10</Bonus>
</Courage>
</Auras>
<Identity>
<Civ>rome</Civ>
<SpecificName>Marcus Claudius Marcellus</SpecificName>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_cavalry_swordsman">
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>10</Bonus>
</Courage>
</Auras>
<Identity>
<Civ>rome</Civ>
<SpecificName>Quinctus Fabius Maximus</SpecificName>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_cavalry_swordsman">
<Auras>
<Courage>
<Radius>20</Radius>
<Bonus>10</Bonus>
</Courage>
</Auras>
<Identity>
<Civ>rome</Civ>
<SpecificName>Scipio Africanus</SpecificName>

View File

@ -1,11 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Entity parent="template_unit_hero_infantry_swordsman">
<Auras>
<Fear>
<Radius>20</Radius>
<Bonus>5</Bonus>
</Fear>
</Auras>
<Identity>
<Civ>spart</Civ>
<GenericName>Brasidas</GenericName>

View File

@ -17,12 +17,6 @@
<MaxRange>6.0</MaxRange>
</Charge>
</Attack>
<Auras>
<Fear>
<Radius>8</Radius>
<Bonus>5</Bonus>
</Fear>
</Auras>
<Identity>
<Civ>spart</Civ>
<GenericName>Leonidas I</GenericName>

View File

@ -125,6 +125,7 @@ public:
LOGERROR(L"Can't find component type " L##name); \
componentManager.AddComponent(systemEntity, cid, noParam)
LOAD_SCRIPTED_COMPONENT("AuraManager");
LOAD_SCRIPTED_COMPONENT("AIInterface");
LOAD_SCRIPTED_COMPONENT("Barter");
LOAD_SCRIPTED_COMPONENT("EndGameManager");