forked from mirrors/0ad
Fix mirages (and any other entity that blocks something but not BlockConstruction) blocking foundation construction following 29492badb7 / D21.
Clean the code by removing the animal hardcoding in the Foundation component and adding a flag DeleteUponConstruction to the Obstruction component. Have locked gates and upgraded entities equally delete entities when transforming. Add a workaround for trees inside walls on random maps. Reviewed by: temple Differential Revision: https://code.wildfiregames.com/D1415 Refs #4268 This was SVN commit r21624.
This commit is contained in:
@@ -122,6 +122,9 @@ function placeStartingWalls(position, playerID, wallType, orientation = BUILDING
|
||||
if (civ != "iber" || g_Map.getSize() <= 128)
|
||||
return;
|
||||
|
||||
// TODO: should prevent trees inside walls
|
||||
// When fixing, remove the DeleteUponConstruction flag from template_gaia_flora.xml
|
||||
|
||||
if (wallType == "towers")
|
||||
placePolygonalWall(position, 15, ["entry"], "tower", civ, playerID, orientation, 7);
|
||||
else if (wallType)
|
||||
|
||||
@@ -191,31 +191,22 @@ Foundation.prototype.Build = function(builderEnt, work)
|
||||
if (this.GetBuildProgress() == 1.0)
|
||||
return;
|
||||
|
||||
// If there's any units in the way, ask them to move away
|
||||
// and return early from this method.
|
||||
var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
|
||||
// If there are any units in the way, ask them to move away and return early from this method.
|
||||
if (cmpObstruction && cmpObstruction.GetBlockMovementFlag())
|
||||
{
|
||||
// Remove all obstructions at the new entity, especially animal corpses
|
||||
let collisions = cmpObstruction.GetEntityCollisions();
|
||||
// Remove animal corpses
|
||||
for (let ent of cmpObstruction.GetEntitiesDeletedUponConstruction())
|
||||
Engine.DestroyEntity(ent);
|
||||
|
||||
let collisions = cmpObstruction.GetEntitiesBlockingConstruction();
|
||||
if (collisions.length)
|
||||
{
|
||||
var cmpFoundationOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
|
||||
for (var ent of collisions)
|
||||
{
|
||||
var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI);
|
||||
if (cmpUnitAI)
|
||||
cmpUnitAI.LeaveFoundation(this.entity);
|
||||
else
|
||||
{
|
||||
// If obstructing fauna is gaia or our own but doesn't have UnitAI, just destroy it
|
||||
var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
|
||||
var cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
|
||||
if (cmpOwnership && cmpIdentity && cmpIdentity.HasClass("Animal")
|
||||
&& (cmpOwnership.GetOwner() == 0 || cmpFoundationOwnership && cmpOwnership.GetOwner() == cmpFoundationOwnership.GetOwner()))
|
||||
Engine.DestroyEntity(ent);
|
||||
}
|
||||
|
||||
// TODO: What if an obstruction has no UnitAI?
|
||||
}
|
||||
|
||||
@@ -140,14 +140,19 @@ Gate.prototype.IsLocked = function()
|
||||
Gate.prototype.LockGate = function()
|
||||
{
|
||||
this.locked = true;
|
||||
|
||||
// Delete animal corpses to prevent units trying to gather the unreachable entity
|
||||
let cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
|
||||
if (cmpObstruction && cmpObstruction.GetBlockMovementFlag())
|
||||
for (let ent of cmpObstruction.GetEntitiesDeletedUponConstruction())
|
||||
Engine.DestroyEntity(ent);
|
||||
|
||||
// If the door is closed, enable 'block pathfinding'
|
||||
// Else 'block pathfinding' will be enabled the next time the gate close
|
||||
if (!this.opened)
|
||||
{
|
||||
var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
|
||||
if (!cmpObstruction)
|
||||
return;
|
||||
cmpObstruction.SetDisableBlockMovementPathfinding(false, false, 0);
|
||||
if (cmpObstruction)
|
||||
cmpObstruction.SetDisableBlockMovementPathfinding(false, false, 0);
|
||||
}
|
||||
else
|
||||
this.OperateGate();
|
||||
@@ -215,7 +220,7 @@ Gate.prototype.CloseGate = function()
|
||||
return;
|
||||
|
||||
// The gate can't be closed if there are entities colliding with it.
|
||||
var collisions = cmpObstruction.GetUnitCollisions();
|
||||
var collisions = cmpObstruction.GetEntitiesBlockingConstruction();
|
||||
if (collisions.length)
|
||||
{
|
||||
if (!this.timer)
|
||||
|
||||
@@ -62,7 +62,8 @@ function testFoundation(...mocks)
|
||||
|
||||
AddMock(foundationEnt, IID_Obstruction, {
|
||||
"GetBlockMovementFlag": () => true,
|
||||
"GetEntityCollisions": () => [],
|
||||
"GetEntitiesBlockingConstruction": () => [],
|
||||
"GetEntitiesDeletedUponConstruction": () => [],
|
||||
"SetDisableBlockMovementPathfinding": () => {},
|
||||
});
|
||||
|
||||
|
||||
@@ -190,7 +190,11 @@ function ObstructionsBlockingTemplateChange(ent, templateArg)
|
||||
var cmpNewObstruction = Engine.QueryInterface(previewEntity, IID_Obstruction);
|
||||
if (cmpNewObstruction && cmpNewObstruction.GetBlockMovementFlag())
|
||||
{
|
||||
let collisions = cmpNewObstruction.GetEntityCollisions();
|
||||
// Remove all obstructions at the new entity, especially animal corpses
|
||||
for (let ent of cmpNewObstruction.GetEntitiesDeletedUponConstruction())
|
||||
Engine.DestroyEntity(ent);
|
||||
|
||||
let collisions = cmpNewObstruction.GetEntitiesBlockingConstruction();
|
||||
if (collisions.length)
|
||||
return DeleteEntityAndReturn(previewEntity, cmpPosition, pos, angle, cmpNewPosition, true);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<BlockPathfinding>false</BlockPathfinding>
|
||||
<BlockFoundation>false</BlockFoundation>
|
||||
<BlockConstruction>false</BlockConstruction>
|
||||
<DeleteUponConstruction>false</DeleteUponConstruction>
|
||||
</Obstruction>
|
||||
<OverlayRenderer merge=""/>
|
||||
<Ownership merge=""/>
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
(but can still be used for testing this entity for collisions against others) -->
|
||||
<Obstruction merge="">
|
||||
<Active>false</Active>
|
||||
<DeleteUponConstruction>false</DeleteUponConstruction>
|
||||
</Obstruction>
|
||||
<Ownership merge=""/>
|
||||
<Position merge=""/>
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
<BlockMovement>false</BlockMovement>
|
||||
<BlockPathfinding>false</BlockPathfinding>
|
||||
<BlockFoundation>false</BlockFoundation>
|
||||
<BlockConstruction>false</BlockConstruction>
|
||||
<BlockConstruction>true</BlockConstruction>
|
||||
<DeleteUponConstruction>true</DeleteUponConstruction>
|
||||
<DisableBlockMovement>false</DisableBlockMovement>
|
||||
<DisableBlockPathfinding>false</DisableBlockPathfinding>
|
||||
<Static width="2.0" depth="2.0"/>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<BlockConstruction>true</BlockConstruction>
|
||||
<DisableBlockMovement>false</DisableBlockMovement>
|
||||
<DisableBlockPathfinding>false</DisableBlockPathfinding>
|
||||
<DeleteUponConstruction>false</DeleteUponConstruction>
|
||||
</Obstruction>
|
||||
<OverlayRenderer/>
|
||||
<StatusBars>
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
</Minimap>
|
||||
<Obstruction>
|
||||
<Static width="1.6" depth="1.6"/>
|
||||
<!-- Trees are deleted as a workaround for gates until random maps are smart enough to not place trees inside walls -->
|
||||
<DeleteUponConstruction>true</DeleteUponConstruction>
|
||||
</Obstruction>
|
||||
<ResourceSupply>
|
||||
<KillBeforeGather>false</KillBeforeGather>
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
<BlockConstruction>true</BlockConstruction>
|
||||
<DisableBlockMovement>false</DisableBlockMovement>
|
||||
<DisableBlockPathfinding>false</DisableBlockPathfinding>
|
||||
<DeleteUponConstruction>false</DeleteUponConstruction>
|
||||
</Obstruction>
|
||||
<OverlayRenderer/>
|
||||
<ProductionQueue>
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
<BlockConstruction>true</BlockConstruction>
|
||||
<DisableBlockMovement>false</DisableBlockMovement>
|
||||
<DisableBlockPathfinding>false</DisableBlockPathfinding>
|
||||
<DeleteUponConstruction>false</DeleteUponConstruction>
|
||||
</Obstruction>
|
||||
<OverlayRenderer/>
|
||||
<RangeOverlayManager/>
|
||||
|
||||
@@ -168,6 +168,9 @@ public:
|
||||
"<element name='BlockConstruction' a:help='Whether players should be unable to begin constructing buildings placed on top of this entity'>"
|
||||
"<data type='boolean'/>"
|
||||
"</element>"
|
||||
"<element name='DeleteUponConstruction' a:help='Whether this entity should be deleted when construction on a buildings placed on top of this entity is started.'>"
|
||||
"<data type='boolean'/>"
|
||||
"</element>"
|
||||
"<element name='DisableBlockMovement' a:help='If true, BlockMovement will be overridden and treated as false. (This is a special case to handle foundations)'>"
|
||||
"<data type='boolean'/>"
|
||||
"</element>"
|
||||
@@ -195,6 +198,8 @@ public:
|
||||
m_TemplateFlags |= ICmpObstructionManager::FLAG_BLOCK_FOUNDATION;
|
||||
if (paramNode.GetChild("BlockConstruction").ToBool())
|
||||
m_TemplateFlags |= ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION;
|
||||
if (paramNode.GetChild("DeleteUponConstruction").ToBool())
|
||||
m_TemplateFlags |= ICmpObstructionManager::FLAG_DELETE_UPON_CONSTRUCTION;
|
||||
|
||||
m_Flags = m_TemplateFlags;
|
||||
if (paramNode.GetChild("DisableBlockMovement").ToBool())
|
||||
@@ -615,7 +620,7 @@ public:
|
||||
return !cmpObstructionManager->TestStaticShape(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, NULL );
|
||||
}
|
||||
|
||||
virtual std::vector<entity_id_t> GetUnitCollisions() const
|
||||
virtual std::vector<entity_id_t> GetEntitiesByFlags(flags_t flags) const
|
||||
{
|
||||
std::vector<entity_id_t> ret;
|
||||
|
||||
@@ -623,36 +628,11 @@ public:
|
||||
if (!cmpObstructionManager)
|
||||
return ret; // error
|
||||
|
||||
// There are four 'block' flags: construction, foundation, movement,
|
||||
// and pathfinding. Structures have all of these flags, while most units
|
||||
// block only movement and construction.
|
||||
flags_t flags = ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION;
|
||||
|
||||
// Ignore collisions within the same control group, or with other shapes that don't match the filter.
|
||||
// Note that, since the control group for each entity defaults to the entity's ID, this is typically
|
||||
// equivalent to only ignoring the entity's own shape and other shapes that don't match the filter.
|
||||
SkipControlGroupsRequireFlagObstructionFilter filter(false, m_ControlGroup, m_ControlGroup2, flags);
|
||||
|
||||
ICmpObstructionManager::ObstructionSquare square;
|
||||
if (!GetObstructionSquare(square))
|
||||
return ret; // error
|
||||
|
||||
cmpObstructionManager->GetUnitsOnObstruction(square, ret, filter);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual std::vector<entity_id_t> GetEntityCollisions() const
|
||||
{
|
||||
std::vector<entity_id_t> ret;
|
||||
|
||||
CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSystemEntity());
|
||||
if (!cmpObstructionManager)
|
||||
return ret; // error
|
||||
|
||||
// Ignore collisions within the same control group.
|
||||
SkipControlGroupsRequireFlagObstructionFilter filter(true, m_ControlGroup, m_ControlGroup2, 0);
|
||||
|
||||
ICmpObstructionManager::ObstructionSquare square;
|
||||
if (!GetObstructionSquare(square))
|
||||
return ret; // error
|
||||
@@ -663,6 +643,16 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
virtual std::vector<entity_id_t> GetEntitiesBlockingConstruction() const
|
||||
{
|
||||
return GetEntitiesByFlags(ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION);
|
||||
}
|
||||
|
||||
virtual std::vector<entity_id_t> GetEntitiesDeletedUponConstruction() const
|
||||
{
|
||||
return GetEntitiesByFlags(ICmpObstructionManager::FLAG_DELETE_UPON_CONSTRUCTION);
|
||||
}
|
||||
|
||||
virtual void SetMovingFlag(bool enabled)
|
||||
{
|
||||
m_Moving = enabled;
|
||||
|
||||
@@ -50,8 +50,8 @@ DEFINE_INTERFACE_METHOD_CONST_0("GetUnitRadius", entity_pos_t, ICmpObstruction,
|
||||
DEFINE_INTERFACE_METHOD_CONST_0("CheckShorePlacement", bool, ICmpObstruction, CheckShorePlacement)
|
||||
DEFINE_INTERFACE_METHOD_CONST_2("CheckFoundation", std::string, ICmpObstruction, CheckFoundation_wrapper, std::string, bool)
|
||||
DEFINE_INTERFACE_METHOD_CONST_0("CheckDuplicateFoundation", bool, ICmpObstruction, CheckDuplicateFoundation)
|
||||
DEFINE_INTERFACE_METHOD_CONST_0("GetUnitCollisions", std::vector<entity_id_t>, ICmpObstruction, GetUnitCollisions)
|
||||
DEFINE_INTERFACE_METHOD_CONST_0("GetEntityCollisions", std::vector<entity_id_t>, ICmpObstruction, GetEntityCollisions)
|
||||
DEFINE_INTERFACE_METHOD_CONST_0("GetEntitiesBlockingConstruction", std::vector<entity_id_t>, ICmpObstruction, GetEntitiesBlockingConstruction)
|
||||
DEFINE_INTERFACE_METHOD_CONST_0("GetEntitiesDeletedUponConstruction", std::vector<entity_id_t>, ICmpObstruction, GetEntitiesDeletedUponConstruction)
|
||||
DEFINE_INTERFACE_METHOD_1("SetActive", void, ICmpObstruction, SetActive, bool)
|
||||
DEFINE_INTERFACE_METHOD_3("SetDisableBlockMovementPathfinding", void, ICmpObstruction, SetDisableBlockMovementPathfinding, bool, bool, int32_t)
|
||||
DEFINE_INTERFACE_METHOD_CONST_0("GetBlockMovementFlag", bool, ICmpObstruction, GetBlockMovementFlag)
|
||||
|
||||
@@ -89,17 +89,22 @@ public:
|
||||
virtual bool CheckDuplicateFoundation() const = 0;
|
||||
|
||||
/**
|
||||
* Returns a list of units that are colliding with this entity.
|
||||
* @return vector of blocking units
|
||||
* Returns a list of entities that have an obstruction matching the given flag and intersect the current obstruction.
|
||||
* @return vector of blocking entities
|
||||
*/
|
||||
virtual std::vector<entity_id_t> GetUnitCollisions() const = 0;
|
||||
virtual std::vector<entity_id_t> GetEntitiesByFlags(ICmpObstructionManager::flags_t flags) const = 0;
|
||||
|
||||
/**
|
||||
* Returns a list of entities that are colliding with this entity (excluding self).
|
||||
* This can be used to retrieve units with static obstructions, such as animal corpses.
|
||||
* @return vector of blocking units
|
||||
* Returns a list of entities that are blocking construction of a foundation.
|
||||
* @return vector of blocking entities
|
||||
*/
|
||||
virtual std::vector<entity_id_t> GetEntityCollisions() const = 0;
|
||||
virtual std::vector<entity_id_t> GetEntitiesBlockingConstruction() const = 0;
|
||||
|
||||
/**
|
||||
* Returns a list of entities that shall be deleted when a construction on this obstruction starts,
|
||||
* for example sheep carcasses.
|
||||
*/
|
||||
virtual std::vector<entity_id_t> GetEntitiesDeletedUponConstruction() const = 0;
|
||||
|
||||
/**
|
||||
* Detects collisions between foundation-blocking entities and
|
||||
|
||||
@@ -71,11 +71,12 @@ public:
|
||||
*/
|
||||
enum EFlags
|
||||
{
|
||||
FLAG_BLOCK_MOVEMENT = (1 << 0), // prevents units moving through this shape
|
||||
FLAG_BLOCK_FOUNDATION = (1 << 1), // prevents foundations being placed on this shape
|
||||
FLAG_BLOCK_CONSTRUCTION = (1 << 2), // prevents buildings being constructed on this shape
|
||||
FLAG_BLOCK_PATHFINDING = (1 << 3), // prevents the tile pathfinder choosing paths through this shape
|
||||
FLAG_MOVING = (1 << 4) // indicates this unit is currently moving
|
||||
FLAG_BLOCK_MOVEMENT = (1 << 0), // prevents units moving through this shape
|
||||
FLAG_BLOCK_FOUNDATION = (1 << 1), // prevents foundations being placed on this shape
|
||||
FLAG_BLOCK_CONSTRUCTION = (1 << 2), // prevents buildings being constructed on this shape
|
||||
FLAG_BLOCK_PATHFINDING = (1 << 3), // prevents the tile pathfinder choosing paths through this shape
|
||||
FLAG_MOVING = (1 << 4), // indicates this unit is currently moving
|
||||
FLAG_DELETE_UPON_CONSTRUCTION = (1 << 5) // this entity is deleted when construction of a building placed on top of this entity starts
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user