Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/portals2/src/modules/objects/triggers/DistanceTrigger.cc @ 8536

Last change on this file since 8536 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: 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    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* player = orxonox_cast<Pawn*>(entity);
208                    this->setTriggeringPlayer(player);
209                }
210               
211                // Add the entity to the cache.
212                this->cache_ = WeakPtr<WorldEntity>(entity);
213
214                return true;
215            }
216        }
217
218        return false;
219    }
220
221    /**
222    @brief
223        Set the beacon mode.
224    @param mode
225        The mode as an enum.
226    */
227    void DistanceTrigger::setBeaconModeDirect(distanceTriggerBeaconMode::Value mode)
228    {
229        this->beaconMode_ = mode;
230        if(this->beaconMode_ == distanceTriggerBeaconMode::identify && this->beaconMask_ == NULL)
231        {
232            this->beaconMask_ = new ClassTreeMask();
233            this->beaconMask_->exclude(Class(BaseObject));
234            this->beaconMask_->include(Class(DistanceTriggerBeacon));
235        }
236    }
237
238    /**
239    @brief
240        Get the beacon mode.
241    @return
242        Returns the mode as a string.
243    */
244    const std::string& DistanceTrigger::getBeaconMode(void) const
245    {
246        switch(this->getBeaconModeDirect())
247        {
248            case distanceTriggerBeaconMode::off :
249                return DistanceTrigger::beaconModeOff_s;
250            case distanceTriggerBeaconMode::identify:
251                return DistanceTrigger::beaconModeIdentify_s;
252            case distanceTriggerBeaconMode::exclude:
253                return DistanceTrigger::beaconModeExlcude_s;
254            default :
255                assert(0); // This is impossible.
256                return BLANKSTRING;
257        }
258    }
259
260    /**
261    @brief
262        Set the beacon mode.
263    @param mode
264        The mode as a string.
265    */
266    void DistanceTrigger::setBeaconMode(const std::string& mode)
267    {
268        if(mode == DistanceTrigger::beaconModeOff_s)
269            this->setBeaconModeDirect(distanceTriggerBeaconMode::off);
270        else if(mode == DistanceTrigger::beaconModeIdentify_s)
271            this->setBeaconModeDirect(distanceTriggerBeaconMode::identify);
272        else if(mode == DistanceTrigger::beaconModeExlcude_s)
273            this->setBeaconModeDirect(distanceTriggerBeaconMode::exclude);
274        else
275            COUT(1) << "Invalid beacon mode in DistanceTrigger." << endl;
276    }
277
278    /**
279    @brief
280        Check whether the DistanceTrigger is triggered.
281        It is triggered if it is triggered according only to its mode (i.e. its sub-triggers) and if a target is in range.
282    @param
283        Returns true if it is triggered ,false if not.
284    */
285    bool DistanceTrigger::isTriggered(TriggerMode::Value mode)
286    {
287        if (Trigger::isTriggered(mode))
288            return checkDistance();
289        else
290            return false;
291    }
292}
Note: See TracBrowser for help on using the repository browser.