Ticket #1551: gate-close-2.patch
File gate-close-2.patch, 14.4 KB (added by , 12 years ago) |
---|
-
binaries/data/mods/public/simulation/components/Foundation.js
109 109 // Otherwise enable this obstruction so it blocks any further 110 110 // units, and continue building. 111 111 112 var collisions = cmpObstruction.Get ConstructionCollisions();112 var collisions = cmpObstruction.GetEntityCollisions(true, true); 113 113 if (collisions.length) 114 114 { 115 115 for each (var ent in collisions) -
binaries/data/mods/public/simulation/components/Gate.js
14 14 */ 15 15 Gate.prototype.Init = function() 16 16 { 17 this. units = [];17 this.allies = []; 18 18 this.opened = false; 19 19 this.locked = false; 20 20 }; … … 48 48 { 49 49 var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 50 50 var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 51 var cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(owner), IID_Player); 51 52 if (this.unitsQuery) 52 53 cmpRangeManager.DestroyActiveQuery(this.unitsQuery); 53 var players = []54 54 55 var numPlayers = cmpPlayerManager.GetNumPlayers(); 55 // Only allied units can make the gate open. 56 var players = []; 57 for (var i = 0; i < cmpPlayer.GetDiplomacy().length; ++i) 58 if (cmpPlayer.IsAlly(i)) 59 players.push(i); 56 60 57 // Ignore gaia units58 for (var i = 1; i < numPlayers; ++i)59 players.push(i);60 61 61 var range = this.GetPassRange(); 62 62 if (range > 0) 63 63 { … … 77 77 78 78 if (msg.added.length > 0) 79 79 for each (var entity in msg.added) 80 this. units.push(entity);80 this.allies.push(entity); 81 81 82 82 if (msg.removed.length > 0) 83 83 for each (var entity in msg.removed) 84 this. units.splice(this.units.indexOf(entity), 1);84 this.allies.splice(this.allies.indexOf(entity), 1); 85 85 86 86 this.OperateGate(); 87 87 }; … … 96 96 97 97 /** 98 98 * Attempt to open or close the gate. 99 * An ally unit must be in range to open the gate, but there must be100 * no units (including enemies) in range to close it again.99 * An ally must be in range to open the gate, but an unlocked gate will only close 100 * if there are no allies in range and no units are inside the gate's obstruction. 101 101 */ 102 102 Gate.prototype.OperateGate = function() 103 103 { 104 if (this.opened == true ) 104 // Cancel the closing-blocked timer if it's running. 105 if (this.timer) 105 106 { 106 // If no units are in range, close the gate107 if (this.units.length == 0)108 this.CloseGate();107 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 108 cmpTimer.CancelTimer(this.timer); 109 this.timer = undefined; 109 110 } 110 else 111 { 112 // If one units in range is owned by an ally, open the gate 113 for each (var ent in this.units) 114 { 115 if (IsOwnedByAllyOfEntity(this.entity, ent)) 116 { 117 this.OpenGate(); 118 break; 119 } 120 } 121 } 111 112 if (this.opened && (this.allies.length == 0 || this.locked)) 113 this.CloseGate(); 114 else if (!this.opened && this.allies.length) 115 this.OpenGate(); 122 116 }; 123 117 124 118 Gate.prototype.IsLocked = function() … … 141 135 return; 142 136 cmpObstruction.SetDisableBlockMovementPathfinding(false, false, 0); 143 137 } 138 else 139 this.OperateGate(); 144 140 145 141 // TODO: Possibly move the lock/unlock sounds to UI? Needs testing 146 142 PlaySound("gate_locked", this.entity); … … 157 153 return; 158 154 159 155 // Disable 'block pathfinding' 160 cmpObstruction.SetDisableBlockMovementPathfinding( false, true, 0);156 cmpObstruction.SetDisableBlockMovementPathfinding(this.opened, true, 0); 161 157 this.locked = false; 162 158 163 159 // TODO: Possibly move the lock/unlock sounds to UI? Needs testing … … 201 197 if (!cmpObstruction) 202 198 return; 203 199 200 // The gate can't be closed if there are entities colliding with it. 201 var collisions = cmpObstruction.GetEntityCollisions(false, true); 202 if (collisions.length) 203 { 204 if (!this.timer) 205 { 206 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 207 this.timer = cmpTimer.SetTimeout(this.entity, IID_Gate, "OperateGate", 500, {}); 208 } 209 return; 210 } 211 204 212 // If we ordered the gate to be locked, enable 'block movement' and 'block pathfinding' 205 213 if (this.locked) 206 214 cmpObstruction.SetDisableBlockMovementPathfinding(false, false, 0); -
source/simulation2/components/ICmpObstruction.cpp
24 24 BEGIN_INTERFACE_WRAPPER(Obstruction) 25 25 DEFINE_INTERFACE_METHOD_0("GetUnitRadius", entity_pos_t, ICmpObstruction, GetUnitRadius) 26 26 DEFINE_INTERFACE_METHOD_1("CheckFoundation", bool, ICmpObstruction, CheckFoundation, std::string) 27 DEFINE_INTERFACE_METHOD_ 0("GetConstructionCollisions", std::vector<entity_id_t>, ICmpObstruction, GetConstructionCollisions)27 DEFINE_INTERFACE_METHOD_2("GetEntityCollisions", std::vector<entity_id_t>, ICmpObstruction, GetEntityCollisions, bool, bool) 28 28 DEFINE_INTERFACE_METHOD_1("SetActive", void, ICmpObstruction, SetActive, bool) 29 29 DEFINE_INTERFACE_METHOD_3("SetDisableBlockMovementPathfinding", void, ICmpObstruction, SetDisableBlockMovementPathfinding, bool, bool, int32_t) 30 30 DEFINE_INTERFACE_METHOD_0("GetBlockMovementFlag", bool, ICmpObstruction, GetBlockMovementFlag) -
source/simulation2/components/ICmpObstruction.h
50 50 virtual bool CheckFoundation(std::string className) = 0; 51 51 52 52 /** 53 * Returns a list of entities that are colliding with this entity, and that54 * are set to block construction.53 * Returns a list of entities that are colliding with this entity, 54 * filtered depending on type of entities that are requested. 55 55 * @return vector of blocking entities 56 56 */ 57 virtual std::vector<entity_id_t> Get ConstructionCollisions() = 0;57 virtual std::vector<entity_id_t> GetEntityCollisions(bool checkStructures, bool checkUnits) = 0; 58 58 59 59 virtual void SetActive(bool active) = 0; 60 60 -
source/simulation2/components/ICmpObstructionManager.h
365 365 */ 366 366 class SkipControlGroupsRequireFlagObstructionFilter : public IObstructionTestFilter 367 367 { 368 bool m_Exclude; 368 369 entity_id_t m_Group; 369 370 entity_id_t m_Group2; 370 371 flags_t m_Mask; 371 372 372 373 public: 373 SkipControlGroupsRequireFlagObstructionFilter( entity_id_t group1, entity_id_t group2, flags_t mask) :374 m_ Group(group1), m_Group2(group2), m_Mask(mask)374 SkipControlGroupsRequireFlagObstructionFilter(bool exclude, entity_id_t group1, entity_id_t group2, flags_t mask) : 375 m_Exclude(exclude), m_Group(group1), m_Group2(group2), m_Mask(mask) 375 376 { 376 377 // the primary control group to filter out must be valid 377 378 ENSURE(m_Group != INVALID_ENTITY); … … 386 387 { 387 388 // To be included in the testing, a shape must have at least one of the flags in m_Mask set, and its 388 389 // primary control group must be valid and must equal neither our primary nor secondary control group. 389 bool includeInTesting = ((flags & m_Mask) != 0 && group != m_Group && group != m_Group2); 390 bool includeInTesting; 391 if (m_Exclude) 392 includeInTesting = (flags & m_Mask) == 0; 393 else 394 includeInTesting = (flags & m_Mask) != 0; 395 includeInTesting = (includeInTesting && group != m_Group && group != m_Group2); 390 396 391 397 // If the shape being tested has a valid secondary control group, exclude it from testing if it 392 398 // matches either our primary or secondary control group. -
source/simulation2/components/CCmpObstruction.cpp
492 492 // Ignore collisions within the same control group, or with other non-foundation-blocking shapes. 493 493 // Note that, since the control group for each entity defaults to the entity's ID, this is typically 494 494 // equivalent to only ignoring the entity's own shape and other non-foundation-blocking shapes. 495 SkipControlGroupsRequireFlagObstructionFilter filter( m_ControlGroup, m_ControlGroup2,495 SkipControlGroupsRequireFlagObstructionFilter filter(false, m_ControlGroup, m_ControlGroup2, 496 496 ICmpObstructionManager::FLAG_BLOCK_FOUNDATION); 497 497 498 498 if (m_Type == STATIC) … … 503 503 return cmpPathfinder->CheckBuildingPlacement(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, GetEntityId(), passClass); 504 504 } 505 505 506 virtual std::vector<entity_id_t> Get ConstructionCollisions()506 virtual std::vector<entity_id_t> GetEntityCollisions(bool checkStructures, bool checkUnits) 507 507 { 508 508 std::vector<entity_id_t> ret; 509 509 … … 523 523 // required precondition to use SkipControlGroupsRequireFlagObstructionFilter 524 524 if (m_ControlGroup == INVALID_ENTITY) 525 525 { 526 LOGERROR(L"[CmpObstruction] Cannot test for constructionobstructions; primary control group must be valid");526 LOGERROR(L"[CmpObstruction] Cannot test for unit obstructions; primary control group must be valid"); 527 527 return ret; 528 528 } 529 529 530 // Ignore collisions within the same control group, or with other non-construction-blocking shapes. 530 // Structures block movment, foundation, construction, pathfinding. 531 // Units only block movement and construction. 532 flags_t flags = 0; 533 bool invertMatch = false; 534 if (checkStructures && checkUnits) 535 flags = ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION; 536 else if (checkStructures) 537 flags = ICmpObstructionManager::FLAG_BLOCK_FOUNDATION; 538 else if (checkUnits) 539 { 540 // Matching is inverted as units block a subset of what structures do. 541 flags = ICmpObstructionManager::FLAG_BLOCK_FOUNDATION | ICmpObstructionManager::FLAG_BLOCK_PATHFINDING; 542 invertMatch = true; 543 } 544 545 // Ignore collisions within the same control group, or with other shapes that don't match the filter. 531 546 // Note that, since the control group for each entity defaults to the entity's ID, this is typically 532 // equivalent to only ignoring the entity's own shape and other non-construction-blocking shapes.533 SkipControlGroupsRequireFlagObstructionFilter filter( m_ControlGroup, m_ControlGroup2,534 ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION);547 // equivalent to only ignoring the entity's own shape and other shapes that don't match the filter. 548 SkipControlGroupsRequireFlagObstructionFilter filter(invertMatch, 549 m_ControlGroup, m_ControlGroup2, flags); 535 550 536 551 if (m_Type == STATIC) 537 552 cmpObstructionManager->TestStaticShape(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, &ret); -
source/simulation2/components/tests/test_ObstructionManager.h
282 282 // group, and shape 3 has the BLOCK_FOUNDATION flag (but not BLOCK_CONSTRUCTION), we should find only 283 283 // shape 3 in the result. 284 284 285 SkipControlGroupsRequireFlagObstructionFilter skipGroup1ReqFoundConstr( ent1g1, INVALID_ENTITY,285 SkipControlGroupsRequireFlagObstructionFilter skipGroup1ReqFoundConstr(false, ent1g1, INVALID_ENTITY, 286 286 ICmpObstructionManager::FLAG_BLOCK_FOUNDATION | ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION); 287 287 288 288 cmp->TestUnitShape(skipGroup1ReqFoundConstr, ent1x, ent1z, fixed::FromInt(10), &out); … … 299 299 // group). Despite shape 3 having at least one of the required flags set, it should now also be ignored, 300 300 // yielding an empty result set. 301 301 302 SkipControlGroupsRequireFlagObstructionFilter skipGroup1And3ReqFoundConstr( ent1g1, ent3g,302 SkipControlGroupsRequireFlagObstructionFilter skipGroup1And3ReqFoundConstr(false, ent1g1, ent3g, 303 303 ICmpObstructionManager::FLAG_BLOCK_FOUNDATION | ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION); 304 304 305 305 cmp->TestUnitShape(skipGroup1And3ReqFoundConstr, ent1x, ent1z, fixed::FromInt(10), &out); … … 314 314 // to be set. Since both shape 1 and shape 2 have at least one flag set and are both in a different control 315 315 // group, we should find them in the result. 316 316 317 SkipControlGroupsRequireFlagObstructionFilter skipGroup3RequireAnyFlag( ent3g, INVALID_ENTITY,317 SkipControlGroupsRequireFlagObstructionFilter skipGroup3RequireAnyFlag(false, ent3g, INVALID_ENTITY, 318 318 (ICmpObstructionManager::flags_t) -1); 319 319 320 320 cmp->TestUnitShape(skipGroup3RequireAnyFlag, ent1x, ent1z, fixed::FromInt(10), &out); … … 333 333 // impossible for shape 1 and shape 2 to have at least one of the required flags set, and shape 3 is excluded by 334 334 // virtue of the control group filtering, we should find an empty result. 335 335 336 SkipControlGroupsRequireFlagObstructionFilter skipGroup3RequireNoFlags( ent3g, INVALID_ENTITY, 0U);336 SkipControlGroupsRequireFlagObstructionFilter skipGroup3RequireNoFlags(false, ent3g, INVALID_ENTITY, 0U); 337 337 338 338 cmp->TestUnitShape(skipGroup3RequireNoFlags, ent1x, ent1z, fixed::FromInt(10), &out); 339 339 TS_ASSERT_EQUALS(0U, out.size()); … … 369 369 // Since neither shape 2 nor shape 3 are part of those control groups and both have at least one available flag set, 370 370 // the results should only those two shapes' entities. 371 371 372 SkipControlGroupsRequireFlagObstructionFilter skipGroup1SecAnd4SecRequireAny( ent1g2_new, ent4g2,372 SkipControlGroupsRequireFlagObstructionFilter skipGroup1SecAnd4SecRequireAny(false, ent1g2_new, ent4g2, 373 373 (ICmpObstructionManager::flags_t) -1); 374 374 375 375 cmp->TestUnitShape(skipGroup1SecAnd4SecRequireAny, ent1x, ent1z, fixed::FromInt(10), &out); … … 388 388 // any available flag to be set. (Note that the test above used shape 4's secondary control group). Results should 389 389 // remain the same. 390 390 391 SkipControlGroupsRequireFlagObstructionFilter skipGroup1SecAnd4PrimRequireAny( ent1g2_new, ent4g1,391 SkipControlGroupsRequireFlagObstructionFilter skipGroup1SecAnd4PrimRequireAny(false, ent1g2_new, ent4g1, 392 392 (ICmpObstructionManager::flags_t) -1); 393 393 394 394 cmp->TestUnitShape(skipGroup1SecAnd4PrimRequireAny, ent1x, ent1z, fixed::FromInt(10), &out);