Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/output/src/modules/objects/triggers/DistanceMultiTrigger.cc @ 9215

Last change on this file since 9215 was 8811, checked in by landauf, 13 years ago

Replaced COUT() with orxout() in all modules. phew.

  • Property svn:eol-style set to native
File size: 11.0 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)
56    {
57        RegisterObject(DistanceMultiTrigger);
58
59        this->distance_ = 100.0f;
60        this->setBeaconModeDirect(distanceMultiTriggerBeaconMode::off);
61        this->targetName_ = "";
62        this->beaconMask_.exclude(Class(BaseObject));
63        this->beaconMask_.include(Class(DistanceTriggerBeacon));
64    }
65
66    /**
67    @brief
68        Destructor.
69    */
70    DistanceMultiTrigger::~DistanceMultiTrigger()
71    {
72
73    }
74
75    /**
76    @brief
77        Method for creating a DistanceMultiTrigger object through XML.
78    */
79    void DistanceMultiTrigger::XMLPort(Element& xmlelement, XMLPort::Mode mode)
80    {
81        SUPER(DistanceMultiTrigger, XMLPort, xmlelement, mode);
82
83        XMLPortParam(DistanceMultiTrigger, "distance", setDistance, getDistance, xmlelement, mode);
84        XMLPortParam(DistanceMultiTrigger, "beaconMode", setBeaconMode, getBeaconMode, xmlelement, mode);
85        XMLPortParam(DistanceMultiTrigger, "targetname", setTargetName, getTargetName, xmlelement, mode);
86    }
87
88    /**
89    @brief
90        This method is called by the MultiTrigger to get information about new trigger events that need to be looked at.
91
92        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.
93    @return
94        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.
95    */
96    std::queue<MultiTriggerState*>* DistanceMultiTrigger::letTrigger(void)
97    {
98
99        std::queue<MultiTriggerState*>* queue = NULL;
100
101        // Check for objects that were in range but no longer are. Iterate through all objects, that are in range.
102        for(std::map<WorldEntity*, WeakPtr<WorldEntity>* >::iterator it = this->range_.begin(); it != this->range_.end(); )
103        {
104            WorldEntity* entity = it->second->get();
105            WorldEntity* key = it->first;
106            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.
107            // If the entity no longer exists.
108            if(entity == NULL)
109            {
110                this->removeFromRange(key);
111                continue;
112            }
113
114            Vector3 distanceVec = entity->getWorldPosition() - this->getWorldPosition();
115            // If the object is no longer in range.
116            if (distanceVec.length() > this->distance_)
117            {
118                // If for some reason the entity could not be removed.
119                if(!this->removeFromRange(key))
120                    continue;
121
122                // If no queue has been created, yet.
123                if(queue == NULL)
124                    queue = new std::queue<MultiTriggerState*>();
125
126                // Create a state and append it to the queue.
127                MultiTriggerState* state = new MultiTriggerState;
128                state->bTriggered = false; // Because the entity went out of range.
129                state->originator = entity;
130                queue->push(state);
131            }
132        }
133
134        // Check for new objects that are in range
135        ClassTreeMask targetMask = this->getTargetMask();
136        // If we are in identify-mode another target mask has to be applies to find the DistanceTriggerBeacons.
137        if(this->beaconMode_ == distanceMultiTriggerBeaconMode::identify)
138            targetMask = this->beaconMask_;
139
140        // Iterate through all objects that are targets of the DistanceMultiTrigger.
141        for(ClassTreeMaskObjectIterator it = targetMask.begin(); it != targetMask.end(); ++it)
142        {
143            WorldEntity* entity = static_cast<WorldEntity*>(*it);
144
145            // If the DistanceMultiTrigger is in identify-mode and the DistanceTriggerBeacon attached to the object has the wrong name we ignore it.
146            if(this->beaconMode_ == distanceMultiTriggerBeaconMode::identify)
147            {
148                if(entity->getName() != this->targetName_)
149                    continue;
150                // If the object, the DistanceTriggerBeacon is attached to, is not a target of this DistanceMultiTrigger.
151                else if(this->getTargetMask().isExcluded(entity->getParent()->getIdentifier()))
152                    continue;
153            }
154           
155            // If the DistanceMultiTrigger is in exclude mode and the DistanceTriggerBeacon attached to the object has the right name, we ignore it.
156            if(this->beaconMode_ == distanceMultiTriggerBeaconMode::exclude)
157            {
158               
159                const std::set<WorldEntity*> attached = entity->getAttachedObjects();
160                bool found = false;
161                for(std::set<WorldEntity*>::const_iterator it = attached.begin(); it != attached.end(); it++)
162                {
163                    if((*it)->isA(ClassIdentifier<DistanceTriggerBeacon>::getIdentifier()) && static_cast<DistanceTriggerBeacon*>(*it)->getName() == this->targetName_)
164                    {
165                        found = true;
166                        break;
167                    }
168                }
169                if(found)
170                    continue;
171            }
172
173            Vector3 distanceVec = entity->getWorldPosition() - this->getWorldPosition();
174            // If the object is in range.
175            if (distanceVec.length() <= this->distance_)
176            {
177                // Add the object to the objects that are in range.
178                // 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.
179                if(!this->addToRange(entity))
180                    continue;
181
182                // Change the entity to the parent of the DistanceTriggerBeacon (if in identify-mode), which is the entity to which the beacon is attached.
183                if(this->beaconMode_ == distanceMultiTriggerBeaconMode::identify)
184                    entity = entity->getParent();
185
186                // If no queue has been created, yet.
187                if(queue == NULL)
188                    queue = new std::queue<MultiTriggerState*>();
189
190                // Create a state and append it to the queue.
191                MultiTriggerState* state = new MultiTriggerState;
192                state->bTriggered = true; // Because the entity came into range.
193                state->originator = entity;
194                queue->push(state);
195            }
196        }
197
198        return queue;
199    }
200   
201    /**
202    @brief
203        Set the beacon mode.
204    @param mode
205        The mode as an enum.
206    */
207    void DistanceMultiTrigger::setBeaconModeDirect(distanceMultiTriggerBeaconMode::Value mode)
208    {
209        this->beaconMode_ = mode;
210    }
211   
212    /**
213    @brief
214        Get the beacon mode.
215    @return
216        Returns the mode as a string.
217    */
218    const std::string& DistanceMultiTrigger::getBeaconMode(void) const
219    {
220        switch(this->getBeaconModeDirect())
221        {
222            case distanceMultiTriggerBeaconMode::off :
223                return DistanceMultiTrigger::beaconModeOff_s;
224            case distanceMultiTriggerBeaconMode::identify:
225                return DistanceMultiTrigger::beaconModeIdentify_s;
226            case distanceMultiTriggerBeaconMode::exclude:
227                return DistanceMultiTrigger::beaconModeExlcude_s;
228            default :
229                assert(0); // This is impossible.
230                return BLANKSTRING;
231        }
232    }
233   
234    /**
235    @brief
236        Set the beacon mode.
237    @param mode
238        The mode as a string.
239    */
240    void DistanceMultiTrigger::setBeaconMode(const std::string& mode)
241    {
242        if(mode == DistanceMultiTrigger::beaconModeOff_s)
243            this->setBeaconModeDirect(distanceMultiTriggerBeaconMode::off);
244        else if(mode == DistanceMultiTrigger::beaconModeIdentify_s)
245            this->setBeaconModeDirect(distanceMultiTriggerBeaconMode::identify);
246        else if(mode == DistanceMultiTrigger::beaconModeExlcude_s)
247            this->setBeaconModeDirect(distanceMultiTriggerBeaconMode::exclude);
248        else
249            orxout(internal_error, context::triggers) << "Invalid beacon mode in DistanceMultiTrigger." << endl;
250    }
251
252    /**
253    @brief
254        Add a given entity to the entities, that currently are in range of the DistanceMultiTrigger.
255    @param entity
256        A pointer to the entity.
257    @return
258        Returns true if successful, false if not.
259    */
260    bool DistanceMultiTrigger::addToRange(WorldEntity* entity)
261    {
262        WeakPtr<WorldEntity>* weakptr = new WeakPtr<WorldEntity>(entity);
263        std::pair<std::map<WorldEntity*, WeakPtr<WorldEntity>* >::iterator, bool> pair = this->range_.insert(std::pair<WorldEntity*, WeakPtr<WorldEntity>* >(entity, weakptr));
264
265        if(!pair.second)
266        {
267            delete weakptr;
268            return false;
269        }
270
271        return true;
272    }
273
274    /**
275    @brief
276        Remove a given entity from the set of entities, that currently are in range of the DistanceMultiTrigger.
277    @param entity
278        A pointer ot the entity.
279    @return
280        Returns true if successful.
281    */
282    bool DistanceMultiTrigger::removeFromRange(WorldEntity* entity)
283    {
284        WeakPtr<WorldEntity>* weakptr = this->range_.find(entity)->second;
285        bool erased = this->range_.erase(entity) > 0;
286        if(erased)
287            delete weakptr;
288        return erased;
289    }
290
291}
Note: See TracBrowser for help on using the repository browser.