mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-07-06 23:15:47 -07:00
Follow-up to e18001e897.
This moves responsibilities even further to the garrisoning entity.
Fixes the garrison flag when renaming entities cannot garrison (#5906).
Allows easy fixing of #6087.
Ticket: #6081
Differential revision: D3628
Comments by: @Stan, @wraitii (also in length on IRC)
This was SVN commit r25019.
141 lines
5.1 KiB
JavaScript
141 lines
5.1 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.UnitFilter = function(unit)
|
|
{
|
|
let cmpIdentity = Engine.QueryInterface(unit, IID_Identity);
|
|
return cmpIdentity && MatchesClassList(cmpIdentity.GetClassesList(), this.template.List._string);
|
|
};
|
|
|
|
AlertRaiser.prototype.RaiseAlert = function()
|
|
{
|
|
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
|
if (cmpTimer.GetTime() == this.lastTime)
|
|
return;
|
|
|
|
this.lastTime = cmpTimer.GetTime();
|
|
PlaySound("alert_raise", this.entity);
|
|
|
|
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
|
if (!cmpOwnership || cmpOwnership.GetOwner() == INVALID_PLAYER)
|
|
return;
|
|
|
|
let owner = cmpOwnership.GetOwner();
|
|
let cmpPlayer = QueryOwnerInterface(this.entity);
|
|
let mutualAllies = cmpPlayer ? cmpPlayer.GetMutualAllies() : [owner];
|
|
let 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
|
|
let reserved = new Map();
|
|
|
|
let units = cmpRangeManager.ExecuteQuery(this.entity, 0, +this.template.RaiseAlertRange, [owner], IID_UnitAI, true).filter(ent => this.UnitFilter(ent));
|
|
for (let unit of units)
|
|
{
|
|
let cmpUnitAI = Engine.QueryInterface(unit, IID_UnitAI);
|
|
|
|
let 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;
|
|
|
|
let cmpGarrisonHolder = Engine.QueryInterface(ent, IID_GarrisonHolder);
|
|
if (!reserved.has(ent))
|
|
reserved.set(ent, cmpGarrisonHolder.GetCapacity() - cmpGarrisonHolder.OccupiedSlots());
|
|
|
|
return cmpGarrisonHolder.IsAllowedToGarrison(unit) && reserved.get(ent);
|
|
});
|
|
|
|
if (holder)
|
|
{
|
|
reserved.set(holder, reserved.get(holder) - 1);
|
|
cmpUnitAI.ReplaceOrder("Garrison", { "target": holder, "force": true });
|
|
}
|
|
else
|
|
// If no available spots, stop moving
|
|
cmpUnitAI.ReplaceOrder("Stop", { "force": true });
|
|
}
|
|
};
|
|
|
|
AlertRaiser.prototype.EndOfAlert = function()
|
|
{
|
|
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
|
|
if (cmpTimer.GetTime() == this.lastTime)
|
|
return;
|
|
|
|
this.lastTime = cmpTimer.GetTime();
|
|
PlaySound("alert_end", this.entity);
|
|
|
|
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
|
if (!cmpOwnership || cmpOwnership.GetOwner() == INVALID_PLAYER)
|
|
return;
|
|
|
|
let owner = cmpOwnership.GetOwner();
|
|
let cmpPlayer = QueryOwnerInterface(this.entity);
|
|
let mutualAllies = cmpPlayer ? cmpPlayer.GetMutualAllies() : [owner];
|
|
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
|
|
|
// Units that are not garrisoned should go back to work
|
|
let units = cmpRangeManager.ExecuteQuery(this.entity, 0, +this.template.EndOfAlertRange, [owner], IID_UnitAI, true).filter(ent => this.UnitFilter(ent));
|
|
for (let unit of units)
|
|
{
|
|
let 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
|
|
let 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 (let holder of holders)
|
|
{
|
|
if (Engine.QueryInterface(holder, IID_UnitAI))
|
|
continue;
|
|
|
|
let cmpGarrisonHolder = Engine.QueryInterface(holder, IID_GarrisonHolder);
|
|
let units = cmpGarrisonHolder.GetEntities().filter(ent => {
|
|
let cmpOwner = Engine.QueryInterface(ent, IID_Ownership);
|
|
return cmpOwner && cmpOwner.GetOwner() == owner && this.UnitFilter(ent);
|
|
});
|
|
|
|
for (let unit of units)
|
|
if (cmpGarrisonHolder.Unload(unit))
|
|
{
|
|
let 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);
|