Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/tutoriallevel3/src/modules/objects/triggers/DistanceMultiTrigger.cc @ 8452

Last change on this file since 8452 was 8213, checked in by dafrick, 14 years ago

Adding changes made to DistanceTrigger also in trunk.
Also documenting trigger.

  • Property svn:eol-style set to native
File size: 11.3 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Damian 'Mozork' Frick
24 *   Co-authors:
25 *      ...
26 *
27*/
28
29/**
30    @file DistanceMultiTrigger.cc
31    @brief Implementation of the DistanceMultiTrigger class.
32    @ingroup MultiTrigger
33*/
34
35#include "DistanceMultiTrigger.h"
36
37#include "core/CoreIncludes.h"
38#include "core/XMLPort.h"
39
40#include "DistanceTriggerBeacon.h"
41
42namespace orxonox
43{
44
45    /*static*/ const std::string DistanceMultiTrigger::beaconModeOff_s = "off";
46    /*static*/ const std::string DistanceMultiTrigger::beaconModeIdentify_s = "identify";
47    /*static*/ const std::string DistanceMultiTrigger::beaconModeExlcude_s = "exclude";
48   
49    CreateFactory(DistanceMultiTrigger);
50
51    /**
52    @brief
53        Default Constructor. Registers the object and initializes default values.
54    */
55    DistanceMultiTrigger::DistanceMultiTrigger(BaseObject* creator) : MultiTrigger(creator), beaconMask_(NULL)
56    {
57        RegisterObject(DistanceMultiTrigger);
58
59        this->distance_ = 100.0f;
60        this->setBeaconModeDirect(distanceMultiTriggerBeaconMode::off);
61        this->targetName_ = "";
62    }
63
64    /**
65    @brief
66        Destructor.
67    */
68    DistanceMultiTrigger::~DistanceMultiTrigger()
69    {
70        if(this->beaconMask_ != NULL)
71            delete this->beaconMask_;
72    }
73
74    /**
75    @brief
76        Method for creating a DistanceMultiTrigger object through XML.
77    */
78    void DistanceMultiTrigger::XMLPort(Element& xmlelement, XMLPort::Mode mode)
79    {
80        SUPER(DistanceMultiTrigger, XMLPort, xmlelement, mode);
81
82        XMLPortParam(DistanceMultiTrigger, "distance", setDistance, getDistance, xmlelement, mode);
83        XMLPortParam(DistanceMultiTrigger, "beaconMode", setBeaconMode, getBeaconMode, xmlelement, mode);
84        XMLPortParam(DistanceMultiTrigger, "targetname", setTargetName, getTargetName, xmlelement, mode);
85    }
86
87    /**
88    @brief
89        This method is called by the MultiTrigger to get information about new trigger events that need to be looked at.
90
91        In this implementation we iterate through all possible objects and check whether the fact that they are in range or not has changed and fire and hand a state ofer to the MultiTrigger if so.
92    @return
93        Returns a pointer to a queue of MultiTriggerState pointers, containing all the necessary information to decide whether these states should indeed become new states of the MultiTrigger.
94    */
95    std::queue<MultiTriggerState*>* DistanceMultiTrigger::letTrigger(void)
96    {
97
98        std::queue<MultiTriggerState*>* queue = NULL;
99
100        // Check for objects that were in range but no longer are. Iterate through all objects, that are in range.
101        for(std::map<WorldEntity*, WeakPtr<WorldEntity>* >::iterator it = this->range_.begin(); it != this->range_.end(); )
102        {
103            WorldEntity* entity = it->second->get();
104            WorldEntity* key = it->first;
105            it++; // Incrementing the iterator in advance, since we don't need the current anymore and we potentially are going to delete the current element thus invalidating the iterator.
106            // If the entity no longer exists.
107            if(entity == NULL)
108            {
109                this->removeFromRange(key);
110                continue;
111            }
112
113            Vector3 distanceVec = entity->getWorldPosition() - this->getWorldPosition();
114            // If the object is no longer in range.
115            if (distanceVec.length() > this->distance_)
116            {
117                // If for some reason the entity could not be removed.
118                if(!this->removeFromRange(key))
119                    continue;
120
121                // If no queue has been created, yet.
122                if(queue == NULL)
123                    queue = new std::queue<MultiTriggerState*>();
124
125                // Create a state and append it to the queue.
126                MultiTriggerState* state = new MultiTriggerState;
127                state->bTriggered = false; // Because the entity went out of range.
128                state->originator = entity;
129                queue->push(state);
130            }
131        }
132
133        // Check for new objects that are in range
134        ClassTreeMask targetMask = this->getTargetMask();
135        // If we are in identify-mode another target mask has to be applies to find the DistanceTriggerBeacons.
136        if(this->beaconMode_ == distanceMultiTriggerBeaconMode::identify)
137            targetMask = *this->beaconMask_;
138
139        // Iterate through all objects that are targets of the DistanceMultiTrigger.
140        for(ClassTreeMaskObjectIterator it = targetMask.begin(); it != targetMask.end(); ++it)
141        {
142            WorldEntity* entity = static_cast<WorldEntity*>(*it);
143
144            // If the DistanceMultiTrigger is in identify-mode and the DistanceTriggerBeacon attached to the object has the wrong name we ignore it.
145            if(this->beaconMode_ == distanceMultiTriggerBeaconMode::identify)
146            {
147                if(entity->getName() != this->targetName_)
148                    continue;
149                // If the object, the DistanceTriggerBeacon is attached to, is not a target of this DistanceMultiTrigger.
150                else if(this->getTargetMask().isExcluded(entity->getParent()->getIdentifier()))
151                    continue;
152            }
153           
154            // If the DistanceMultiTrigger is in exclude mode and the DistanceTriggerBeacon attached to the object has the right name, we ignore it.
155            if(this->beaconMode_ == distanceMultiTriggerBeaconMode::exclude)
156            {
157               
158                const std::set<WorldEntity*> attached = entity->getAttachedObjects();
159                bool found = false;
160                for(std::set<WorldEntity*>::const_iterator it = attached.begin(); it != attached.end(); it++)
161                {
162                    if((*it)->isA(ClassIdentifier<DistanceTriggerBeacon>::getIdentifier()) && static_cast<DistanceTriggerBeacon*>(*it)->getName() == this->targetName_)
163                    {
164                        found = true;
165                        break;
166                    }
167                }
168                if(found)
169                    continue;
170            }
171
172            Vector3 distanceVec = entity->getWorldPosition() - this->getWorldPosition();
173            // If the object is in range.
174            if (distanceVec.length() <= this->distance_)
175            {
176                // Add the object to the objects that are in range.
177                // Objects that already are in range are not added twice, because in a map (this->range_) each key can only exist once and thus addToRange() will reject all attempts of duplicate entries.
178                if(!this->addToRange(entity))
179                    continue;
180
181                // Change the entity to the parent of the DistanceTriggerBeacon (if in identify-mode), which is the entity to which the beacon is attached.
182                if(this->beaconMode_ == distanceMultiTriggerBeaconMode::identify)
183                    entity = entity->getParent();
184
185                // If no queue has been created, yet.
186                if(queue == NULL)
187                    queue = new std::queue<MultiTriggerState*>();
188
189                // Create a state and append it to the queue.
190                MultiTriggerState* state = new MultiTriggerState;
191                state->bTriggered = true; // Because the entity came into range.
192                state->originator = entity;
193                queue->push(state);
194            }
195        }
196
197        return queue;
198    }
199   
200    /**
201    @brief
202        Set the beacon mode.
203    @param mode
204        The mode as an enum.
205    */
206    void DistanceMultiTrigger::setBeaconModeDirect(distanceMultiTriggerBeaconMode::Value mode)
207    {
208        this->beaconMode_ = mode;
209        if(this->beaconMode_ == distanceMultiTriggerBeaconMode::identify && this->beaconMask_ == NULL)
210        {
211            this->beaconMask_ = new ClassTreeMask();
212            this->beaconMask_->exclude(Class(BaseObject));
213            this->beaconMask_->include(Class(DistanceTriggerBeacon));
214        }
215    }
216   
217    /**
218    @brief
219        Get the beacon mode.
220    @return
221        Returns the mode as a string.
222    */
223    const std::string& DistanceMultiTrigger::getBeaconMode(void) const
224    {
225        switch(this->getBeaconModeDirect())
226        {
227            case distanceMultiTriggerBeaconMode::off :
228                return DistanceMultiTrigger::beaconModeOff_s;
229            case distanceMultiTriggerBeaconMode::identify:
230                return DistanceMultiTrigger::beaconModeIdentify_s;
231            case distanceMultiTriggerBeaconMode::exclude:
232                return DistanceMultiTrigger::beaconModeExlcude_s;
233            default :
234                assert(0); // This is impossible.
235                return BLANKSTRING;
236        }
237    }
238   
239    /**
240    @brief
241        Set the beacon mode.
242    @param mode
243        The mode as a string.
244    */
245    void DistanceMultiTrigger::setBeaconMode(const std::string& mode)
246    {
247        if(mode == DistanceMultiTrigger::beaconModeOff_s)
248            this->setBeaconModeDirect(distanceMultiTriggerBeaconMode::off);
249        else if(mode == DistanceMultiTrigger::beaconModeIdentify_s)
250            this->setBeaconModeDirect(distanceMultiTriggerBeaconMode::identify);
251        else if(mode == DistanceMultiTrigger::beaconModeExlcude_s)
252            this->setBeaconModeDirect(distanceMultiTriggerBeaconMode::exclude);
253        else
254            COUT(1) << "Invalid beacon mode in DistanceMultiTrigger." << endl;
255    }
256
257    /**
258    @brief
259        Add a given entity to the entities, that currently are in range of the DistanceMultiTrigger.
260    @param entity
261        A pointer to the entity.
262    @return
263        Returns true if successful, false if not.
264    */
265    bool DistanceMultiTrigger::addToRange(WorldEntity* entity)
266    {
267        WeakPtr<WorldEntity>* weakptr = new WeakPtr<WorldEntity>(entity);
268        std::pair<std::map<WorldEntity*, WeakPtr<WorldEntity>* >::iterator, bool> pair = this->range_.insert(std::pair<WorldEntity*, WeakPtr<WorldEntity>* >(entity, weakptr));
269
270        if(!pair.second)
271        {
272            delete weakptr;
273            return false;
274        }
275
276        return true;
277    }
278
279    /**
280    @brief
281        Remove a given entity from the set of entities, that currently are in range of the DistanceMultiTrigger.
282    @param entity
283        A pointer ot the entity.
284    @return
285        Returns true if successful.
286    */
287    bool DistanceMultiTrigger::removeFromRange(WorldEntity* entity)
288    {
289        WeakPtr<WorldEntity>* weakptr = this->range_.find(entity)->second;
290        bool erased = this->range_.erase(entity) > 0;
291        if(erased)
292            delete weakptr;
293        return erased;
294    }
295
296}
Note: See TracBrowser for help on using the repository browser.