mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-07-25 20:31:58 +00:00
BuildingAI style fixes, refs #3763.
Remove a duplicate targetUnits-, some useless length-checks and unneeded comments. This was SVN commit r17783.
This commit is contained in:
@@ -51,20 +51,23 @@ function damageTypeDetails(dmg)
|
||||
|
||||
function attackRateDetails(entState, type)
|
||||
{
|
||||
// Either one arrow shot by UnitAI,
|
||||
let time = entState.attack[type].repeatTime / 1000;
|
||||
let timeString = sprintf(translatePlural("%(time)s %(second)s", "%(time)s %(second)s", time), {
|
||||
"time": time,
|
||||
"second": g_TooltipTextFormats.unit[0] + translatePlural("second", "seconds", time) + g_TooltipTextFormats.unit[1]
|
||||
});
|
||||
|
||||
// or multiple arrows shot by BuildingAI
|
||||
if (!entState.buildingAI)
|
||||
return timeString;
|
||||
|
||||
let arrows = Math.max(entState.buildingAI.arrowCount, entState.buildingAI.defaultArrowCount);
|
||||
let arrows = entState.buildingAI.arrowCount;
|
||||
let arrowString = sprintf(translatePlural("%(arrowcount)s %(arrow)s", "%(arrowcount)s %(arrow)s", arrows), {
|
||||
"arrowcount": arrows,
|
||||
"arrow": g_TooltipTextFormats.unit[0] + translatePlural("arrow", "arrows", arrows) + g_TooltipTextFormats.unit[1]
|
||||
});
|
||||
|
||||
return sprintf(translate("%(arrowString)s / %(timeString)s"), {
|
||||
"arrowString": arrowString,
|
||||
"timeString": timeString
|
||||
|
||||
@@ -17,22 +17,16 @@ BuildingAI.prototype.Schema =
|
||||
|
||||
BuildingAI.prototype.MAX_PREFERENCE_BONUS = 2;
|
||||
|
||||
/**
|
||||
* Initialize BuildingAI Component
|
||||
*/
|
||||
BuildingAI.prototype.Init = function()
|
||||
{
|
||||
this.currentRound = 0;
|
||||
//Arrows left to fire
|
||||
this.arrowsLeft = 0;
|
||||
this.targetUnits = [];
|
||||
};
|
||||
|
||||
BuildingAI.prototype.OnOwnershipChanged = function(msg)
|
||||
{
|
||||
// Remove current targets, to prevent them from being added twice
|
||||
this.targetUnits = [];
|
||||
|
||||
this.SetupRangeQuery();
|
||||
this.SetupGaiaRangeQuery();
|
||||
};
|
||||
@@ -48,20 +42,17 @@ BuildingAI.prototype.OnDiplomacyChanged = function(msg)
|
||||
this.SetupGaiaRangeQuery();
|
||||
};
|
||||
|
||||
/**
|
||||
* Cleanup on destroy
|
||||
*/
|
||||
BuildingAI.prototype.OnDestroy = function()
|
||||
{
|
||||
if (this.timer)
|
||||
{
|
||||
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
||||
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
||||
cmpTimer.CancelTimer(this.timer);
|
||||
this.timer = undefined;
|
||||
}
|
||||
|
||||
// Clean up range queries
|
||||
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
if (this.enemyUnitsQuery)
|
||||
cmpRangeManager.DestroyActiveQuery(this.enemyUnitsQuery);
|
||||
if (this.gaiaUnitsQuery)
|
||||
@@ -101,20 +92,20 @@ BuildingAI.prototype.SetupRangeQuery = function()
|
||||
if (!cmpPlayer)
|
||||
return;
|
||||
|
||||
var players = [];
|
||||
var enemies = [];
|
||||
var numPlayers = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager).GetNumPlayers();
|
||||
for (var i = 1; i < numPlayers; ++i)
|
||||
{ // Exclude gaia, allies, and self
|
||||
// TODO: How to handle neutral players - Special query to attack military only?
|
||||
for (let i = 1; i < numPlayers; ++i)
|
||||
if (cmpPlayer.IsEnemy(i))
|
||||
players.push(i);
|
||||
}
|
||||
enemies.push(i);
|
||||
|
||||
if (!players.length)
|
||||
if (!enemies.length)
|
||||
return;
|
||||
|
||||
var range = cmpAttack.GetRange(attackType);
|
||||
this.enemyUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(this.entity, range.min, range.max, range.elevationBonus, players, IID_DamageReceiver, cmpRangeManager.GetEntityFlagMask("normal"));
|
||||
this.enemyUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(
|
||||
this.entity, range.min, range.max, range.elevationBonus,
|
||||
enemies, IID_DamageReceiver, cmpRangeManager.GetEntityFlagMask("normal"));
|
||||
|
||||
cmpRangeManager.EnableActiveQuery(this.enemyUnitsQuery);
|
||||
};
|
||||
|
||||
@@ -140,7 +131,10 @@ BuildingAI.prototype.SetupGaiaRangeQuery = function()
|
||||
var range = cmpAttack.GetRange(attackType);
|
||||
|
||||
// This query is only interested in Gaia entities that can attack.
|
||||
this.gaiaUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(this.entity, range.min, range.max, range.elevationBonus, [0], IID_Attack, cmpRangeManager.GetEntityFlagMask("normal"));
|
||||
this.gaiaUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(
|
||||
this.entity, range.min, range.max, range.elevationBonus,
|
||||
[0], IID_Attack, cmpRangeManager.GetEntityFlagMask("normal"));
|
||||
|
||||
cmpRangeManager.EnableActiveQuery(this.gaiaUnitsQuery);
|
||||
};
|
||||
|
||||
@@ -154,40 +148,28 @@ BuildingAI.prototype.OnRangeUpdate = function(msg)
|
||||
if (!cmpAttack)
|
||||
return;
|
||||
|
||||
// Target enemy units except non-dangerous animals
|
||||
if (msg.tag == this.gaiaUnitsQuery)
|
||||
{
|
||||
const filter = function(e) {
|
||||
var cmpUnitAI = Engine.QueryInterface(e, IID_UnitAI);
|
||||
return (cmpUnitAI && (!cmpUnitAI.IsAnimal() || cmpUnitAI.IsDangerousAnimal()));
|
||||
};
|
||||
|
||||
if (msg.added.length)
|
||||
msg.added = msg.added.filter(filter);
|
||||
|
||||
// Removed entities may not have cmpUnitAI.
|
||||
for (var i = 0; i < msg.removed.length; ++i)
|
||||
if (this.targetUnits.indexOf(msg.removed[i]) == -1)
|
||||
msg.removed.splice(i--, 1);
|
||||
msg.added = msg.added.filter(e => {
|
||||
let cmpUnitAI = Engine.QueryInterface(e, IID_UnitAI);
|
||||
return cmpUnitAI && (!cmpUnitAI.IsAnimal() || cmpUnitAI.IsDangerousAnimal());
|
||||
});
|
||||
}
|
||||
else if (msg.tag != this.enemyUnitsQuery)
|
||||
return;
|
||||
|
||||
if (msg.added.length > 0)
|
||||
// Add new targets
|
||||
for (let entity of msg.added)
|
||||
if (cmpAttack.CanAttack(entity))
|
||||
this.targetUnits.push(entity);
|
||||
|
||||
// Remove targets outside of vision-range
|
||||
for (let entity of msg.removed)
|
||||
{
|
||||
for each (var entity in msg.added)
|
||||
{
|
||||
if (cmpAttack.CanAttack(entity))
|
||||
this.targetUnits.push(entity);
|
||||
}
|
||||
}
|
||||
if (msg.removed.length > 0)
|
||||
{
|
||||
for each (var entity in msg.removed)
|
||||
{
|
||||
var index = this.targetUnits.indexOf(entity);
|
||||
if (index > -1)
|
||||
this.targetUnits.splice(index, 1);
|
||||
}
|
||||
let index = this.targetUnits.indexOf(entity);
|
||||
if (index > -1)
|
||||
this.targetUnits.splice(index, 1);
|
||||
}
|
||||
|
||||
if (this.targetUnits.length)
|
||||
@@ -205,7 +187,9 @@ BuildingAI.prototype.StartTimer = function()
|
||||
|
||||
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
||||
var attackTimers = cmpAttack.GetTimers(attackType);
|
||||
this.timer = cmpTimer.SetInterval(this.entity, IID_BuildingAI, "FireArrows", attackTimers.prepare, attackTimers.repeat / roundCount, null);
|
||||
|
||||
this.timer = cmpTimer.SetInterval(this.entity, IID_BuildingAI, "FireArrows",
|
||||
attackTimers.prepare, attackTimers.repeat / roundCount, null);
|
||||
};
|
||||
|
||||
BuildingAI.prototype.GetDefaultArrowCount = function()
|
||||
@@ -235,12 +219,12 @@ BuildingAI.prototype.GetGarrisonArrowClasses = function()
|
||||
*/
|
||||
BuildingAI.prototype.GetArrowCount = function()
|
||||
{
|
||||
var count = this.GetDefaultArrowCount();
|
||||
var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder);
|
||||
let count = this.GetDefaultArrowCount();
|
||||
|
||||
let cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder);
|
||||
if (cmpGarrisonHolder)
|
||||
{
|
||||
count += Math.round(cmpGarrisonHolder.GetGarrisonedArcherCount(this.GetGarrisonArrowClasses()) * this.GetGarrisonArrowMultiplier());
|
||||
}
|
||||
|
||||
return count;
|
||||
};
|
||||
|
||||
@@ -252,7 +236,8 @@ BuildingAI.prototype.SetUnitAITarget = function(ent)
|
||||
};
|
||||
|
||||
/**
|
||||
* Fires arrows. Called 'roundCount' times every 'RepeatTime' seconds when there are units in the range
|
||||
* Fire arrows with random temporal distribution on prefered targets.
|
||||
* Called 'roundCount' times every 'RepeatTime' seconds when there are units in the range.
|
||||
*/
|
||||
BuildingAI.prototype.FireArrows = function()
|
||||
{
|
||||
@@ -261,91 +246,76 @@ BuildingAI.prototype.FireArrows = function()
|
||||
if (!this.timer)
|
||||
return;
|
||||
|
||||
// stop the timer
|
||||
var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
||||
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
||||
cmpTimer.CancelTimer(this.timer);
|
||||
this.timer = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||
let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack);
|
||||
if (!cmpAttack)
|
||||
return;
|
||||
|
||||
var arrowsToFire = 0;
|
||||
if (this.currentRound > (roundCount - 1))
|
||||
{
|
||||
//Reached end of rounds. Reset count
|
||||
if (this.currentRound > roundCount - 1)
|
||||
this.currentRound = 0;
|
||||
}
|
||||
|
||||
if (this.currentRound == 0)
|
||||
{
|
||||
//First round. Calculate arrows to fire
|
||||
this.arrowsLeft = this.GetArrowCount();
|
||||
}
|
||||
|
||||
if (this.currentRound == (roundCount - 1))
|
||||
{
|
||||
//Last round. Need to fire all left-over arrows
|
||||
let arrowsToFire = 0;
|
||||
if (this.currentRound == roundCount - 1)
|
||||
arrowsToFire = this.arrowsLeft;
|
||||
}
|
||||
else
|
||||
{
|
||||
//Fire N arrows, 0 <= N <= Number of arrows left
|
||||
arrowsToFire = Math.min(
|
||||
Math.round(2*Math.random() * this.GetArrowCount()/roundCount),
|
||||
Math.round(2 * Math.random() * this.GetArrowCount() / roundCount),
|
||||
this.arrowsLeft
|
||||
);
|
||||
}
|
||||
|
||||
if (arrowsToFire <= 0)
|
||||
{
|
||||
this.currentRound++;
|
||||
++this.currentRound;
|
||||
return;
|
||||
}
|
||||
|
||||
// add targets to a weighted list, to allow preferences
|
||||
var targets = new WeightedList();
|
||||
var maxPreferenceBonus = this.MAX_PREFERENCE_BONUS;
|
||||
var addTarget = function(target)
|
||||
// Add targets to a weighted list, to allow preferences
|
||||
let targets = new WeightedList();
|
||||
let addTarget = function(target)
|
||||
{
|
||||
var preference = cmpAttack.GetPreference(target);
|
||||
var weight = 1;
|
||||
if (preference !== null && preference !== undefined)
|
||||
{
|
||||
// Lower preference scores indicate a higher preference so they
|
||||
// should result in a higher weight.
|
||||
weight = 1 + maxPreferenceBonus / (1 + preference);
|
||||
}
|
||||
targets.push(target, weight);
|
||||
let preference = cmpAttack.GetPreference(target);
|
||||
let weight = 1;
|
||||
|
||||
if (preference !== null && preference !== undefined)
|
||||
weight += this.MAX_PREFERENCE_BONUS / (1 + preference);
|
||||
|
||||
targets.push(target, weight);
|
||||
};
|
||||
// add the unit ai 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)
|
||||
addTarget(this.unitAITarget);
|
||||
for (let target of this.targetUnits)
|
||||
addTarget(target);
|
||||
|
||||
for (var i = 0;i < arrowsToFire;i++)
|
||||
for (let i = 0; i < arrowsToFire; ++i)
|
||||
{
|
||||
var selectedIndex = targets.randomIndex();
|
||||
var selectedTarget = targets.itemAt(selectedIndex);
|
||||
let selectedIndex = targets.randomIndex();
|
||||
let selectedTarget = targets.itemAt(selectedIndex);
|
||||
|
||||
if (selectedTarget && this.CheckTargetVisible(selectedTarget))
|
||||
{
|
||||
cmpAttack.PerformAttack(attackType, selectedTarget);
|
||||
PlaySound("attack", this.entity);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
||||
// Could not attack target, retry
|
||||
targets.removeAt(selectedIndex);
|
||||
--i;
|
||||
|
||||
if (!targets.length())
|
||||
{
|
||||
targets.removeAt(selectedIndex);
|
||||
i--; // one extra arrow left to fire
|
||||
if(targets.length() < 1)
|
||||
{
|
||||
this.arrowsLeft += arrowsToFire;
|
||||
// no targets found in this round, save arrows and go to next round
|
||||
break;
|
||||
}
|
||||
this.arrowsLeft += arrowsToFire;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,8 +337,8 @@ BuildingAI.prototype.CheckTargetVisible = function(target)
|
||||
if (cmpFogging && cmpFogging.IsMiraged(cmpOwnership.GetOwner()))
|
||||
return true;
|
||||
|
||||
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
// Either visible directly, or visible in fog
|
||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
return cmpRangeManager.GetLosVisibility(target, cmpOwnership.GetOwner()) != "hidden";
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user