Ticket #1551: gate-close.patch

File gate-close.patch, 13.5 KB (added by Deiz, 12 years ago)
  • binaries/data/mods/public/simulation/components/Gate.js

     
    1414 */
    1515Gate.prototype.Init = function()
    1616{
    17     this.units = [];
     17    this.allies = [];
    1818    this.opened = false;
    1919    this.locked = false;
    2020};
     
    4848{
    4949    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
    5050    var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager);
     51    var cmpPlayer = Engine.QueryInterface(cmpPlayerManager.GetPlayerByID(owner), IID_Player);
    5152    if (this.unitsQuery)
    5253        cmpRangeManager.DestroyActiveQuery(this.unitsQuery);
    53     var players = []
    5454
    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);
    5660
    57     // Ignore gaia units
    58     for (var i = 1; i < numPlayers; ++i)
    59         players.push(i);
    60 
    6161    var range = this.GetPassRange();
    6262    if (range > 0)
    6363    {
     
    7777
    7878    if (msg.added.length > 0)
    7979        for each (var entity in msg.added)
    80             this.units.push(entity);
     80            this.allies.push(entity);
    8181
    8282    if (msg.removed.length > 0)
    8383        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);
    8585
    8686    this.OperateGate();
    8787};
     
    9696
    9797/**
    9898 * Attempt to open or close the gate.
    99  * An ally unit must be in range to open the gate, but there must be
    100  *  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.
    101101 */
    102102Gate.prototype.OperateGate = function()
    103103{
    104     if (this.opened == true )
     104    // Cancel the closing-blocked timer if it's running.
     105    if (this.timer)
    105106    {
    106         // If no units are in range, close the gate
    107         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;
    109110    }
    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();
    122116};
    123117
    124118Gate.prototype.IsLocked = function()
     
    141135            return;
    142136        cmpObstruction.SetDisableBlockMovementPathfinding(false, false, 0);
    143137    }
     138    else
     139        this.OperateGate();
    144140
    145141    // TODO: Possibly move the lock/unlock sounds to UI? Needs testing
    146142    PlaySound("gate_locked", this.entity);
     
    157153        return;
    158154
    159155    // Disable 'block pathfinding'
    160     cmpObstruction.SetDisableBlockMovementPathfinding(false, true, 0);
     156    cmpObstruction.SetDisableBlockMovementPathfinding(this.opened, true, 0);
    161157    this.locked = false;
    162158
    163159    // TODO: Possibly move the lock/unlock sounds to UI? Needs testing
     
    201197    if (!cmpObstruction)
    202198        return;
    203199
     200    // The gate can't be closed if there are entities colliding with it.
     201    var collisions = cmpObstruction.GetStructureUnitCollisions();
     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
    204212    // If we ordered the gate to be locked, enable 'block movement' and 'block pathfinding'
    205213    if (this.locked)
    206214        cmpObstruction.SetDisableBlockMovementPathfinding(false, false, 0);
  • source/simulation2/components/CCmpObstruction.cpp

     
    492492        // Ignore collisions within the same control group, or with other non-foundation-blocking shapes.
    493493        // Note that, since the control group for each entity defaults to the entity's ID, this is typically
    494494        // 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,
    496496            ICmpObstructionManager::FLAG_BLOCK_FOUNDATION);
    497497
    498498        if (m_Type == STATIC)
     
    530530        // Ignore collisions within the same control group, or with other non-construction-blocking shapes.
    531531        // Note that, since the control group for each entity defaults to the entity's ID, this is typically
    532532        // equivalent to only ignoring the entity's own shape and other non-construction-blocking shapes.
    533         SkipControlGroupsRequireFlagObstructionFilter filter(m_ControlGroup, m_ControlGroup2,
     533        SkipControlGroupsRequireFlagObstructionFilter filter(false, m_ControlGroup, m_ControlGroup2,
    534534            ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION);
    535535
    536536        if (m_Type == STATIC)
     
    543543        return ret;
    544544    }
    545545
     546    virtual std::vector<entity_id_t> GetStructureUnitCollisions()
     547    {
     548        std::vector<entity_id_t> ret;
     549
     550        CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId());
     551        if (!cmpPosition)
     552            return ret; // error
     553
     554        if (!cmpPosition->IsInWorld())
     555            return ret; // no obstruction
     556
     557        CFixedVector2D pos = cmpPosition->GetPosition2D();
     558
     559        CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY);
     560        if (!cmpObstructionManager)
     561            return ret; // error
     562
     563        // required precondition to use SkipControlGroupsRequireFlagObstructionFilter
     564        if (m_ControlGroup == INVALID_ENTITY)
     565        {
     566            LOGERROR(L"[CmpObstruction] Cannot test for unit obstructions; primary control group must be valid");
     567            return ret;
     568        }
     569
     570        // Ignore collisions within the same control group, or with other non-construction-blocking shapes.
     571        // Note that, since the control group for each entity defaults to the entity's ID, this is typically
     572        // equivalent to only ignoring the entity's own shape and other non-construction-blocking shapes.
     573        SkipControlGroupsRequireFlagObstructionFilter filter(true, m_ControlGroup, m_ControlGroup2,
     574            ICmpObstructionManager::FLAG_BLOCK_FOUNDATION | ICmpObstructionManager::FLAG_BLOCK_PATHFINDING);
     575
     576        cmpObstructionManager->TestStaticShape(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, &ret);
     577   
     578        return ret;
     579    }
     580
    546581    virtual void SetMovingFlag(bool enabled)
    547582    {
    548583        m_Moving = enabled;
  • source/simulation2/components/ICmpObstructionManager.h

     
    365365 */
    366366class SkipControlGroupsRequireFlagObstructionFilter : public IObstructionTestFilter
    367367{
     368    bool m_Exclude;
    368369    entity_id_t m_Group;
    369370    entity_id_t m_Group2;
    370371    flags_t m_Mask;
    371372
    372373public:
    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)
    375376    {
    376377        // the primary control group to filter out must be valid
    377378        ENSURE(m_Group != INVALID_ENTITY);
     
    386387    {
    387388        // To be included in the testing, a shape must have at least one of the flags in m_Mask set, and its
    388389        // 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);
    390396
    391397        // If the shape being tested has a valid secondary control group, exclude it from testing if it
    392398        // matches either our primary or secondary control group.
  • source/simulation2/components/tests/test_ObstructionManager.h

     
    282282        // group, and shape 3 has the BLOCK_FOUNDATION flag (but not BLOCK_CONSTRUCTION), we should find only
    283283        // shape 3 in the result.
    284284
    285         SkipControlGroupsRequireFlagObstructionFilter skipGroup1ReqFoundConstr(ent1g1, INVALID_ENTITY,
     285        SkipControlGroupsRequireFlagObstructionFilter skipGroup1ReqFoundConstr(false, ent1g1, INVALID_ENTITY,
    286286            ICmpObstructionManager::FLAG_BLOCK_FOUNDATION | ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION);
    287287
    288288        cmp->TestUnitShape(skipGroup1ReqFoundConstr, ent1x, ent1z, fixed::FromInt(10), &out);
     
    299299        // group). Despite shape 3 having at least one of the required flags set, it should now also be ignored,
    300300        // yielding an empty result set.
    301301       
    302         SkipControlGroupsRequireFlagObstructionFilter skipGroup1And3ReqFoundConstr(ent1g1, ent3g,
     302        SkipControlGroupsRequireFlagObstructionFilter skipGroup1And3ReqFoundConstr(false, ent1g1, ent3g,
    303303            ICmpObstructionManager::FLAG_BLOCK_FOUNDATION | ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION);
    304304
    305305        cmp->TestUnitShape(skipGroup1And3ReqFoundConstr, ent1x, ent1z, fixed::FromInt(10), &out);
     
    314314        // to be set. Since both shape 1 and shape 2 have at least one flag set and are both in a different control
    315315        // group, we should find them in the result.
    316316       
    317         SkipControlGroupsRequireFlagObstructionFilter skipGroup3RequireAnyFlag(ent3g, INVALID_ENTITY,
     317        SkipControlGroupsRequireFlagObstructionFilter skipGroup3RequireAnyFlag(false, ent3g, INVALID_ENTITY,
    318318            (ICmpObstructionManager::flags_t) -1);
    319319
    320320        cmp->TestUnitShape(skipGroup3RequireAnyFlag, ent1x, ent1z, fixed::FromInt(10), &out);
     
    333333        // impossible for shape 1 and shape 2 to have at least one of the required flags set, and shape 3 is excluded by
    334334        // virtue of the control group filtering, we should find an empty result.
    335335
    336         SkipControlGroupsRequireFlagObstructionFilter skipGroup3RequireNoFlags(ent3g, INVALID_ENTITY, 0U);
     336        SkipControlGroupsRequireFlagObstructionFilter skipGroup3RequireNoFlags(false, ent3g, INVALID_ENTITY, 0U);
    337337
    338338        cmp->TestUnitShape(skipGroup3RequireNoFlags, ent1x, ent1z, fixed::FromInt(10), &out);
    339339        TS_ASSERT_EQUALS(0U, out.size());
     
    369369        // Since neither shape 2 nor shape 3 are part of those control groups and both have at least one available flag set,
    370370        // the results should only those two shapes' entities.
    371371
    372         SkipControlGroupsRequireFlagObstructionFilter skipGroup1SecAnd4SecRequireAny(ent1g2_new, ent4g2,
     372        SkipControlGroupsRequireFlagObstructionFilter skipGroup1SecAnd4SecRequireAny(false, ent1g2_new, ent4g2,
    373373            (ICmpObstructionManager::flags_t) -1);
    374374
    375375        cmp->TestUnitShape(skipGroup1SecAnd4SecRequireAny, ent1x, ent1z, fixed::FromInt(10), &out);
     
    388388        // any available flag to be set. (Note that the test above used shape 4's secondary control group). Results should
    389389        // remain the same.
    390390       
    391         SkipControlGroupsRequireFlagObstructionFilter skipGroup1SecAnd4PrimRequireAny(ent1g2_new, ent4g1,
     391        SkipControlGroupsRequireFlagObstructionFilter skipGroup1SecAnd4PrimRequireAny(false, ent1g2_new, ent4g1,
    392392            (ICmpObstructionManager::flags_t) -1);
    393393
    394394        cmp->TestUnitShape(skipGroup1SecAnd4PrimRequireAny, ent1x, ent1z, fixed::FromInt(10), &out);
  • source/simulation2/components/ICmpObstruction.h

     
    5656     */
    5757    virtual std::vector<entity_id_t> GetConstructionCollisions() = 0;
    5858
     59    /**
     60     * Returns a list of entities that are colliding with this entity, and
     61     * which are not set to block pathfinding or foundation placement.
     62     * @return vector of blocking entities
     63     */
     64    virtual std::vector<entity_id_t> GetStructureUnitCollisions() = 0;
     65
    5966    virtual void SetActive(bool active) = 0;
    6067
    6168    virtual void SetMovingFlag(bool enabled) = 0;
  • source/simulation2/components/ICmpObstruction.cpp

     
    2525DEFINE_INTERFACE_METHOD_0("GetUnitRadius", entity_pos_t, ICmpObstruction, GetUnitRadius)
    2626DEFINE_INTERFACE_METHOD_1("CheckFoundation", bool, ICmpObstruction, CheckFoundation, std::string)
    2727DEFINE_INTERFACE_METHOD_0("GetConstructionCollisions", std::vector<entity_id_t>, ICmpObstruction, GetConstructionCollisions)
     28DEFINE_INTERFACE_METHOD_0("GetStructureUnitCollisions", std::vector<entity_id_t>, ICmpObstruction, GetStructureUnitCollisions)
    2829DEFINE_INTERFACE_METHOD_1("SetActive", void, ICmpObstruction, SetActive, bool)
    2930DEFINE_INTERFACE_METHOD_3("SetDisableBlockMovementPathfinding", void, ICmpObstruction, SetDisableBlockMovementPathfinding, bool, bool, int32_t)
    3031DEFINE_INTERFACE_METHOD_0("GetBlockMovementFlag", bool, ICmpObstruction, GetBlockMovementFlag)