Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core7/src/modules/objects/triggers/DistanceTrigger.cc @ 10328

Last change on this file since 10328 was 9667, checked in by landauf, 11 years ago

merged core6 back to trunk

  • Property svn:eol-style set to native
File size: 10.4 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    RegisterClass(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(Context* context) : Trigger(context)
60    {
61        RegisterObject(DistanceTrigger);
62
63        this->distance_ = 100;
64        this->targetMask_.exclude(Class(BaseObject));
65        this->targetName_ = "";
66        this->beaconMask_.exclude(Class(BaseObject));
67        this->beaconMask_.include(Class(DistanceTriggerBeacon));
68    }
69
70    /**
71    @brief
72        Destructor.
73    */
74    DistanceTrigger::~DistanceTrigger()
75    {
76
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            orxout(internal_error, context::triggers) << "\"" << targetStr << "\" is not a valid class name to include in ClassTreeMask (in " << this->getName() << ", class " << this->getIdentifier()->getName() << ')' << 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                        orxout(internal_warning, context::triggers) << "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    }
234
235    /**
236    @brief
237        Get the beacon mode.
238    @return
239        Returns the mode as a string.
240    */
241    const std::string& DistanceTrigger::getBeaconMode(void) const
242    {
243        switch(this->getBeaconModeDirect())
244        {
245            case distanceTriggerBeaconMode::off :
246                return DistanceTrigger::beaconModeOff_s;
247            case distanceTriggerBeaconMode::identify:
248                return DistanceTrigger::beaconModeIdentify_s;
249            case distanceTriggerBeaconMode::exclude:
250                return DistanceTrigger::beaconModeExlcude_s;
251            default :
252                assert(0); // This is impossible.
253                return BLANKSTRING;
254        }
255    }
256
257    /**
258    @brief
259        Set the beacon mode.
260    @param mode
261        The mode as a string.
262    */
263    void DistanceTrigger::setBeaconMode(const std::string& mode)
264    {
265        if(mode == DistanceTrigger::beaconModeOff_s)
266            this->setBeaconModeDirect(distanceTriggerBeaconMode::off);
267        else if(mode == DistanceTrigger::beaconModeIdentify_s)
268            this->setBeaconModeDirect(distanceTriggerBeaconMode::identify);
269        else if(mode == DistanceTrigger::beaconModeExlcude_s)
270            this->setBeaconModeDirect(distanceTriggerBeaconMode::exclude);
271        else
272            orxout(internal_error, context::triggers) << "Invalid beacon mode in DistanceTrigger." << endl;
273    }
274
275    /**
276    @brief
277        Check whether the DistanceTrigger is triggered.
278        It is triggered if it is triggered according only to its mode (i.e. its sub-triggers) and if a target is in range.
279    @param mode
280        The mode for which it is tested, whether the DistanceTrigger is triggered.
281    @return
282        Returns true if it is triggered ,false if not.
283    */
284    bool DistanceTrigger::isTriggered(TriggerMode::Value mode)
285    {
286        if (Trigger::isTriggered(mode))
287            return checkDistance();
288        else
289            return false;
290    }
291}
Note: See TracBrowser for help on using the repository browser.