Ticket #1960: elevation_advantage.diff
File elevation_advantage.diff, 22.5 KB (added by , 11 years ago) |
---|
-
binaries/data/mods/public/simulation/components/BuildingAI.js
99 99 if (cmpAttack) 100 100 { 101 101 var range = cmpAttack.GetRange("Ranged"); 102 this.enemyUnitsQuery = cmpRangeManager.CreateActive Query(this.entity, range.min, range.max, players, IID_DamageReceiver, cmpRangeManager.GetEntityFlagMask("normal"));102 this.enemyUnitsQuery = cmpRangeManager.CreateActiveParabolicQuery(this.entity, range.min, range.max, players, IID_DamageReceiver, cmpRangeManager.GetEntityFlagMask("normal")); 103 103 cmpRangeManager.EnableActiveQuery(this.enemyUnitsQuery); 104 104 } 105 105 }; … … 133 133 var range = cmpAttack.GetRange("Ranged"); 134 134 135 135 // This query is only interested in Gaia entities that can attack. 136 this.gaiaUnitsQuery = rangeMan.CreateActive Query(this.entity, range.min, range.max, [0], IID_Attack, rangeMan.GetEntityFlagMask("normal"));136 this.gaiaUnitsQuery = rangeMan.CreateActiveParabolicQuery(this.entity, range.min, range.max, [0], IID_Attack, rangeMan.GetEntityFlagMask("normal")); 137 137 rangeMan.EnableActiveQuery(this.gaiaUnitsQuery); 138 138 } 139 139 }; … … 239 243 //Fire N arrows, 0 <= N <= Number of arrows left 240 244 arrowsToFire = Math.floor(Math.random() * this.arrowsLeft); 241 245 } 246 242 247 if (this.targetUnits.length > 0) 243 248 { 249 var clonedTargets = this.targetUnits.slice(); 244 250 for (var i = 0;i < arrowsToFire;i++) 245 251 { 246 cmpAttack.PerformAttack("Ranged", this.targetUnits[Math.floor(Math.random() * this.targetUnits.length)]); 247 PlaySound("arrowfly", this.entity); 252 var target = clonedTargets[Math.floor(Math.random() * this.targetUnits.length)]; 253 if ( 254 target && 255 this.CheckTargetVisible(target) 256 ) 257 { 258 cmpAttack.PerformAttack("Ranged", target); 259 PlaySound("arrowfly", this.entity); 260 261 } 262 else 263 { 264 clonedTargets.splice(clonedTargets.indexOf(target),1); 265 i--; // one extra arrow left to fire 266 if(clonedTargets.length < 1) 267 { 268 this.arrowsLeft += arrowsToFire; 269 // no targets found in this round, save arrows and go to next round 270 break; 271 } 272 } 248 273 } 249 274 this.arrowsLeft -= arrowsToFire; 250 275 } … … 252 277 } 253 278 }; 254 279 280 /** 281 * Returns true if the target entity is visible through the FoW/SoD. 282 */ 283 BuildingAI.prototype.CheckTargetVisible = function(target) 284 { 285 var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); 286 if (!cmpOwnership) 287 return false; 288 289 var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 290 291 if (cmpRangeManager.GetLosVisibility(target, cmpOwnership.GetOwner(), false) == "hidden") 292 return false; 293 294 // Either visible directly, or visible in fog 295 return true; 296 }; 297 255 298 Engine.RegisterComponentType(IID_BuildingAI, "BuildingAI", BuildingAI); -
binaries/data/mods/public/simulation/components/UnitAI.js
367 367 this.attackType = type; 368 368 369 369 // If we are already at the target, try attacking it from here 370 if (this.CheckTarget Range(this.order.data.target, IID_Attack, this.attackType))370 if (this.CheckTargetAttackRange(this.order.data.target, IID_Attack, this.attackType)) 371 371 { 372 372 this.StopMoving(); 373 373 // For packable units within attack range: … … 427 427 return; 428 428 } 429 429 430 // Try to move within attack range 431 if (this.MoveToTarget Range(this.order.data.target, IID_Attack, this.attackType))430 // Try to move within attack range 431 if (this.MoveToTargetAttackRange(this.order.data.target, IID_Attack, this.attackType,0.5)) 432 432 { 433 433 // We've started walking to the given point 434 434 if (this.IsAnimal()) … … 1314 1314 }, 1315 1315 1316 1316 "MoveCompleted": function() { 1317 // If the unit needs to unpack, do so 1318 if (this.CanUnpack()) 1319 this.SetNextState("UNPACKING"); 1320 else 1321 this.SetNextState("ATTACKING"); 1317 1318 if (this.CheckTargetAttackRange(this.order.data.target, IID_Attack , this.attackType)) 1319 { 1320 // If the unit needs to unpack, do so 1321 if (this.CanUnpack()) 1322 this.SetNextState("UNPACKING"); 1323 else 1324 this.SetNextState("ATTACKING"); 1325 } 1326 else 1327 { 1328 if (this.MoveToTargetAttackRange(this.order.data.target, IID_Attack, this.attackType,0)) 1329 { 1330 this.SetNextState("APPROACHING"); 1331 } 1332 else 1333 { 1334 // Give up 1335 this.FinishOrder(); 1336 } 1337 } 1322 1338 }, 1323 1339 1324 1340 "Attacked": function(msg) { … … 1334 1350 "UNPACKING": { 1335 1351 "enter": function() { 1336 1352 // If we're not in range yet (maybe we stopped moving), move to target again 1337 if (!this.CheckTarget Range(this.order.data.target, IID_Attack, this.attackType))1353 if (!this.CheckTargetAttackRange(this.order.data.target, IID_Attack, this.attackType)) 1338 1354 { 1339 if (this.MoveToTarget Range(this.order.data.target, IID_Attack, this.attackType))1355 if (this.MoveToTargetAttackRange(this.order.data.target, IID_Attack, this.attackType,0)) 1340 1356 this.SetNextState("APPROACHING"); 1341 1357 else 1342 1358 { … … 1402 1418 if (this.TargetIsAlive(target) && this.CanAttack(target, this.order.data.forceResponse || null)) 1403 1419 { 1404 1420 // Check we can still reach the target 1405 if (this.CheckTarget Range(target, IID_Attack, this.attackType))1421 if (this.CheckTargetAttackRange(target, IID_Attack, this.attackType)) 1406 1422 { 1407 1423 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 1408 1424 this.lastAttacked = cmpTimer.GetTime() - msg.lateness; … … 3287 3303 return cmpUnitMotion.MoveToTargetRange(target, range.min, range.max); 3288 3304 }; 3289 3305 3306 /** 3307 * Move unit so we hope the target is in the attack range 3308 * for melee attacks, this goes straight to the default range checks 3309 * for ranged attacks, the parabolic range is used, so we can't know exactly at what horizontal range the target can be reached 3310 * That's why a guess is needed 3311 * a guess of 1 will take the maximum of the possible ranges, and stay far away 3312 * a guess of 0 will take the minimum of the possible ranges and, in most cases, will have the target in range. 3313 * every guess inbetween is a linear interpollation 3314 */ 3315 UnitAI.prototype.MoveToTargetAttackRange = function(target, iid, type,guess) 3316 { 3317 3318 if(type!= "Ranged") { 3319 return this.MoveToTargetRange(target, iid, type); 3320 } 3321 if (!this.CheckTargetVisible(target)) { 3322 return false; 3323 } 3324 var cmpRanged = Engine.QueryInterface(this.entity, iid); 3325 var range = cmpRanged.GetRange(type); 3326 3327 var thisCmpPosition = Engine.QueryInterface(this.entity, IID_Position); 3328 var s = thisCmpPosition.GetPosition(); 3329 3330 var targetCmpPosition = Engine.QueryInterface(target, IID_Position); 3331 if(!targetCmpPosition.IsInWorld()) 3332 return false; 3333 3334 var t = targetCmpPosition.GetPosition(); 3335 // h is positive when I'm higher than the target 3336 var h = s.y-t.y; 3337 3338 // No negative roots please 3339 if(h>-range.max/2) { 3340 var parabolicMaxRange = Math.sqrt(range.max*range.max+2*range.max*h); 3341 } else { 3342 // return false? Or hope you come close enough? 3343 var parabolicMaxRange = 0; 3344 //return false; 3345 } 3346 // the parabole changes while walking, take something in the middle 3347 var guessedMaxRange = Math.max(range.max, parabolicMaxRange)*guess+Math.min(range.max, parabolicMaxRange)*(1-guess) ; 3348 3349 var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); 3350 var r = cmpUnitMotion.MoveToTargetRange(target, range.min, guessedMaxRange); 3351 return r; 3352 }; 3353 3290 3354 UnitAI.prototype.MoveToTargetRangeExplicit = function(target, min, max) 3291 3355 { 3292 3356 if (!this.CheckTargetVisible(target)) … … 3311 3375 return cmpUnitMotion.IsInTargetRange(target, range.min, range.max); 3312 3376 }; 3313 3377 3378 /** 3379 * Check if the target is inside the attack range 3380 * For melee attacks, this goes straigt to the regular range calculation 3381 * For ranged attacks, the parabolic formula is used to accout for bigger ranges 3382 * when the target is lower, and smaller ranges when the target is higher 3383 */ 3384 UnitAI.prototype.CheckTargetAttackRange = function(target, iid, type) 3385 { 3386 3387 if (type != "Ranged") 3388 { 3389 return this.CheckTargetRange(target,iid,type); 3390 } 3391 3392 var targetCmpPosition = Engine.QueryInterface(target, IID_Position); 3393 if (!targetCmpPosition || !targetCmpPosition.IsInWorld()) 3394 { 3395 return false; 3396 } 3397 3398 var cmpRanged = Engine.QueryInterface(this.entity, iid); 3399 var range = cmpRanged.GetRange(type); 3400 3401 var thisCmpPosition = Engine.QueryInterface(this.entity, IID_Position); 3402 var s = thisCmpPosition.GetPosition(); 3403 3404 var t = targetCmpPosition.GetPosition(); 3405 3406 var h = s.y-t.y; 3407 var maxRangeSq = 2*range.max*(h + range.max/2); 3408 if (maxRangeSq<0) 3409 { 3410 // certainly outside the range, the target is even too high to reach. 3411 return false; 3412 } 3413 3414 // use native range checking function to take account of target shape 3415 // in case of big targets 3416 return this.CheckTargetRangeExplicit(target,range.min,Math.sqrt(maxRangeSq)); 3417 }; 3418 3314 3419 UnitAI.prototype.CheckTargetRangeExplicit = function(target, min, max) 3315 3420 { 3316 3421 var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); -
source/simulation2/components/CCmpRangeManager.cpp
20 20 #include "simulation2/system/Component.h" 21 21 #include "ICmpRangeManager.h" 22 22 23 #include "ICmpTerrain.h" 23 24 #include "simulation2/MessageTypes.h" 24 25 #include "simulation2/components/ICmpPosition.h" 25 26 #include "simulation2/components/ICmpTerritoryManager.h" 26 27 #include "simulation2/components/ICmpVision.h" 28 #include "simulation2/components/ICmpWaterManager.h" 27 29 #include "simulation2/helpers/Render.h" 28 30 #include "simulation2/helpers/Spatial.h" 29 31 … … 44 46 struct Query 45 47 { 46 48 bool enabled; 49 bool parabolic; 47 50 entity_id_t source; 48 51 entity_pos_t minRange; 49 52 entity_pos_t maxRange; … … 88 91 } 89 92 90 93 /** 94 * Checks whether v is in a parabolic range of (0,0,0) 95 * The highest point of the paraboloid is (0,range/2,0) 96 * and the circle of distance 'range' around (0,0,0) on height y=0 is part of the paraboloid 97 * 98 * Avoids sqrting and overflowing. 99 */ 100 static bool InParabolicRange(CFixedVector3D v, fixed range) 101 { 102 i64 x = (i64)v.X.GetInternalValue(); // abs(x) <= 2^31 103 i64 z = (i64)v.Z.GetInternalValue(); 104 i64 xx = (x * x); // xx <= 2^62 105 i64 zz = (z * z); 106 i64 d2 = (xx + zz) >> 1; // d2 <= 2^62 (no overflow) 107 108 i64 y = (i64)v.Y.GetInternalValue(); 109 110 i64 c = (i64)range.GetInternalValue(); 111 i64 c_2 = c >> 1; 112 113 i64 c2 = (c_2-y)*c; 114 115 if (d2 <= c2) 116 return true; 117 118 return false; 119 } 120 121 struct EntityParabolicRangeOutline 122 { 123 entity_id_t source; 124 CFixedVector3D position; 125 entity_pos_t range; 126 std::vector<float> outline; 127 }; 128 129 static std::map<entity_id_t, EntityParabolicRangeOutline> ParabolicRangesOutlines; 130 131 /** 91 132 * Representation of an entity, with the data needed for queries. 92 133 */ 93 134 struct EntityData … … 113 154 void operator()(S& serialize, const char* UNUSED(name), Query& value) 114 155 { 115 156 serialize.Bool("enabled", value.enabled); 157 serialize.Bool("parabolic",value.parabolic); 116 158 serialize.NumberU32_Unbounded("source", value.source); 117 159 serialize.NumberFixed_Unbounded("min range", value.minRange); 118 160 serialize.NumberFixed_Unbounded("max range", value.maxRange); … … 589 631 return id; 590 632 } 591 633 634 virtual tag_t CreateActiveParabolicQuery(entity_id_t source, 635 entity_pos_t minRange, entity_pos_t maxRange, 636 std::vector<int> owners, int requiredInterface, u8 flags) 637 { 638 tag_t id = m_QueryNext++; 639 m_Queries[id] = ConstructParabolicQuery(source, minRange, maxRange, owners, requiredInterface, flags); 640 641 return id; 642 } 643 592 644 virtual void DestroyActiveQuery(tag_t tag) 593 645 { 594 646 if (m_Queries.find(tag) == m_Queries.end()) … … 812 864 r.push_back(it->first); 813 865 } 814 866 } 815 else 867 // Not the entire world, so check a parabolic range, or a regular range 868 else if (q.parabolic) 816 869 { 870 CFixedVector3D pos3d = cmpSourcePosition->GetPosition(); 871 // Get a quick list of entities that are potentially in range, with a cutoff of 3*maxRange 872 std::vector<entity_id_t> ents = m_Subdivision.GetNear(pos, q.maxRange*2); 873 874 for (size_t i = 0; i < ents.size(); ++i) 875 { 876 std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.find(ents[i]); 877 ENSURE(it != m_EntityData.end()); 878 879 if (!TestEntityQuery(q, it->first, it->second)) 880 continue; 881 882 CmpPtr<ICmpPosition> cmpSecondPosition(GetSimContext(), ents[i]); 883 if (!cmpSecondPosition || !cmpSecondPosition->IsInWorld()) 884 continue; 885 CFixedVector3D secondPosition = cmpSecondPosition->GetPosition(); 886 887 // Restrict based on precise distance 888 if (!InParabolicRange( 889 CFixedVector3D(it->second.x, secondPosition.Y, it->second.z) 890 - pos3d, 891 q.maxRange)) 892 continue; 893 894 if (!q.minRange.IsZero()) 895 { 896 int distVsMin = (CFixedVector2D(it->second.x, it->second.z) - pos).CompareLength(q.minRange); 897 if (distVsMin < 0) 898 continue; 899 } 900 901 r.push_back(it->first); 902 903 } 904 } 905 // check a regular range (i.e. not the entire world, and not parabolic) 906 else 907 { 817 908 // Get a quick list of entities that are potentially in range 818 909 std::vector<entity_id_t> ents = m_Subdivision.GetNear(pos, q.maxRange); 819 910 … … 838 929 } 839 930 840 931 r.push_back(it->first); 932 841 933 } 842 934 } 843 935 } 844 936 937 virtual std::vector<float> getParabolicRangeForm(CFixedVector3D pos, entity_pos_t maxRange, entity_pos_t cutoff) 938 { 939 940 entity_pos_t minAngle = entity_pos_t::FromFloat(2.0f*3.15f/80.0f); 941 942 entity_pos_t precision = entity_pos_t::FromInt((int)TERRAIN_TILE_SIZE)/8; 943 944 std::vector<float> r; 945 946 947 CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY); 948 CmpPtr<ICmpWaterManager> cmpWaterManager(GetSimContext(), SYSTEM_ENTITY); 949 entity_pos_t waterLevel = cmpWaterManager->GetWaterLevel(pos.X,pos.Z); 950 951 if (cmpTerrain) 952 { 953 for (entity_pos_t angle = entity_pos_t::Zero(); angle < entity_pos_t::FromFloat(2.0f*3.14); angle += minAngle) 954 { 955 entity_pos_t sin; 956 entity_pos_t cos; 957 entity_pos_t minDistance = entity_pos_t::Zero(); 958 entity_pos_t maxDistance = cutoff; 959 sincos_approx(angle,sin,cos); 960 961 CFixedVector2D minVector = CFixedVector2D(entity_pos_t::Zero(),entity_pos_t::Zero()); 962 CFixedVector2D maxVector = CFixedVector2D(cos,sin).Multiply(cutoff); 963 entity_pos_t targetHeight = cmpTerrain->GetGroundLevel(pos.X+maxVector.X,pos.Z+maxVector.Y); 964 // use water level to display range on water 965 targetHeight = targetHeight > waterLevel ? targetHeight : waterLevel; 966 967 if (InParabolicRange(CFixedVector3D(maxVector.X,targetHeight-pos.Y,maxVector.Y),maxRange)) 968 { 969 r.push_back((pos.X+maxVector.X).ToFloat()); 970 r.push_back((pos.Z+maxVector.Y).ToFloat()); 971 continue; 972 } 973 974 // Loop until vectors come close enough 975 while ((maxVector - minVector).CompareLength(precision) > 0) 976 { 977 // difference still bigger than precision, bisect to get smaller difference 978 entity_pos_t newDistance = (minDistance+maxDistance)/entity_pos_t::FromInt(2); 979 980 CFixedVector2D newVector = CFixedVector2D(cos,sin).Multiply(newDistance); 981 982 // get the height of the ground 983 targetHeight = cmpTerrain->GetGroundLevel(pos.X+newVector.X,pos.Z+newVector.Y); 984 targetHeight = targetHeight > waterLevel ? targetHeight : waterLevel; 985 986 if (InParabolicRange(CFixedVector3D(newVector.X,targetHeight-pos.Y,newVector.Y),maxRange)) 987 { 988 // new vector is in parabolic range, so this is a new minVector 989 minVector = newVector; 990 minDistance = newDistance; 991 } 992 else 993 { 994 // new vector is out parabolic range, so this is a new maxVector 995 maxVector = newVector; 996 maxDistance = newDistance; 997 } 998 999 } 1000 r.push_back((pos.X+maxVector.X).ToFloat()); 1001 r.push_back((pos.Z+maxVector.Y).ToFloat()); 1002 1003 } 1004 r.push_back(r[0]); 1005 r.push_back(r[1]); 1006 1007 } 1008 return r; 1009 1010 } 1011 845 1012 Query ConstructQuery(entity_id_t source, 846 1013 entity_pos_t minRange, entity_pos_t maxRange, 847 1014 const std::vector<int>& owners, int requiredInterface, u8 flagsMask) … … 856 1023 857 1024 Query q; 858 1025 q.enabled = false; 1026 q.parabolic = false; 859 1027 q.source = source; 860 1028 q.minRange = minRange; 861 1029 q.maxRange = maxRange; … … 870 1038 return q; 871 1039 } 872 1040 1041 Query ConstructParabolicQuery(entity_id_t source, 1042 entity_pos_t minRange, entity_pos_t maxRange, 1043 const std::vector<int>& owners, int requiredInterface, u8 flagsMask) 1044 { 1045 Query q = ConstructQuery(source,minRange,maxRange,owners,requiredInterface,flagsMask); 1046 q.parabolic = true; 1047 return q; 1048 } 1049 1050 873 1051 void RenderSubmit(SceneCollector& collector) 874 1052 { 875 1053 if (!m_DebugOverlayEnabled) 876 1054 return; 877 878 1055 CColor enabledRingColour(0, 1, 0, 1); 879 1056 CColor disabledRingColour(1, 0, 0, 1); 880 1057 CColor rayColour(1, 1, 0, 0.2f); … … 893 1070 CFixedVector2D pos = cmpSourcePosition->GetPosition2D(); 894 1071 895 1072 // Draw the max range circle 896 m_DebugOverlayLines.push_back(SOverlayLine()); 897 m_DebugOverlayLines.back().m_Color = (q.enabled ? enabledRingColour : disabledRingColour); 898 SimRender::ConstructCircleOnGround(GetSimContext(), pos.X.ToFloat(), pos.Y.ToFloat(), q.maxRange.ToFloat(), m_DebugOverlayLines.back(), true); 1073 if (!q.parabolic) 1074 { 1075 m_DebugOverlayLines.push_back(SOverlayLine()); 1076 m_DebugOverlayLines.back().m_Color = (q.enabled ? enabledRingColour : disabledRingColour); 1077 SimRender::ConstructCircleOnGround(GetSimContext(), pos.X.ToFloat(), pos.Y.ToFloat(), q.maxRange.ToFloat(), m_DebugOverlayLines.back(), true); 1078 } 1079 else 1080 { 1081 CFixedVector3D pos = cmpSourcePosition->GetPosition(); 1082 std::vector<float> coords; 1083 1084 // Get the outline from cache if possible 1085 if (ParabolicRangesOutlines.find(q.source) != ParabolicRangesOutlines.end()) 1086 { 1087 EntityParabolicRangeOutline e = ParabolicRangesOutlines[q.source]; 1088 if (e.position == pos && e.range == q.maxRange) 1089 { 1090 // outline is cached correctly, use it 1091 coords = e.outline; 1092 } 1093 else 1094 { 1095 // outline was cached, but important parameters changed 1096 // (position, elevation, range) 1097 // update it 1098 coords = getParabolicRangeForm(pos,q.maxRange,q.maxRange*2); 1099 e.outline = coords; 1100 e.range = q.maxRange; 1101 e.position = pos; 1102 ParabolicRangesOutlines[q.source] = e; 1103 } 1104 } 1105 else 1106 { 1107 // outline wasn't cached (first time you enable the range overlay 1108 // or you created a new entiy) 1109 // cache a new outline 1110 coords = getParabolicRangeForm(pos,q.maxRange,q.maxRange*2); 1111 EntityParabolicRangeOutline e; 1112 e.source = q.source; 1113 e.range = q.maxRange; 1114 e.position = pos; 1115 e.outline = coords; 1116 ParabolicRangesOutlines[q.source] = e; 1117 } 1118 1119 CColor thiscolor = q.enabled ? enabledRingColour : disabledRingColour; 1120 1121 // draw the outline (piece by piece) 1122 for (size_t i = 3; i < coords.size(); i += 2) 1123 { 1124 std::vector<float> c; 1125 c.push_back(coords[i-3]); 1126 c.push_back(coords[i-2]); 1127 c.push_back(coords[i-1]); 1128 c.push_back(coords[i]); 1129 m_DebugOverlayLines.push_back(SOverlayLine()); 1130 m_DebugOverlayLines.back().m_Color = thiscolor; 1131 SimRender::ConstructLineOnGround(GetSimContext(), c, m_DebugOverlayLines.back(), true); 1132 } 1133 } 899 1134 900 1135 // Draw the min range circle 901 1136 if (!q.minRange.IsZero()) -
source/simulation2/components/ICmpRangeManager.cpp
36 36 BEGIN_INTERFACE_WRAPPER(RangeManager) 37 37 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) 38 38 DEFINE_INTERFACE_METHOD_6("CreateActiveQuery", ICmpRangeManager::tag_t, ICmpRangeManager, CreateActiveQuery, entity_id_t, entity_pos_t, entity_pos_t, std::vector<int>, int, u8) 39 DEFINE_INTERFACE_METHOD_6("CreateActiveParabolicQuery", ICmpRangeManager::tag_t, ICmpRangeManager, CreateActiveParabolicQuery, entity_id_t, entity_pos_t, entity_pos_t, std::vector<int>, int, u8) 39 40 DEFINE_INTERFACE_METHOD_1("DestroyActiveQuery", void, ICmpRangeManager, DestroyActiveQuery, ICmpRangeManager::tag_t) 40 41 DEFINE_INTERFACE_METHOD_1("EnableActiveQuery", void, ICmpRangeManager, EnableActiveQuery, ICmpRangeManager::tag_t) 41 42 DEFINE_INTERFACE_METHOD_1("DisableActiveQuery", void, ICmpRangeManager, DisableActiveQuery, ICmpRangeManager::tag_t) -
source/simulation2/components/ICmpRangeManager.h
102 102 virtual tag_t CreateActiveQuery(entity_id_t source, 103 103 entity_pos_t minRange, entity_pos_t maxRange, std::vector<int> owners, int requiredInterface, u8 flags) = 0; 104 104 105 /** 106 * Construct an active query of a paraboloic form around the unit. 107 * The query will be disabled by default. 108 * @param source the entity around which the range will be computed. 109 * @param minRange non-negative minimum horizontal distance in metres (inclusive). MinRange doesn't do parabolic checks. 110 * @param maxRange non-negative maximum distance in metres (inclusive) for units on the same elevation; 111 * or -1.0 to ignore distance. 112 * For units on a different elevation, a physical correct paraboloid with height=maxRange/2 above the unit is used to query them 113 * @param owners list of player IDs that matching entities may have; -1 matches entities with no owner. 114 * @param requiredInterface if non-zero, an interface ID that matching entities must implement. 115 * @param flags if a entity in range has one of the flags set it will show up. 116 * @return unique non-zero identifier of query. 117 */ 118 virtual tag_t CreateActiveParabolicQuery(entity_id_t source, 119 entity_pos_t minRange, entity_pos_t maxRange, std::vector<int> owners, int requiredInterface, u8 flags) = 0; 120 121 105 122 /** 106 123 * Destroy a query and clean up resources. This must be called when an entity no longer needs its 107 124 * query (e.g. when the entity is destroyed).