Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/presentation/src/modules/objects/triggers/DistanceTrigger.cc @ 8667

Last change on this file since 8667 was 8667, checked in by dafrick, 13 years ago

Possible fix for segfaults due to player being NULL.

  • Property svn:eol-style set to native
File size: 10.6 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 *      Benjamin Knecht
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30    @file DistanceTrigger.cc
31    @brief Implementation of the DistanceTrigger class.
32    @ingroup NormalTrigger
33*/
34
35#include "DistanceTrigger.h"
36
37#include "core/CoreIncludes.h"
38#include "core/XMLPort.h"
39
40#include "worldentities/pawns/Pawn.h"
41
42#include "DistanceTriggerBeacon.h"
43
44namespace orxonox
45{
46
47    /*static*/ const std::string DistanceTrigger::beaconModeOff_s = "off";
48    /*static*/ const std::string DistanceTrigger::beaconModeIdentify_s = "identify";
49    /*static*/ const std::string DistanceTrigger::beaconModeExlcude_s = "exclude";
50
51    CreateFactory(DistanceTrigger);
52
53    /**
54    @brief
55        Constructor. Registers and initializes the object.
56    @param creator
57        The creator of this trigger.
58    */
59    DistanceTrigger::DistanceTrigger(BaseObject* creator) : Trigger(creator), beaconMask_(NULL)
60    {
61        RegisterObject(DistanceTrigger);
62
63        this->distance_ = 100;
64        this->targetMask_.exclude(Class(BaseObject));
65        this->targetName_ = "";
66    }
67
68    /**
69    @brief
70        Destructor.
71    */
72    DistanceTrigger::~DistanceTrigger()
73    {
74        // Delete the beacon mask if it exists.
75        if(this->beaconMask_ != NULL)
76            delete this->beaconMask_;
77    }
78
79    /**
80    @brief
81        Method for creating a DistanceTrigger object through XML.
82    */
83    void DistanceTrigger::XMLPort(Element& xmlelement, XMLPort::Mode mode)
84    {
85        SUPER(DistanceTrigger, XMLPort, xmlelement, mode);
86
87        XMLPortParam(DistanceTrigger, "distance", setDistance, getDistance, xmlelement, mode).defaultValues(100.0f);
88        XMLPortParamLoadOnly(DistanceTrigger, "target", addTarget, xmlelement, mode).defaultValues("Pawn");
89        XMLPortParam(DistanceTrigger, "beaconMode", setBeaconMode, getBeaconMode, xmlelement, mode);
90        XMLPortParam(DistanceTrigger, "targetname", setTargetName, getTargetName, xmlelement, mode);
91    }
92
93    /**
94    @brief
95        Add some target to the DistanceTrigger.
96    @param targetStr
97        The target class name as a string.
98    */
99    void DistanceTrigger::addTarget(const std::string& targetStr)
100    {
101        Identifier* targetId = ClassByString(targetStr);
102
103        // Checks whether the target is (or is derived from) a Pawn and if so set the PlayerTrigger aspect of this trigger to be for the player, meaning, that from this Trigger one can derive the Pawn that caused it to trigger.
104        Identifier* pawnId = Class(Pawn);
105        if(targetId->isA(pawnId))
106            this->setForPlayer(true);
107
108        if (targetId == NULL)
109        {
110            COUT(1) << "Error: \"" << targetStr << "\" is not a valid class name to include in ClassTreeMask (in " << this->getName() << ", class " << this->getIdentifier()->getName() << ')' << std::endl;
111            return;
112        }
113
114        // Add the target to the target mask.
115        this->targetMask_.include(targetId);
116
117        // The DistanceTrigger shouldn't react to itself or other triggers.
118        this->targetMask_.exclude(Class(TriggerBase), true);
119
120        // We only want WorldEntities (since only they have a position)
121        ClassTreeMask WEMask;
122        WEMask.include(Class(WorldEntity));
123        this->targetMask_ *= WEMask;
124
125        this->notifyMaskUpdate(); // Inform interested parties that the target mask has been updated.
126    }
127
128    /**
129    @brief
130        Remove some target from the DistanceTrigger.
131    @param targetStr
132        The target class name as a string.
133    */
134    void DistanceTrigger::removeTarget(const std::string& targetStr)
135    {
136        Identifier* targetId = ClassByString(targetStr);
137        this->targetMask_.exclude(targetId);
138    }
139
140    /**
141    @brief
142        Check, whether there are entities that are targets of this DistanceTrigger in its range.
143    @return
144        Returns true if there are valid entities in its range.
145    */
146    bool DistanceTrigger::checkDistance()
147    {
148        // Check whether there is a cached object, it still exists and whether it is still in range, if so nothing further needs to be done.
149        if(this->cache_.get() != NULL)
150        {
151            if((this->cache_.get()->getWorldPosition() - this->getWorldPosition()).length() < this->distance_)
152                return true;
153            else
154                this->cache_.reset();
155        }
156       
157        // Check for new objects that are in range
158        ClassTreeMask targetMask = this->targetMask_;
159        // If we are in identify-mode another target mask has to be applies to find the DistanceTriggerBeacons.
160        if(this->beaconMode_ == distanceTriggerBeaconMode::identify)
161            targetMask = *this->beaconMask_;
162
163        // Iterate through all objects that are targets of the DistanceTrigger.
164        for (ClassTreeMaskObjectIterator it = targetMask.begin(); it != targetMask.end(); ++it)
165        {
166            WorldEntity* entity = static_cast<WorldEntity*>(*it);
167
168            // If the DistanceTrigger is in identify-mode and the DistanceTriggerBeacon attached to the object has the wrong name we ignore it.
169            if(this->beaconMode_ == distanceTriggerBeaconMode::identify)
170            {
171                if(entity->getName() != this->targetName_)
172                    continue;
173                // If the object, the DistanceTriggerBeacon is attached to, is not a target of this DistanceMultiTrigger.
174                else if(this->targetMask_.isExcluded(entity->getParent()->getIdentifier()))
175                    continue;
176            }
177
178            // If the DistanceTrigger is in exclude mode and the DistanceTriggerBeacon attached to the object has the right name, we ignore it.
179            if(this->beaconMode_ == distanceTriggerBeaconMode::exclude)
180            {
181
182                const std::set<WorldEntity*> attached = entity->getAttachedObjects();
183                bool found = false;
184                for(std::set<WorldEntity*>::const_iterator it = attached.begin(); it != attached.end(); it++)
185                {
186                    if((*it)->isA(ClassIdentifier<DistanceTriggerBeacon>::getIdentifier()) && static_cast<DistanceTriggerBeacon*>(*it)->getName() == this->targetName_)
187                    {
188                        found = true;
189                        break;
190                    }
191                }
192                if(found)
193                    continue;
194            }
195
196            // Check if the entity is in range.
197            Vector3 distanceVec = entity->getWorldPosition() - this->getWorldPosition();
198            if (distanceVec.length() < this->distance_)
199            {
200                // If the target is a player (resp. is a, or is derived from a, Pawn) the triggeringPlayer is set to the target entity.
201                if(this->isForPlayer())
202                {
203                    // Change the entity to the parent of the DistanceTriggerBeacon (if in identify-mode), which is the entity to which the beacon is attached.
204                    if(this->beaconMode_ == distanceTriggerBeaconMode::identify)
205                        entity = entity->getParent();
206
207                    Pawn* pawn = orxonox_cast<Pawn*>(entity);
208                    if(pawn != NULL)
209                        this->setTriggeringPawn(pawn);
210                    else
211                        CCOUT(2) << "Pawn was NULL." << endl;
212                }
213               
214                // Add the entity to the cache.
215                this->cache_ = WeakPtr<WorldEntity>(entity);
216
217                return true;
218            }
219        }
220
221        return false;
222    }
223
224    /**
225    @brief
226        Set the beacon mode.
227    @param mode
228        The mode as an enum.
229    */
230    void DistanceTrigger::setBeaconModeDirect(distanceTriggerBeaconMode::Value mode)
231    {
232        this->beaconMode_ = mode;
233        if(this->beaconMode_ == distanceTriggerBeaconMode::identify && this->beaconMask_ == NULL)
234        {
235            this->beaconMask_ = new ClassTreeMask();
236            this->beaconMask_->exclude(Class(BaseObject));
237            this->beaconMask_->include(Class(DistanceTriggerBeacon));
238        }
239    }
240
241    /**
242    @brief
243        Get the beacon mode.
244    @return
245        Returns the mode as a string.
246    */
247    const std::string& DistanceTrigger::getBeaconMode(void) const
248    {
249        switch(this->getBeaconModeDirect())
250        {
251            case distanceTriggerBeaconMode::off :
252                return DistanceTrigger::beaconModeOff_s;
253            case distanceTriggerBeaconMode::identify:
254                return DistanceTrigger::beaconModeIdentify_s;
255            case distanceTriggerBeaconMode::exclude:
256                return DistanceTrigger::beaconModeExlcude_s;
257            default :
258                assert(0); // This is impossible.
259                return BLANKSTRING;
260        }
261    }
262
263    /**
264    @brief
265        Set the beacon mode.
266    @param mode
267        The mode as a string.
268    */
269    void DistanceTrigger::setBeaconMode(const std::string& mode)
270    {
271        if(mode == DistanceTrigger::beaconModeOff_s)
272            this->setBeaconModeDirect(distanceTriggerBeaconMode::off);
273        else if(mode == DistanceTrigger::beaconModeIdentify_s)
274            this->setBeaconModeDirect(distanceTriggerBeaconMode::identify);
275        else if(mode == DistanceTrigger::beaconModeExlcude_s)
276            this->setBeaconModeDirect(distanceTriggerBeaconMode::exclude);
277        else
278            COUT(1) << "Invalid beacon mode in DistanceTrigger." << endl;
279    }
280
281    /**
282    @brief
283        Check whether the DistanceTrigger is triggered.
284        It is triggered if it is triggered according only to its mode (i.e. its sub-triggers) and if a target is in range.
285    @param mode
286        The mode for which it is tested, whether the DistanceTrigger is triggered.
287    @return
288        Returns true if it is triggered ,false if not.
289    */
290    bool DistanceTrigger::isTriggered(TriggerMode::Value mode)
291    {
292        if (Trigger::isTriggered(mode))
293            return checkDistance();
294        else
295            return false;
296    }
297}
Note: See TracBrowser for help on using the repository browser.