Fix UnitAI range queries - allow queries to ignore sizes - partial revert of d0fc8ff67d
Units sometimes ignored targets that entered their LoS. The cause isd0fc8ff67d
: range queries returned units farther away, and those units might actually be out of range if distance is computed center-to-center, which both UnitAI and LOS do. This meant that code relying on range query updates was possibly broken, and indeed units missed things (see ticket). This introduces a boolean to switch between pre-d0fc8ff67d behaviour (entity-as-point, center-to-center range queries) and post-d0fc8ff67d (entities-as-circumscribing-circle, edge-to-edge range queries). The former is used for UnitAI (where the new behaviour bugged), auras (where varying structure sizes made it awkward) and build restrictions(which simply did not really need it). Reverts7f1ee23d88
,050c5401b1
(with the exception of the iber monument footprint), and the template changes ind0fc8ff67d
itself. It also reduces alertRaiser ranges slightly, this was missed in the original diff. #3381 is not reopened as BuildingAI still uses the new range queries. Reported by: Freagarach Comments By: Angen Fixes #5968 Differential Revision: https://code.wildfiregames.com/D3456 This was SVN commit r24776.
This commit is contained in:
parent
4cc824d620
commit
93a352ad16
@ -90,9 +90,10 @@ PETRA.createObstructionMap = function(gameState, accessIndex, template)
|
||||
{
|
||||
let obstructionRadius = template.obstructionRadius();
|
||||
if (obstructionRadius)
|
||||
minDist += obstructionRadius.max;
|
||||
minDist -= obstructionRadius.min;
|
||||
let fromClass = distance.FromClass;
|
||||
let cellSize = passabilityMap.cellSize;
|
||||
let cellDist = 1 + minDist / cellSize;
|
||||
let structures = gameState.getOwnStructures().filter(API3.Filters.byClass(fromClass));
|
||||
for (let ent of structures.values())
|
||||
{
|
||||
@ -101,9 +102,7 @@ PETRA.createObstructionMap = function(gameState, accessIndex, template)
|
||||
let pos = ent.position();
|
||||
let x = Math.round(pos[0] / cellSize);
|
||||
let z = Math.round(pos[1] / cellSize);
|
||||
let entRadius = ent.obstructionRadius();
|
||||
let dist = 1 + (minDist + (entRadius ? entRadius.max : 0)) / cellSize;
|
||||
map.addInfluence(x, z, dist, -255, "constant");
|
||||
map.addInfluence(x, z, cellDist, -255, "constant");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,12 +44,12 @@ AlertRaiser.prototype.RaiseAlert = function()
|
||||
// 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).filter(ent => this.UnitFilter(ent));
|
||||
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).find(ent => {
|
||||
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;
|
||||
@ -98,7 +98,7 @@ AlertRaiser.prototype.EndOfAlert = function()
|
||||
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).filter(ent => this.UnitFilter(ent));
|
||||
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);
|
||||
@ -110,7 +110,7 @@ AlertRaiser.prototype.EndOfAlert = function()
|
||||
}
|
||||
|
||||
// Units that are garrisoned should ungarrison and go back to work
|
||||
let holders = cmpRangeManager.ExecuteQuery(this.entity, 0, +this.template.EndOfAlertRange, mutualAllies, IID_GarrisonHolder);
|
||||
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);
|
||||
|
||||
|
@ -267,13 +267,17 @@ Auras.prototype.Clean = function()
|
||||
|
||||
if (this[name].isApplied && (this.IsRangeAura(name) || this.IsGlobalAura(name) && !!this.GetOverlayIcon(name)))
|
||||
{
|
||||
// Do not account for entity sizes: structures can have various sizes
|
||||
// and we currently prefer auras to not depend on the source size
|
||||
// (this is generally irrelevant for units).
|
||||
this[name].rangeQuery = cmpRangeManager.CreateActiveQuery(
|
||||
this.entity,
|
||||
0,
|
||||
this.GetRange(name),
|
||||
affectedPlayers,
|
||||
IID_Identity,
|
||||
cmpRangeManager.GetEntityFlagMask("normal")
|
||||
cmpRangeManager.GetEntityFlagMask("normal"),
|
||||
false
|
||||
);
|
||||
cmpRangeManager.EnableActiveQuery(this[name].rangeQuery);
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ BuildRestrictions.prototype.CheckPlacement = function()
|
||||
if (this.template.Distance.MinDistance !== undefined)
|
||||
{
|
||||
let minDistance = ApplyValueModificationsToTemplate("BuildRestrictions/Distance/MinDistance", +this.template.Distance.MinDistance, cmpPlayer.GetPlayerID(), template);
|
||||
if (cmpRangeManager.ExecuteQuery(this.entity, 0, minDistance, [cmpPlayer.GetPlayerID()], IID_BuildRestrictions).some(filter))
|
||||
if (cmpRangeManager.ExecuteQuery(this.entity, 0, minDistance, [cmpPlayer.GetPlayerID()], IID_BuildRestrictions, false).some(filter))
|
||||
{
|
||||
let result = markForPluralTranslation(
|
||||
"%(name)s too close to a %(category)s, must be at least %(distance)s meter away",
|
||||
@ -277,7 +277,7 @@ BuildRestrictions.prototype.CheckPlacement = function()
|
||||
if (this.template.Distance.MaxDistance !== undefined)
|
||||
{
|
||||
let maxDistance = ApplyValueModificationsToTemplate("BuildRestrictions/Distance/MaxDistance", +this.template.Distance.MaxDistance, cmpPlayer.GetPlayerID(), template);
|
||||
if (!cmpRangeManager.ExecuteQuery(this.entity, 0, maxDistance, [cmpPlayer.GetPlayerID()], IID_BuildRestrictions).some(filter))
|
||||
if (!cmpRangeManager.ExecuteQuery(this.entity, 0, maxDistance, [cmpPlayer.GetPlayerID()], IID_BuildRestrictions, false).some(filter))
|
||||
{
|
||||
let result = markForPluralTranslation(
|
||||
"%(name)s too far from a %(category)s, must be within %(distance)s meter",
|
||||
|
@ -139,6 +139,7 @@ BuildingAI.prototype.SetupRangeQuery = function()
|
||||
return;
|
||||
|
||||
var range = cmpAttack.GetRange(attackType);
|
||||
// This takes entity sizes into accounts, so no need to compensate for structure size.
|
||||
this.enemyUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(
|
||||
this.entity, range.min, range.max, range.elevationBonus,
|
||||
enemies, IID_Resistance, cmpRangeManager.GetEntityFlagMask("normal"));
|
||||
@ -168,6 +169,7 @@ BuildingAI.prototype.SetupGaiaRangeQuery = function()
|
||||
var range = cmpAttack.GetRange(attackType);
|
||||
|
||||
// This query is only interested in Gaia entities that can attack.
|
||||
// This takes entity sizes into accounts, so no need to compensate for structure size.
|
||||
this.gaiaUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(
|
||||
this.entity, range.min, range.max, range.elevationBonus,
|
||||
[0], IID_Attack, cmpRangeManager.GetEntityFlagMask("normal"));
|
||||
|
@ -78,7 +78,7 @@ Gate.prototype.SetupRangeQuery = function(owner)
|
||||
if (range > 0)
|
||||
{
|
||||
// Only find entities with IID_UnitAI interface
|
||||
this.unitsQuery = cmpRangeManager.CreateActiveQuery(this.entity, 0, range, players, IID_UnitAI, cmpRangeManager.GetEntityFlagMask("normal"));
|
||||
this.unitsQuery = cmpRangeManager.CreateActiveQuery(this.entity, 0, range, players, IID_UnitAI, cmpRangeManager.GetEntityFlagMask("normal"), true);
|
||||
cmpRangeManager.EnableActiveQuery(this.unitsQuery);
|
||||
}
|
||||
};
|
||||
|
@ -48,15 +48,12 @@ RangeOverlayManager.prototype.RegenerateRangeOverlays = function(forceUpdate)
|
||||
if (!this.enabled && !forceUpdate)
|
||||
return;
|
||||
|
||||
let cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
|
||||
let rangeBonus = cmpObstruction ? cmpObstruction.GetSize() : 0;
|
||||
|
||||
// Only render individual range types that have been enabled
|
||||
for (let rangeOverlayType of this.rangeVisualizations.keys())
|
||||
if (this.enabledRangeTypes[rangeOverlayType])
|
||||
for (let rangeOverlay of this.rangeVisualizations.get(rangeOverlayType))
|
||||
cmpRangeOverlayRenderer.AddRangeOverlay(
|
||||
rangeOverlay.radius + rangeBonus,
|
||||
rangeOverlay.radius,
|
||||
rangeOverlay.texture,
|
||||
rangeOverlay.textureMask,
|
||||
rangeOverlay.thickness);
|
||||
|
@ -45,7 +45,7 @@ TriggerPoint.prototype.RegisterRangeTrigger = function(action, data)
|
||||
var cid = data.requiredComponent || -1;
|
||||
|
||||
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
var tag = cmpRangeManager.CreateActiveQuery(this.entity, minRange, maxRange, players, cid, cmpRangeManager.GetEntityFlagMask("normal"));
|
||||
var tag = cmpRangeManager.CreateActiveQuery(this.entity, minRange, maxRange, players, cid, cmpRangeManager.GetEntityFlagMask("normal"), true);
|
||||
|
||||
this.currentCollections[tag] = [];
|
||||
this.actions[tag] = action;
|
||||
|
@ -3791,7 +3791,10 @@ UnitAI.prototype.SetupLOSRangeQuery = function(enable = true)
|
||||
return;
|
||||
|
||||
let range = this.GetQueryRange(IID_Vision);
|
||||
this.losRangeQuery = cmpRangeManager.CreateActiveQuery(this.entity, range.min, range.max, players, IID_Identity, cmpRangeManager.GetEntityFlagMask("normal"));
|
||||
// Do not compensate for entity sizes: LOS doesn't, and UnitAI relies on that.
|
||||
this.losRangeQuery = cmpRangeManager.CreateActiveQuery(this.entity,
|
||||
range.min, range.max, players, IID_Identity,
|
||||
cmpRangeManager.GetEntityFlagMask("normal"), false);
|
||||
|
||||
if (enable)
|
||||
cmpRangeManager.EnableActiveQuery(this.losRangeQuery);
|
||||
@ -3820,7 +3823,10 @@ UnitAI.prototype.SetupHealRangeQuery = function(enable = true)
|
||||
let players = cmpPlayer.GetAllies();
|
||||
let range = this.GetQueryRange(IID_Heal);
|
||||
|
||||
this.losHealRangeQuery = cmpRangeManager.CreateActiveQuery(this.entity, range.min, range.max, players, IID_Health, cmpRangeManager.GetEntityFlagMask("injured"));
|
||||
// Do not compensate for entity sizes: LOS doesn't, and UnitAI relies on that.
|
||||
this.losHealRangeQuery = cmpRangeManager.CreateActiveQuery(this.entity,
|
||||
range.min, range.max, players, IID_Health,
|
||||
cmpRangeManager.GetEntityFlagMask("injured"), false);
|
||||
|
||||
if (enable)
|
||||
cmpRangeManager.EnableActiveQuery(this.losHealRangeQuery);
|
||||
@ -3852,7 +3858,10 @@ UnitAI.prototype.SetupAttackRangeQuery = function(enable = true)
|
||||
return;
|
||||
|
||||
let range = this.GetQueryRange(IID_Attack);
|
||||
this.losAttackRangeQuery = cmpRangeManager.CreateActiveQuery(this.entity, range.min, range.max, players, IID_Resistance, cmpRangeManager.GetEntityFlagMask("normal"));
|
||||
// Do not compensate for entity sizes: LOS doesn't, and UnitAI relies on that.
|
||||
this.losAttackRangeQuery = cmpRangeManager.CreateActiveQuery(this.entity,
|
||||
range.min, range.max, players, IID_Resistance,
|
||||
cmpRangeManager.GetEntityFlagMask("normal"), false);
|
||||
|
||||
if (enable)
|
||||
cmpRangeManager.EnableActiveQuery(this.losAttackRangeQuery);
|
||||
@ -4437,7 +4446,8 @@ UnitAI.prototype.FindNearbyResource = function(position, filter)
|
||||
|
||||
let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager);
|
||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
let nearby = cmpRangeManager.ExecuteQueryAroundPos(position, 0, range, players, IID_ResourceSupply);
|
||||
// Don't account for entity size, we need to match LOS visibility.
|
||||
let nearby = cmpRangeManager.ExecuteQueryAroundPos(position, 0, range, players, IID_ResourceSupply, false);
|
||||
return nearby.find(ent => {
|
||||
if (!this.CanGather(ent) || !this.CheckTargetVisible(ent))
|
||||
return false;
|
||||
@ -4476,7 +4486,7 @@ UnitAI.prototype.FindNearestDropsite = function(genericType)
|
||||
let owner = cmpOwnership.GetOwner();
|
||||
let cmpPlayer = QueryOwnerInterface(this.entity);
|
||||
let players = cmpPlayer && cmpPlayer.HasSharedDropsites() ? cmpPlayer.GetMutualAllies() : [owner];
|
||||
let nearestDropsites = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager).ExecuteQuery(this.entity, 0, -1, players, IID_ResourceDropsite);
|
||||
let nearestDropsites = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager).ExecuteQuery(this.entity, 0, -1, players, IID_ResourceDropsite, false);
|
||||
|
||||
let isShip = Engine.QueryInterface(this.entity, IID_Identity).HasClass("Ship");
|
||||
let cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager);
|
||||
@ -4526,7 +4536,8 @@ UnitAI.prototype.FindNearbyFoundation = function(position)
|
||||
|
||||
let range = 64; // TODO: what's a sensible number?
|
||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
let nearby = cmpRangeManager.ExecuteQueryAroundPos(position, 0, range, players, IID_Foundation);
|
||||
// Don't account for entity size, we need to match LOS visibility.
|
||||
let nearby = cmpRangeManager.ExecuteQueryAroundPos(position, 0, range, players, IID_Foundation, false);
|
||||
|
||||
// Skip foundations that are already complete. (This matters since
|
||||
// we process the ConstructionFinished message before the foundation
|
||||
@ -6556,7 +6567,7 @@ UnitAI.prototype.CallPlayerOwnedEntitiesFunctionInRange = function(funcname, arg
|
||||
if (owner == INVALID_PLAYER)
|
||||
return;
|
||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
let nearby = cmpRangeManager.ExecuteQuery(this.entity, 0, range, [owner], IID_UnitAI);
|
||||
let nearby = cmpRangeManager.ExecuteQuery(this.entity, 0, range, [owner], IID_UnitAI, true);
|
||||
for (let i = 0; i < nearby.length; ++i)
|
||||
{
|
||||
let cmpUnitAI = Engine.QueryInterface(nearby[i], IID_UnitAI);
|
||||
|
@ -122,7 +122,7 @@ function TestFormationExiting(mode)
|
||||
});
|
||||
|
||||
AddMock(SYSTEM_ENTITY, IID_RangeManager, {
|
||||
CreateActiveQuery: function(ent, minRange, maxRange, players, iid, flags) {
|
||||
CreateActiveQuery: function(ent, minRange, maxRange, players, iid, flags, accountForSize) {
|
||||
return 1;
|
||||
},
|
||||
EnableActiveQuery: function(id) { },
|
||||
@ -293,7 +293,7 @@ function TestMoveIntoFormationWhileAttacking()
|
||||
|
||||
|
||||
AddMock(SYSTEM_ENTITY, IID_RangeManager, {
|
||||
CreateActiveQuery: function(ent, minRange, maxRange, players, iid, flags) {
|
||||
CreateActiveQuery: function(ent, minRange, maxRange, players, iid, flags, accountForSize) {
|
||||
return 1;
|
||||
},
|
||||
EnableActiveQuery: function(id) { },
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"type": "range",
|
||||
"radius": 45,
|
||||
"radius": 50,
|
||||
"affects": ["Soldier"],
|
||||
"modifications": [
|
||||
{ "value": "Attack/Melee/Damage/Hack", "multiply": 1.2 },
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"type": "range",
|
||||
"radius": 50,
|
||||
"radius": 60,
|
||||
"affects": ["Worker"],
|
||||
"modifications": [
|
||||
{ "value": "ResourceGatherer/BaseSpeed", "multiply": 1.15 }
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"type": "range",
|
||||
"radius": 55,
|
||||
"radius": 70,
|
||||
"affects": ["Soldier"],
|
||||
"modifications": [
|
||||
{ "value": "Attack/Melee/Damage/Hack", "multiply": 1.1 },
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"type": "range",
|
||||
"radius": 60,
|
||||
"radius": 75,
|
||||
"affects": ["Structure"],
|
||||
"modifications": [
|
||||
{ "value": "Capturable/GarrisonRegenRate", "multiply": 1.5 }
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"type": "range",
|
||||
"radius": 70,
|
||||
"radius": 75,
|
||||
"affects": ["Trader"],
|
||||
"modifications": [
|
||||
{ "value": "UnitMotion/WalkSpeed", "multiply": 1.2 }
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"type": "range",
|
||||
"radius": 50,
|
||||
"radius": 60,
|
||||
"affects": ["Worker"],
|
||||
"modifications": [
|
||||
{ "value": "ResourceGatherer/Rates/food.grain", "multiply": 1.25 }
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"type": "range",
|
||||
"radius": 20,
|
||||
"radius": 40,
|
||||
"affects": ["Human"],
|
||||
"modifications": [
|
||||
{ "value": "Health/RegenRate", "add": 1 }
|
||||
|
@ -34,7 +34,7 @@ PositionHelper.prototype.EntitiesNearPoint = function(origin, radius, players, i
|
||||
return [];
|
||||
|
||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
|
||||
return cmpRangeManager.ExecuteQueryAroundPos(origin, 0, radius, players, iid);
|
||||
return cmpRangeManager.ExecuteQueryAroundPos(origin, 0, radius, players, iid, true);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -7,7 +7,7 @@
|
||||
<Category>Monument</Category>
|
||||
<Distance>
|
||||
<FromClass>Monument</FromClass>
|
||||
<MinDistance>145</MinDistance>
|
||||
<MinDistance>150</MinDistance>
|
||||
</Distance>
|
||||
</BuildRestrictions>
|
||||
<Capturable disable=""/>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<Category>Pillar</Category>
|
||||
<Distance>
|
||||
<FromClass>Pillar</FromClass>
|
||||
<MinDistance>70</MinDistance>
|
||||
<MinDistance>75</MinDistance>
|
||||
</Distance>
|
||||
</BuildRestrictions>
|
||||
<Capturable disable=""/>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<Territory>own neutral</Territory>
|
||||
<Distance>
|
||||
<FromClass>MercenaryCamp</FromClass>
|
||||
<MinDistance>70</MinDistance>
|
||||
<MinDistance>100</MinDistance>
|
||||
</Distance>
|
||||
</BuildRestrictions>
|
||||
<Cost>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<Territory>own neutral</Territory>
|
||||
<Distance>
|
||||
<FromClass>MercenaryCamp</FromClass>
|
||||
<MinDistance>70</MinDistance>
|
||||
<MinDistance>100</MinDistance>
|
||||
</Distance>
|
||||
</BuildRestrictions>
|
||||
<Cost>
|
||||
|
@ -38,7 +38,7 @@
|
||||
<Category>ArmyCamp</Category>
|
||||
<Distance>
|
||||
<FromClass>ArmyCamp</FromClass>
|
||||
<MinDistance>45</MinDistance>
|
||||
<MinDistance>80</MinDistance>
|
||||
</Distance>
|
||||
</BuildRestrictions>
|
||||
<Capturable>
|
||||
|
@ -2,8 +2,8 @@
|
||||
<Entity parent="template_structure_civic">
|
||||
<AlertRaiser>
|
||||
<List datatype="tokens">FemaleCitizen</List>
|
||||
<RaiseAlertRange>140</RaiseAlertRange>
|
||||
<EndOfAlertRange>190</EndOfAlertRange>
|
||||
<RaiseAlertRange>120</RaiseAlertRange>
|
||||
<EndOfAlertRange>180</EndOfAlertRange>
|
||||
<SearchRange>100</SearchRange>
|
||||
</AlertRaiser>
|
||||
<Attack>
|
||||
@ -44,7 +44,7 @@
|
||||
<Category>CivilCentre</Category>
|
||||
<Distance>
|
||||
<FromClass>CivilCentre</FromClass>
|
||||
<MinDistance>160</MinDistance>
|
||||
<MinDistance>200</MinDistance>
|
||||
</Distance>
|
||||
</BuildRestrictions>
|
||||
<Capturable>
|
||||
|
@ -8,7 +8,7 @@
|
||||
<Category>Colony</Category>
|
||||
<Distance>
|
||||
<FromClass>CivilCentre</FromClass>
|
||||
<MinDistance>80</MinDistance>
|
||||
<MinDistance>120</MinDistance>
|
||||
</Distance>
|
||||
</BuildRestrictions>
|
||||
<Cost>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<Territory>own neutral</Territory>
|
||||
<Distance>
|
||||
<FromClass>Outpost</FromClass>
|
||||
<MinDistance>45</MinDistance>
|
||||
<MinDistance>50</MinDistance>
|
||||
</Distance>
|
||||
</BuildRestrictions>
|
||||
<Cost>
|
||||
|
@ -37,7 +37,7 @@
|
||||
<Category>Tower</Category>
|
||||
<Distance>
|
||||
<FromClass>Tower</FromClass>
|
||||
<MinDistance>55</MinDistance>
|
||||
<MinDistance>60</MinDistance>
|
||||
</Distance>
|
||||
</BuildRestrictions>
|
||||
<GarrisonHolder>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Entity parent="template_structure_economic">
|
||||
<AlertRaiser>
|
||||
<List datatype="tokens">FemaleCitizen</List>
|
||||
<RaiseAlertRange>60</RaiseAlertRange>
|
||||
<RaiseAlertRange>50</RaiseAlertRange>
|
||||
<EndOfAlertRange>100</EndOfAlertRange>
|
||||
<SearchRange>100</SearchRange>
|
||||
</AlertRaiser>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<Entity parent="template_structure_economic">
|
||||
<AlertRaiser>
|
||||
<List datatype="tokens">FemaleCitizen</List>
|
||||
<RaiseAlertRange>60</RaiseAlertRange>
|
||||
<RaiseAlertRange>50</RaiseAlertRange>
|
||||
<EndOfAlertRange>100</EndOfAlertRange>
|
||||
<SearchRange>100</SearchRange>
|
||||
</AlertRaiser>
|
||||
|
@ -37,7 +37,7 @@
|
||||
<Category>Fortress</Category>
|
||||
<Distance>
|
||||
<FromClass>Fortress</FromClass>
|
||||
<MinDistance>55</MinDistance>
|
||||
<MinDistance>80</MinDistance>
|
||||
</Distance>
|
||||
</BuildRestrictions>
|
||||
<Capturable>
|
||||
|
@ -153,6 +153,7 @@ struct Query
|
||||
u8 flagsMask;
|
||||
bool enabled;
|
||||
bool parabolic;
|
||||
bool accountForSize; // If true, the query accounts for unit sizes, otherwise it treats all entities as points.
|
||||
};
|
||||
|
||||
/**
|
||||
@ -244,8 +245,6 @@ struct SerializeHelper<Query>
|
||||
template<typename S>
|
||||
void Common(S& serialize, const char* UNUSED(name), Serialize::qualify<S, Query> value)
|
||||
{
|
||||
serialize.Bool("enabled", value.enabled);
|
||||
serialize.Bool("parabolic",value.parabolic);
|
||||
serialize.NumberFixed_Unbounded("min range", value.minRange);
|
||||
serialize.NumberFixed_Unbounded("max range", value.maxRange);
|
||||
serialize.NumberFixed_Unbounded("elevation bonus", value.elevationBonus);
|
||||
@ -253,6 +252,9 @@ struct SerializeHelper<Query>
|
||||
serialize.NumberI32_Unbounded("interface", value.interface);
|
||||
Serializer(serialize, "last match", value.lastMatch);
|
||||
serialize.NumberU8_Unbounded("flagsMask", value.flagsMask);
|
||||
serialize.Bool("enabled", value.enabled);
|
||||
serialize.Bool("parabolic",value.parabolic);
|
||||
serialize.Bool("account for size",value.accountForSize);
|
||||
}
|
||||
|
||||
void operator()(ISerializer& serialize, const char* name, Query& value, const CSimContext& UNUSED(context))
|
||||
@ -907,10 +909,10 @@ public:
|
||||
|
||||
virtual tag_t CreateActiveQuery(entity_id_t source,
|
||||
entity_pos_t minRange, entity_pos_t maxRange,
|
||||
const std::vector<int>& owners, int requiredInterface, u8 flags)
|
||||
const std::vector<int>& owners, int requiredInterface, u8 flags, bool accountForSize)
|
||||
{
|
||||
tag_t id = m_QueryNext++;
|
||||
m_Queries[id] = ConstructQuery(source, minRange, maxRange, owners, requiredInterface, flags);
|
||||
m_Queries[id] = ConstructQuery(source, minRange, maxRange, owners, requiredInterface, flags, accountForSize);
|
||||
|
||||
return id;
|
||||
}
|
||||
@ -920,7 +922,7 @@ public:
|
||||
const std::vector<int>& owners, int requiredInterface, u8 flags)
|
||||
{
|
||||
tag_t id = m_QueryNext++;
|
||||
m_Queries[id] = ConstructParabolicQuery(source, minRange, maxRange, elevationBonus, owners, requiredInterface, flags);
|
||||
m_Queries[id] = ConstructParabolicQuery(source, minRange, maxRange, elevationBonus, owners, requiredInterface, flags, true);
|
||||
|
||||
return id;
|
||||
}
|
||||
@ -977,9 +979,9 @@ public:
|
||||
|
||||
virtual std::vector<entity_id_t> ExecuteQueryAroundPos(const CFixedVector2D& pos,
|
||||
entity_pos_t minRange, entity_pos_t maxRange,
|
||||
const std::vector<int>& owners, int requiredInterface)
|
||||
const std::vector<int>& owners, int requiredInterface, bool accountForSize)
|
||||
{
|
||||
Query q = ConstructQuery(INVALID_ENTITY, minRange, maxRange, owners, requiredInterface, GetEntityFlagMask("normal"));
|
||||
Query q = ConstructQuery(INVALID_ENTITY, minRange, maxRange, owners, requiredInterface, GetEntityFlagMask("normal"), accountForSize);
|
||||
std::vector<entity_id_t> r;
|
||||
PerformQuery(q, r, pos);
|
||||
|
||||
@ -991,11 +993,11 @@ public:
|
||||
|
||||
virtual std::vector<entity_id_t> ExecuteQuery(entity_id_t source,
|
||||
entity_pos_t minRange, entity_pos_t maxRange,
|
||||
const std::vector<int>& owners, int requiredInterface)
|
||||
const std::vector<int>& owners, int requiredInterface, bool accountForSize)
|
||||
{
|
||||
PROFILE("ExecuteQuery");
|
||||
|
||||
Query q = ConstructQuery(source, minRange, maxRange, owners, requiredInterface, GetEntityFlagMask("normal"));
|
||||
Query q = ConstructQuery(source, minRange, maxRange, owners, requiredInterface, GetEntityFlagMask("normal"), accountForSize);
|
||||
|
||||
std::vector<entity_id_t> r;
|
||||
|
||||
@ -1221,8 +1223,8 @@ public:
|
||||
// they have an intersection after which the former grows slower, and then use that to prove the above.
|
||||
// Note that this is only true because we do not account for vertical size here,
|
||||
// if we did, we would also need to artificially 'raise' the source over the target.
|
||||
if (!InParabolicRange(CFixedVector3D(it->second.x, secondPosition.Y, it->second.z) - pos3d,
|
||||
q.maxRange + fixed::FromInt(it->second.size)))
|
||||
entity_pos_t range = q.maxRange + (q.accountForSize ? fixed::FromInt(it->second.size) : fixed::Zero());
|
||||
if (!InParabolicRange(CFixedVector3D(it->second.x, secondPosition.Y, it->second.z) - pos3d, range))
|
||||
continue;
|
||||
|
||||
if (!q.minRange.IsZero())
|
||||
@ -1249,7 +1251,8 @@ public:
|
||||
continue;
|
||||
|
||||
// Restrict based on approximate circle-circle distance.
|
||||
if ((CFixedVector2D(it->second.x, it->second.z) - pos).CompareLength(q.maxRange + fixed::FromInt(it->second.size)) > 0)
|
||||
entity_pos_t range = q.maxRange + (q.accountForSize ? fixed::FromInt(it->second.size) : fixed::Zero());
|
||||
if ((CFixedVector2D(it->second.x, it->second.z) - pos).CompareLength(range) > 0)
|
||||
continue;
|
||||
|
||||
if (!q.minRange.IsZero())
|
||||
@ -1364,7 +1367,7 @@ public:
|
||||
|
||||
Query ConstructQuery(entity_id_t source,
|
||||
entity_pos_t minRange, entity_pos_t maxRange,
|
||||
const std::vector<int>& owners, int requiredInterface, u8 flagsMask) const
|
||||
const std::vector<int>& owners, int requiredInterface, u8 flagsMask, bool accountForSize) const
|
||||
{
|
||||
// Min range must be non-negative
|
||||
if (minRange < entity_pos_t::Zero())
|
||||
@ -1381,8 +1384,9 @@ public:
|
||||
q.minRange = minRange;
|
||||
q.maxRange = maxRange;
|
||||
q.elevationBonus = entity_pos_t::Zero();
|
||||
q.accountForSize = accountForSize;
|
||||
|
||||
if (q.source.GetId() != INVALID_ENTITY && q.maxRange != entity_pos_t::FromInt(-1))
|
||||
if (q.accountForSize && q.source.GetId() != INVALID_ENTITY && q.maxRange != entity_pos_t::FromInt(-1))
|
||||
{
|
||||
u32 size = 0;
|
||||
if (ENTITY_IS_LOCAL(q.source.GetId()))
|
||||
@ -1418,9 +1422,9 @@ public:
|
||||
|
||||
Query ConstructParabolicQuery(entity_id_t source,
|
||||
entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t elevationBonus,
|
||||
const std::vector<int>& owners, int requiredInterface, u8 flagsMask) const
|
||||
const std::vector<int>& owners, int requiredInterface, u8 flagsMask, bool accountForSize) const
|
||||
{
|
||||
Query q = ConstructQuery(source,minRange,maxRange,owners,requiredInterface,flagsMask);
|
||||
Query q = ConstructQuery(source, minRange, maxRange, owners, requiredInterface, flagsMask, accountForSize);
|
||||
q.parabolic = true;
|
||||
q.elevationBonus = elevationBonus;
|
||||
return q;
|
||||
|
@ -45,9 +45,9 @@ std::string ICmpRangeManager::GetLosVisibilityPosition_wrapper(entity_pos_t x, e
|
||||
}
|
||||
|
||||
BEGIN_INTERFACE_WRAPPER(RangeManager)
|
||||
DEFINE_INTERFACE_METHOD_5("ExecuteQuery", std::vector<entity_id_t>, ICmpRangeManager, ExecuteQuery, entity_id_t, entity_pos_t, entity_pos_t, std::vector<int>, int)
|
||||
DEFINE_INTERFACE_METHOD_5("ExecuteQueryAroundPos", std::vector<entity_id_t>, ICmpRangeManager, ExecuteQueryAroundPos, CFixedVector2D, entity_pos_t, entity_pos_t, std::vector<int>, int)
|
||||
DEFINE_INTERFACE_METHOD_6("CreateActiveQuery", ICmpRangeManager::tag_t, ICmpRangeManager, CreateActiveQuery, entity_id_t, entity_pos_t, entity_pos_t, std::vector<int>, int, u8)
|
||||
DEFINE_INTERFACE_METHOD_6("ExecuteQuery", std::vector<entity_id_t>, ICmpRangeManager, ExecuteQuery, entity_id_t, entity_pos_t, entity_pos_t, std::vector<int>, int, bool)
|
||||
DEFINE_INTERFACE_METHOD_6("ExecuteQueryAroundPos", std::vector<entity_id_t>, ICmpRangeManager, ExecuteQueryAroundPos, CFixedVector2D, entity_pos_t, entity_pos_t, std::vector<int>, int, bool)
|
||||
DEFINE_INTERFACE_METHOD_7("CreateActiveQuery", ICmpRangeManager::tag_t, ICmpRangeManager, CreateActiveQuery, entity_id_t, entity_pos_t, entity_pos_t, std::vector<int>, int, u8, bool)
|
||||
DEFINE_INTERFACE_METHOD_7("CreateActiveParabolicQuery", ICmpRangeManager::tag_t, ICmpRangeManager, CreateActiveParabolicQuery, entity_id_t, entity_pos_t, entity_pos_t, entity_pos_t, std::vector<int>, int, u8)
|
||||
DEFINE_INTERFACE_METHOD_1("DestroyActiveQuery", void, ICmpRangeManager, DestroyActiveQuery, ICmpRangeManager::tag_t)
|
||||
DEFINE_INTERFACE_METHOD_1("EnableActiveQuery", void, ICmpRangeManager, EnableActiveQuery, ICmpRangeManager::tag_t)
|
||||
|
@ -73,7 +73,8 @@ class CLosQuerier;
|
||||
*
|
||||
* In most cases the users are event-based and want notifications when something
|
||||
* has entered or left the range, and the query can be set up once and rarely changed.
|
||||
* These queries have to be fast. Entities are approximated as circles.
|
||||
* These queries have to be fast. Entities are approximated as points or circles
|
||||
* (queries can be set up to ignore sizes because LOS currently ignores it, and mismatches are problematic).
|
||||
*
|
||||
* Current design:
|
||||
*
|
||||
@ -116,10 +117,11 @@ public:
|
||||
* @param maxRange non-negative maximum distance in metres (inclusive); or -1.0 to ignore distance.
|
||||
* @param owners list of player IDs that matching entities may have; -1 matches entities with no owner.
|
||||
* @param requiredInterface if non-zero, an interface ID that matching entities must implement.
|
||||
* @param accountForSize if true, compensate for source/target entity sizes.
|
||||
* @return list of entities matching the query, ordered by increasing distance from the source entity.
|
||||
*/
|
||||
virtual std::vector<entity_id_t> ExecuteQuery(entity_id_t source,
|
||||
entity_pos_t minRange, entity_pos_t maxRange, const std::vector<int>& owners, int requiredInterface) = 0;
|
||||
virtual std::vector<entity_id_t> ExecuteQuery(entity_id_t source, entity_pos_t minRange, entity_pos_t maxRange,
|
||||
const std::vector<int>& owners, int requiredInterface, bool accountForSize) = 0;
|
||||
|
||||
/**
|
||||
* Execute a passive query.
|
||||
@ -128,10 +130,11 @@ public:
|
||||
* @param maxRange non-negative maximum distance in metres (inclusive); or -1.0 to ignore distance.
|
||||
* @param owners list of player IDs that matching entities may have; -1 matches entities with no owner.
|
||||
* @param requiredInterface if non-zero, an interface ID that matching entities must implement.
|
||||
* @param accountForSize if true, compensate for source/target entity sizes.
|
||||
* @return list of entities matching the query, ordered by increasing distance from the source entity.
|
||||
*/
|
||||
virtual std::vector<entity_id_t> ExecuteQueryAroundPos(const CFixedVector2D& pos,
|
||||
entity_pos_t minRange, entity_pos_t maxRange, const std::vector<int>& owners, int requiredInterface) = 0;
|
||||
virtual std::vector<entity_id_t> ExecuteQueryAroundPos(const CFixedVector2D& pos, entity_pos_t minRange, entity_pos_t maxRange,
|
||||
const std::vector<int>& owners, int requiredInterface, bool accountForSize) = 0;
|
||||
|
||||
/**
|
||||
* Construct an active query. The query will be disabled by default.
|
||||
@ -141,10 +144,11 @@ public:
|
||||
* @param owners list of player IDs that matching entities may have; -1 matches entities with no owner.
|
||||
* @param requiredInterface if non-zero, an interface ID that matching entities must implement.
|
||||
* @param flags if a entity in range has one of the flags set it will show up.
|
||||
* @param accountForSize if true, compensate for source/target entity sizes.
|
||||
* @return unique non-zero identifier of query.
|
||||
*/
|
||||
virtual tag_t CreateActiveQuery(entity_id_t source,
|
||||
entity_pos_t minRange, entity_pos_t maxRange, const std::vector<int>& owners, int requiredInterface, u8 flags) = 0;
|
||||
virtual tag_t CreateActiveQuery(entity_id_t source, entity_pos_t minRange, entity_pos_t maxRange,
|
||||
const std::vector<int>& owners, int requiredInterface, u8 flags, bool accountForSize) = 0;
|
||||
|
||||
/**
|
||||
* Construct an active query of a paraboloic form around the unit.
|
||||
@ -158,10 +162,11 @@ public:
|
||||
* @param owners list of player IDs that matching entities may have; -1 matches entities with no owner.
|
||||
* @param requiredInterface if non-zero, an interface ID that matching entities must implement.
|
||||
* @param flags if a entity in range has one of the flags set it will show up.
|
||||
* NB: this one has no accountForSize parameter (assumed true), because we currently can only have 7 arguments for JS functions.
|
||||
* @return unique non-zero identifier of query.
|
||||
*/
|
||||
virtual tag_t CreateActiveParabolicQuery(entity_id_t source,
|
||||
entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t elevationBonus, const std::vector<int>& owners, int requiredInterface, u8 flags) = 0;
|
||||
virtual tag_t CreateActiveParabolicQuery(entity_id_t source, entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t elevationBonus,
|
||||
const std::vector<int>& owners, int requiredInterface, u8 flags) = 0;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -230,41 +230,41 @@ public:
|
||||
move(100, position, fixed::FromInt(10), fixed::FromInt(10));
|
||||
move(101, position2, fixed::FromInt(10), fixed::FromInt(20));
|
||||
|
||||
std::vector<entity_id_t> nearby = cmp->ExecuteQuery(100, fixed::FromInt(0), fixed::FromInt(4), {1}, 0);
|
||||
std::vector<entity_id_t> nearby = cmp->ExecuteQuery(100, fixed::FromInt(0), fixed::FromInt(4), {1}, 0, true);
|
||||
TS_ASSERT_EQUALS(nearby, std::vector<entity_id_t>{});
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(4), fixed::FromInt(50), {1}, 0);
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(4), fixed::FromInt(50), {1}, 0, true);
|
||||
TS_ASSERT_EQUALS(nearby, std::vector<entity_id_t>{101});
|
||||
|
||||
move(101, position2, fixed::FromInt(10), fixed::FromInt(10));
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(0), fixed::FromInt(4), {1}, 0);
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(0), fixed::FromInt(4), {1}, 0, true);
|
||||
TS_ASSERT_EQUALS(nearby, std::vector<entity_id_t>{101});
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(4), fixed::FromInt(50), {1}, 0);
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(4), fixed::FromInt(50), {1}, 0, true);
|
||||
TS_ASSERT_EQUALS(nearby, std::vector<entity_id_t>{});
|
||||
|
||||
move(101, position2, fixed::FromInt(10), fixed::FromInt(13));
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(0), fixed::FromInt(4), {1}, 0);
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(0), fixed::FromInt(4), {1}, 0, true);
|
||||
TS_ASSERT_EQUALS(nearby, std::vector<entity_id_t>{101});
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(4), fixed::FromInt(50), {1}, 0);
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(4), fixed::FromInt(50), {1}, 0, true);
|
||||
TS_ASSERT_EQUALS(nearby, std::vector<entity_id_t>{});
|
||||
|
||||
move(101, position2, fixed::FromInt(10), fixed::FromInt(15));
|
||||
// In range thanks to self obstruction size.
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(0), fixed::FromInt(4), {1}, 0);
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(0), fixed::FromInt(4), {1}, 0, true);
|
||||
TS_ASSERT_EQUALS(nearby, std::vector<entity_id_t>{101});
|
||||
// In range thanks to target obstruction size.
|
||||
nearby = cmp->ExecuteQuery(101, fixed::FromInt(0), fixed::FromInt(4), {1}, 0);
|
||||
nearby = cmp->ExecuteQuery(101, fixed::FromInt(0), fixed::FromInt(4), {1}, 0, true);
|
||||
TS_ASSERT_EQUALS(nearby, std::vector<entity_id_t>{100});
|
||||
|
||||
// Trickier: min-range is closest-to-closest, but rotation may change the real distance.
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(2), fixed::FromInt(50), {1}, 0);
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(2), fixed::FromInt(50), {1}, 0, true);
|
||||
TS_ASSERT_EQUALS(nearby, std::vector<entity_id_t>{101});
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(5), fixed::FromInt(50), {1}, 0);
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(5), fixed::FromInt(50), {1}, 0, true);
|
||||
TS_ASSERT_EQUALS(nearby, std::vector<entity_id_t>{101});
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(6), fixed::FromInt(50), {1}, 0);
|
||||
nearby = cmp->ExecuteQuery(100, fixed::FromInt(6), fixed::FromInt(50), {1}, 0, true);
|
||||
TS_ASSERT_EQUALS(nearby, std::vector<entity_id_t>{});
|
||||
nearby = cmp->ExecuteQuery(101, fixed::FromInt(5), fixed::FromInt(50), {1}, 0);
|
||||
nearby = cmp->ExecuteQuery(101, fixed::FromInt(5), fixed::FromInt(50), {1}, 0, true);
|
||||
TS_ASSERT_EQUALS(nearby, std::vector<entity_id_t>{100});
|
||||
nearby = cmp->ExecuteQuery(101, fixed::FromInt(6), fixed::FromInt(50), {1}, 0);
|
||||
nearby = cmp->ExecuteQuery(101, fixed::FromInt(6), fixed::FromInt(50), {1}, 0, true);
|
||||
TS_ASSERT_EQUALS(nearby, std::vector<entity_id_t>{});
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user