Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/modules/objects/triggers/Trigger.cc @ 12386

Last change on this file since 12386 was 11099, checked in by muemart, 9 years ago

Fix loads of doxygen warnings and other documentation issues

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