1
0
forked from 0ad/0ad

Fix arrow count not being properly calculated when autogarrisoning.

423b3cbcaa Moved the message sent that an entity garrisons from
`PerformGarrison` to `Garrison`. However, when an entity is
autogarrisoned from `ProductionQueue` `PerformGarrison` is called thus
not triggering the message. When ejecting the entity from the structure
there is a message sent that the entity is removed, thus allowing for a
negative amount of archers/arrows in `BuildingAI` (see
423b3cbcaa#42654).

Note that `PerformGarrison` was explicitly split in 2102648f7c when
introducing autogarrisoning. It probably has something to do with the
position, since that was split. But I couldn't find any reason why it
cannot be used now.

A side effect of this is that when autogarrisoning an entity with
visible garrison points those will be occupied as well now.

Reviewed By: wraitii
Differential Revision: https://code.wildfiregames.com/D2790
This was SVN commit r23743.
This commit is contained in:
wraitii 2020-06-06 10:19:42 +00:00
parent 4588ee3bbc
commit 759bc754c3
3 changed files with 34 additions and 48 deletions

View File

@ -173,20 +173,27 @@ GarrisonHolder.prototype.GetGarrisonedEntitiesCount = function()
return count;
};
GarrisonHolder.prototype.IsAllowedToGarrison = function(ent)
GarrisonHolder.prototype.IsAllowedToGarrison = function(entity)
{
if (!this.IsGarrisoningAllowed())
return false;
if (!IsOwnedByMutualAllyOfEntity(ent, this.entity))
if (!IsOwnedByMutualAllyOfEntity(entity, this.entity))
return false;
let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
let extraCount = 0;
let cmpGarrisonHolder = Engine.QueryInterface(entity, IID_GarrisonHolder);
if (cmpGarrisonHolder)
extraCount += cmpGarrisonHolder.GetGarrisonedEntitiesCount();
if (this.GetGarrisonedEntitiesCount() + extraCount >= this.GetCapacity())
return false;
let cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
if (!cmpIdentity)
return false;
let entityClasses = cmpIdentity.GetClassesList();
return MatchesClassList(entityClasses, this.template.List._string) && !!Engine.QueryInterface(ent, IID_Garrisonable);
return MatchesClassList(entityClasses, this.template.List._string) && !!Engine.QueryInterface(entity, IID_Garrisonable);
};
/**
@ -214,12 +221,31 @@ GarrisonHolder.prototype.AllowedToVisibleGarrisoning = function(entity, visibleG
*/
GarrisonHolder.prototype.Garrison = function(entity, vgpEntity)
{
if (!this.IsAllowedToGarrison(entity))
return false;
if (!this.HasEnoughHealth())
return false;
let cmpPosition = Engine.QueryInterface(entity, IID_Position);
if (!cmpPosition)
return false;
if (!this.PerformGarrison(entity))
return false;
if (!this.timer && this.GetHealRate() > 0)
{
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
this.timer = cmpTimer.SetTimeout(this.entity, IID_GarrisonHolder, "HealTimeout", 1000, {});
}
this.entities.push(entity);
this.UpdateGarrisonFlag();
let cmpProductionQueue = Engine.QueryInterface(entity, IID_ProductionQueue);
if (cmpProductionQueue)
cmpProductionQueue.PauseProduction();
let cmpAura = Engine.QueryInterface(entity, IID_Auras);
if (cmpAura && cmpAura.HasGarrisonAura())
cmpAura.ApplyGarrisonAura(this.entity);
let visibleGarrisonPoint;
if (vgpEntity && this.AllowedToVisibleGarrisoning(entity, vgpEntity))
@ -273,46 +299,6 @@ GarrisonHolder.prototype.Garrison = function(entity, vgpEntity)
return true;
};
/**
* @return {boolean} Whether the entity was garrisonned.
*/
GarrisonHolder.prototype.PerformGarrison = function(entity)
{
if (!this.HasEnoughHealth())
return false;
// Check if the unit is allowed to be garrisoned inside the building
if (!this.IsAllowedToGarrison(entity))
return false;
// Check the capacity
let extraCount = 0;
let cmpGarrisonHolder = Engine.QueryInterface(entity, IID_GarrisonHolder);
if (cmpGarrisonHolder)
extraCount += cmpGarrisonHolder.GetGarrisonedEntitiesCount();
if (this.GetGarrisonedEntitiesCount() + extraCount >= this.GetCapacity())
return false;
if (!this.timer && this.GetHealRate() > 0)
{
let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
this.timer = cmpTimer.SetTimeout(this.entity, IID_GarrisonHolder, "HealTimeout", 1000, {});
}
// Actual garrisoning happens here
this.entities.push(entity);
this.UpdateGarrisonFlag();
let cmpProductionQueue = Engine.QueryInterface(entity, IID_ProductionQueue);
if (cmpProductionQueue)
cmpProductionQueue.PauseProduction();
let cmpAura = Engine.QueryInterface(entity, IID_Auras);
if (cmpAura && cmpAura.HasGarrisonAura())
cmpAura.ApplyGarrisonAura(this.entity);
return true;
};
/**
* Simply eject the unit from the garrisoning entity without moving it
* @param {number} entity - Id of the entity to be ejected.

View File

@ -626,7 +626,7 @@ ProductionQueue.prototype.SpawnUnits = function(templateName, count, metadata)
{
// Temporary owner affectation needed for GarrisonHolder checks.
cmpNewOwnership.SetOwnerQuiet(cmpOwnership.GetOwner());
garrisoned = cmpAutoGarrison.PerformGarrison(ent);
garrisoned = cmpAutoGarrison.Garrison(ent);
cmpNewOwnership.SetOwnerQuiet(INVALID_PLAYER);
}

View File

@ -168,7 +168,7 @@ TS_ASSERT_EQUALS(cmpGarrisonHolder.IsFull(), false);
TS_ASSERT_EQUALS(cmpGarrisonHolder.IsAllowedToGarrison(enemyUnitId), false);
TS_ASSERT_EQUALS(cmpGarrisonHolder.IsAllowedToGarrison(unitToGarrisonId), true);
TS_ASSERT_EQUALS(cmpGarrisonHolder.HasEnoughHealth(), false);
TS_ASSERT_EQUALS(cmpGarrisonHolder.PerformGarrison(unitToGarrisonId), false);
TS_ASSERT_EQUALS(cmpGarrisonHolder.Garrison(unitToGarrisonId), false);
AddMock(garrisonHolderId, IID_Health, {
"GetHitpoints": () => 600,