restore random arrows.
This commit is contained in:
parent
ce2febaeba
commit
e8ba5dffcf
File diff suppressed because it is too large
Load Diff
@ -1,414 +1,354 @@
|
|||||||
// Number of rounds of firing per 2 seconds.
|
// Number of rounds of firing per 2 seconds.
|
||||||
const roundCount = 10;
|
const roundCount = 10;
|
||||||
const attackType = "Ranged";
|
const attackType = "Ranged";
|
||||||
|
|
||||||
function BuildingAI() {}
|
function BuildingAI() { }
|
||||||
|
|
||||||
BuildingAI.prototype.Schema =
|
BuildingAI.prototype.Schema =
|
||||||
"<element name='DefaultArrowCount'>" +
|
"<element name='DefaultArrowCount'>" +
|
||||||
"<data type='nonNegativeInteger'/>" +
|
"<data type='nonNegativeInteger'/>" +
|
||||||
"</element>" +
|
"</element>" +
|
||||||
"<optional>" +
|
"<optional>" +
|
||||||
"<element name='MaxArrowCount' a:help='Limit the number of arrows to a certain amount'>" +
|
"<element name='MaxArrowCount' a:help='Limit the number of arrows to a certain amount'>" +
|
||||||
"<data type='nonNegativeInteger'/>" +
|
"<data type='nonNegativeInteger'/>" +
|
||||||
"</element>" +
|
"</element>" +
|
||||||
"</optional>" +
|
"</optional>" +
|
||||||
"<element name='GarrisonArrowMultiplier'>" +
|
"<element name='GarrisonArrowMultiplier'>" +
|
||||||
"<ref name='nonNegativeDecimal'/>" +
|
"<ref name='nonNegativeDecimal'/>" +
|
||||||
"</element>" +
|
"</element>" +
|
||||||
"<element name='GarrisonArrowClasses' a:help='Add extra arrows for this class list'>" +
|
"<element name='GarrisonArrowClasses' a:help='Add extra arrows for this class list'>" +
|
||||||
"<text/>" +
|
"<text/>" +
|
||||||
"</element>";
|
"</element>";
|
||||||
|
|
||||||
BuildingAI.prototype.MAX_PREFERENCE_BONUS = 2;
|
BuildingAI.prototype.MAX_PREFERENCE_BONUS = 2;
|
||||||
|
|
||||||
BuildingAI.prototype.Init = function()
|
BuildingAI.prototype.Init = function () {
|
||||||
{
|
this.currentRound = 0;
|
||||||
this.currentRound = 0;
|
this.archersGarrisoned = 0;
|
||||||
this.archersGarrisoned = 0;
|
this.arrowsLeft = 0;
|
||||||
this.arrowsLeft = 0;
|
this.targetUnits = [];
|
||||||
this.targetUnits = [];
|
|
||||||
this.focusTargets = [];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BuildingAI.prototype.OnGarrisonedUnitsChanged = function(msg)
|
BuildingAI.prototype.OnGarrisonedUnitsChanged = function (msg) {
|
||||||
{
|
let classes = this.template.GarrisonArrowClasses;
|
||||||
let classes = this.template.GarrisonArrowClasses;
|
for (let ent of msg.added) {
|
||||||
for (let ent of msg.added)
|
let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
|
||||||
{
|
if (cmpIdentity && MatchesClassList(cmpIdentity.GetClassesList(), classes))
|
||||||
let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
|
++this.archersGarrisoned;
|
||||||
if (cmpIdentity && MatchesClassList(cmpIdentity.GetClassesList(), classes))
|
}
|
||||||
++this.archersGarrisoned;
|
for (let ent of msg.removed) {
|
||||||
}
|
let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
|
||||||
for (let ent of msg.removed)
|
if (cmpIdentity && MatchesClassList(cmpIdentity.GetClassesList(), classes))
|
||||||
{
|
--this.archersGarrisoned;
|
||||||
let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
|
}
|
||||||
if (cmpIdentity && MatchesClassList(cmpIdentity.GetClassesList(), classes))
|
|
||||||
--this.archersGarrisoned;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BuildingAI.prototype.OnOwnershipChanged = function(msg)
|
BuildingAI.prototype.OnOwnershipChanged = function (msg) {
|
||||||
{
|
this.targetUnits = [];
|
||||||
this.targetUnits = [];
|
this.SetupRangeQuery();
|
||||||
this.focusTargets = [];
|
this.SetupGaiaRangeQuery();
|
||||||
this.SetupRangeQuery();
|
|
||||||
this.SetupGaiaRangeQuery();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BuildingAI.prototype.OnDiplomacyChanged = function(msg)
|
BuildingAI.prototype.OnDiplomacyChanged = function (msg) {
|
||||||
{
|
if (!IsOwnedByPlayer(msg.player, this.entity))
|
||||||
if (!IsOwnedByPlayer(msg.player, this.entity))
|
return;
|
||||||
return;
|
|
||||||
|
|
||||||
// Remove maybe now allied/neutral units.
|
// Remove maybe now allied/neutral units.
|
||||||
this.targetUnits = [];
|
this.targetUnits = [];
|
||||||
this.SetupRangeQuery();
|
this.SetupRangeQuery();
|
||||||
this.SetupGaiaRangeQuery();
|
this.SetupGaiaRangeQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
BuildingAI.prototype.OnDestroy = function()
|
BuildingAI.prototype.OnDestroy = function () {
|
||||||
{
|
if (this.timer) {
|
||||||
if (this.timer)
|
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
||||||
{
|
cmpTimer.CancelTimer(this.timer);
|
||||||
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
this.timer = undefined;
|
||||||
cmpTimer.CancelTimer(this.timer);
|
}
|
||||||
this.timer = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up range queries.
|
// Clean up range queries.
|
||||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||||
if (this.enemyUnitsQuery)
|
if (this.enemyUnitsQuery)
|
||||||
cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
|
cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
|
||||||
if (this.gaiaUnitsQuery)
|
if (this.gaiaUnitsQuery)
|
||||||
cmpRangeManager.DestroyActiveQuery(this.gaiaUnitsQuery);
|
cmpRangeManager.DestroyActiveQuery(this.gaiaUnitsQuery);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* React on Attack value modifications, as it might influence the range.
|
* React on Attack value modifications, as it might influence the range.
|
||||||
*/
|
*/
|
||||||
BuildingAI.prototype.OnValueModification = function(msg)
|
BuildingAI.prototype.OnValueModification = function (msg) {
|
||||||
{
|
if (msg.component != "Attack")
|
||||||
if (msg.component != "Attack")
|
return;
|
||||||
return;
|
|
||||||
|
|
||||||
this.targetUnits = [];
|
this.targetUnits = [];
|
||||||
this.SetupRangeQuery();
|
this.SetupRangeQuery();
|
||||||
this.SetupGaiaRangeQuery();
|
this.SetupGaiaRangeQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup the Range Query to detect units coming in & out of range.
|
* Setup the Range Query to detect units coming in & out of range.
|
||||||
*/
|
*/
|
||||||
BuildingAI.prototype.SetupRangeQuery = function()
|
BuildingAI.prototype.SetupRangeQuery = function () {
|
||||||
{
|
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
if (!cmpAttack)
|
||||||
if (!cmpAttack)
|
return;
|
||||||
return;
|
|
||||||
|
|
||||||
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||||
if (this.enemyUnitsQuery)
|
if (this.enemyUnitsQuery) {
|
||||||
{
|
cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
|
||||||
cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
|
this.enemyUnitsQuery = undefined;
|
||||||
this.enemyUnitsQuery = undefined;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var cmpPlayer = QueryOwnerInterface(this.entity);
|
var cmpPlayer = QueryOwnerInterface(this.entity);
|
||||||
if (!cmpPlayer)
|
if (!cmpPlayer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var enemies = cmpPlayer.GetEnemies();
|
var enemies = cmpPlayer.GetEnemies();
|
||||||
// Remove gaia.
|
// Remove gaia.
|
||||||
if (enemies.length && enemies[0] == 0)
|
if (enemies.length && enemies[0] == 0)
|
||||||
enemies.shift();
|
enemies.shift();
|
||||||
|
|
||||||
if (!enemies.length)
|
if (!enemies.length)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const range = cmpAttack.GetRange(attackType);
|
const range = cmpAttack.GetRange(attackType);
|
||||||
const yOrigin = cmpAttack.GetAttackYOrigin(attackType);
|
const yOrigin = cmpAttack.GetAttackYOrigin(attackType);
|
||||||
// This takes entity sizes into accounts, so no need to compensate for structure size.
|
// This takes entity sizes into accounts, so no need to compensate for structure size.
|
||||||
this.enemyUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(
|
this.enemyUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(
|
||||||
this.entity, range.min, range.max, yOrigin,
|
this.entity, range.min, range.max, yOrigin,
|
||||||
enemies, IID_Resistance, cmpRangeManager.GetEntityFlagMask("normal"));
|
enemies, IID_Resistance, cmpRangeManager.GetEntityFlagMask("normal"));
|
||||||
|
|
||||||
cmpRangeManager.EnableActiveQuery(this.enemyUnitsQuery);
|
cmpRangeManager.EnableActiveQuery(this.enemyUnitsQuery);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set up a range query for Gaia units within LOS range which can be attacked.
|
// Set up a range query for Gaia units within LOS range which can be attacked.
|
||||||
// This should be called whenever our ownership changes.
|
// This should be called whenever our ownership changes.
|
||||||
BuildingAI.prototype.SetupGaiaRangeQuery = function()
|
BuildingAI.prototype.SetupGaiaRangeQuery = function () {
|
||||||
{
|
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
if (!cmpAttack)
|
||||||
if (!cmpAttack)
|
return;
|
||||||
return;
|
|
||||||
|
|
||||||
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||||
if (this.gaiaUnitsQuery)
|
if (this.gaiaUnitsQuery) {
|
||||||
{
|
cmpRangeManager.DestroyActiveQuery(this.gaiaUnitsQuery);
|
||||||
cmpRangeManager.DestroyActiveQuery(this.gaiaUnitsQuery);
|
this.gaiaUnitsQuery = undefined;
|
||||||
this.gaiaUnitsQuery = undefined;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var cmpPlayer = QueryOwnerInterface(this.entity);
|
var cmpPlayer = QueryOwnerInterface(this.entity);
|
||||||
if (!cmpPlayer || !cmpPlayer.IsEnemy(0))
|
if (!cmpPlayer || !cmpPlayer.IsEnemy(0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const range = cmpAttack.GetRange(attackType);
|
const range = cmpAttack.GetRange(attackType);
|
||||||
const yOrigin = cmpAttack.GetAttackYOrigin(attackType);
|
const yOrigin = cmpAttack.GetAttackYOrigin(attackType);
|
||||||
|
|
||||||
// This query is only interested in Gaia entities that can attack.
|
// This query is only interested in Gaia entities that can attack.
|
||||||
// This takes entity sizes into accounts, so no need to compensate for structure size.
|
// This takes entity sizes into accounts, so no need to compensate for structure size.
|
||||||
this.gaiaUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(
|
this.gaiaUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(
|
||||||
this.entity, range.min, range.max, yOrigin,
|
this.entity, range.min, range.max, yOrigin,
|
||||||
[0], IID_Attack, cmpRangeManager.GetEntityFlagMask("normal"));
|
[0], IID_Attack, cmpRangeManager.GetEntityFlagMask("normal"));
|
||||||
|
|
||||||
cmpRangeManager.EnableActiveQuery(this.gaiaUnitsQuery);
|
cmpRangeManager.EnableActiveQuery(this.gaiaUnitsQuery);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when units enter or leave range.
|
* Called when units enter or leave range.
|
||||||
*/
|
*/
|
||||||
BuildingAI.prototype.OnRangeUpdate = function(msg)
|
BuildingAI.prototype.OnRangeUpdate = function (msg) {
|
||||||
{
|
|
||||||
|
|
||||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||||
if (!cmpAttack)
|
if (!cmpAttack)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Target enemy units except non-dangerous animals.
|
// Target enemy units except non-dangerous animals.
|
||||||
if (msg.tag == this.gaiaUnitsQuery)
|
if (msg.tag == this.gaiaUnitsQuery) {
|
||||||
{
|
msg.added = msg.added.filter(e => {
|
||||||
msg.added = msg.added.filter(e => {
|
let cmpUnitAI = Engine.QueryInterface(e, IID_UnitAI);
|
||||||
let cmpUnitAI = Engine.QueryInterface(e, IID_UnitAI);
|
return cmpUnitAI && (!cmpUnitAI.IsAnimal() || cmpUnitAI.IsDangerousAnimal());
|
||||||
return cmpUnitAI && (!cmpUnitAI.IsAnimal() || cmpUnitAI.IsDangerousAnimal());
|
});
|
||||||
});
|
}
|
||||||
}
|
else if (msg.tag != this.enemyUnitsQuery)
|
||||||
else if (msg.tag != this.enemyUnitsQuery)
|
return;
|
||||||
return;
|
|
||||||
|
|
||||||
// Add new targets.
|
// Add new targets.
|
||||||
for (let entity of msg.added)
|
for (let entity of msg.added)
|
||||||
if (cmpAttack.CanAttack(entity))
|
if (cmpAttack.CanAttack(entity))
|
||||||
this.targetUnits.push(entity);
|
this.targetUnits.push(entity);
|
||||||
|
|
||||||
// Remove targets outside of vision-range.
|
// Remove targets outside of vision-range.
|
||||||
for (let entity of msg.removed)
|
for (let entity of msg.removed) {
|
||||||
{
|
let index = this.targetUnits.indexOf(entity);
|
||||||
let index = this.targetUnits.indexOf(entity);
|
if (index > -1)
|
||||||
if (index > -1)
|
this.targetUnits.splice(index, 1);
|
||||||
this.targetUnits.splice(index, 1);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (this.targetUnits.length)
|
if (this.targetUnits.length)
|
||||||
this.StartTimer();
|
this.StartTimer();
|
||||||
};
|
};
|
||||||
|
|
||||||
BuildingAI.prototype.StartTimer = function()
|
BuildingAI.prototype.StartTimer = function () {
|
||||||
{
|
if (this.timer)
|
||||||
if (this.timer)
|
return;
|
||||||
return;
|
|
||||||
|
|
||||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||||
if (!cmpAttack)
|
if (!cmpAttack)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
||||||
var attackTimers = cmpAttack.GetTimers(attackType);
|
var attackTimers = cmpAttack.GetTimers(attackType);
|
||||||
|
|
||||||
this.timer = cmpTimer.SetInterval(this.entity, IID_BuildingAI, "FireArrows",
|
this.timer = cmpTimer.SetInterval(this.entity, IID_BuildingAI, "FireArrows",
|
||||||
attackTimers.prepare, attackTimers.repeat / roundCount, null);
|
attackTimers.prepare, attackTimers.repeat / roundCount, null);
|
||||||
};
|
};
|
||||||
|
|
||||||
BuildingAI.prototype.GetDefaultArrowCount = function()
|
BuildingAI.prototype.GetDefaultArrowCount = function () {
|
||||||
{
|
var arrowCount = +this.template.DefaultArrowCount;
|
||||||
var arrowCount = +this.template.DefaultArrowCount;
|
return Math.round(ApplyValueModificationsToEntity("BuildingAI/DefaultArrowCount", arrowCount, this.entity));
|
||||||
return Math.round(ApplyValueModificationsToEntity("BuildingAI/DefaultArrowCount", arrowCount, this.entity));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BuildingAI.prototype.GetMaxArrowCount = function()
|
BuildingAI.prototype.GetMaxArrowCount = function () {
|
||||||
{
|
if (!this.template.MaxArrowCount)
|
||||||
if (!this.template.MaxArrowCount)
|
return Infinity;
|
||||||
return Infinity;
|
|
||||||
|
|
||||||
let maxArrowCount = +this.template.MaxArrowCount;
|
let maxArrowCount = +this.template.MaxArrowCount;
|
||||||
return Math.round(ApplyValueModificationsToEntity("BuildingAI/MaxArrowCount", maxArrowCount, this.entity));
|
return Math.round(ApplyValueModificationsToEntity("BuildingAI/MaxArrowCount", maxArrowCount, this.entity));
|
||||||
};
|
};
|
||||||
|
|
||||||
BuildingAI.prototype.GetGarrisonArrowMultiplier = function()
|
BuildingAI.prototype.GetGarrisonArrowMultiplier = function () {
|
||||||
{
|
var arrowMult = +this.template.GarrisonArrowMultiplier;
|
||||||
var arrowMult = +this.template.GarrisonArrowMultiplier;
|
return ApplyValueModificationsToEntity("BuildingAI/GarrisonArrowMultiplier", arrowMult, this.entity);
|
||||||
return ApplyValueModificationsToEntity("BuildingAI/GarrisonArrowMultiplier", arrowMult, this.entity);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BuildingAI.prototype.GetGarrisonArrowClasses = function()
|
BuildingAI.prototype.GetGarrisonArrowClasses = function () {
|
||||||
{
|
var string = this.template.GarrisonArrowClasses;
|
||||||
var string = this.template.GarrisonArrowClasses;
|
if (string)
|
||||||
if (string)
|
return string.split(/\s+/);
|
||||||
return string.split(/\s+/);
|
return [];
|
||||||
return [];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of arrows which needs to be fired.
|
* Returns the number of arrows which needs to be fired.
|
||||||
* DefaultArrowCount + Garrisoned Archers (i.e., any unit capable
|
* DefaultArrowCount + Garrisoned Archers (i.e., any unit capable
|
||||||
* of shooting arrows from inside buildings).
|
* of shooting arrows from inside buildings).
|
||||||
*/
|
*/
|
||||||
BuildingAI.prototype.GetArrowCount = function()
|
BuildingAI.prototype.GetArrowCount = function () {
|
||||||
{
|
let count = this.GetDefaultArrowCount() +
|
||||||
let count = this.GetDefaultArrowCount() +
|
Math.round(this.archersGarrisoned * this.GetGarrisonArrowMultiplier());
|
||||||
Math.round(this.archersGarrisoned * this.GetGarrisonArrowMultiplier());
|
|
||||||
|
|
||||||
return Math.min(count, this.GetMaxArrowCount());
|
return Math.min(count, this.GetMaxArrowCount());
|
||||||
};
|
};
|
||||||
|
|
||||||
BuildingAI.prototype.SetUnitAITarget = function(ent)
|
BuildingAI.prototype.SetUnitAITarget = function (ent) {
|
||||||
{
|
this.unitAITarget = ent;
|
||||||
this.unitAITarget = ent;
|
if (ent)
|
||||||
if (ent)
|
this.StartTimer();
|
||||||
this.StartTimer();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds index to keep track of the user-targeted units supporting a queue
|
* Fire arrows with random temporal distribution on prefered targets.
|
||||||
* @param {ent} - Target of rallypoint selection when selection is an enemy unit from unit_actions.js
|
* Called 'roundCount' times every 'RepeatTime' seconds when there are units in the range.
|
||||||
*/
|
*/
|
||||||
BuildingAI.prototype.AddFocusTarget = function(ent, queued, push)
|
BuildingAI.prototype.FireArrows = function () {
|
||||||
{
|
if (!this.targetUnits.length && !this.unitAITarget) {
|
||||||
if (!ent || this.targetUnits.indexOf(ent) === -1)
|
if (!this.timer)
|
||||||
return;
|
return;
|
||||||
if (queued)
|
|
||||||
this.focusTargets.push({"entityId": ent});
|
|
||||||
else if (push)
|
|
||||||
this.focusTargets.unshift({"entityId": ent});
|
|
||||||
else
|
|
||||||
this.focusTargets = [{"entityId": ent}];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
||||||
* Fire arrows with random temporal distribution on prefered targets.
|
cmpTimer.CancelTimer(this.timer);
|
||||||
* Called 'roundCount' times every 'RepeatTime' seconds when there are units in the range.
|
this.timer = undefined;
|
||||||
*/
|
return;
|
||||||
BuildingAI.prototype.FireArrows = function()
|
}
|
||||||
{
|
|
||||||
if (!this.targetUnits.length && !this.unitAITarget)
|
|
||||||
{
|
|
||||||
if (!this.timer)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||||
cmpTimer.CancelTimer(this.timer);
|
if (!cmpAttack)
|
||||||
this.timer = undefined;
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
if (this.currentRound > roundCount - 1)
|
||||||
if (!cmpAttack)
|
this.currentRound = 0;
|
||||||
return;
|
|
||||||
|
|
||||||
if (this.currentRound > roundCount - 1)
|
if (this.currentRound == 0)
|
||||||
this.currentRound = 0;
|
this.arrowsLeft = this.GetArrowCount();
|
||||||
|
|
||||||
if (this.currentRound == 0)
|
let arrowsToFire = 0;
|
||||||
this.arrowsLeft = this.GetArrowCount();
|
if (this.currentRound == roundCount - 1)
|
||||||
|
arrowsToFire = this.arrowsLeft;
|
||||||
|
else
|
||||||
|
arrowsToFire = Math.min(
|
||||||
|
randIntInclusive(0, 2 * this.GetArrowCount() / roundCount),
|
||||||
|
this.arrowsLeft
|
||||||
|
);
|
||||||
|
|
||||||
let arrowsToFire = 0;
|
if (arrowsToFire <= 0) {
|
||||||
if (this.currentRound == roundCount - 1)
|
++this.currentRound;
|
||||||
arrowsToFire = this.arrowsLeft;
|
return;
|
||||||
else
|
}
|
||||||
arrowsToFire = Math.min(
|
|
||||||
randIntInclusive(0, 2 * this.GetArrowCount() / roundCount),
|
|
||||||
this.arrowsLeft
|
|
||||||
);
|
|
||||||
|
|
||||||
if (arrowsToFire <= 0)
|
// Add targets to a weighted list, to allow preferences.
|
||||||
{
|
let targets = new WeightedList();
|
||||||
++this.currentRound;
|
let maxPreference = this.MAX_PREFERENCE_BONUS;
|
||||||
return;
|
let addTarget = function (target) {
|
||||||
}
|
let preference = cmpAttack.GetPreference(target);
|
||||||
|
let weight = 1;
|
||||||
|
|
||||||
|
if (preference !== null && preference !== undefined)
|
||||||
|
weight += maxPreference / (1 + preference);
|
||||||
|
|
||||||
|
targets.push(target, weight);
|
||||||
|
};
|
||||||
|
|
||||||
// Add targets to a list.
|
|
||||||
let targets = [];
|
|
||||||
let addTarget = function(target)
|
|
||||||
{
|
|
||||||
const pref = (cmpAttack.GetPreference(target) ?? 49);
|
|
||||||
targets.push({"entityId": target, "preference": pref});
|
|
||||||
};
|
|
||||||
// Add the UnitAI target separately, as the UnitMotion and RangeManager implementations differ.
|
// Add the UnitAI target separately, as the UnitMotion and RangeManager implementations differ.
|
||||||
if (this.unitAITarget && this.targetUnits.indexOf(this.unitAITarget) == -1)
|
if (this.unitAITarget && this.targetUnits.indexOf(this.unitAITarget) == -1)
|
||||||
addTarget(this.unitAITarget);
|
addTarget(this.unitAITarget);
|
||||||
else if (this.unitAITarget && this.targetUnits.indexOf(this.unitAITarget) != -1)
|
for (let target of this.targetUnits)
|
||||||
this.focusTargets = [{"entityId": this.unitAITarget}];
|
addTarget(target);
|
||||||
if (!this.focusTargets.length)
|
|
||||||
{
|
// The obstruction manager performs approximate range checks.
|
||||||
for (let target of this.targetUnits)
|
// so we need to verify them here.
|
||||||
addTarget(target);
|
// TODO: perhaps an optional 'precise' mode to range queries would be more performant.
|
||||||
// Sort targets by preference and then by proximity.
|
const cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager);
|
||||||
targets.sort( (a,b) => {
|
const range = cmpAttack.GetRange(attackType);
|
||||||
if (a.preference > b.preference) return 1;
|
const yOrigin = cmpAttack.GetAttackYOrigin(attackType);
|
||||||
else if (a.preference < b.preference) return -1;
|
|
||||||
else if (PositionHelper.DistanceBetweenEntities(this.entity,a.entityId) > PositionHelper.DistanceBetweenEntities(this.entity,b.entityId)) return 1;
|
let firedArrows = 0;
|
||||||
return -1;
|
while (firedArrows < arrowsToFire && targets.length()) {
|
||||||
});
|
const selectedTarget = targets.randomItem();
|
||||||
|
if (this.CheckTargetVisible(selectedTarget) && cmpObstructionManager.IsInTargetParabolicRange(
|
||||||
|
this.entity,
|
||||||
|
selectedTarget,
|
||||||
|
range.min,
|
||||||
|
range.max,
|
||||||
|
yOrigin,
|
||||||
|
false)) {
|
||||||
|
cmpAttack.PerformAttack(attackType, selectedTarget);
|
||||||
|
PlaySound("attack_" + attackType.toLowerCase(), this.entity);
|
||||||
|
++firedArrows;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Could not attack target, try a different target.
|
||||||
|
targets.remove(selectedTarget);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
targets = this.focusTargets;
|
|
||||||
|
|
||||||
// The obstruction manager performs approximate range checks.
|
this.arrowsLeft -= firedArrows;
|
||||||
// so we need to verify them here.
|
++this.currentRound;
|
||||||
// TODO: perhaps an optional 'precise' mode to range queries would be more performant.
|
|
||||||
const cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager);
|
|
||||||
const range = cmpAttack.GetRange(attackType);
|
|
||||||
const yOrigin = cmpAttack.GetAttackYOrigin(attackType);
|
|
||||||
|
|
||||||
let firedArrows = 0;
|
|
||||||
let killedTargets = 0;
|
|
||||||
while (firedArrows < arrowsToFire && killedTargets < targets.length)
|
|
||||||
{
|
|
||||||
|
|
||||||
let selectedTarget = targets[killedTargets].entityId;
|
|
||||||
if (this.CheckTargetVisible(selectedTarget) && cmpObstructionManager.IsInTargetParabolicRange(
|
|
||||||
this.entity,
|
|
||||||
selectedTarget,
|
|
||||||
range.min,
|
|
||||||
range.max,
|
|
||||||
yOrigin,
|
|
||||||
false))
|
|
||||||
{
|
|
||||||
cmpAttack.PerformAttack(attackType, selectedTarget);
|
|
||||||
PlaySound("attack_" + attackType.toLowerCase(), this.entity);
|
|
||||||
++firedArrows;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Could not attack target, try a different target.
|
|
||||||
++killedTargets;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
targets.splice(0,killedTargets);
|
|
||||||
killedTargets = 0;//not sure if this is necessary
|
|
||||||
this.arrowsLeft -= firedArrows;
|
|
||||||
++this.currentRound;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the target entity is visible through the FoW/SoD.
|
* Returns true if the target entity is visible through the FoW/SoD.
|
||||||
*/
|
*/
|
||||||
BuildingAI.prototype.CheckTargetVisible = function(target)
|
BuildingAI.prototype.CheckTargetVisible = function (target) {
|
||||||
{
|
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||||
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
if (!cmpOwnership)
|
||||||
if (!cmpOwnership)
|
return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
// Entities that are hidden and miraged are considered visible.
|
// Entities that are hidden and miraged are considered visible.
|
||||||
var cmpFogging = Engine.QueryInterface(target, IID_Fogging);
|
var cmpFogging = Engine.QueryInterface(target, IID_Fogging);
|
||||||
if (cmpFogging && cmpFogging.IsMiraged(cmpOwnership.GetOwner()))
|
if (cmpFogging && cmpFogging.IsMiraged(cmpOwnership.GetOwner()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Either visible directly, or visible in fog.
|
// Either visible directly, or visible in fog.
|
||||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||||
return cmpRangeManager.GetLosVisibility(target, cmpOwnership.GetOwner()) != "hidden";
|
return cmpRangeManager.GetLosVisibility(target, cmpOwnership.GetOwner()) != "hidden";
|
||||||
};
|
};
|
||||||
|
|
||||||
Engine.RegisterComponentType(IID_BuildingAI, "BuildingAI", BuildingAI);
|
Engine.RegisterComponentType(IID_BuildingAI, "BuildingAI", BuildingAI);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,48 +1,44 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Entity parent="structures/han/civil_centre">
|
<Entity parent="structures/han/civil_centre">
|
||||||
<BuildRestrictions>
|
<BuildRestrictions>
|
||||||
<Category>ImperialCourt</Category>
|
<Category>ImperialCourt</Category>
|
||||||
</BuildRestrictions>
|
</BuildRestrictions>
|
||||||
<Capturable>
|
<Capturable>
|
||||||
<CapturePoints op="mul">1.5</CapturePoints>
|
<CapturePoints op="mul">1.5</CapturePoints>
|
||||||
</Capturable>
|
</Capturable>
|
||||||
<GarrisonHolder>
|
<GarrisonHolder>
|
||||||
<Max op="mul">1.5</Max>
|
<Max op="mul">1.5</Max>
|
||||||
</GarrisonHolder>
|
</GarrisonHolder>
|
||||||
<BuildingAI>
|
<Health>
|
||||||
<DefaultArrowCount>10</DefaultArrowCount>
|
<Max op="mul">1.5</Max>
|
||||||
<MaxArrowCount>24</MaxArrowCount>
|
</Health>
|
||||||
</BuildingAI>
|
<Identity>
|
||||||
<Health>
|
<Civ>han</Civ>
|
||||||
<Max op="mul">1.5</Max>
|
<GenericName>Imperial Court</GenericName>
|
||||||
</Health>
|
<SpecificName>Cháotíng</SpecificName>
|
||||||
<Identity>
|
<VisibleClasses datatype="tokens">Defensive ImperialCourt City</VisibleClasses>
|
||||||
<Civ>han</Civ>
|
<Classes datatype="tokens">CivCentre CivSpecific</Classes>
|
||||||
<GenericName>Imperial Court</GenericName>
|
<RequiredTechnology>phase_city</RequiredTechnology>
|
||||||
<SpecificName>Cháotíng</SpecificName>
|
<Icon>structures/military_settlement.png</Icon>
|
||||||
<VisibleClasses datatype="tokens">Defensive ImperialCourt City</VisibleClasses>
|
</Identity>
|
||||||
<Classes datatype="tokens">CivCentre CivSpecific</Classes>
|
<Population>
|
||||||
<RequiredTechnology>phase_city</RequiredTechnology>
|
<Bonus>30</Bonus>
|
||||||
<Icon>structures/military_settlement.png</Icon>
|
</Population>
|
||||||
</Identity>
|
<Researcher>
|
||||||
<Population>
|
<Technologies datatype="tokens">
|
||||||
<Bonus>30</Bonus>
|
-phase_town_{civ}
|
||||||
</Population>
|
</Technologies>
|
||||||
<Researcher>
|
</Researcher>
|
||||||
<Technologies datatype="tokens">
|
<Trainer>
|
||||||
-phase_town_{civ}
|
<BatchTimeModifier op="mul">0.5</BatchTimeModifier>
|
||||||
</Technologies>
|
<Entities datatype="tokens">
|
||||||
</Researcher>
|
units/{civ}/hero_han_xin_horse
|
||||||
<Trainer>
|
units/{civ}/hero_liu_bang_horse
|
||||||
<BatchTimeModifier op="mul">0.75</BatchTimeModifier>
|
units/{civ}/hero_wei_qing_chariot
|
||||||
<Entities datatype="tokens">
|
</Entities>
|
||||||
units/{civ}/hero_han_xin_horse
|
</Trainer>
|
||||||
units/{civ}/hero_liu_bang_horse
|
<Upgrade disable=""/>
|
||||||
units/{civ}/hero_wei_qing_chariot
|
<VisualActor>
|
||||||
</Entities>
|
<Actor>structures/han/imperial_court.xml</Actor>
|
||||||
</Trainer>
|
</VisualActor>
|
||||||
<Upgrade disable=""/>
|
|
||||||
<VisualActor>
|
|
||||||
<Actor>structures/han/imperial_court.xml</Actor>
|
|
||||||
</VisualActor>
|
|
||||||
</Entity>
|
</Entity>
|
||||||
|
@ -1,50 +1,50 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Entity parent="template_structure_defensive_tower_stone">
|
<Entity parent="template_structure_defensive_tower_stone">
|
||||||
<Attack>
|
<Attack>
|
||||||
<Ranged>
|
<Ranged>
|
||||||
<MinRange>12</MinRange>
|
<MinRange>12</MinRange>
|
||||||
</Ranged>
|
</Ranged>
|
||||||
</Attack>
|
</Attack>
|
||||||
<BuildingAI>
|
<BuildingAI>
|
||||||
<DefaultArrowCount>4</DefaultArrowCount>
|
<DefaultArrowCount>2</DefaultArrowCount>
|
||||||
</BuildingAI>
|
</BuildingAI>
|
||||||
<Cost>
|
<Cost>
|
||||||
<BuildTime>200</BuildTime>
|
<BuildTime>200</BuildTime>
|
||||||
<Resources>
|
<Resources>
|
||||||
<wood>50</wood>
|
<wood>50</wood>
|
||||||
<stone>250</stone>
|
<stone>250</stone>
|
||||||
</Resources>
|
</Resources>
|
||||||
</Cost>
|
</Cost>
|
||||||
<Footprint replace="">
|
<Footprint replace="">
|
||||||
<Circle radius="8.0"/>
|
<Circle radius="8.0"/>
|
||||||
<Height>12.0</Height>
|
<Height>12.0</Height>
|
||||||
</Footprint>
|
</Footprint>
|
||||||
<GarrisonHolder>
|
<GarrisonHolder>
|
||||||
<Max>8</Max>
|
<Max>8</Max>
|
||||||
</GarrisonHolder>
|
</GarrisonHolder>
|
||||||
<Health>
|
<Health>
|
||||||
<Max>2400</Max>
|
<Max>2400</Max>
|
||||||
<SpawnEntityOnDeath>decay|rubble/rubble_stone_3x3</SpawnEntityOnDeath>
|
<SpawnEntityOnDeath>decay|rubble/rubble_stone_3x3</SpawnEntityOnDeath>
|
||||||
</Health>
|
</Health>
|
||||||
<Identity>
|
<Identity>
|
||||||
<Civ>iber</Civ>
|
<Civ>iber</Civ>
|
||||||
<SpecificName>Dorre</SpecificName>
|
<SpecificName>Dorre</SpecificName>
|
||||||
</Identity>
|
</Identity>
|
||||||
<Loot>
|
<Loot>
|
||||||
<wood>10</wood>
|
<wood>10</wood>
|
||||||
<stone>50</stone>
|
<stone>50</stone>
|
||||||
</Loot>
|
</Loot>
|
||||||
<Obstruction>
|
<Obstruction>
|
||||||
<Static width="14.0" depth="14.0"/>
|
<Static width="14.0" depth="14.0"/>
|
||||||
</Obstruction>
|
</Obstruction>
|
||||||
<StatusBars>
|
<StatusBars>
|
||||||
<HeightOffset>17.0</HeightOffset>
|
<HeightOffset>17.0</HeightOffset>
|
||||||
</StatusBars>
|
</StatusBars>
|
||||||
<TerritoryInfluence>
|
<TerritoryInfluence>
|
||||||
<Radius>38</Radius>
|
<Radius>38</Radius>
|
||||||
</TerritoryInfluence>
|
</TerritoryInfluence>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<Actor>structures/iberians/scout_tower.xml</Actor>
|
<Actor>structures/iberians/scout_tower.xml</Actor>
|
||||||
<FoundationActor>structures/fndn_4x4.xml</FoundationActor>
|
<FoundationActor>structures/fndn_4x4.xml</FoundationActor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
</Entity>
|
</Entity>
|
||||||
|
@ -1,152 +1,151 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Entity parent="template_structure_civic">
|
<Entity parent="template_structure_civic">
|
||||||
<AlertRaiser>
|
<AlertRaiser>
|
||||||
<List datatype="tokens">FemaleCitizen</List>
|
<List datatype="tokens">FemaleCitizen</List>
|
||||||
<RaiseAlertRange>120</RaiseAlertRange>
|
<RaiseAlertRange>120</RaiseAlertRange>
|
||||||
<EndOfAlertRange>180</EndOfAlertRange>
|
<EndOfAlertRange>180</EndOfAlertRange>
|
||||||
<SearchRange>100</SearchRange>
|
<SearchRange>100</SearchRange>
|
||||||
</AlertRaiser>
|
</AlertRaiser>
|
||||||
<Attack>
|
<Attack>
|
||||||
<Ranged>
|
<Ranged>
|
||||||
<AttackName>Bow</AttackName>
|
<AttackName>Bow</AttackName>
|
||||||
<Damage>
|
<Damage>
|
||||||
<Pierce>10</Pierce>
|
<Pierce>10</Pierce>
|
||||||
</Damage>
|
</Damage>
|
||||||
<MaxRange>60</MaxRange>
|
<MaxRange>60</MaxRange>
|
||||||
<PrepareTime>1200</PrepareTime>
|
<PrepareTime>1200</PrepareTime>
|
||||||
<RepeatTime>4000</RepeatTime>
|
<RepeatTime>2000</RepeatTime>
|
||||||
<Projectile>
|
<Projectile>
|
||||||
<Speed>100</Speed>
|
<Speed>100</Speed>
|
||||||
<Spread>2</Spread>
|
<Spread>1.5</Spread>
|
||||||
<Gravity>50</Gravity>
|
<Gravity>50</Gravity>
|
||||||
<FriendlyFire>false</FriendlyFire>
|
<FriendlyFire>false</FriendlyFire>
|
||||||
<LaunchPoint y="3"/>
|
<LaunchPoint y="3"/>
|
||||||
</Projectile>
|
</Projectile>
|
||||||
<PreferredClasses datatype="tokens">Human</PreferredClasses>
|
<PreferredClasses datatype="tokens">Human</PreferredClasses>
|
||||||
<RangeOverlay>
|
<RangeOverlay>
|
||||||
<LineTexture>outline_border.png</LineTexture>
|
<LineTexture>outline_border.png</LineTexture>
|
||||||
<LineTextureMask>outline_border_mask.png</LineTextureMask>
|
<LineTextureMask>outline_border_mask.png</LineTextureMask>
|
||||||
<LineThickness>0.175</LineThickness>
|
<LineThickness>0.175</LineThickness>
|
||||||
</RangeOverlay>
|
</RangeOverlay>
|
||||||
</Ranged>
|
</Ranged>
|
||||||
</Attack>
|
</Attack>
|
||||||
<BuildRestrictions>
|
<BuildRestrictions>
|
||||||
<Territory>own neutral</Territory>
|
<Territory>own neutral</Territory>
|
||||||
<Category>CivilCentre</Category>
|
<Category>CivilCentre</Category>
|
||||||
<Distance>
|
<Distance>
|
||||||
<FromClass>CivilCentre</FromClass>
|
<FromClass>CivilCentre</FromClass>
|
||||||
<MinDistance>200</MinDistance>
|
<MinDistance>200</MinDistance>
|
||||||
</Distance>
|
</Distance>
|
||||||
</BuildRestrictions>
|
</BuildRestrictions>
|
||||||
<BuildingAI>
|
<BuildingAI>
|
||||||
<DefaultArrowCount>8</DefaultArrowCount>
|
<DefaultArrowCount>3</DefaultArrowCount>
|
||||||
<GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
|
<GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
|
||||||
<GarrisonArrowClasses>Soldier</GarrisonArrowClasses>
|
<GarrisonArrowClasses>Soldier</GarrisonArrowClasses>
|
||||||
<MaxArrowCount>18</MaxArrowCount>
|
</BuildingAI>
|
||||||
</BuildingAI>
|
<Capturable>
|
||||||
<Capturable>
|
<CapturePoints>2500</CapturePoints>
|
||||||
<CapturePoints>2500</CapturePoints>
|
<RegenRate>5.0</RegenRate>
|
||||||
<RegenRate>5.0</RegenRate>
|
</Capturable>
|
||||||
</Capturable>
|
<Cost>
|
||||||
<Cost>
|
<BuildTime>500</BuildTime>
|
||||||
<BuildTime>500</BuildTime>
|
<Resources>
|
||||||
<Resources>
|
<wood>300</wood>
|
||||||
<wood>300</wood>
|
<stone>300</stone>
|
||||||
<stone>300</stone>
|
<metal>250</metal>
|
||||||
<metal>250</metal>
|
</Resources>
|
||||||
</Resources>
|
</Cost>
|
||||||
</Cost>
|
<Footprint>
|
||||||
<Footprint>
|
<Square depth="32.0" width="32.0"/>
|
||||||
<Square depth="32.0" width="32.0"/>
|
<Height>8.0</Height>
|
||||||
<Height>8.0</Height>
|
</Footprint>
|
||||||
</Footprint>
|
<GarrisonHolder>
|
||||||
<GarrisonHolder>
|
<Max>20</Max>
|
||||||
<Max>20</Max>
|
<EjectHealth>0.1</EjectHealth>
|
||||||
<EjectHealth>0.1</EjectHealth>
|
<EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
|
||||||
<EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
|
<List datatype="tokens">Support Infantry Cavalry</List>
|
||||||
<List datatype="tokens">Support Infantry Cavalry</List>
|
<BuffHeal>1</BuffHeal>
|
||||||
<BuffHeal>1</BuffHeal>
|
<LoadingRange>1</LoadingRange>
|
||||||
<LoadingRange>1</LoadingRange>
|
</GarrisonHolder>
|
||||||
</GarrisonHolder>
|
<Health>
|
||||||
<Health>
|
<Max>3000</Max>
|
||||||
<Max>3000</Max>
|
<SpawnEntityOnDeath>decay|rubble/rubble_stone_6x6</SpawnEntityOnDeath>
|
||||||
<SpawnEntityOnDeath>decay|rubble/rubble_stone_6x6</SpawnEntityOnDeath>
|
</Health>
|
||||||
</Health>
|
<Identity>
|
||||||
<Identity>
|
<GenericName>Civic Center</GenericName>
|
||||||
<GenericName>Civic Center</GenericName>
|
<SelectionGroupName>template_structure_civic_civil_centre</SelectionGroupName>
|
||||||
<SelectionGroupName>template_structure_civic_civil_centre</SelectionGroupName>
|
<Tooltip>Build in own or neutral territory. Acquire large tracts of territory. Territory root. Train Citizens and research technologies. Garrison Soldiers for additional arrows.</Tooltip>
|
||||||
<Tooltip>Build in own or neutral territory. Acquire large tracts of territory. Territory root. Train Citizens and research technologies. Garrison Soldiers for additional arrows.</Tooltip>
|
<Classes datatype="tokens">CivCentre</Classes>
|
||||||
<Classes datatype="tokens">CivCentre</Classes>
|
<VisibleClasses datatype="tokens">Defensive CivilCentre</VisibleClasses>
|
||||||
<VisibleClasses datatype="tokens">Defensive CivilCentre</VisibleClasses>
|
<Icon>structures/civic_centre.png</Icon>
|
||||||
<Icon>structures/civic_centre.png</Icon>
|
</Identity>
|
||||||
</Identity>
|
<Loot>
|
||||||
<Loot>
|
<wood>60</wood>
|
||||||
<wood>60</wood>
|
<stone>60</stone>
|
||||||
<stone>60</stone>
|
<metal>50</metal>
|
||||||
<metal>50</metal>
|
</Loot>
|
||||||
</Loot>
|
<Minimap>
|
||||||
<Minimap>
|
<Type>structure</Type>
|
||||||
<Type>structure</Type>
|
<Icon size="16.0">civil_centre.png</Icon>
|
||||||
<Icon size="16.0">civil_centre.png</Icon>
|
</Minimap>
|
||||||
</Minimap>
|
<Obstruction>
|
||||||
<Obstruction>
|
<Static depth="30.0" width="30.0"/>
|
||||||
<Static depth="30.0" width="30.0"/>
|
</Obstruction>
|
||||||
</Obstruction>
|
<Population>
|
||||||
<Population>
|
<Bonus>20</Bonus>
|
||||||
<Bonus>20</Bonus>
|
</Population>
|
||||||
</Population>
|
<ProductionQueue/>
|
||||||
<ProductionQueue/>
|
<Researcher>
|
||||||
<Researcher>
|
<Technologies datatype="tokens">
|
||||||
<Technologies datatype="tokens">
|
phase_town_{civ}
|
||||||
phase_town_{civ}
|
phase_city_{civ}
|
||||||
phase_city_{civ}
|
unlock_shared_los
|
||||||
unlock_shared_los
|
unlock_shared_dropsites
|
||||||
unlock_shared_dropsites
|
unlock_spies
|
||||||
unlock_spies
|
spy_counter
|
||||||
spy_counter
|
archery_tradition
|
||||||
archery_tradition
|
hoplite_tradition
|
||||||
hoplite_tradition
|
hellenistic_metropolis
|
||||||
hellenistic_metropolis
|
</Technologies>
|
||||||
</Technologies>
|
</Researcher>
|
||||||
</Researcher>
|
<Resistance>
|
||||||
<Resistance>
|
<Entity>
|
||||||
<Entity>
|
<Damage>
|
||||||
<Damage>
|
<Hack op="add">5</Hack>
|
||||||
<Hack op="add">5</Hack>
|
<Pierce op="add">5</Pierce>
|
||||||
<Pierce op="add">5</Pierce>
|
</Damage>
|
||||||
</Damage>
|
</Entity>
|
||||||
</Entity>
|
</Resistance>
|
||||||
</Resistance>
|
<ResourceDropsite>
|
||||||
<ResourceDropsite>
|
<Types>food wood stone metal</Types>
|
||||||
<Types>food wood stone metal</Types>
|
<Sharable>true</Sharable>
|
||||||
<Sharable>true</Sharable>
|
</ResourceDropsite>
|
||||||
</ResourceDropsite>
|
<Sound>
|
||||||
<Sound>
|
<SoundGroups>
|
||||||
<SoundGroups>
|
<select>interface/select/building/sel_civ_center.xml</select>
|
||||||
<select>interface/select/building/sel_civ_center.xml</select>
|
<constructed>interface/complete/building/complete_civ_center.xml</constructed>
|
||||||
<constructed>interface/complete/building/complete_civ_center.xml</constructed>
|
<upgraded>interface/complete/building/complete_civ_center.xml</upgraded>
|
||||||
<upgraded>interface/complete/building/complete_civ_center.xml</upgraded>
|
<alert_raise>interface/alarm/alarm_alert_0.xml</alert_raise>
|
||||||
<alert_raise>interface/alarm/alarm_alert_0.xml</alert_raise>
|
<alert_end>interface/alarm/alarm_alert_1.xml</alert_end>
|
||||||
<alert_end>interface/alarm/alarm_alert_1.xml</alert_end>
|
<attack_ranged>attack/weapon/bow_attack.xml</attack_ranged>
|
||||||
<attack_ranged>attack/weapon/bow_attack.xml</attack_ranged>
|
<attack_impact_ranged>attack/impact/arrow_impact.xml</attack_impact_ranged>
|
||||||
<attack_impact_ranged>attack/impact/arrow_impact.xml</attack_impact_ranged>
|
</SoundGroups>
|
||||||
</SoundGroups>
|
</Sound>
|
||||||
</Sound>
|
<TerritoryInfluence>
|
||||||
<TerritoryInfluence>
|
<Root>true</Root>
|
||||||
<Root>true</Root>
|
<Radius>140</Radius>
|
||||||
<Radius>140</Radius>
|
<Weight>10000</Weight>
|
||||||
<Weight>10000</Weight>
|
</TerritoryInfluence>
|
||||||
</TerritoryInfluence>
|
<Trainer>
|
||||||
<Trainer>
|
<BatchTimeModifier>0.8</BatchTimeModifier>
|
||||||
<BatchTimeModifier>0.8</BatchTimeModifier>
|
<Entities datatype="tokens">
|
||||||
<Entities datatype="tokens">
|
units/{civ}/support_female_citizen
|
||||||
units/{civ}/support_female_citizen
|
</Entities>
|
||||||
</Entities>
|
</Trainer>
|
||||||
</Trainer>
|
<Vision>
|
||||||
<Vision>
|
<Range>90</Range>
|
||||||
<Range>90</Range>
|
</Vision>
|
||||||
</Vision>
|
<VisualActor>
|
||||||
<VisualActor>
|
<FoundationActor>structures/fndn_8x8.xml</FoundationActor>
|
||||||
<FoundationActor>structures/fndn_8x8.xml</FoundationActor>
|
</VisualActor>
|
||||||
</VisualActor>
|
|
||||||
</Entity>
|
</Entity>
|
||||||
|
@ -1,55 +1,54 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Entity parent="template_structure_civic_civil_centre">
|
<Entity parent="template_structure_civic_civil_centre">
|
||||||
<BuildRestrictions>
|
<BuildRestrictions>
|
||||||
<Territory>own neutral</Territory>
|
<Territory>own neutral</Territory>
|
||||||
<Category>Colony</Category>
|
<Category>Colony</Category>
|
||||||
<Distance>
|
<Distance>
|
||||||
<FromClass>CivilCentre</FromClass>
|
<FromClass>CivilCentre</FromClass>
|
||||||
<MinDistance>120</MinDistance>
|
<MinDistance>120</MinDistance>
|
||||||
</Distance>
|
</Distance>
|
||||||
</BuildRestrictions>
|
</BuildRestrictions>
|
||||||
<BuildingAI>
|
<BuildingAI>
|
||||||
<DefaultArrowCount>6</DefaultArrowCount>
|
<DefaultArrowCount>1</DefaultArrowCount>
|
||||||
<MaxArrowCount>16</MaxArrowCount>
|
</BuildingAI>
|
||||||
</BuildingAI>
|
<Cost>
|
||||||
<Cost>
|
<BuildTime>300</BuildTime>
|
||||||
<BuildTime>300</BuildTime>
|
<Resources>
|
||||||
<Resources>
|
<wood>200</wood>
|
||||||
<wood>200</wood>
|
<stone>200</stone>
|
||||||
<stone>200</stone>
|
<metal>150</metal>
|
||||||
<metal>150</metal>
|
</Resources>
|
||||||
</Resources>
|
</Cost>
|
||||||
</Cost>
|
<Health>
|
||||||
<Health>
|
<Max>2000</Max>
|
||||||
<Max>2000</Max>
|
<SpawnEntityOnDeath>decay|rubble/rubble_stone_5x5</SpawnEntityOnDeath>
|
||||||
<SpawnEntityOnDeath>decay|rubble/rubble_stone_5x5</SpawnEntityOnDeath>
|
</Health>
|
||||||
</Health>
|
<Identity>
|
||||||
<Identity>
|
<GenericName>Military Colony</GenericName>
|
||||||
<GenericName>Military Colony</GenericName>
|
<SelectionGroupName>template_structure_civic_civil_centre_military_colony</SelectionGroupName>
|
||||||
<SelectionGroupName>template_structure_civic_civil_centre_military_colony</SelectionGroupName>
|
<VisibleClasses datatype="tokens">Colony</VisibleClasses>
|
||||||
<VisibleClasses datatype="tokens">Colony</VisibleClasses>
|
<Icon>structures/military_settlement.png</Icon>
|
||||||
<Icon>structures/military_settlement.png</Icon>
|
<RequiredTechnology>phase_town</RequiredTechnology>
|
||||||
<RequiredTechnology>phase_town</RequiredTechnology>
|
</Identity>
|
||||||
</Identity>
|
<Loot>
|
||||||
<Loot>
|
<wood>40</wood>
|
||||||
<wood>40</wood>
|
<stone>40</stone>
|
||||||
<stone>40</stone>
|
<metal>30</metal>
|
||||||
<metal>30</metal>
|
</Loot>
|
||||||
</Loot>
|
<Researcher>
|
||||||
<Researcher>
|
<Technologies datatype="tokens">
|
||||||
<Technologies datatype="tokens">
|
-phase_town_{civ}
|
||||||
-phase_town_{civ}
|
-phase_city_{civ}
|
||||||
-phase_city_{civ}
|
-hellenistic_metropolis
|
||||||
-hellenistic_metropolis
|
</Technologies>
|
||||||
</Technologies>
|
</Researcher>
|
||||||
</Researcher>
|
<Sound>
|
||||||
<Sound>
|
<SoundGroups>
|
||||||
<SoundGroups>
|
<select>interface/select/building/sel_gymnasium.xml</select>
|
||||||
<select>interface/select/building/sel_gymnasium.xml</select>
|
<constructed>interface/complete/building/complete_gymnasium.xml</constructed>
|
||||||
<constructed>interface/complete/building/complete_gymnasium.xml</constructed>
|
</SoundGroups>
|
||||||
</SoundGroups>
|
</Sound>
|
||||||
</Sound>
|
<TerritoryInfluence>
|
||||||
<TerritoryInfluence>
|
<Radius>75</Radius>
|
||||||
<Radius>75</Radius>
|
</TerritoryInfluence>
|
||||||
</TerritoryInfluence>
|
|
||||||
</Entity>
|
</Entity>
|
||||||
|
@ -1,72 +1,72 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Entity parent="template_structure_defensive">
|
<Entity parent="template_structure_defensive">
|
||||||
<Attack>
|
<Attack>
|
||||||
<Ranged>
|
<Ranged>
|
||||||
<AttackName>Bow</AttackName>
|
<AttackName>Bow</AttackName>
|
||||||
<Damage>
|
<Damage>
|
||||||
<Pierce>11</Pierce>
|
<Pierce>11</Pierce>
|
||||||
</Damage>
|
</Damage>
|
||||||
<MaxRange>60</MaxRange>
|
<MaxRange>60</MaxRange>
|
||||||
<MinRange>10</MinRange>
|
<MinRange>10</MinRange>
|
||||||
<PrepareTime>1200</PrepareTime>
|
<PrepareTime>1200</PrepareTime>
|
||||||
<RepeatTime>4000</RepeatTime>
|
<RepeatTime>2000</RepeatTime>
|
||||||
<Projectile>
|
<Projectile>
|
||||||
<Speed>100</Speed>
|
<Speed>100</Speed>
|
||||||
<Spread>1.5</Spread>
|
<Spread>1.5</Spread>
|
||||||
<Gravity>50</Gravity>
|
<Gravity>50</Gravity>
|
||||||
<FriendlyFire>false</FriendlyFire>
|
<FriendlyFire>false</FriendlyFire>
|
||||||
<LaunchPoint y="3"/>
|
<LaunchPoint y="3"/>
|
||||||
</Projectile>
|
</Projectile>
|
||||||
<PreferredClasses datatype="tokens">Human</PreferredClasses>
|
<PreferredClasses datatype="tokens">Human</PreferredClasses>
|
||||||
<RangeOverlay>
|
<RangeOverlay>
|
||||||
<LineTexture>outline_border.png</LineTexture>
|
<LineTexture>outline_border.png</LineTexture>
|
||||||
<LineTextureMask>outline_border_mask.png</LineTextureMask>
|
<LineTextureMask>outline_border_mask.png</LineTextureMask>
|
||||||
<LineThickness>0.175</LineThickness>
|
<LineThickness>0.175</LineThickness>
|
||||||
</RangeOverlay>
|
</RangeOverlay>
|
||||||
</Ranged>
|
</Ranged>
|
||||||
</Attack>
|
</Attack>
|
||||||
<BuildingAI>
|
<BuildingAI>
|
||||||
<DefaultArrowCount>2</DefaultArrowCount>
|
<DefaultArrowCount>1</DefaultArrowCount>
|
||||||
<GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
|
<GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
|
||||||
<GarrisonArrowClasses>Infantry</GarrisonArrowClasses>
|
<GarrisonArrowClasses>Infantry</GarrisonArrowClasses>
|
||||||
</BuildingAI>
|
</BuildingAI>
|
||||||
<BuildRestrictions>
|
<BuildRestrictions>
|
||||||
<Category>Tower</Category>
|
<Category>Tower</Category>
|
||||||
<Distance>
|
<Distance>
|
||||||
<FromClass>Tower</FromClass>
|
<FromClass>Tower</FromClass>
|
||||||
<MinDistance>60</MinDistance>
|
<MinDistance>60</MinDistance>
|
||||||
</Distance>
|
</Distance>
|
||||||
</BuildRestrictions>
|
</BuildRestrictions>
|
||||||
<GarrisonHolder>
|
<GarrisonHolder>
|
||||||
<EjectHealth>0.1</EjectHealth>
|
<EjectHealth>0.1</EjectHealth>
|
||||||
<EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
|
<EjectClassesOnDestroy datatype="tokens">Unit</EjectClassesOnDestroy>
|
||||||
<List datatype="tokens">Support Infantry</List>
|
<List datatype="tokens">Support Infantry</List>
|
||||||
<BuffHeal>0</BuffHeal>
|
<BuffHeal>0</BuffHeal>
|
||||||
<LoadingRange>2</LoadingRange>
|
<LoadingRange>2</LoadingRange>
|
||||||
</GarrisonHolder>
|
</GarrisonHolder>
|
||||||
<Health>
|
<Health>
|
||||||
<Max>1000</Max>
|
<Max>1000</Max>
|
||||||
<SpawnEntityOnDeath>decay|rubble/rubble_stone_2x2</SpawnEntityOnDeath>
|
<SpawnEntityOnDeath>decay|rubble/rubble_stone_2x2</SpawnEntityOnDeath>
|
||||||
</Health>
|
</Health>
|
||||||
<Identity>
|
<Identity>
|
||||||
<GenericName>Tower</GenericName>
|
<GenericName>Tower</GenericName>
|
||||||
<VisibleClasses datatype="tokens">Tower</VisibleClasses>
|
<VisibleClasses datatype="tokens">Tower</VisibleClasses>
|
||||||
</Identity>
|
</Identity>
|
||||||
<Sound>
|
<Sound>
|
||||||
<SoundGroups>
|
<SoundGroups>
|
||||||
<constructed>interface/complete/building/complete_tower.xml</constructed>
|
<constructed>interface/complete/building/complete_tower.xml</constructed>
|
||||||
<select>interface/select/building/sel_tower.xml</select>
|
<select>interface/select/building/sel_tower.xml</select>
|
||||||
<attack_ranged>attack/weapon/bow_attack.xml</attack_ranged>
|
<attack_ranged>attack/weapon/bow_attack.xml</attack_ranged>
|
||||||
<attack_impact_ranged>attack/impact/arrow_impact.xml</attack_impact_ranged>
|
<attack_impact_ranged>attack/impact/arrow_impact.xml</attack_impact_ranged>
|
||||||
</SoundGroups>
|
</SoundGroups>
|
||||||
</Sound>
|
</Sound>
|
||||||
<StatusBars>
|
<StatusBars>
|
||||||
<HeightOffset>18.0</HeightOffset>
|
<HeightOffset>18.0</HeightOffset>
|
||||||
</StatusBars>
|
</StatusBars>
|
||||||
<Vision>
|
<Vision>
|
||||||
<Range>80</Range>
|
<Range>80</Range>
|
||||||
</Vision>
|
</Vision>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<FoundationActor>structures/fndn_3x3.xml</FoundationActor>
|
<FoundationActor>structures/fndn_3x3.xml</FoundationActor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
</Entity>
|
</Entity>
|
||||||
|
@ -1,69 +1,69 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Entity parent="template_structure_defensive_tower">
|
<Entity parent="template_structure_defensive_tower">
|
||||||
<Attack>
|
<Attack>
|
||||||
<Ranged>
|
<Ranged>
|
||||||
<Origin>
|
<Origin>
|
||||||
<X>0</X>
|
<X>0</X>
|
||||||
<Y>9</Y>
|
<Y>9</Y>
|
||||||
<Z>0</Z>
|
<Z>0</Z>
|
||||||
</Origin>
|
</Origin>
|
||||||
</Ranged>
|
</Ranged>
|
||||||
</Attack>
|
</Attack>
|
||||||
<BuildingAI>
|
<BuildingAI>
|
||||||
<MaxArrowCount>5</MaxArrowCount>
|
<MaxArrowCount>4</MaxArrowCount>
|
||||||
</BuildingAI>
|
</BuildingAI>
|
||||||
<Cost>
|
<Cost>
|
||||||
<BuildTime>40</BuildTime>
|
<BuildTime>40</BuildTime>
|
||||||
<Resources>
|
<Resources>
|
||||||
<wood>125</wood>
|
<wood>100</wood>
|
||||||
</Resources>
|
</Resources>
|
||||||
</Cost>
|
</Cost>
|
||||||
<Footprint>
|
<Footprint>
|
||||||
<Square width="9.5" depth="8.5"/>
|
<Square width="9.5" depth="8.5"/>
|
||||||
<Height>9.0</Height>
|
<Height>9.0</Height>
|
||||||
</Footprint>
|
</Footprint>
|
||||||
<GarrisonHolder>
|
<GarrisonHolder>
|
||||||
<Max>3</Max>
|
<Max>3</Max>
|
||||||
</GarrisonHolder>
|
</GarrisonHolder>
|
||||||
<Health>
|
<Health>
|
||||||
<Max>400</Max>
|
<Max>400</Max>
|
||||||
</Health>
|
</Health>
|
||||||
<Identity>
|
<Identity>
|
||||||
<GenericName>Sentry Tower</GenericName>
|
<GenericName>Sentry Tower</GenericName>
|
||||||
<SelectionGroupName>template_structure_defensive_tower_sentry</SelectionGroupName>
|
<SelectionGroupName>template_structure_defensive_tower_sentry</SelectionGroupName>
|
||||||
<Tooltip>Garrison Infantry for additional arrows. Needs the “Murder Holes” technology to protect its foot.</Tooltip>
|
<Tooltip>Garrison Infantry for additional arrows. Needs the “Murder Holes” technology to protect its foot.</Tooltip>
|
||||||
<VisibleClasses datatype="tokens">SentryTower</VisibleClasses>
|
<VisibleClasses datatype="tokens">SentryTower</VisibleClasses>
|
||||||
<Icon>structures/sentry_tower.png</Icon>
|
<Icon>structures/sentry_tower.png</Icon>
|
||||||
<RequiredTechnology>phase_village</RequiredTechnology>
|
<RequiredTechnology>phase_village</RequiredTechnology>
|
||||||
</Identity>
|
</Identity>
|
||||||
<Loot>
|
<Loot>
|
||||||
<wood>25</wood>
|
<wood>20</wood>
|
||||||
</Loot>
|
</Loot>
|
||||||
<Obstruction>
|
<Obstruction>
|
||||||
<Static width="9.0" depth="7.5"/>
|
<Static width="9.0" depth="7.5"/>
|
||||||
</Obstruction>
|
</Obstruction>
|
||||||
<ProductionQueue/>
|
<ProductionQueue/>
|
||||||
<Researcher>
|
<Researcher>
|
||||||
<Technologies datatype="tokens">
|
<Technologies datatype="tokens">
|
||||||
tower_watch
|
tower_watch
|
||||||
</Technologies>
|
</Technologies>
|
||||||
</Researcher>
|
</Researcher>
|
||||||
<TerritoryInfluence>
|
<TerritoryInfluence>
|
||||||
<Root>false</Root>
|
<Root>false</Root>
|
||||||
<Radius>16</Radius>
|
<Radius>16</Radius>
|
||||||
<Weight>30000</Weight>
|
<Weight>30000</Weight>
|
||||||
</TerritoryInfluence>
|
</TerritoryInfluence>
|
||||||
<Upgrade>
|
<Upgrade>
|
||||||
<Tower>
|
<Tower>
|
||||||
<Entity>structures/{civ}/defense_tower</Entity>
|
<Entity>structures/{civ}/defense_tower</Entity>
|
||||||
<Tooltip>Reinforce with stone and upgrade to a defense tower.</Tooltip>
|
<Tooltip>Reinforce with stone and upgrade to a defense tower.</Tooltip>
|
||||||
<RequiredTechnology>phase_town</RequiredTechnology>
|
<RequiredTechnology>phase_town</RequiredTechnology>
|
||||||
<Cost>
|
<Cost>
|
||||||
<wood>25</wood>
|
<wood>50</wood>
|
||||||
<stone>100</stone>
|
<stone>100</stone>
|
||||||
</Cost>
|
</Cost>
|
||||||
<Variant>upgrading</Variant>
|
<Variant>upgrading</Variant>
|
||||||
<Time>100</Time>
|
<Time>100</Time>
|
||||||
</Tower>
|
</Tower>
|
||||||
</Upgrade>
|
</Upgrade>
|
||||||
</Entity>
|
</Entity>
|
||||||
|
@ -1,62 +1,59 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Entity parent="template_structure_defensive_tower">
|
<Entity parent="template_structure_defensive_tower">
|
||||||
<Attack>
|
<Attack>
|
||||||
<Ranged>
|
<Ranged>
|
||||||
<Origin>
|
<Origin>
|
||||||
<X>0</X>
|
<X>0</X>
|
||||||
<Y>15</Y>
|
<Y>15</Y>
|
||||||
<Z>0</Z>
|
<Z>0</Z>
|
||||||
</Origin>
|
</Origin>
|
||||||
</Ranged>
|
</Ranged>
|
||||||
</Attack>
|
</Attack>
|
||||||
<Cost>
|
<Cost>
|
||||||
<BuildTime>150</BuildTime>
|
<BuildTime>150</BuildTime>
|
||||||
<Resources>
|
<Resources>
|
||||||
<wood>100</wood>
|
<wood>100</wood>
|
||||||
<stone>100</stone>
|
<stone>100</stone>
|
||||||
</Resources>
|
</Resources>
|
||||||
</Cost>
|
</Cost>
|
||||||
<Footprint>
|
<Footprint>
|
||||||
<Square width="10.0" depth="10.0"/>
|
<Square width="10.0" depth="10.0"/>
|
||||||
<Height>15.0</Height>
|
<Height>15.0</Height>
|
||||||
</Footprint>
|
</Footprint>
|
||||||
<BuildingAI>
|
<GarrisonHolder>
|
||||||
<DefaultArrowCount>3</DefaultArrowCount>
|
<Max>5</Max>
|
||||||
</BuildingAI>
|
</GarrisonHolder>
|
||||||
<GarrisonHolder>
|
<Health>
|
||||||
<Max>5</Max>
|
<Max>1000</Max>
|
||||||
</GarrisonHolder>
|
</Health>
|
||||||
<Health>
|
<Identity>
|
||||||
<Max>1000</Max>
|
<GenericName>Stone Tower</GenericName>
|
||||||
</Health>
|
<SelectionGroupName>template_structure_defensive_tower_stone</SelectionGroupName>
|
||||||
<Identity>
|
<Tooltip>Garrison Infantry for additional arrows. Needs the “Murder Holes” technology to protect its foot.</Tooltip>
|
||||||
<GenericName>Stone Tower</GenericName>
|
<VisibleClasses datatype="tokens">StoneTower</VisibleClasses>
|
||||||
<SelectionGroupName>template_structure_defensive_tower_stone</SelectionGroupName>
|
<Icon>structures/defense_tower.png</Icon>
|
||||||
<Tooltip>Garrison Infantry for additional arrows. Needs the “Murder Holes” technology to protect its foot.</Tooltip>
|
<RequiredTechnology>phase_town</RequiredTechnology>
|
||||||
<VisibleClasses datatype="tokens">StoneTower</VisibleClasses>
|
</Identity>
|
||||||
<Icon>structures/defense_tower.png</Icon>
|
<Loot>
|
||||||
<RequiredTechnology>phase_town</RequiredTechnology>
|
<wood>20</wood>
|
||||||
</Identity>
|
<stone>20</stone>
|
||||||
<Loot>
|
</Loot>
|
||||||
<wood>20</wood>
|
<Obstruction>
|
||||||
<stone>20</stone>
|
<Static width="7.0" depth="7.0"/>
|
||||||
</Loot>
|
</Obstruction>
|
||||||
<Obstruction>
|
<ProductionQueue/>
|
||||||
<Static width="7.0" depth="7.0"/>
|
<Researcher>
|
||||||
</Obstruction>
|
<Technologies datatype="tokens">
|
||||||
<ProductionQueue/>
|
tower_watch
|
||||||
<Researcher>
|
tower_crenellations
|
||||||
<Technologies datatype="tokens">
|
tower_range
|
||||||
tower_watch
|
tower_murderholes
|
||||||
tower_crenellations
|
tower_health
|
||||||
tower_range
|
</Technologies>
|
||||||
tower_murderholes
|
</Researcher>
|
||||||
tower_health
|
<TerritoryInfluence>
|
||||||
</Technologies>
|
<Root>false</Root>
|
||||||
</Researcher>
|
<Radius>32</Radius>
|
||||||
<TerritoryInfluence>
|
<Weight>30000</Weight>
|
||||||
<Root>false</Root>
|
</TerritoryInfluence>
|
||||||
<Radius>32</Radius>
|
|
||||||
<Weight>30000</Weight>
|
|
||||||
</TerritoryInfluence>
|
|
||||||
</Entity>
|
</Entity>
|
||||||
|
@ -1,112 +1,112 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Entity parent="template_structure_military">
|
<Entity parent="template_structure_military">
|
||||||
<Attack>
|
<Attack>
|
||||||
<Ranged>
|
<Ranged>
|
||||||
<AttackName>Bow</AttackName>
|
<AttackName>Bow</AttackName>
|
||||||
<Damage>
|
<Damage>
|
||||||
<Pierce>10</Pierce>
|
<Pierce>10</Pierce>
|
||||||
</Damage>
|
</Damage>
|
||||||
<MaxRange>60</MaxRange>
|
<MaxRange>60</MaxRange>
|
||||||
<PrepareTime>1200</PrepareTime>
|
<PrepareTime>1200</PrepareTime>
|
||||||
<RepeatTime>4000</RepeatTime>
|
<RepeatTime>2000</RepeatTime>
|
||||||
<Projectile>
|
<Projectile>
|
||||||
<Speed>100</Speed>
|
<Speed>100</Speed>
|
||||||
<Spread>2.5</Spread>
|
<Spread>1.5</Spread>
|
||||||
<Gravity>50</Gravity>
|
<Gravity>50</Gravity>
|
||||||
<FriendlyFire>false</FriendlyFire>
|
<FriendlyFire>false</FriendlyFire>
|
||||||
<LaunchPoint y="3"/>
|
<LaunchPoint y="3"/>
|
||||||
</Projectile>
|
</Projectile>
|
||||||
<PreferredClasses datatype="tokens">Human</PreferredClasses>
|
<PreferredClasses datatype="tokens">Human</PreferredClasses>
|
||||||
<RangeOverlay>
|
<RangeOverlay>
|
||||||
<LineTexture>outline_border.png</LineTexture>
|
<LineTexture>outline_border.png</LineTexture>
|
||||||
<LineTextureMask>outline_border_mask.png</LineTextureMask>
|
<LineTextureMask>outline_border_mask.png</LineTextureMask>
|
||||||
<LineThickness>0.175</LineThickness>
|
<LineThickness>0.175</LineThickness>
|
||||||
</RangeOverlay>
|
</RangeOverlay>
|
||||||
</Ranged>
|
</Ranged>
|
||||||
</Attack>
|
</Attack>
|
||||||
<BuildRestrictions>
|
<BuildRestrictions>
|
||||||
<Category>Fortress</Category>
|
<Category>Fortress</Category>
|
||||||
<Distance>
|
<Distance>
|
||||||
<FromClass>Fortress</FromClass>
|
<FromClass>Fortress</FromClass>
|
||||||
<MinDistance>80</MinDistance>
|
<MinDistance>80</MinDistance>
|
||||||
</Distance>
|
</Distance>
|
||||||
</BuildRestrictions>
|
</BuildRestrictions>
|
||||||
<BuildingAI>
|
<BuildingAI>
|
||||||
<DefaultArrowCount>12</DefaultArrowCount>
|
<DefaultArrowCount>4</DefaultArrowCount>
|
||||||
<GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
|
<GarrisonArrowMultiplier>1</GarrisonArrowMultiplier>
|
||||||
<GarrisonArrowClasses>Soldier</GarrisonArrowClasses>
|
<GarrisonArrowClasses>Soldier</GarrisonArrowClasses>
|
||||||
</BuildingAI>
|
</BuildingAI>
|
||||||
<Capturable>
|
<Capturable>
|
||||||
<CapturePoints op="mul">8</CapturePoints>
|
<CapturePoints op="mul">8</CapturePoints>
|
||||||
<RegenRate>10.0</RegenRate>
|
<RegenRate>10.0</RegenRate>
|
||||||
</Capturable>
|
</Capturable>
|
||||||
<Cost>
|
<Cost>
|
||||||
<BuildTime>450</BuildTime>
|
<BuildTime>450</BuildTime>
|
||||||
<Resources>
|
<Resources>
|
||||||
<wood>300</wood>
|
<wood>300</wood>
|
||||||
<stone>600</stone>
|
<stone>600</stone>
|
||||||
</Resources>
|
</Resources>
|
||||||
</Cost>
|
</Cost>
|
||||||
<Footprint>
|
<Footprint>
|
||||||
<Square width="30.0" depth="30.0"/>
|
<Square width="30.0" depth="30.0"/>
|
||||||
<Height>8.0</Height>
|
<Height>8.0</Height>
|
||||||
</Footprint>
|
</Footprint>
|
||||||
<GarrisonHolder>
|
<GarrisonHolder>
|
||||||
<Max>20</Max>
|
<Max>20</Max>
|
||||||
<EjectHealth>0.075</EjectHealth>
|
<EjectHealth>0.075</EjectHealth>
|
||||||
<List datatype="tokens">Support Infantry Cavalry Siege</List>
|
<List datatype="tokens">Support Infantry Cavalry Siege</List>
|
||||||
<LoadingRange>6</LoadingRange>
|
<LoadingRange>6</LoadingRange>
|
||||||
</GarrisonHolder>
|
</GarrisonHolder>
|
||||||
<Health>
|
<Health>
|
||||||
<Max>5200</Max>
|
<Max>5200</Max>
|
||||||
<SpawnEntityOnDeath>decay|rubble/rubble_stone_6x6</SpawnEntityOnDeath>
|
<SpawnEntityOnDeath>decay|rubble/rubble_stone_6x6</SpawnEntityOnDeath>
|
||||||
</Health>
|
</Health>
|
||||||
<Identity>
|
<Identity>
|
||||||
<GenericName>Fortress</GenericName>
|
<GenericName>Fortress</GenericName>
|
||||||
<SelectionGroupName>template_structure_military_fortress</SelectionGroupName>
|
<SelectionGroupName>template_structure_military_fortress</SelectionGroupName>
|
||||||
<Tooltip>Garrison Soldiers for additional arrows.</Tooltip>
|
<Tooltip>Garrison Soldiers for additional arrows.</Tooltip>
|
||||||
<Classes datatype="tokens">GarrisonFortress</Classes>
|
<Classes datatype="tokens">GarrisonFortress</Classes>
|
||||||
<VisibleClasses datatype="tokens">Defensive Fortress</VisibleClasses>
|
<VisibleClasses datatype="tokens">Defensive Fortress</VisibleClasses>
|
||||||
<Icon>structures/fortress.png</Icon>
|
<Icon>structures/fortress.png</Icon>
|
||||||
<RequiredTechnology>phase_city</RequiredTechnology>
|
<RequiredTechnology>phase_city</RequiredTechnology>
|
||||||
</Identity>
|
</Identity>
|
||||||
<Loot>
|
<Loot>
|
||||||
<wood>60</wood>
|
<wood>60</wood>
|
||||||
<stone>120</stone>
|
<stone>120</stone>
|
||||||
</Loot>
|
</Loot>
|
||||||
<Obstruction>
|
<Obstruction>
|
||||||
<Static width="25.0" depth="25.0"/>
|
<Static width="25.0" depth="25.0"/>
|
||||||
</Obstruction>
|
</Obstruction>
|
||||||
<ProductionQueue/>
|
<ProductionQueue/>
|
||||||
<Researcher>
|
<Researcher>
|
||||||
<Technologies datatype="tokens">
|
<Technologies datatype="tokens">
|
||||||
attack_soldiers_will
|
attack_soldiers_will
|
||||||
art_of_war
|
art_of_war
|
||||||
poison_arrows
|
poison_arrows
|
||||||
poison_blades
|
poison_blades
|
||||||
</Technologies>
|
</Technologies>
|
||||||
</Researcher>
|
</Researcher>
|
||||||
<Sound>
|
<Sound>
|
||||||
<SoundGroups>
|
<SoundGroups>
|
||||||
<select>interface/select/building/sel_fortress.xml</select>
|
<select>interface/select/building/sel_fortress.xml</select>
|
||||||
<constructed>interface/complete/building/complete_fortress.xml</constructed>
|
<constructed>interface/complete/building/complete_fortress.xml</constructed>
|
||||||
<attack_ranged>attack/weapon/bow_attack.xml</attack_ranged>
|
<attack_ranged>attack/weapon/bow_attack.xml</attack_ranged>
|
||||||
<attack_impact_ranged>attack/impact/arrow_impact.xml</attack_impact_ranged>
|
<attack_impact_ranged>attack/impact/arrow_impact.xml</attack_impact_ranged>
|
||||||
</SoundGroups>
|
</SoundGroups>
|
||||||
</Sound>
|
</Sound>
|
||||||
<TerritoryDecay>
|
<TerritoryDecay>
|
||||||
<DecayRate op="mul">2</DecayRate>
|
<DecayRate op="mul">2</DecayRate>
|
||||||
</TerritoryDecay>
|
</TerritoryDecay>
|
||||||
<TerritoryInfluence>
|
<TerritoryInfluence>
|
||||||
<Radius>80</Radius>
|
<Radius>80</Radius>
|
||||||
</TerritoryInfluence>
|
</TerritoryInfluence>
|
||||||
<Trainer>
|
<Trainer>
|
||||||
<BatchTimeModifier>0.8</BatchTimeModifier>
|
<BatchTimeModifier>0.8</BatchTimeModifier>
|
||||||
</Trainer>
|
</Trainer>
|
||||||
<Vision>
|
<Vision>
|
||||||
<Range>90</Range>
|
<Range>90</Range>
|
||||||
</Vision>
|
</Vision>
|
||||||
<VisualActor>
|
<VisualActor>
|
||||||
<FoundationActor>structures/fndn_8x8.xml</FoundationActor>
|
<FoundationActor>structures/fndn_8x8.xml</FoundationActor>
|
||||||
</VisualActor>
|
</VisualActor>
|
||||||
</Entity>
|
</Entity>
|
||||||
|
Loading…
Reference in New Issue
Block a user