0ad/binaries/data/mods/public/simulation/components/AlertRaiser.js
Dunedan 93ce94655d
Use @stylistic/brace-style for eslint
Up to now `eslint-plugin-brace-rules` was used to enforce a common brace
style for JavaScript code. This plugin was however updated the last time
over 9 years ago and will be incompatible with ESLint v10, as that
[removes `context.getSourceCode()`][1], the plugin relies on.

To keep the eslint config working with ESLint v10, this replaces
`eslint-plugin-brace-rules` with the [`@stylistic/brace-style`][2] rule
from `@stylistic/eslint-plugin`, a package we already use.

While `@stylistic/brace-style` doesn't offer an option to format braces
in exactly the same way as before, the "allman" style seems to be the
one closest to the existing code.

[1]: https://eslint.org/blog/2025/11/eslint-v10.0.0-alpha.0-released/#removed-deprecated-rule-context-members
[2]: https://eslint.style/rules/brace-style
2026-01-12 21:33:52 +01:00

153 lines
5.4 KiB
JavaScript

function AlertRaiser() {}
AlertRaiser.prototype.Schema =
"<element name='List' a:help='Classes of entities which are affected by this alert raiser'>" +
"<attribute name='datatype'>" +
"<value>tokens</value>" +
"</attribute>" +
"<text/>" +
"</element>" +
"<element name='RaiseAlertRange'><data type='integer'/></element>" +
"<element name='EndOfAlertRange'><data type='integer'/></element>" +
"<element name='SearchRange'><data type='integer'/></element>";
AlertRaiser.prototype.Init = function()
{
// Store the last time the alert was used so players can't lag the game by raising alerts repeatedly.
this.lastTime = 0;
};
AlertRaiser.prototype.GetTargetClasses = function()
{
return this.template.List._string;
};
AlertRaiser.prototype.UnitFilter = function(unit)
{
const cmpIdentity = Engine.QueryInterface(unit, IID_Identity);
return cmpIdentity && MatchesClassList(cmpIdentity.GetClassesList(), this.GetTargetClasses());
};
AlertRaiser.prototype.RaiseAlert = function()
{
const cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
if (cmpTimer.GetTime() == this.lastTime)
return;
this.lastTime = cmpTimer.GetTime();
PlaySound("alert_raise", this.entity);
const cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
if (!cmpOwnership || cmpOwnership.GetOwner() == INVALID_PLAYER)
return;
const owner = cmpOwnership.GetOwner();
const cmpDiplomacy = QueryPlayerIDInterface(owner, IID_Diplomacy);
const mutualAllies = cmpDiplomacy ? cmpDiplomacy.GetMutualAllies() : [owner];
const cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
// Store the number of available garrison spots so that units don't try to garrison in buildings that will be full
const reserved = new Map();
const units = cmpRangeManager.ExecuteQuery(this.entity, 0, +this.template.RaiseAlertRange, [owner], IID_UnitAI, true).filter(ent => this.UnitFilter(ent));
for (const unit of units)
{
const cmpGarrisonable = Engine.QueryInterface(unit, IID_Garrisonable);
if (!cmpGarrisonable)
continue;
const size = cmpGarrisonable.TotalSize();
const cmpUnitAI = Engine.QueryInterface(unit, IID_UnitAI);
const holder = cmpRangeManager.ExecuteQuery(unit, 0, +this.template.SearchRange, mutualAllies, IID_GarrisonHolder, true).find(ent =>
{
// Ignore moving garrison holders
if (Engine.QueryInterface(ent, IID_UnitAI))
return false;
// Ensure that the garrison holder is within range of the alert raiser
if (+this.template.EndOfAlertRange > 0 && PositionHelper.DistanceBetweenEntities(this.entity, ent) > +this.template.EndOfAlertRange)
return false;
if (!cmpUnitAI.CheckTargetVisible(ent))
return false;
const cmpGarrisonHolder = Engine.QueryInterface(ent, IID_GarrisonHolder);
if (!reserved.has(ent))
reserved.set(ent, cmpGarrisonHolder.GetCapacity() - cmpGarrisonHolder.OccupiedSlots());
return cmpGarrisonHolder.IsAllowedToGarrison(unit) && reserved.get(ent) >= size;
});
if (holder)
{
reserved.set(holder, reserved.get(holder) - size);
cmpUnitAI.Garrison(holder, false, false);
}
else
// If no available spots, stop moving
cmpUnitAI.ReplaceOrder("Stop", { "force": true });
}
};
AlertRaiser.prototype.EndOfAlert = function()
{
const cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
if (cmpTimer.GetTime() == this.lastTime)
return;
this.lastTime = cmpTimer.GetTime();
PlaySound("alert_end", this.entity);
const cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
if (!cmpOwnership || cmpOwnership.GetOwner() == INVALID_PLAYER)
return;
const owner = cmpOwnership.GetOwner();
const cmpDiplomacy = QueryPlayerIDInterface(owner, IID_Diplomacy);
const mutualAllies = cmpDiplomacy ? cmpDiplomacy.GetMutualAllies() : [owner];
const cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
// Units that are not garrisoned should go back to work
const units = cmpRangeManager.ExecuteQuery(this.entity, 0, +this.template.EndOfAlertRange, [owner], IID_UnitAI, true).filter(ent => this.UnitFilter(ent));
for (const unit of units)
{
const cmpUnitAI = Engine.QueryInterface(unit, IID_UnitAI);
if (cmpUnitAI.HasWorkOrders() && cmpUnitAI.ShouldRespondToEndOfAlert())
cmpUnitAI.BackToWork();
else if (cmpUnitAI.ShouldRespondToEndOfAlert())
// Stop rather than continue to try to garrison
cmpUnitAI.ReplaceOrder("Stop", { "force": true });
}
// Units that are garrisoned should ungarrison and go back to work
const holders = cmpRangeManager.ExecuteQuery(this.entity, 0, +this.template.EndOfAlertRange, mutualAllies, IID_GarrisonHolder, true);
if (Engine.QueryInterface(this.entity, IID_GarrisonHolder))
holders.push(this.entity);
for (const holder of holders)
{
if (Engine.QueryInterface(holder, IID_UnitAI))
continue;
const cmpGarrisonHolder = Engine.QueryInterface(holder, IID_GarrisonHolder);
const garrisonedUnits = cmpGarrisonHolder.GetEntities().filter(ent =>
{
const cmpOwner = Engine.QueryInterface(ent, IID_Ownership);
return cmpOwner && cmpOwner.GetOwner() == owner && this.UnitFilter(ent);
});
for (const unit of garrisonedUnits)
if (cmpGarrisonHolder.Unload(unit))
{
const cmpUnitAI = Engine.QueryInterface(unit, IID_UnitAI);
if (cmpUnitAI.HasWorkOrders())
cmpUnitAI.BackToWork();
else
// Stop rather than walk to the rally point
cmpUnitAI.ReplaceOrder("Stop", { "force": true });
}
}
};
Engine.RegisterComponentType(IID_AlertRaiser, "AlertRaiser", AlertRaiser);