Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/portals2/src/modules/objects/triggers/Trigger.cc @ 8740

Last change on this file since 8740 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: 12.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 Trigger.cc
31    @brief Implementation of the Trigger class.
32    @ingroup NormalTrigger
33*/
34
35#include "Trigger.h"
36
37#include "core/CoreIncludes.h"
38#include "core/GameMode.h"
39#include "core/XMLPort.h"
40#include "core/command/ConsoleCommand.h"
41
42#include "Scene.h"
43
44namespace orxonox
45{
46
47    SetConsoleCommand("Trigger", "debugFlares", &Trigger::debugFlares).defaultValues(false);
48
49    CreateFactory(Trigger);
50
51    /**
52    @brief
53        Constructor. Registers and initializes the object.
54    @param creator
55        The creator of the Trigger.
56    */
57    Trigger::Trigger(BaseObject* creator) : TriggerBase(creator)
58    {
59        RegisterObject(Trigger);
60
61        this->bActive_ = false;
62        this->bTriggered_ = false;
63        this->latestState_ = 0x0;
64
65        this->remainingTime_ = 0.0f;
66        this->timeSinceLastEvent_ = 0.0f;
67
68        // Set the debug billboard.
69        if (this->getScene() && GameMode::showsGraphics())
70        {
71            this->debugBillboard_.setBillboardSet(this->getScene()->getSceneManager(), "Examples/Flare", ColourValue(1.0, 0.0, 0.0), 1);
72            this->debugBillboard_.setVisible(false);
73
74            if (this->debugBillboard_.getBillboardSet())
75                this->attachOgreObject(this->debugBillboard_.getBillboardSet());
76        }
77
78        this->setSyncMode(0x0);
79    }
80
81    /**
82    @brief
83        Destructor.
84    */
85    Trigger::~Trigger()
86    {
87
88    }
89
90    /**
91    @brief
92        Method for creating a Trigger object through XML.
93    */
94    void Trigger::XMLPort(Element& xmlelement, XMLPort::Mode mode)
95    {
96        SUPER(Trigger, XMLPort, xmlelement, mode);
97    }
98
99    /**
100    @brief
101
102    @param dt
103        The time elapsed since last tick.
104    */
105    void Trigger::tick(float dt)
106    {
107        // If this is the first tick, announce, that the trigger is not triggered.
108        // This is needed, e.g. for an inverted trigger, that needs to announce at the beginning, that it is active.
109        if (this->bFirstTick_)
110        {
111            this->bFirstTick_ = false;
112            this->triggered(false);
113        }
114
115        // Check if the object is active (this is NOT Trigger::isActive()!)
116        // If the object is not active we do nothing.
117        if (!this->BaseObject::isActive())
118            return;
119
120        SUPER(Trigger, tick, dt);
121
122        // Apply the invert operation.
123        bool newTriggered = this->isTriggered() ^ this->getInvert();
124
125        // Check if new triggering event is really new. (i.e. if the previous triggering state is not the same as the current)
126        if ((this->latestState_ & 0x1) != newTriggered)
127        {
128            // Create new state
129            if (newTriggered)
130            {
131                this->latestState_ |= 1; // Set triggered bit to 1.
132                this->switchState(); // Toggle the activity of the trigger.
133            }
134            else
135            {
136                this->latestState_ &= 0xFE; // Set triggered bit to 0.
137                // If this trigger is not in switched-mode (i.e. it switches its activity only if it changes from not triggered to triggered and not the other way around), the activity of the trigger is toggled.
138                if (!this->getSwitch())
139                    this->switchState();
140            }
141        }
142
143        // If there is time remaining, i.e. there are states in the queue waiting to take effect.
144        if (this->remainingTime_ > 0.0)
145        {
146            // Discount the last tick time from the time remaining.
147            this->remainingTime_ -= dt;
148            // Increase the time since the last event (the time since the last state took effect), but only when actually waiting for a state in the queue
149            if (this->timeSinceLastEvent_ >= 0.0)
150                this->timeSinceLastEvent_ += dt;
151        }
152
153        // If the remaining time has run out and there are states in the queue waiting to take effect.
154        while (this->remainingTime_ <= 0.0 && this->stateChanges_.size() > 0)
155        {
156            // Get the state to take effect and apply it.
157            char newState = this->stateChanges_.front().second;
158            this->bTriggered_ = (newState & 0x1);
159            this->bActive_ = newState & 0x2;
160
161            // Fire a triggered (or un-triggered, depending on the activity) event.
162            this->triggered(this->bActive_);
163
164            // Remove the state that was just applied from the queue.
165            this->stateChanges_.pop();
166
167            // If there are still states in the queue, set the remaining time to the time of the next state to take effect.
168            if (this->stateChanges_.size() != 0)
169                this->remainingTime_ = this->stateChanges_.front().first;
170            // Else the time since the last event is set to the delay.
171            else
172                this->timeSinceLastEvent_ = this->getDelay();
173        }
174
175        // Set the color of the debug billboard according to the current state of the trigger.
176        if (this->bTriggered_ && this->bActive_)
177            this->setBillboardColour(ColourValue(0.5, 1.0, 0.0));
178        else if (!this->bTriggered_ && this->bActive_)
179            this->setBillboardColour(ColourValue(0.0, 1.0, 0.0));
180        else if (this->bTriggered_ && !this->bActive_)
181            this->setBillboardColour(ColourValue(1.0, 0.5, 0.0));
182        else
183            this->setBillboardColour(ColourValue(1.0, 0.0, 0.0));
184    }
185
186    /**
187    @brief
188        Fires an event with the input triggered state.
189    @param bIsTriggered
190        The triggered state.
191    */
192    void Trigger::triggered(bool bIsTriggered)
193    {
194        this->fireEvent(bIsTriggered);
195    }
196
197    /**
198    @brief
199        Check whether the Trigger should be triggered, given only its sub-triggers, given a specific mode.
200    @param mode
201        The Trigger mode. Specifies how the sub-triggers are combined and how they affect the Trigger.
202    @return
203        Returns true if the Trigger should be triggered and false if not.
204    */
205    bool Trigger::isTriggered(TriggerMode::Value mode)
206    {
207        // If the trigger has sub-triggers.
208        if (this->children_.size() > 0)
209        {
210            switch (mode)
211            {
212                case TriggerMode::EventTriggerAND:
213                    return checkAnd();
214                case TriggerMode::EventTriggerOR:
215                    return checkOr();
216                case TriggerMode::EventTriggerXOR:
217                    return checkXor();
218                default:
219                    return false;
220            }
221        }
222        // If the trigger has no sub-triggers, whether it is triggered should only depend on itself and nothing else, thus this returns true.
223        return true;
224    }
225
226    /**
227    @brief
228        Check whether all the sub-triggers of this Trigger are active.
229        This is in fact the conjunction (logical AND) of the activity of all its sub-triggers.
230    @return
231        Returns true if all the sub-triggers of this Trigger are active, false if at least one of them is not active.
232    */
233    bool Trigger::checkAnd()
234    {
235        // Iterate over all sub-triggers.
236        for (std::set<TriggerBase*>::iterator it = this->children_.begin(); it != this->children_.end(); ++it)
237        {
238            if (!(*it)->isActive())
239                return false;
240        }
241        return true;
242    }
243
244    /**
245    @brief
246        Check whether at least one of the sub-triggers of this Trigger is active.
247        This is in fact the disjunction (logical OR) of the activity of all its sub-triggers.
248    @return
249        Returns true if at least one of the sub-triggers of this Trigger is active, false if none of them is active.
250    */
251    bool Trigger::checkOr()
252    {
253        // Iterate over all sub-triggers.
254        for (std::set<TriggerBase*>::iterator it = this->children_.begin(); it != this->children_.end(); ++it)
255        {
256            if ((*it)->isActive())
257                return true;
258        }
259        return false;
260    }
261
262    /**
263    @brief
264        Check whether exactly one of the sub-triggers of this Trigger is active.
265        This is in fact the logical XOR of the activity of all its sub-triggers.
266    @return
267        Returns true if exactly one of the sub-triggers of this Trigger is active, false if none of them or two or more of them are active.
268    */
269    bool Trigger::checkXor()
270    {
271        bool test = false;
272        for (std::set<TriggerBase*>::iterator it = this->children_.begin(); it != this->children_.end(); ++it)
273        {
274            if (test && (*it)->isActive())
275                return false;
276            if ((*it)->isActive())
277                test = true;
278        }
279        return test;
280    }
281
282    /**
283    @brief
284        Switch (toggle) the activity of the Trigger.
285    @return
286        Returns true if the activity of the Trigger has changed. False if not.
287    */
288    bool Trigger::switchState()
289    {
290        // If the previous state was active and there are no remaining activations, but the trigger stays active.
291        // or if the previous state was inactive and there are no remaining activations.
292        // the activity is not switched.
293        if (( (this->latestState_ & 0x2) && this->getStayActive() && (this->remainingActivations_ <= 0))
294           || (!(this->latestState_ & 0x2)                        && (this->remainingActivations_ == 0)))
295            return false;
296        // Else the activity is switched.
297        else
298        {
299            this->latestState_ ^= 0x2; // Toggle activity bit.
300
301            // If the activity has switched to active, decrease the remaining activations.
302            if (this->latestState_ & 0x2 && this->remainingActivations_ > 0)
303                this->remainingActivations_--;
304
305            // Store the new state in the queue.
306            this->storeState();
307
308            return true;
309        }
310    }
311
312    /**
313    @brief
314        Stores the state in the queue.
315        The queue is a list of states that are waiting to take effect paired with the time it has to wait after its preceding state takes effect.
316    */
317    void Trigger::storeState()
318    {
319        // Put the state change into the queue.
320        this->stateChanges_.push(std::pair<float, char>(this->timeSinceLastEvent_, this->latestState_));
321        // Reset time since last event
322        this->timeSinceLastEvent_ = 0.0;
323
324        // If there is just one state in the queue. (i.e. the one that we just added), The remaining time is set to the time it takes for the next state to take effect.
325        if (this->stateChanges_.size() == 1)
326            this->remainingTime_ = this->stateChanges_.front().first;
327    }
328
329    /**
330    @brief
331        React to a change in delay.
332        Only newly arriving states are affected by a change in delay.
333    */
334    void Trigger::delayChanged(void)
335    {
336        this->timeSinceLastEvent_ = this->getDelay();
337    }
338
339    /**
340    @brief
341        Set the visibility of all debug billboards of all Triggers.
342    @param bVisible
343        The visibility the billboards are set to.
344    */
345    void Trigger::debugFlares(bool bVisible)
346    {
347        // Iterate over all Triggers.
348        for (ObjectList<Trigger>::iterator it = ObjectList<Trigger>::begin(); it != ObjectList<Trigger>::end(); ++it)
349            it->setVisible(bVisible);
350    }
351
352    /**
353    @brief
354        Set the colour of the debug billboard.
355    @param colour
356        The colour the billboard is set to.
357    */
358    void Trigger::setBillboardColour(const ColourValue& colour)
359    {
360        this->debugBillboard_.setColour(colour);
361    }
362
363    /**
364    @brief
365        React to a change of visibility of the trigger by adjusting the visibility of the debug billboards.
366    */
367    void Trigger::changedVisibility()
368    {
369        SUPER(Trigger, changedVisibility);
370
371        this->debugBillboard_.setVisible(this->isVisible());
372    }
373}
Note: See TracBrowser for help on using the repository browser.