Index: ps/trunk/binaries/data/mods/public/simulation/data/auras/ship_speed.json
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/data/auras/ship_speed.json (revision 14245)
+++ ps/trunk/binaries/data/mods/public/simulation/data/auras/ship_speed.json (nonexistent)
@@ -1,5 +0,0 @@
-{
- "affects":["Ship"],
- "affectedPlayers":["Player","MutualAlly"],
- "modifications":[{"value":"UnitMotion/WalkSpeed","multiply":1.5}]
-}
Index: ps/trunk/binaries/data/mods/public/simulation/components/Auras.js
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/components/Auras.js (revision 14245)
+++ ps/trunk/binaries/data/mods/public/simulation/components/Auras.js (revision 14246)
@@ -1,364 +1,368 @@
function Auras() {}
Auras.prototype.Schema =
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"formation" +
"range" +
"garrison" +
"global" +
"" +
"" +
"" +
"";
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.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) == "garrison";
};
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":[]});
+
+ if (this.IsGlobalAura(name))
+ {
+ // update stats in for all templates
+ this.ApplyTemplateBonus(name, affectedPlayers);
+ // 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)
{
this[name].targetUnits.push(ent);
this.ApplyBonus(name,ent);
}
}
};
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)
{
this[name].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 auraNames)
{
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);
var players = this.GetAffectedPlayers(name);
for each (var mod in modifications)
for each (var player in players)
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 (var 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 (var 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.OnValueModification = function(msg)
{
if (msg.component == "Auras")
this.Clean();
};
Engine.RegisterComponentType(IID_Auras, "Auras", Auras);
Index: ps/trunk/binaries/data/mods/public/simulation/components/Health.js
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/components/Health.js (revision 14245)
+++ ps/trunk/binaries/data/mods/public/simulation/components/Health.js (revision 14246)
@@ -1,359 +1,356 @@
function Health() {}
Health.prototype.Schema =
"Deals with hitpoints and death." +
"" +
"100" +
"1.0" +
"corpse" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"vanish" +
"corpse" +
"remain" +
"" +
"" +
"" +
"" +
"" +
"" +
"" +
"";
Health.prototype.Init = function()
{
// Cache this value so it allows techs to maintain previous health level
this.maxHitpoints = +this.template.Max;
// Default to , but use if it's undefined or zero
// (Allowing 0 initial HP would break our death detection code)
this.hitpoints = +(this.template.Initial || this.GetMaxHitpoints());
- this.regenRate = +this.template.RegenRate;
+ this.regenRate = ApplyValueModificationsToEntity("Health/RegenRate", +this.template.RegenRate, this.entity);
this.CheckRegenTimer();
};
//// Interface functions ////
/**
* Returns the current hitpoint value.
* This is 0 if (and only if) the unit is dead.
*/
Health.prototype.GetHitpoints = function()
{
return this.hitpoints;
};
Health.prototype.GetMaxHitpoints = function()
{
return this.maxHitpoints;
};
Health.prototype.SetHitpoints = function(value)
{
// If we're already dead, don't allow resurrection
if (this.hitpoints == 0)
return;
var old = this.hitpoints;
this.hitpoints = Math.max(1, Math.min(this.GetMaxHitpoints(), value));
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
if (cmpRangeManager)
{
if (this.hitpoints < this.GetMaxHitpoints())
cmpRangeManager.SetEntityFlag(this.entity, "injured", true);
else
cmpRangeManager.SetEntityFlag(this.entity, "injured", false);
}
Engine.PostMessage(this.entity, MT_HealthChanged, { "from": old, "to": this.hitpoints });
};
Health.prototype.IsRepairable = function()
{
return (this.template.Repairable == "true");
};
Health.prototype.IsUnhealable = function()
{
return (this.template.Unhealable == "true"
|| this.GetHitpoints() <= 0
|| this.GetHitpoints() >= this.GetMaxHitpoints());
};
Health.prototype.GetRegenRate = function()
{
return this.regenRate;
};
Health.prototype.ExecuteRegeneration = function()
{
var regen = this.GetRegenRate();
if (regen > 0)
this.Increase(regen);
else
this.Reduce(-regen);
};
/*
* Check if the regeneration timer needs to be started or stopped
*/
Health.prototype.CheckRegenTimer = function()
{
// check if we need a timer
if (this.GetRegenRate() == 0 ||
this.GetHitpoints() == this.GetMaxHitpoints() && this.GetRegenRate() > 0 ||
this.GetHitpoints() == 0)
{
// we don't need a timer, disable if one exists
if (this.regenTimer)
{
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
cmpTimer.CancelTimer(this.regenTimer);
this.regenTimer = undefined;
}
return;
}
- // we need a timer, enable is one doesn't exist
+ // we need a timer, enable if one doesn't exist
if (this.regenTimer)
return;
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
this.regenTimer = cmpTimer.SetInterval(this.entity, IID_Health, "ExecuteRegeneration", 1000, 1000, null);
};
Health.prototype.Kill = function()
{
this.Reduce(this.hitpoints);
};
/**
* Reduces entity's health by amount HP.
* Returns object of the form { "killed": false, "change": -12 }
*/
Health.prototype.Reduce = function(amount)
{
var state = { "killed": false };
if (amount >= 0 && this.hitpoints == this.GetMaxHitpoints())
{
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
if (cmpRangeManager)
cmpRangeManager.SetEntityFlag(this.entity, "injured", true);
}
var oldHitpoints = this.hitpoints;
if (amount >= this.hitpoints)
{
// If this is the first time we reached 0, then die.
// (The entity will exist a little while after calling DestroyEntity so this
// might get called multiple times)
if (this.hitpoints)
{
state.killed = true;
PlaySound("death", this.entity);
// If SpawnEntityOnDeath is set, spawn the entity
if(this.template.SpawnEntityOnDeath)
this.CreateDeathSpawnedEntity();
if (this.template.DeathType == "corpse")
{
this.CreateCorpse();
Engine.DestroyEntity(this.entity);
}
else if (this.template.DeathType == "vanish")
{
Engine.DestroyEntity(this.entity);
}
else if (this.template.DeathType == "remain")
{
var resource = this.CreateCorpse(true);
if (resource != INVALID_ENTITY)
Engine.BroadcastMessage(MT_EntityRenamed, { entity: this.entity, newentity: resource });
Engine.DestroyEntity(this.entity);
}
this.hitpoints = 0;
Engine.PostMessage(this.entity, MT_HealthChanged, { "from": oldHitpoints, "to": this.hitpoints });
}
}
else
{
this.hitpoints -= amount;
Engine.PostMessage(this.entity, MT_HealthChanged, { "from": oldHitpoints, "to": this.hitpoints });
}
state.change = this.hitpoints - oldHitpoints;
return state;
};
Health.prototype.Increase = function(amount)
{
if (this.hitpoints == this.GetMaxHitpoints())
return {"old": this.hitpoints, "new":this.hitpoints};
// If we're already dead, don't allow resurrection
if (this.hitpoints == 0)
return undefined;
var old = this.hitpoints;
this.hitpoints = Math.min(this.hitpoints + amount, this.GetMaxHitpoints());
if (this.hitpoints == this.GetMaxHitpoints())
{
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
if (cmpRangeManager)
cmpRangeManager.SetEntityFlag(this.entity, "injured", false);
}
Engine.PostMessage(this.entity, MT_HealthChanged, { "from": old, "to": this.hitpoints });
// We return the old and the actual hp
return { "old": old, "new": this.hitpoints};
};
//// Private functions ////
Health.prototype.CreateCorpse = function(leaveResources)
{
// If the unit died while not in the world, don't create any corpse for it
// since there's nowhere for the corpse to be placed
var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
if (!cmpPosition.IsInWorld())
return INVALID_ENTITY;
// Either creates a static local version of the current entity, or a
// persistent corpse retaining the ResourceSupply element of the parent.
var cmpTempMan = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
var templateName = cmpTempMan.GetCurrentTemplateName(this.entity);
var corpse;
if (leaveResources)
corpse = Engine.AddEntity("resource|" + templateName);
else
corpse = Engine.AddLocalEntity("corpse|" + templateName);
// Copy various parameters so it looks just like us
var cmpCorpsePosition = Engine.QueryInterface(corpse, IID_Position);
var pos = cmpPosition.GetPosition();
cmpCorpsePosition.JumpTo(pos.x, pos.z);
var rot = cmpPosition.GetRotation();
cmpCorpsePosition.SetYRotation(rot.y);
cmpCorpsePosition.SetXZRotation(rot.x, rot.z);
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
var cmpCorpseOwnership = Engine.QueryInterface(corpse, IID_Ownership);
cmpCorpseOwnership.SetOwner(cmpOwnership.GetOwner());
var cmpVisual = Engine.QueryInterface(this.entity, IID_Visual);
var cmpCorpseVisual = Engine.QueryInterface(corpse, IID_Visual);
cmpCorpseVisual.SetActorSeed(cmpVisual.GetActorSeed());
// Make it fall over
cmpCorpseVisual.SelectAnimation("death", true, 1.0, "");
return corpse;
};
Health.prototype.CreateDeathSpawnedEntity = function()
{
// If the unit died while not in the world, don't spawn a death entity for it
// since there's nowhere for it to be placed
var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
if (!cmpPosition.IsInWorld())
return INVALID_ENTITY;
// Create SpawnEntityOnDeath entity
var spawnedEntity = Engine.AddLocalEntity(this.template.SpawnEntityOnDeath);
// Move to same position
var cmpSpawnedPosition = Engine.QueryInterface(spawnedEntity, IID_Position);
var pos = cmpPosition.GetPosition();
cmpSpawnedPosition.JumpTo(pos.x, pos.z);
var rot = cmpPosition.GetRotation();
cmpSpawnedPosition.SetYRotation(rot.y);
cmpSpawnedPosition.SetXZRotation(rot.x, rot.z);
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
var cmpSpawnedOwnership = Engine.QueryInterface(spawnedEntity, IID_Ownership);
if (cmpOwnership && cmpSpawnedOwnership)
cmpSpawnedOwnership.SetOwner(cmpOwnership.GetOwner());
return spawnedEntity;
};
Health.prototype.Repair = function(builderEnt, work)
{
var damage = this.GetMaxHitpoints() - this.GetHitpoints();
// Do nothing if we're already at full hitpoints
if (damage <= 0)
return;
// Calculate the amount of hitpoints that will be added
// TODO: what computation should we use?
// TODO: should we do some diminishing returns thing? (see Foundation.Build)
var amount = Math.min(damage, work);
// TODO: resource costs?
// Add hitpoints
this.Increase(amount);
// If we repaired all the damage, send a message to entities
// to stop repairing this building
if (amount >= damage)
{
Engine.PostMessage(this.entity, MT_ConstructionFinished,
{ "entity": this.entity, "newentity": this.entity });
}
};
Health.prototype.OnValueModification = function(msg)
{
if (msg.component != "Health")
return;
var oldMaxHitpoints = this.GetMaxHitpoints();
var newMaxHitpoints = Math.round(ApplyValueModificationsToEntity("Health/Max", +this.template.Max, this.entity));
if (oldMaxHitpoints != newMaxHitpoints)
{
var newHitpoints = Math.round(this.GetHitpoints() * newMaxHitpoints/oldMaxHitpoints);
this.maxHitpoints = newMaxHitpoints;
this.SetHitpoints(newHitpoints);
}
var oldRegenRate = this.regenRate;
this.regenRate = ApplyValueModificationsToEntity("Health/RegenRate", +this.template.RegenRate, this.entity);
- if (this.IsUnhealable())
- this.regenRate = Math.min(0,this.regenRate);
-
if (this.regenRate != oldRegenRate)
this.CheckRegenTimer();
};
Health.prototype.OnHealthChanged = function()
{
this.CheckRegenTimer();
};
Engine.RegisterComponentType(IID_Health, "Health", Health);
Index: ps/trunk/binaries/data/mods/public/simulation/data/auras/champion_attack_5.json
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/data/auras/champion_attack_5.json (nonexistent)
+++ ps/trunk/binaries/data/mods/public/simulation/data/auras/champion_attack_5.json (revision 14246)
@@ -0,0 +1,5 @@
+{
+ "affects":["Champion"],
+ "affectedPlayers":["Player"],
+ "modifications":[{"value":"Attack/Ranged/Pierce","add":5},{"value":"Attack/Melee/Hack","add":5}]
+}
Index: ps/trunk/binaries/data/mods/public/simulation/data/auras/champion_speed_25.json
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/data/auras/champion_speed_25.json (nonexistent)
+++ ps/trunk/binaries/data/mods/public/simulation/data/auras/champion_speed_25.json (revision 14246)
@@ -0,0 +1,5 @@
+{
+ "affects":["Champion"],
+ "affectedPlayers":["Player"],
+ "modifications":[{"value":"UnitMotion/WalkSpeed","multiply":1.25}]
+}
Index: ps/trunk/binaries/data/mods/public/simulation/data/auras/unit_attack_2.json
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/data/auras/unit_attack_2.json (nonexistent)
+++ ps/trunk/binaries/data/mods/public/simulation/data/auras/unit_attack_2.json (revision 14246)
@@ -0,0 +1,5 @@
+{
+ "affects":["Unit"],
+ "affectedPlayers":["Ally"],
+ "modifications":[{"value":"Attack/Ranged/Pierce","add":2},{"value":"Attack/Melee/Hack","add":2}]
+}
Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca.xml (revision 14245)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca.xml (revision 14246)
@@ -1,46 +1,54 @@
+
+
+ global
+
+
+ global
+
+ 7784502001001005.0britChariotBoudicca
- Hero Aura: Increased Attack and Speed for Champion Units.
+ Hero Aura: +5 Attack and +25% Speed for Champion Units.Ammianus Marcellinus described how difficult it would be for a band of foreigners to deal with a Celt if he called in the help of his wife. For she was stronger than he was and could rain blows and kicks upon the assailants equal in force to the shots of a catapult. Boudicca, queen of the Iceni, was said to be 'very tall and terrifying in appearance; her voice was very harsh and a great mass of red hair fell over her shoulders. She wore a tunic of many colors over which a thick cloak was fastened by a brooch.units/celt_hero_boudicca.pngvoice/hellenes/civ/female/civ_female_walk.xmlvoice/hellenes/civ/female/civ_female_go_out_against.xmlvoice/hellenes/civ/female/civ_female_gather_together.xmlvoice/hellenes/civ/female/civ_female_repair.xmlvoice/hellenes/civ/female/civ_female_garrison.xmlactor/human/death/female_death.xmlunits/celts/boudicca_chariot.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca_sword.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca_sword.xml (revision 14245)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/units/brit_hero_boudicca_sword.xml (revision 14246)
@@ -1,19 +1,27 @@
+
+
+ global
+
+
+ global
+
+ 566britBoudiccaHeroine
- Hero Aura: TBD.
+ Hero Aura: +5 Attack and +25% Speed for Champion units..units/celt_hero_boudicca.pngunits/celts/boudicca.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/brit_hero_caratacos.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/units/brit_hero_caratacos.xml (revision 14245)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/units/brit_hero_caratacos.xml (revision 14246)
@@ -1,26 +1,31 @@
+
+
+ global
+
+ 66727.054.0britCaratacos
- Hero Aura: Increased Speed for all units during his lifetime.
+ Hero Aura: +15% Speed for all units during his lifetime.Caratacos's name is better known in its Romanized form, Caratacus. Under this name he is remembered as a fierce defender of Britain against the Romans after their invasion in 43 AD. Son of King Cynvelin of the Catuvellauni tribe, Caratacos fought for nine years against the Romans with little success, eventually fleeing to the tribes in Wales, where he was defeated decisively. Finally he entered Northern Britain, where was handed over to the Romans. Taken to Rome, Caratacos was allowed to live by the Emperor Claudius and died in Italy.units/celt_hero_caratacos.pngunits/celts/caradoc.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/brit_hero_cynvelin.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/units/brit_hero_cynvelin.xml (revision 14245)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/units/brit_hero_cynvelin.xml (revision 14246)
@@ -1,16 +1,22 @@
+
+
+ range
+ 60
+
+ 10britCynvelin
- Hero Aura: Has a large and powerful Healing Aura, only useful when idle.
+ Hero Aura: Has a large and powerful Healing Aura.Cynvelin was a powerful ruler centered in the territory around modern day London. Ruling the Catuvellauni from Camulodunum, he was a warrior king who conquered a neighboring tribe and was referred to by the Romans as the King of the Britons. Eventually Cynvelin retired to become the arch-druid of Siluria, but was taken to Rome with his son upon Caratacos's capture. According to legend, the Apostle Paul baptized Cynvelin into Christianity before he died in Italy.units/celt_hero_cynvelin.pngunits/celts/cynvelin_horse.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/cart_hero_hamilcar.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/units/cart_hero_hamilcar.xml (revision 14245)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/units/cart_hero_hamilcar.xml (revision 14246)
@@ -1,17 +1,22 @@
+
+
+ global
+
+ cartḤimelqart BaraqHamilcar BarcaFather of Hannibal and virtual military dictator of Carthage. Hamilcar Barca was a soldier and politician who excelled along his entire career. Lived 275-228 BC. While overshadowed by his sons, Hamilcar was great general in his own right, earning the nickname Baraq or Barca for the "lightning" speed of his advance.units/cart_hero_hamilcar.pngClasses: Hero Melee Cavalry Sword.
"Lightning" Aura: All of the player's units +15% movement speed (walk and run, but not charge) while he lives.
Counters: 2x vs. Archers, All Support Units, and Siege Weapons.
Countered by: Spearmen, Cavalry Skirmishers, and Elephants.units/carthaginians/hero_hamilcar_horse.xml
Index: ps/trunk/binaries/data/mods/public/simulation/templates/units/cart_hero_hannibal.xml
===================================================================
--- ps/trunk/binaries/data/mods/public/simulation/templates/units/cart_hero_hannibal.xml (revision 14245)
+++ ps/trunk/binaries/data/mods/public/simulation/templates/units/cart_hero_hannibal.xml (revision 14246)
@@ -1,18 +1,24 @@
+
+
+ range
+ 60
+
+ cartHannibal BarcaḤannibaʿal BaraqCarthage's most famous son. Hannibal Barca was the eldest son of Hamilcar Barca and proved an even greater commander than his father. Lived 247-182 BC. While he ultimately lost the Second Punic War, his victories at Trebia, Lake Trasimene, and Cannae, and the feat of crossing the Alps have secured his position as among the best tacticians and strategists in history.units/cart_hero_hannibal.pngClasses: Hero Melee Elephant.
-"Tactician" Aura: All allied units +15% attack within vision range of him.
+"Tactician" Aura: All allied units +2 attack within vision range of him.
"Strategist" Ability: The player can see changes within the fog of war while Hannibal lives.
Counters: 2x vs. All Cavalry, 1.5x vs. All Structures. Extra 1.5x vs. Gates.
Countered by: Skirmishers and Swordsmen. Can run amok.units/carthaginians/hero_hannibal_mount.xml